Earth sun.py
From GeoMod
To run the code, once you have VPython installed, you can either.
- Download this file: orbit_earth_sun16.py
- or, copy and paste the following code to a file (named "orbit_earth_sun16.py" for example) using your favorite text editor.
from visual import *
from visual.controls import *
from math import *
from Numeric import *
#from Scientific import *
# Program to demonstrate the effects Earth's orbit and revolution on day length, time and seasons
# Written by Lensyl Urbano
# Department of Earth Sciences
# University of Memphis
class camera_rotate:
"event details"
def __init__(self, st, ed, ang, ax):
self.start = st #event starttime
self.end = ed #event end time
self.angle = ang #angle of rotation in degrees
self.axis = ax
self.type = "rotate"
class planet_obj:
"for frame representing the earth"
def __init__(self, n, p, ax, rad, lab):
self.name = n
n.pos = p
n.axis = ax
self.frame = n
self.pos = p
self.radius = rad
self.globe = sphere(frame = n, radius = rad, color = color.cyan, mass = 6e24)
self.equator = ring(frame=n, axis=(1,0,0), radius=rad, thickness=rad/40.0, color=vector(0,0,1))
self.meridian = ring(frame=n, axis=(0,1,0), radius=rad, thickness=rad/40.0, color=vector(1,0,0))
self.long90 = ring(frame=n, axis=(0,0,1), radius=rad, thickness=rad/80.0, color=vector(1,0,0))
self.long45 = ring(frame=n, axis=(0,1,1), radius=rad, thickness=rad/80.0, color=vector(1,0,0))
self.long135 = ring(frame=n, axis=(0,1,-1), radius=rad, thickness=rad/80.0, color=vector(1,0,0))
self.noon = ring(pos=n.pos, axis=cross(scene.lights[0],vector(0,1,0)), radius=1.1 * rad, thickness=rad/40.0, color=vector(1,1,0))
self.terminator = ring(pos = n.pos, axis=scene.lights[0], radius=1.1 * rad, thickness=rad/40.0, color=vector(1,1,0))
self.label = label(pos=p, text=lab, xoffset=20, yoffset=12, space=rad, height=10, border=6)
self.loc1 = sphere(frame=n, pos=(0,-rad,0), radius=rad/10.0)
self.label1 = label(frame=n, pos=(0,-rad,0), text='1', xoffset=20, yoffset=12, space=rad/10.0, height=10, border=6,visible=0)
self.arrow1 = arrow(pos=(0,-rad,0), axis=scene.lights[0], shaftwidth=rad/20, length = rad/10.0, color=(1,1,0), visible=0)
self.loc2 = sphere(frame=n, pos=(0,-rad,0), radius=rad/10.0)
self.label2 = label(frame=n, pos=(0,-rad,0), text='2', xoffset=20, yoffset=12, space=rad/10.0, height=10, border=6,visible=0)
self.arrow2 = arrow(pos=(0,-rad,0), axis=scene.lights[0], shaftwidth=rad/20, length = rad/10.0, color=(1,1,0), visible=0)
def camera_fly(s,ang):
if s == "left":
scene.forward = rotate(scene.forward, angle=-ang*2*pi/360, axis=scene.up)
elif s == "right":
scene.forward = rotate(scene.forward, angle=+ang*2*pi/360, axis=scene.up)
elif s == "up":
scene.forward = rotate(scene.forward, angle=ang*2*pi/360, axis=cross(scene.up,scene.forward))
scene.up = rotate(scene.up, angle=ang*2*pi/360, axis=cross(scene.up,scene.forward))
elif s == "down":
scene.forward = rotate(scene.forward, angle=-ang*2*pi/360, axis=cross(scene.up,scene.forward))
scene.up = rotate(scene.up, angle=-ang*2*pi/360, axis=cross(scene.up,scene.forward))
if s == "ctrl+left":
scene.forward = rotate(scene.forward, angle=ang*2*pi/360, axis=scene.up)
elif s == "ctrl+right":
scene.forward = rotate(scene.forward, angle=-ang*2*pi/360, axis=scene.up)
elif s == "ctrl+up":
scene.forward = rotate(scene.forward, angle=ang*2*pi/360, axis=cross(scene.up,scene.forward))
scene.up = rotate(scene.up, angle=ang*2*pi/360, axis=cross(scene.up,scene.forward))
elif s == "ctrl+down":
scene.forward = rotate(scene.forward, angle=-ang*2*pi/360, axis=cross(scene.up,scene.forward))
scene.up = rotate(scene.up, angle=-ang*2*pi/360, axis=cross(scene.up,scene.forward))
def world_space_pos(frame, local):
"""Returns the position of local in world space."""
x_axis = norm(frame.axis)
z_axis = norm(cross(frame.axis, frame.up))
y_axis = norm(cross(z_axis, x_axis))
return frame.pos+local.x*x_axis+local.y*y_axis+local.z*z_axis
def setrate(val): # called on slider drag events
cuberate = val # value is min-max slider position
def setloc(obj,val): # called on slider drag events
obj.pos = (0,-2e10,0)
obj.rotate(angle=((val-90)*pi/180), origin=(0,0,0), axis=cross(norm(obj.pos),vector(1,0,0)))
def setlong(obj,val): # called on slider drag events
obj.pos = (0,-2e10,0)
obj.rotate(angle=((val)*pi/180), origin=(0,0,0), axis=vector(1,0,0))
def showobj(obj): # called on button events
scene.autoscale = 1
if obj.visible == 1:
obj.visible = 0
else:
obj.visible = 1
scene.autoscale = 0
def mcolor(obj,val): # change the color of an object on the surface of the rotating globe
if (val > 0.3):
obj.color = vector(1,1,0) #yellow
elif (val <= 0.3 and val > 0):
obj.color = vector(1,val/0.3,0) # to red (1,0,0)
elif (val <= 0.0 and val > -0.1):
obj.color = vector(1-abs(val)/0.1,0,abs(val)/0.1) # to blue (0,0,1)
elif (val <= -0.1 and val > -0.2):
obj.color = vector(0,0,1-(0.1-abs(val))/(0.2-0.1)) # to black (0,0,0)
else:
obj.color = vector(0,0,0)
def setcenter(val):
centerobj = val
def setLight(val):
centerobj = val
def vec_angle(v1,v2):
"calculate the angle between two vectors"
return arccos(dot(norm(v1),norm(v2)))
def viewdir(val,events,runtime, framerate):
"ev is the camera event list"
#time (seconds) it should take to rotate 180 degrees
t180 = 3
if val == "top":
cv = scene.forward
fv = vector(0.0,-1,0.0)
da = vec_angle(cv,fv)
dt = (t180/180.0) * (360*da/(2*pi))
et = runtime + dt
if da <> 0.0:
ang = (da/abs(da)) *(360*da/(2*pi)) / (dt )
ax = cross(scene.forward, fv)
print "runtime " + `runtime`
print "dt " + `dt`
print "ang " + `ang`
print `360*da/(2*pi)`
events.append(camera_rotate(runtime, et, ang , ax))
elif val == "side":
cv = scene.forward
fv = startViewForward
scene.up = vector(0,1,0)
scene.forward = startViewForward
def freezeEarth(e, obj):
scene.select()
e.append(frame())
lab = pos_label(e[-1])
g = planet_obj(e[-1], obj.pos, obj.axis, 2e10, lab )
g.label.text = pos_label(e[-1])
togLight.value = 1
def pos_label(obj):
if abs(obj.pos.z) > 9.8e10:
lab = 'equinox'
elif abs(obj.pos.x) > 9.8e10:
lab = 'solstice'
else:
lab = 'Earth'
return lab
#centerobj = 0
#For screen capture
origx = 0
origy = 0
w = 640+4+4
h = 480+24+4
scene.width=w
scene.height=h
scene.x = origx
scene.y = origy
#set Camtasia capture region to 4, 24 and 640x480
l_slomo = 0 #set to 1 for slow motion
slomo = 4.0
scene.lights = [vector(-1,0,0)]
scene.ambient = 0.15
#scene.stereo = 'redcyan'
sun = sphere(color=color.yellow, radius=1e10, pos=(0,0,0))
#sun.mass = 3e30
orbitalradius = 1e11
earthradius = 2e10
elist = []
#elist.append(frame())
#planet_obj(elist[0], vector(-orbitalradius,0,0), vector(-0.435,1,0), earthradius)
earth = frame()
ea = planet_obj(earth, vector(orbitalradius,0,0), vector(-0.435,1,0), earthradius, "Earth")
ea.loc1.rotate(angle=(35*pi/180), origin=(0,0,0), axis=vector(0,0,1))
#noon = ring( pos=earth.pos, axis=cross(scene.lights[0],vector(0,1,0)), radius=2.25e10, thickness=5e8, color=vector(1,1,0))
#terminator = ring(pos = earth.pos, axis=scene.lights[0], radius=2.25e10, thickness=5e8, color=vector(1,1,0))
#earthlabel = label(pos=earth.pos, text='Earth', xoffset=20, yoffset=12, space=2e10, height=10, border=6)
#
origx = origx
origy = origy + h
w = 640
h = 200
display(x=origx, y=origy, width=w, height=h, range=1.5, forward=-vector(0,1,1), newzoom=1)
c = controls(x=origx, y=origy, width=w, height=h, range=75)
srotate = slider(pos=(25,0), min= 0, max = 5, width=2, length=10, axis=(0,1,0), text="rotate", action=lambda: setrate(srotate.value))
srotate.value = 0
srotate_label = button(pos=srotate.pos-vector(0,5,0), text='Rotate', color = (1,1,1), height=6, width=15)
sorbit = slider(pos=(30,0), min= 0, max = 5, width=2, length=10, axis=(0,1,0), action=lambda: setrate(sorbit.value))
sorbit.value = 0
sorbit_label = button(pos=sorbit.pos+vector(0,sorbit.length+5,0), text='Orbit', color = (1,1,1), height=6, width=15,)
s2 = slider(pos=(-45,0), min= 0, max = 180, width=2, length=10, axis=(0,1,0), action=lambda: setloc(ea.loc1,s2.value))
s2.value = 90 + 35
s3 = slider(pos=(-50,0), min= 0, max = 180, width=2, length=10, axis=(0,1,0), action=lambda: setloc(ea.loc2,s3.value))
s3.value = 90
s4 = slider(pos=s2.pos-vector(15,2,0), min= 0, max = 360, width=2, length=15, axis=(1,0,0), action=lambda: setlong(ea.loc1,s4.value))
s4.value = 0
bh = 7.5 #button height
bw = 20 #button width
bel = button(pos=(-30,10), height=bh, width=bw, text='Earth', action=lambda: showobj(ea.label))
bml = button(pos=(bel.pos.x,bel.pos.y-bh), height=bh, width=bw, text='Loc 1', action=lambda: showobj(ea.label1))
bm2l = button(pos=(bel.pos.x,bel.pos.y-(bh*2)), height=bh, width=bw, text='Loc 2', action=lambda: showobj(ea.label2))
bnoon = button(pos=(5,15), height=bh, width=bw, text='Noon', action=lambda: showobj(ea.noon))
bterm = button(pos=(5,5), height=bh, width=bw, text='Circ Illum', action=lambda: showobj(ea.terminator))
bsun = button(pos=(5,-5), height=bh, width=bw, text='Sun', action=lambda: showobj(sun))
bmla = button(pos=(bml.pos.x+bw-5,bml.pos.y), height=bh, width=bw/2, text='-->', action=lambda: showobj(ea.arrow1))
bm2la = button(pos=(bm2l.pos.x+bw-5,bm2l.pos.y), height=bh, width=bw/2, text='-->', action=lambda: showobj(ea.arrow2))
btopview = button(pos=(47,0), height=10, width=12, text='Top', action=lambda: viewdir("top",events,runtime, framerate))
bsideview = button(pos=(47,-10), height=10, width=12, text='Side', action=lambda: viewdir("side",events,runtime, framerate))
bloc1 = button(pos=(47,10), height=10, width=12, text='Loc 1', action=lambda: viewdir("loc_1",events,runtime, framerate))
bfreeze = button(pos=(-65,15), height=bh, width=bw, text='Freeze', action=lambda: freezeEarth(elist, earth))
togCenter = toggle(pos=(60,0), width=10, height=10, text0='Earth', text1='Sun', action=lambda: setcenter(togCenter.value))
togLight = toggle(pos=(-65,-12), width=5, height=5, text0='Ambient', text1='Directed', action=lambda: setLight(togLight.value))
ea.noon.visible = 0
ea.terminator.visible = 0
ea.label.visible = 1
ea.label1.visible = 0
ea.label2.visible = 0
ea.arrow1.visible = 0
ea.arrow2.visible = 0
sun.visible = 0
centerobj = 0
scene.center = earth.pos
startViewForward = scene.forward
#dt = 86400
srotate.value = 0
scene.autoscale = 0
runtime = 0.0
framerate = 100
#set up camera events
#events = [camera_rotate(10.0, 9999.0, -1.0, scene.up)]
events = []
while 1:
rate(framerate)
runtime = runtime + (1.0/framerate)
if l_slomo == 1:
rate(slomo)
c.interact()
if scene.mouse.events:
m1 = scene.mouse.getevent() # obtain drag or drop event
#earthlabel.text = `world_space_pos(m1.pick.frame, m1.pick.pos)`
if m1.pick <> None and m1.release:
select_obj = m1.pick
if m1.pick.frame:
scene.center = m1.pick.frame.pos
else:
scene.center = m1.pick.pos
earth.rotate(angle=srotate.value*pi/1000, axis=earth.axis)
for n in elist:
n.rotate(angle=srotate.value*pi/1000, axis=earth.axis)
ea.label.pos = earth.pos
orbit_rate = sorbit.value*pi/1000
earth.rotate(angle=orbit_rate, axis=vector(0,1,0), origin=sun.pos)
earth.rotate(angle=-orbit_rate, axis=vector(0,1,0))
scene.lights = [-norm(earth.pos)]
if togLight.value == 1:
scene.ambient = 0.7
else:
scene.ambient = 0.15
if togCenter.value == 0:
scene.center = earth.pos
else:
scene.center = sun.pos
ea.terminator.pos = earth.pos
ea.terminator.axis = scene.lights[0]
ea.noon.pos = earth.pos
ea.noon.axis = cross(scene.lights[0],earth.axis)
m_global_pos = world_space_pos(earth, ea.loc1)
m_vec = vector(m_global_pos) - vector(earth.pos)
m_angle = dot(norm(scene.lights[0]),norm(vector(m_vec.x,0,m_vec.z)))
mcolor(ea.loc1, m_angle)
mcolor(ea.arrow1, m_angle)
ea.label1.pos = ea.loc1.pos
ea.label1.text = `round(s2.value-90)`
ea.arrow1.pos=m_global_pos
ea.arrow1.axis = scene.lights[0]
ea.arrow1.shaftwidth=1e9
ea.arrow1.length = 2e10
m_global_pos = world_space_pos(earth, ea.loc2)
m_vec = vector(m_global_pos) - vector(earth.pos)
m_angle = dot(norm(scene.lights[0]),norm(vector(m_vec.x,0,m_vec.z)))
mcolor(ea.loc2, m_angle)
mcolor(ea.arrow2, m_angle)
ea.label2.pos = ea.loc2.pos
ea.label2.text = `round(s2.value-90)`
ea.arrow2.pos=m_global_pos
ea.arrow2.axis = scene.lights[0]
ea.arrow2.shaftwidth=1e9
ea.arrow2.length = 2e10
#ea.label.text = pos_label(earth)
if scene.kb.keys: # is there an event waiting to be processed?
s = scene.kb.getkey() # obtain keyboard information
#ea.label.text = `s`
if s == "t":
showobj(terminator)
elif s == "n":
showobj(noon)
elif s == "s":
showobj(sun)
elif s == "ctrl+s":
togCenter.value = 1
elif s == "e":
showobj(sun)
elif s == "ctrl+e":
togCenter.value = 0
elif s == "shift+up":
sorbit.value = sorbit.value + 0.25
elif s == "shift+down":
sorbit.value = sorbit.value - 0.25
elif s == "shift+left":
sorbit.value = 0
elif s == "alt+up":
srotate.value = srotate.value + 0.25
elif s == "alt+down":
srotate.value = srotate.value - 0.25
elif s == "alt+left":
srotate.value = 0
camera_fly(s,1)
#camera motions
#earthlabel.text = `runtime`
for e in events:
#earthlabel.text = `e.start` + `e.end` + `runtime` + `e.type`
if runtime >= e.start and runtime <= e.end:
#earthlabel.text = `e.type`
if e.type == "rotate":
#print "scene.forward " + `scene.forward`
scene.forward = rotate(scene.forward, angle=(1.0/framerate)*e.angle*2*pi/360, axis=e.axis)
scene.up = rotate(scene.up, angle=(1.0/framerate)*e.angle*2*pi/360, axis=e.axis)

