.. 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 <sphx_glr_download_auto_examples_01_introductory_viz_solar_system.py>`
        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-18

.. code-block:: Python


    import itertools

    import numpy as np

    import fury


.. GENERATED FROM PYTHON SOURCE LINES 19-20

Create a scene to start.

.. GENERATED FROM PYTHON SOURCE LINES 20-41

.. code-block:: Python


    scene = fury.window.Scene()

    # Create a panel and the start/pause buttons

    panel = fury.ui.Panel2D(size=(300, 100), color=(1, 1, 1), align="right")
    panel.center = (400, 50)

    pause_button = fury.ui.Button2D(
        icon_fnames=[("square", fury.data.read_viz_icons(fname="pause2.png"))]
    )
    start_button = fury.ui.Button2D(
        icon_fnames=[("square", fury.data.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 42-44

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

.. GENERATED FROM PYTHON SOURCE LINES 44-99

.. 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)},
    ]
    fury.data.fetch_viz_textures()


.. GENERATED FROM PYTHON SOURCE LINES 100-104

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 104-131

.. 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 = fury.data.read_viz_textures(planet_data["filename"])
        planet_image = fury.io.load_image(planet_file)
        planet_actor = fury.actor.texture_on_sphere(planet_image)
        planet_actor.SetPosition(planet_data["position"], 0, 0)
        if planet_data["filename"] != "8k_saturn_ring_alpha.png":
            fury.utils.rotate(planet_actor, rotation=(90, 1, 0, 0))
        planet_actor.SetScale(planet_data["scale"])
        scene.add(planet_actor)
        return planet_actor



.. GENERATED FROM PYTHON SOURCE LINES 132-135

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 135-150

.. 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 151-155

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 155-164

.. 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 165-169

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 169-182

.. 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 183-186

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 186-195

.. code-block:: Python



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



.. GENERATED FROM PYTHON SOURCE LINES 196-197

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

.. GENERATED FROM PYTHON SOURCE LINES 197-200

.. code-block:: Python


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


.. GENERATED FROM PYTHON SOURCE LINES 201-203

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

.. GENERATED FROM PYTHON SOURCE LINES 203-209

.. code-block:: Python


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


.. GENERATED FROM PYTHON SOURCE LINES 210-213

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 213-216

.. code-block:: Python


    counter = itertools.count()


.. GENERATED FROM PYTHON SOURCE LINES 217-219

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

.. GENERATED FROM PYTHON SOURCE LINES 219-227

.. 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 228-230

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

.. GENERATED FROM PYTHON SOURCE LINES 230-240

.. 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 241-246

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 246-274

.. 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 275-276

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

.. GENERATED FROM PYTHON SOURCE LINES 276-279

.. code-block:: Python


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


.. GENERATED FROM PYTHON SOURCE LINES 280-282

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 282-286

.. code-block:: Python


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


.. GENERATED FROM PYTHON SOURCE LINES 287-291

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 291-314

.. 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 315-316

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

.. GENERATED FROM PYTHON SOURCE LINES 316-330

.. 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 331-332

Watch the planets orbit the sun in your new animation!

.. GENERATED FROM PYTHON SOURCE LINES 332-340

.. code-block:: Python



    showm.add_timer_callback(True, 10, timer_callback)
    showm.start()

    fury.window.record(
        scene=showm.scene, size=(900, 768), out_path="viz_solar_system_animation.png"
    )


.. _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 <viz_solar_system.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: viz_solar_system.py <viz_solar_system.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: viz_solar_system.zip <viz_solar_system.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_