Note
Go to the end to download the full example code.
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
import fury
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 = fury.window.Scene()
fury.data.fetch_viz_textures()
earth_file = fury.data.read_viz_textures("1_earth_16k.jpg")
earth_image = fury.io.load_image(earth_file)
earth_actor = fury.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()
.
fury.utils.rotate(earth_actor, rotation=(-90, 1, 0, 0))
fury.utils.rotate(earth_actor, rotation=(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 = fury.actor.sphere(centers, colors, radii=radii)
scene.add(sphere_actor)
Create some text actors to add to the scene indicating each location and its geographical coordinates.
nyc_actor = fury.actor.text_3d(
"New York City, New York\n40.7128° N, 74.0060° W",
position=(locationone[0] - 0.04, locationone[1], locationone[2] + 0.07),
color=fury.window.colors.white,
font_size=0.01,
)
paris_actor = fury.actor.text_3d(
"Paris, France\n48.8566° N, 2.3522° E",
position=(locationthree[0] - 0.04, locationthree[1], locationthree[2] - 0.07),
color=fury.window.colors.white,
font_size=0.01,
)
beijing_actor = fury.actor.text_3d(
"Beijing, China\n39.9042° N, 116.4074° E",
position=(locationtwo[0] - 0.06, locationtwo[1], locationtwo[2] - 0.07),
color=fury.window.colors.white,
font_size=0.01,
)
fury.utils.rotate(paris_actor, rotation=(85, 0, 1, 0))
fury.utils.rotate(beijing_actor, rotation=(180, 0, 1, 0))
fury.utils.rotate(nyc_actor, rotation=(5, 1, 0, 0))
Create a ShowManager object, which acts as the interface between the scene, the window and the interactor.
showm = fury.window.ShowManager(
scene=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()
fury.window.record(
scene=showm.scene, size=(900, 768), out_path="viz_earth_coordinates.png"
)