Earth sun.py

From GeoMod

Jump to: navigation, search

To run the code, once you have VPython installed, you can either.

  1. Download this file: orbit_earth_sun16.py
  2. 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)

Personal tools