GlowScript 2.7 VPython
#Travelling to Mars
#Developed by A.Titus
#pos unit is m
#time unit is s

#pos and vel generated by http://ssd.jpl.nasa.gov/horizons.cgi

#Aug 29, 2015

#no z components
marspos=1000*vec(-1.176389005286295E+08,2.135936464902488E+08,0)
marsvel=1000*vec(-2.027713823922661E+01,-9.661960006152405E+00,0)
earthpos=1000*vec(1.376368513677354E+08,-6.342242292720988E+07,0)
earthvel=1000*vec(1.203162796791987E+01,2.691852057718956E+01,0)

scene = display(width=430, height=400)
scene.append_to_title("""<br>When Earth passes between Mars and the Sun, the simulation will stop.<br> Click the simulation to start it again.<br> The synodic period is the time for Earth to pass between Mars and the Sun.""")
#set the scene's range to avoid autoscaling
scene.range=1.5*mag(marspos)

#constants
AU=1000*149597871 #1 astronomical unit in m
G=6.67384e-11

#diameters for drawing Sun, Mars, and Earth. It is not to scale
Dsun=0.2*AU
Dearth=0.1*AU
Dmars=0.1*AU

# masses
Msun=1.989e30
Mearth=5.97219e24
Mmars=6.4185e23

#define velocity and momentum
vearth=earthvel
vmars=marsvel
pearth=Mearth*vearth
pmars=Mmars*vmars

#time
dt=2*3600 #use 24 to be faster, rocket use 2 written by lookang
day=24*3600
t=0

#create 3D objects
sun=sphere(pos=vec(0,0,0), radius=Dsun/2, color=color.yellow)
mars=sphere(pos=marspos, radius=Dmars/2, color=color.red, make_trail=True, trail_type="curve",interval=1, retain=1000)
earth=sphere(pos=earthpos, radius=Dearth/2, color=color.blue, make_trail=True,trail_type="curve",interval=1, retain=1000)

#create labels for displaying time and a message string
tstr="Time: {:.0f} days".format(0)
tlabel=label(pos=vector(0,1.2*mag(marspos),0), text=tstr)
launchstr="Synodic Period: "
launchlabel=label(pos=vector(0,-1.2*mag(marspos),0), text=launchstr)

# relative positions of mars and earth
suntomars=mars.pos-sun.pos
suntoearth=earth.pos-sun.pos

# change in sign of the cross product can be used to find opposition
cproduct=cross(suntoearth,suntomars)
cproductsign=1
oldproductsign=1

#turn off autocaling now that the scene is set
scene.autoscale=False

# times for oppositions; the difference is the synodic period
ti=0
tf=0

while 1:
    rate(200)

    #starting message
    if(t==0):
        launchstr="Click to Start"
        launchlabel.text=launchstr
        scene.waitfor('click')
        launchstr="Running..."
        launchlabel.text=launchstr

    #earth
    r=earth.pos-sun.pos
    rmag=mag(r)
    runit=norm(r)
    Fearth=-G*Msun*Mearth/rmag**2*runit
    pearth=pearth+Fearth*dt
    earth.pos=earth.pos+pearth/Mearth*dt
    
    #mars
    r=mars.pos-sun.pos
    rmag=mag(r)
    runit=norm(r)
    Fmars=-G*Msun*Mmars/rmag**2*runit
    pmars=pmars+Fmars*dt
    mars.pos=mars.pos+pmars/Mmars*dt

    #use change in sign of cross product to find opopsition
    suntomars=mars.pos-sun.pos
    suntoearth=earth.pos-sun.pos
    cproduct=cross(suntoearth,suntomars)
    oldcproductsign=cproductsign
    if(cproduct.z>=0):
        cproductsign=1
    else:
        cproductsign=-1
    # opposition occurs
    if(oldcproductsign>0 and cproductsign<0):
        if(ti==0):
            ti=t/day
            launchstr="Earth Transit at t="+ti+" days. Click to Continue."
            launchlabel.text=launchstr
            scene.waitfor('click')
            launchstr="Running..."
            launchlabel.text=launchstr
        else if(ti>0 and tf==0):
            tf=t/day
            transit=tf-ti
            launchstr="Earth Transit at t="+tf+" days.\n Synodic period="+transit+" days = {:.1f} months.\n Click to Continue.".format(transit/30.4)
            launchlabel.text=launchstr
            scene.waitfor('click')
            launchstr="Running..."
            launchlabel.text=launchstr
    
    #update time and time label
    t=t+dt
    tstr="Time: {:.0f} days".format(t/day)
    tlabel.text=tstr