"""
.. _planets_example:

3D Earth and Celestial Bodies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Plot the solar system in PyVista using datasets from the
:mod:`~pyvista.examples.planets` module.

This example is inspired by `planet3D-MATLAB
<https://github.com/tamaskis/planet3D-MATLAB>`_.

.. note::
   The purpose of this example is to demonstrate plotting celestial bodies and
   may lack astronomical precision. There may be inaccuracies in the
   representation, so please take care when reusing or repurposing this
   example.

   Please take a look at libraries like `astropy <https://www.astropy.org/>`_
   if you wish to use Python for astronomical calculations.

"""

import pyvista as pv
from pyvista import examples

# sphinx_gallery_start_ignore
# background images do not work in interactive plots currently
PYVISTA_GALLERY_FORCE_STATIC_IN_DOCUMENT = True
# sphinx_gallery_end_ignore

# %%
# Plot the Solar System with Stars in the Background
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# This section relies on calculations in `Visualizing Celestial Bodies in 3D
# <https://tamaskis.github.io/files/Visualizing_Celestial_Bodies_in_3D.pdf>`_.


# Light of the Sun.
light = pv.Light()
light.set_direction_angle(30, -20)

# Load planets
mercury = examples.planets.load_planet(radius=2439.0)
mercury_texture = examples.planets.download_mercury_surface(texture=True)

venus = examples.planets.load_planet(radius=6052.0)
venus_texture = examples.planets.download_venus_surface(texture=True)

earth = examples.planets.load_planet(radius=6378.1)
earth_texture = examples.load_globe_texture()

mars = examples.planets.load_planet(radius=3397.2)
mars_texture = examples.planets.download_mars_surface(texture=True)

jupiter = examples.planets.load_planet(radius=71492.0)
jupiter_texture = examples.planets.download_jupiter_surface(texture=True)

saturn = examples.planets.load_planet(radius=60268.0)
saturn_texture = examples.planets.download_saturn_surface(texture=True)
# Saturn's rings range from 7000.0 km to 80000.0 km from the surface of the planet
inner = 60268.0 + 7000.0
outer = 60268.0 + 80000.0
saturn_rings = examples.planets.load_planet_rings(inner=inner, outer=outer)
saturn_rings_texture = examples.planets.download_saturn_rings(texture=True)

uranus = examples.planets.load_planet(radius=25559.0)
uranus_texture = examples.planets.download_uranus_surface(texture=True)

neptune = examples.planets.load_planet(radius=24764.0)
neptune_texture = examples.planets.download_neptune_surface(texture=True)

pluto = examples.planets.load_planet(radius=1151.0)
pluto_texture = examples.planets.download_pluto_surface(texture=True)

# Move planets to a nice position for the plotter. These numbers are not
# grounded in reality and are for demonstration purposes only.
mercury.translate((0.0, 0.0, 0.0), inplace=True)
venus.translate((-15000.0, 0.0, 0.0), inplace=True)
earth.translate((-30000.0, 0.0, 0.0), inplace=True)
mars.translate((-45000.0, 0.0, 0.0), inplace=True)
jupiter.translate((-150000.0, 0.0, 0.0), inplace=True)
saturn.translate((-400000.0, 0.0, 0.0), inplace=True)
saturn_rings.translate((-400000.0, 0.0, 0.0), inplace=True)
uranus.translate((-600000.0, 0.0, 0.0), inplace=True)
neptune.translate((-700000.0, 0.0, 0.0), inplace=True)

# Add planets to Plotter.
pl = pv.Plotter(lighting='none')
cubemap = examples.download_cubemap_space_4k()
_ = pl.add_actor(cubemap.to_skybox())
pl.set_environment_texture(cubemap, is_srgb=True, resample=1 / 64)
pl.add_light(light)
pl.add_mesh(mercury, texture=mercury_texture, smooth_shading=True)
pl.add_mesh(venus, texture=venus_texture, smooth_shading=True)
pl.add_mesh(earth, texture=earth_texture, smooth_shading=True)
pl.add_mesh(mars, texture=mars_texture, smooth_shading=True)
pl.add_mesh(jupiter, texture=jupiter_texture, smooth_shading=True)
pl.add_mesh(saturn, texture=saturn_texture, smooth_shading=True)
pl.add_mesh(saturn_rings, texture=saturn_rings_texture, smooth_shading=True)
pl.add_mesh(uranus, texture=uranus_texture, smooth_shading=True)
pl.add_mesh(neptune, texture=neptune_texture, smooth_shading=True)
pl.add_mesh(pluto, texture=pluto_texture, smooth_shading=True)
pl.show()


# %%
# Plot the Planets and their Textures
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Each planet here is in a different subplot. The planet's textures are from
# `Solar Textures <https://www.solarsystemscope.com/textures/>`_.

pl = pv.Plotter(shape=(3, 2))
pl.subplot(0, 0)
pl.add_text('Mercury')
pl.add_mesh(examples.planets.download_mercury_surface(), rgb=True)
pl.subplot(0, 1)
pl.add_mesh(mercury, texture=mercury_texture)
pl.subplot(1, 0)
pl.add_text('Venus')
pl.add_mesh(examples.planets.download_venus_surface(atmosphere=True), rgb=True)
pl.subplot(1, 1)
pl.add_mesh(venus, texture=venus_texture)
pl.subplot(2, 0)
pl.add_text('Mars')
pl.add_mesh(examples.planets.download_mars_surface(), rgb=True)
pl.subplot(2, 1)
pl.add_mesh(mars, texture=mars_texture)
pl.show(cpos='xy')


# %%
# Plot the Atmosphere and Surface of Venus
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Here we plot Venus with and without its atmosphere.

venus = examples.planets.load_planet(radius=6052.0)
atmosphere_texture = examples.planets.download_venus_surface(
    atmosphere=True, texture=True
)
surface_texture = examples.planets.download_venus_surface(atmosphere=False, texture=True)

pl = pv.Plotter(shape=(1, 2))
pl.subplot(0, 0)
pl.add_text('Venus Atmosphere')
pl.add_mesh(venus, texture=atmosphere_texture, smooth_shading=True)
pl.subplot(0, 1)
pl.add_text('Venus Surface')
pl.add_mesh(venus, texture=surface_texture, smooth_shading=True)
pl.link_views()
pl.show(cpos='xy')


# %%
# Plot the Earth and Prime Meridian
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Plot the prime meridian at 0° longitude.
# The prime meridian lies in the XZ plane on the +X side of Earth.

earth = examples.planets.load_planet(radius=6378.1)
earth_texture = examples.load_globe_texture()

# Slice Earth with the XZ plane to create the full meridian circle
meridian_circle = earth.slice('y')

# Keep the +X half of the meridian circle (0° longitude)
prime_meridian = meridian_circle.clip('x', origin=(0, 0, 0), invert=False)

pl = pv.Plotter()
pl.add_title('Prime Meridian of Earth', font_size=12)

pl.add_mesh(
    earth,
    texture=earth_texture,
    smooth_shading=True,
)
pl.add_mesh(
    prime_meridian,
    color='magenta',
    line_width=10,
    label='Prime Meridian',
)

pl.show_axes()
pl.show()
