#! /usr/bin/python # -*- coding: utf-8 -*- # Program to make a movie of the earth as it # spins on its axis *and* orbits around the # center-of-mass of the earth/moon system. from __future__ import print_function, division from visual import * import os # needed for catching ^C import traceback # needed for catching ^C from subprocess import Popen import time # for time.sleep def keyInput(evt): s = evt.key print ("[", s, "]") # Would like to increase the range here, # and decrease the fov .... # However, contrary to documentation, # setting scene.fov has no effect. scene = display(title='Whatever', x=0, y=0, width=854+20, height=480+50, center=(0, 0, 0), range=6) if 0: print ("vpython version: ", version) try: scene.bind('keydown', keyInput) except: print ("Note: scene.bind", "requires vpython version 6") # continue without it debug = 0 child = 0 # must be outside the main try block try: #### main program #### # We are looking down on the ecliptic plane # initial condition = March 20 = spring equinox # Gemini / Taurus # # Virgo ... Pisces # # Saggitarius m_e = 5.9726e24 # in kg m_m = 0.07342e24 # in kg r_e = 6371.0e3 # in meters semi_major = 0.3844e9 # in meters rrat = semi_major/r_e mrat = m_e/m_m CoM = rrat / (1. + mrat) print ("distance ratio: ", rrat) print ("mass ratio: ", mrat) print ("CoM: ", CoM) rawfile = "~/video/earth-moon-spin-orbit-raw.mp4" make_target = "earth-moon-spin-orbit-start.jpg" xaxis = vector(1,0,0) # in the ecliptic plane zaxis = vector(0,0,1) # perp to the ecliptic plane deg = pi / 180. # the unit of time is one solar day, # but our reference frame is sidereal solar = 86400. sidereal = 86164.0905 # sidereal day month = 27.321661 # sidereal month, in days year = 366.25 # sidereal year, in days north = vector(0, 0, 1) arm = vector(0, CoM, 0) origin = vector(0, 0, 0) xcross = vector(2, 0, 0) ycross = vector(0, 2, 0) xgrid = curve(pos=[xcross, -xcross], radius=.02, material=materials.emissive, color=color.green) ygrid = curve(pos=[ycross, -ycross], radius=.02, material=materials.emissive, color=color.green) earth = sphere(pos=arm, radius=1, material=materials.earth) pointer = arrow(pos=-ycross+arm/2, axis=-arm, shaftwidth=.075, material=materials.emissive, color=color.gray(0.7)) # random star field in background for x in range(0, 300): xx = random.uniform(-6, 6) yy = random.uniform(-4, 4) mag = random.uniform(-3, 0) rr = 2**mag * .05 star = sphere(pos=(xx, yy, 0), radius=rr, material=materials.emissive, color=color.white) # rotate so north pole is straight up: earth.rotate(angle=pi/2., axis=xaxis) # rotate some more, so axis is tilted relative to ecliptic plane tilt = -23 * deg; earth.rotate(angle=tilt, axis=xaxis) #xx has no effect: #xx north.rotate(angle=tilt, axis=xaxis) north = rotate(north, tilt, xaxis) sundir = vector(1, 0, 0) # kludge: double it, to get twice as much light: sun1 = distant_light(direction=sundir, color=color.white) sun2 = distant_light(direction=sundir, color=color.white) scene.lights = [sun1, sun2] if debug: attrs = [attr for attr in dir(sun1) if not attr.startswith('__')] print(attrs) print (sun1.direction) # so first frame gets rendered before recording starts: time.sleep(0.05) region = " -show_region 0" if 0: region = " -show_region 1" # screencasting video capture command (no audio) cmd = "exec avconv -f x11grab -r 30 " \ + region \ + " -s 854x480 -i :0.0+7,60" \ + " -vcodec libx264 -preset ultrafast " \ + " -t 56.05 " \ + " -y " + rawfile # print(cmd) if debug: cmd = 'exec sleep 60' child = Popen(cmd, shell=1) myrate = 30 walltime = time.time() while 1: rate(myrate) newtime = time.time() dt = newtime - walltime if dt < 0.1/myrate: continue walltime = newtime # sidereal rates, measured in days daily = 2.*pi*dt * solar / sidereal monthly = 2.*pi*dt/month yearly = 2.*pi*dt/year earth.rotate(angle=daily, axis=north) # orbit with spin: pointer.rotate(angle= monthly, axis=zaxis, origin=origin) earth.rotate(angle= monthly, axis=zaxis, origin=origin) # remove spin, to have orbit without spin: earth.rotate(angle=-monthly, axis=zaxis, origin=earth.pos) sundir = rotate(sundir, yearly, zaxis) sun1.direction = sundir sun2.direction = sundir child.poll() if child.returncode is not None: break; except KeyboardInterrupt as e: print ('...Interrupt...') os._exit(1) except: #xxx print("Unexpected error:\n", sys.exc_info()) print("Unexpected error... ", end='') sys.stdout.flush() #xx Contrary to documentation, #xx display object has no attribute 'delete' #xx scene.delete() # clean up a little bit: if child is not 0: print("Child pid: ", child.pid) child.kill() # Use print_exc() instead of raise, because we want to retain control, # so we can force an exit that actually exits, # rather than hanging around with a graphics window open. traceback.print_exc() os._exit(1) print("Hint:") print(":; cd ~/video ; make " + make_target) os._exit(0)