├── .gitignore ├── satellite motion ├── physutil.pyc ├── satellite.py ├── binary.py └── physutil.py ├── kinematics ├── program outline.pdf ├── 1-dMotionSimulation.py ├── PMPM lab.py ├── projectile motion.py ├── PMPM lab iterative.py └── physutil.py ├── README.md ├── special relativity ├── momentum.py └── lengthContraction.py ├── simple harmonic motion └── shm.py ├── energy of mass on spring └── massOnSpring.py ├── inelastic collision └── inelastic.py ├── circular motion ├── circularMotion.py └── physutil.py ├── buoyancy ├── buoyancy.py └── physutil.py └── inclined plane ├── inclinedPlane.py ├── inclinedPlane52.py ├── inclinedPlane53.py ├── inclinedPlane54.py └── physutil.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /satellite motion/physutil.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcschmit/vpython-physics/HEAD/satellite motion/physutil.pyc -------------------------------------------------------------------------------- /kinematics/program outline.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcschmit/vpython-physics/HEAD/kinematics/program outline.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vpython-physics 2 | =============== 3 | 4 | collection of computational physics models using physutil and VPython 5 | 6 | I created this repository to share various models that I created for my AP Physics B class. These examples are functional, but students will extend them to explore other aspects of the topic. 7 | 8 | Feel free to use these in your classes and add your own models to the repository. 9 | 10 | 11 | References 12 | ---------- 13 | 14 | VPython: http://www.vpython.org/ 15 | 16 | Physics Utility for VPython (physutil): 17 | https://per.gatech.edu/wiki/doku.php?id=projects:hscomp:physutil 18 | 19 | John Burk's collection of posts on computational modeling: 20 | https://quantumprogress.wordpress.com/computational-modeling/ 21 | 22 | 23 | 24 | Geoff Schmit 25 | @gcschmit 26 | gcschmit@gmail.com -------------------------------------------------------------------------------- /special relativity/momentum.py: -------------------------------------------------------------------------------- 1 | from __future__ import division, print_function 2 | from visual import * 3 | from visual.graph import * 4 | scene.background = color.white 5 | scene.height = 50 6 | scene.width = 50 7 | scene.x = scene.y =0 8 | ## Josh Gates 2012, started with kernel of Ruth Chabay program 9 | print (""" 10 | Click anywhere in display window to start. 11 | Click to stop. 12 | Momentum and velocity are shown as .6 kg block is pushed with a constant 1,000,000 N force. 13 | Uncomment gamma line to remove classical p def'n/assumption""") 14 | 15 | ## CONSTANTS 16 | delta_t = 0.01 ## for 100 steps 17 | mblock = 0.06 18 | c=3e8 19 | Fnet = vector(1e6,0,0) 20 | 21 | ## OBJECTS & INITIAL VALUES 22 | pblock = mblock*vector(0,0,0) 23 | gamma = 1 24 | 25 | # start time at 0 26 | t = 0 27 | scene.center = (0,.1,0) # move camera up 28 | scene.range = 0.15 29 | 30 | ## GRAPH STUFF 31 | gp = gdisplay(background=color.white, foreground=color.black, y=0, x=250, height=300, 32 | title='Momentum vs. time: block with constant F', xtitle='Time (s)', ytitle='Position (m)', 33 | ymax=3e7,xmax=30) 34 | blockp = gcurve(color=color.magenta) 35 | blockp.plot(pos=(t,pblock.x)) ## initial pos.x of block 36 | 37 | gv = gdisplay(background=color.white, foreground=color.black, y=300, x=250, height=300, 38 | title='Velocity vs. time: block with constant F', xtitle='Time (s)', ytitle='Velocity (m/s)', 39 | ymax = 3e8, ymin=0, xmax=30) 40 | blockv = gcurve(color=color.blue) 41 | blockv.plot(pos=(t,pblock.x/(gamma*mblock))) #initial velocity 42 | asymptote=gcurve(color=color.red) 43 | 44 | 45 | scene.mouse.getclick() 46 | stopper='go' 47 | 48 | a=.1 49 | while a<1000: 50 | asymptote.plot(pos=(30/a,3e8)) 51 | a=a+1 52 | 53 | ## CALCULATIONS 54 | while stopper=='go': 55 | rate(500) 56 | 57 | pblock = pblock + Fnet*delta_t 58 | 59 | # comment to make classical approximation 60 | #gamma = (1-(pblock.x)**2/(mblock**2 * c**2+(pblock.x)**2))**-.5 61 | 62 | # update time 63 | t = t + delta_t 64 | # plot pos.x, velocity.x of block 65 | blockp.plot(pos=(t,pblock.x)) 66 | blockv.plot(pos=(t,pblock.x/(gamma*mblock))) 67 | ## print t, block.y 68 | if scene.mouse.clicked: 69 | stopper='stop' 70 | -------------------------------------------------------------------------------- /kinematics/1-dMotionSimulation.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "My Buggy Model" 14 | 15 | # Make scene background black 16 | scene.background=color.black 17 | 18 | 19 | # Define scene objects 20 | track = box(pos =vector(0,-.1,0),size=(3,.1,1),color = color.green) #units are m 21 | car = box(size=(.3,.1,.2), color = color.blue) 22 | 23 | # Define axis (with a specified length) that marks the track with a specified number of tick marks 24 | axis = PhysAxis(track, 16, length=3) #units are in m 25 | 26 | # Set up graph 27 | positiongraph = PhysGraph() 28 | 29 | # Set up trail to mark the car's trajectory 30 | trail = curve(color = color.yellow, radius = .01) #units in m 31 | 32 | 33 | # Set timer in top right of screen 34 | timerDisplay = PhysTimer(1,1) 35 | 36 | 37 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 38 | # ---------------------------------------------------------------------------------------- 39 | 40 | # Define parameters 41 | car.m = 1. #mass of car in kg 42 | car.pos = vector(0,0,0) #initial position of the car in( x,y,z) form, units are m 43 | car.v = vector(-.5,0,0) #initial velocity of car in (vx,vy,vz) form, units are m/s 44 | 45 | 46 | # Define time parameters 47 | t=0 #starting time 48 | deltat = 0.001 #time step units are s 49 | 50 | 51 | ### CALCULATION LOOP; perform physics updates and drawing 52 | # ------------------------------------------------------------------------------------ 53 | 54 | while car.pos.x > -1.50 and car.pos.x < 1.50 : #while the ball's x-position is between -1.5 and 1.5 55 | 56 | 57 | # Required to make animation visible / refresh smoothly (keeps program from running faster than 1000 frames/s) 58 | rate(1000) 59 | 60 | # Compute Net Force 61 | Fnet = vector(0,0,0) 62 | 63 | # Newton's 2nd Law 64 | car.v = car.v + Fnet/car.m * deltat 65 | 66 | # Position update 67 | car.pos = car.pos + car.v*deltat 68 | 69 | # Update timer, graph, and trail 70 | timerDisplay.update(t) 71 | positiongraph.plot(t,car.pos.x) #this plots one point in the graph in (x,y) form 72 | trail.append(pos = car.pos) 73 | 74 | # Time update 75 | t=t+deltat 76 | 77 | ### OUTPUT 78 | # -------------------------------------------------------------------------------------- 79 | 80 | # Print the final time and the car's final position 81 | print t 82 | print car.pos 83 | -------------------------------------------------------------------------------- /simple harmonic motion/shm.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "Simple Harmonic Motion" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | 18 | # Define scene objects (units are in meters) 19 | springLengthInitial = 1.0 20 | spring = helix(pos = (-springLengthInitial, 0, 0), axis = (1, 0, 0), 21 | length = springLengthInitial, radius = 0.1, 22 | thickness = 0.05, color = color.green) 23 | mass = sphere(radius = 0.2, color = color.blue) 24 | 25 | axis = PhysAxis(spring, 11, # number of tick marks 26 | startPos = vector(-springLengthInitial, -0.5, 0), # start the x axis at the left edge of the scene 27 | length = 2) # units are in meters 28 | 29 | # Set up graphs 30 | energyGraph = PhysGraph(3) 31 | motionGraph = PhysGraph(3) 32 | 33 | 34 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 35 | # ---------------------------------------------------------------------------------------- 36 | 37 | # Define parameters 38 | mass.m = 0.5 # mass in kg 39 | mass.pos = vector(0, 0, 0) # initial position of the mass in(x, y, z) form, units are in meters 40 | mass.v = vector(1.0, 0, 0) # initial velocity of mass in (vx, vy, vz) form, units are m/s 41 | 42 | k = 2.0 # spring constant; units are N/m 43 | 44 | # Define time parameters 45 | t = 0 # starting time 46 | deltat = 0.001 # time step units are s 47 | 48 | 49 | ### CALCULATION LOOP; perform physics updates and drawing 50 | # ------------------------------------------------------------------------------------ 51 | 52 | while t < 10 : # run for ten seconds 53 | 54 | # Required to make animation visible / refresh smoothly (keeps program from running faster 55 | # than 1000 frames/s) 56 | rate(1000) 57 | 58 | # calculate the spring displacement 59 | springDisplacement = (spring.length - springLengthInitial) 60 | 61 | # compute the force on the mass by the spring 62 | Fspring = -k * springDisplacement 63 | 64 | # Compute Net Force 65 | Fnet = vector(Fspring, 0, 0) 66 | 67 | # Newton's 2nd Law 68 | mass.v = mass.v + (Fnet/mass.m * deltat) 69 | 70 | # Position update 71 | mass.pos = mass.pos + mass.v * deltat 72 | spring.length = springLengthInitial + mass.pos.x 73 | 74 | # Calculate energy 75 | KE = 0.5 * mass.m * mag(mass.v)**2 76 | EPE = 0.5 * k * springDisplacement**2 77 | 78 | # Update graphs 79 | energyGraph.plot(t, KE, EPE, (KE + EPE)) # plot energies 80 | motionGraph.plot(t, mass.pos.x, mass.v.x, Fnet.x/mass.m) # plot position, velocity, and acceleration vs. time 81 | 82 | # Time update 83 | t = t + deltat 84 | 85 | 86 | ### OUTPUT 87 | # -------------------------------------------------------------------------------------- 88 | 89 | # Print the final time 90 | print t 91 | -------------------------------------------------------------------------------- /special relativity/lengthContraction.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "Length Contraction" 14 | 15 | # Make scene background black 16 | scene.background=color.black 17 | 18 | # Define scene objects 19 | track = box(pos =vector(0,-1.5,0),size=(10,.1,.1),color = color.green) # units are in meters 20 | car = box(size=(1,1,1), color = color.blue) # units are in meters 21 | 22 | # Define axis that marks the track with a specified number of tick marks 23 | axis = PhysAxis(track, 11, startPos=vector(-5, -2, 0)) 24 | 25 | # Set up trail to mark the car's trajectory 26 | trail = curve(color = color.yellow, radius = 0.1) # units are in meters 27 | 28 | # Set timer in top right of screen (units are in meters) 29 | timerDisplay = PhysTimer(4, 4.5, useScientific=True) 30 | 31 | 32 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 33 | # ---------------------------------------------------------------------------------------- 34 | 35 | # Define parameters 36 | c = 3e8 # speed of light in m/s 37 | 38 | car.m = 1.0 # mass of car in kg 39 | car.pos = vector(0,0,0) # initial position of the car in(x, y, z) form, units are in meters 40 | car.v = vector(2.9e7, 0, 0) # initial velocity of car in (vx, vy, vz) form, units are in m/s 41 | 42 | # calculate the Lorentz factors based on the car's velocity in each direction 43 | lorentzFactors = (1 / (math.sqrt(1 - (car.v.x**2 / c**2))), 44 | 1 / (math.sqrt(1 - (car.v.y**2 / c**2))), 45 | 1 / (math.sqrt(1 - (car.v.z**2 / c**2)))) 46 | 47 | # adjust the size of the car to account for length contraction 48 | car.size = (car.size.x / lorentzFactors[0], 49 | car.size.y / lorentzFactors[1], 50 | car.size.z / lorentzFactors[2]) 51 | 52 | 53 | # Define time parameters 54 | t=0 # starting time 55 | deltat = 1e-11 # time step units are s 56 | 57 | 58 | ### CALCULATION LOOP; perform physics updates and drawing 59 | # ------------------------------------------------------------------------------------ 60 | 61 | # while the car's x-position is between -4.5 m and 4.5 m 62 | while car.pos.x > -4.5 and car.pos.x < 4.5 : 63 | 64 | # Required to make animation visible / refresh smoothly (keeps program from running faster 65 | # than 1000 frames/s) 66 | rate(1000) 67 | 68 | # Compute Net Force 69 | Fnet = vector(0,0,0) 70 | 71 | # Newton's 2nd Law 72 | car.v = car.v + Fnet/car.m * deltat 73 | 74 | # Position update 75 | car.pos = car.pos + car.v*deltat 76 | 77 | # Update timer, graph, and trail 78 | timerDisplay.update(t) 79 | 80 | # Time update 81 | t = t + deltat 82 | 83 | ### OUTPUT 84 | # -------------------------------------------------------------------------------------- 85 | 86 | # Print the final time and the car's size 87 | print t 88 | print car.size 89 | -------------------------------------------------------------------------------- /energy of mass on spring/massOnSpring.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "Mass on Spring" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | scene.center = (0, 1, 0) 18 | 19 | # Define scene objects (units are in meters) 20 | springLengthInitial = 1.0 21 | spring = helix(axis = (0, 1, 0), length = springLengthInitial, radius = 0.1, 22 | thickness = 0.05, color = color.green) 23 | mass = sphere(radius = 0.2, color = color.blue) 24 | 25 | yaxis = PhysAxis(spring, 10, # 5 tick marks 26 | axisType = "y", 27 | labelOrientation = "left", 28 | startPos = vector(-0.5, 0, 0), # start the y axis at the left edge of the scene 29 | length = 2) # units are in meters 30 | 31 | # Set up graph with three plots 32 | energyGraph = PhysGraph(4) 33 | 34 | 35 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 36 | # ---------------------------------------------------------------------------------------- 37 | 38 | # Define parameters 39 | mass.m = 0.5 # mass of cart in kg 40 | mass.pos = vector(0, springLengthInitial, 0) # initial position of the mass in(x, y, z) form, units are in meters 41 | mass.v = vector(0, 0, 0) # initial velocity of mass in (vx, vy, vz) form, units are m/s 42 | 43 | g = -9.8 # acceleration due to gravity; units are m/s/s 44 | 45 | k = 15.0 # spring constant; units are N/m 46 | 47 | # Define time parameters 48 | t = 0 # starting time 49 | deltat = 0.001 # time step units are s 50 | 51 | 52 | ### CALCULATION LOOP; perform physics updates and drawing 53 | # ------------------------------------------------------------------------------------ 54 | 55 | while t < 2 : # run for one second 56 | 57 | # Required to make animation visible / refresh smoothly (keeps program from running faster 58 | # than 1000 frames/s) 59 | rate(1000) 60 | 61 | # calculate the spring displacement 62 | springDisplacement = (spring.length - springLengthInitial) 63 | 64 | # compute the force on the mass by the spring 65 | Fspring = -k * springDisplacement 66 | 67 | # compute the force on the mass by the gravitational field 68 | Fgravity = mass.m * g 69 | 70 | # Compute Net Force 71 | Fnet = vector(0, Fspring + Fgravity, 0) 72 | 73 | # Newton's 2nd Law 74 | mass.v = mass.v + (Fnet/mass.m * deltat) 75 | 76 | # Position update 77 | mass.pos = mass.pos + mass.v * deltat 78 | spring.length = mass.pos.y 79 | 80 | # Calculate energy 81 | KE = 0.5 * mass.m * mag(mass.v)**2 82 | GPE = mass.m * (-g) * mass.pos.y # relative to the ground 83 | EPE = 0.5 * k * springDisplacement**2 84 | 85 | # Update graphs 86 | energyGraph.plot(t, KE, GPE, EPE, (KE + GPE + EPE)) # plot energies 87 | 88 | # Time update 89 | t = t + deltat 90 | 91 | 92 | ### OUTPUT 93 | # -------------------------------------------------------------------------------------- 94 | 95 | # Print the final time 96 | print t 97 | -------------------------------------------------------------------------------- /kinematics/PMPM lab.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "PMPM Lab Model" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | 18 | # Define scene objects (units are in meters) 19 | field = box(pos = vector(1.5, 0, 0), size = (3, .10, 1), color = color.green, opacity = 0.3) 20 | ball = sphere(radius = .05, color = color.blue) 21 | 22 | # Define axis marks the field with a specified number of tick marks 23 | xaxis = PhysAxis(field, 10, length = 4.5) # 10 tick marks 24 | yaxis = PhysAxis(field, 5, # 5 tick marks 25 | axisType = "y", 26 | labelOrientation = "left", 27 | startPos = vector(0, 0, 0), # start the y axis at the left edge of the scene 28 | length = 1) # units are in meters 29 | 30 | # Set up graph with two plots 31 | posgraph = PhysGraph(1) 32 | 33 | # Set up trail to mark the ball's trajectory 34 | trail = curve(color = color.yellow, radius = .01) # units are in meters 35 | 36 | # Set timer in top right of screen 37 | timerDisplay = PhysTimer(2.0, 1.50) # timer position (units are in meters) 38 | 39 | 40 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 41 | # ---------------------------------------------------------------------------------------- 42 | 43 | # Define parameters 44 | theta = 30; # angle in degrees 45 | v = 4.1; # initial launcher velocity in m/s 46 | ball.m = 0.6 # mass of ball in kg 47 | ball.pos = vector(0, 1.17, 0) # initial position of the ball in(x, y, z) form, units are in meters 48 | ball.v = vector(v*cos(radians(theta)), v*sin(radians(theta)), 0) # initial velocity of car in (vx, vy, vz) form, units are m/s 49 | 50 | g = vector(0, -9.8, 0) # acceleration due to gravity; units are m/s/s 51 | 52 | # Define time parameters 53 | t = 0 # starting time 54 | deltat = 0.001 # time step units are s 55 | 56 | 57 | ### CALCULATION LOOP; perform physics updates and drawing 58 | # ------------------------------------------------------------------------------------ 59 | 60 | while ball.pos.y >= 0 : #while the ball's y-position is greater than 0 (above the ground) 61 | 62 | # Required to make animation visible / refresh smoothly (keeps program from running faster 63 | # than 1000 frames/s) 64 | rate(1000) 65 | 66 | # Compute Net Force 67 | Fnet = ball.m * g 68 | 69 | # Newton's 2nd Law 70 | ball.v = ball.v + (Fnet/ball.m * deltat) 71 | 72 | # Position update 73 | ball.pos = ball.pos + ball.v * deltat 74 | 75 | # Update motion map, graph, timer, and trail 76 | posgraph.plot(ball.pos.x, ball.pos.y) # plot x and y position vs. time 77 | trail.append(pos = ball.pos) 78 | timerDisplay.update(t) 79 | 80 | # Time update 81 | t = t + deltat 82 | 83 | 84 | ### OUTPUT 85 | # -------------------------------------------------------------------------------------- 86 | 87 | # Print the final time and the ball's final position 88 | print t 89 | print ball.pos 90 | -------------------------------------------------------------------------------- /satellite motion/satellite.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | 10 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 11 | # ------------------------------------------------------------------------ 12 | 13 | # Set window title 14 | scene.title = "Satellite Motion" 15 | 16 | # Make scene background black 17 | scene.background = color.black 18 | 19 | # Define scene objects (units are in meters) 20 | earth = sphere(radius = 6.378e6, color = color.blue) 21 | 22 | satellite = sphere(radius = 2e6, color = color.green) 23 | 24 | # Set up trail to mark the satellite's trajectory 25 | trail = curve(color = color.yellow, radius = 1e5) # units are in meters 26 | 27 | # Set up motion map for satellite's velocity 28 | vMotionMap = MotionMap(satellite, 100000, # expected end time in seconds 29 | 10, # number of markers to draw 30 | markerScale = 5e3, # scale the vector so it fits on the screen 31 | labelMarkerOrder = False) 32 | 33 | # Set up motion map for satellite's acceleration 34 | aMotionMap = MotionMap(satellite, 100000, # expected end time in seconds 35 | 10, # number of markers to draw 36 | markerScale = 5e7, # scale the vector so it fits on the screen 37 | markerColor = color.orange, 38 | labelMarkerOrder = False) 39 | 40 | 41 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 42 | # ---------------------------------------------------------------------------------------- 43 | 44 | # Define parameters 45 | 46 | earth.m = 5.972e24 # mass of the earth in kg 47 | 48 | satellite.m = 1000 # mass of satellite in kg 49 | satellite.pos = vector(4.23e7, 0, 0) # initial position of the satellite, units are in meters 50 | satellite.v = vector(0, 3.07e3, 0) # initial velocity of the satellite 51 | 52 | # Define time parameters 53 | t = 0 # starting time 54 | deltat = 36 # time step units are s 55 | 56 | 57 | ### CALCULATION LOOP; perform physics updates and drawing 58 | # ------------------------------------------------------------------------------------ 59 | 60 | while t < 1200000 : 61 | 62 | # Required to make animation visible / refresh smoothly (keeps program from running faster 63 | # than 1000 frames/s) 64 | rate(1000) 65 | 66 | # computer the force of gravity on the satellite by the earth 67 | Fg = (6.673e-11) * satellite.m * earth.m / mag(satellite.pos)**2 68 | 69 | # Compute Net Force 70 | Fnet = vector(0, 0, 0) - satellite.pos # direction of the net force is toward the earth 71 | Fnet.mag = Fg # magnitude of the net force is the force of gravity 72 | 73 | # Newton's 2nd Law 74 | satellite.v = satellite.v + (Fnet/satellite.m * deltat) 75 | 76 | # Position update 77 | satellite.pos = satellite.pos + satellite.v * deltat 78 | 79 | # Update motion maps and trail 80 | trail.append(pos = satellite.pos) 81 | # vMotionMap.update(t, satellite.v) 82 | # aMotionMap.update(t, Fnet/satellite.m) 83 | 84 | # Time update 85 | t = t + deltat 86 | 87 | 88 | ### OUTPUT 89 | # -------------------------------------------------------------------------------------- 90 | 91 | # Print the final time and the satellite's final position 92 | print t 93 | print satellite.v 94 | print Fnet/satellite.m 95 | -------------------------------------------------------------------------------- /kinematics/projectile motion.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "Projectile Motion Particle Model" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | 18 | # Define scene objects (units are in meters) 19 | field = box(pos = vector(0, 0, 0), size = (300, 10, 100), color = color.green, opacity = 0.3) 20 | ball = sphere(radius = 5, color = color.blue) 21 | 22 | # Define axis marks the field with a specified number of tick marks 23 | xaxis = PhysAxis(field, 10) # 10 tick marks 24 | yaxis = PhysAxis(field, 5, # 5 tick marks 25 | axisType = "y", 26 | labelOrientation = "left", 27 | startPos = vector(-150, 0, 0), # start the y axis at the left edge of the scene 28 | length = 100) # units are in meters 29 | 30 | # Set up graph with two plots 31 | posgraph = PhysGraph(2) 32 | 33 | # Set up trail to mark the ball's trajectory 34 | trail = curve(color = color.yellow, radius = 1) # units are in meters 35 | 36 | # Set up motion map for ball 37 | motionMap = MotionMap(ball, 8.163, # expected end time in seconds 38 | 10, # number of markers to draw 39 | labelMarkerOffset = vector(0, -20, 0), 40 | dropTime = False) 41 | 42 | # Set timer in top right of screen 43 | timerDisplay = PhysTimer(140, 150) # timer position (units are in meters) 44 | 45 | 46 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 47 | # ---------------------------------------------------------------------------------------- 48 | 49 | # Define parameters 50 | ball.m = 0.6 # mass of ball in kg 51 | ball.pos = vector(-150, 0, 0) # initial position of the ball in(x, y, z) form, units are in meters 52 | ball.v = vector(30, 40, 0) # initial velocity of car in (vx, vy, vz) form, units are m/s 53 | 54 | g = vector(0, -9.8, 0) # acceleration due to gravity; units are m/s/s 55 | 56 | # Define time parameters 57 | t = 0 # starting time 58 | deltat = 0.001 # time step units are s 59 | 60 | 61 | ### CALCULATION LOOP; perform physics updates and drawing 62 | # ------------------------------------------------------------------------------------ 63 | 64 | while ball.pos.y >= 0 : #while the ball's y-position is greater than 0 (above the ground) 65 | 66 | # Required to make animation visible / refresh smoothly (keeps program from running faster 67 | # than 1000 frames/s) 68 | rate(1000) 69 | 70 | # Compute Net Force 71 | Fnet = ball.m * g 72 | 73 | # Newton's 2nd Law 74 | ball.v = ball.v + (Fnet/ball.m * deltat) 75 | 76 | # Position update 77 | ball.pos = ball.pos + ball.v * deltat 78 | 79 | # Update motion map, graph, timer, and trail 80 | motionMap.update(t, ball.v) 81 | posgraph.plot(t, ball.pos.x, ball.pos.y) # plot x and y position vs. time 82 | trail.append(pos = ball.pos) 83 | timerDisplay.update(t) 84 | 85 | # Time update 86 | t = t + deltat 87 | 88 | 89 | ### OUTPUT 90 | # -------------------------------------------------------------------------------------- 91 | 92 | # Print the final time and the ball's final position 93 | print t 94 | print ball.pos 95 | -------------------------------------------------------------------------------- /inelastic collision/inelastic.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "Conservation of Momentum Model (inelastic collisions)" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | 18 | # Define scene objects (units are in meters) 19 | ball1 = sphere(radius = 0.1, color = color.green) 20 | ball2 = sphere(radius = 0.1, color = color.blue) 21 | 22 | # Set up motion map for ball 1 23 | motionMap1 = MotionMap(ball1, 10, # expected end time in seconds 24 | 10, # number of markers to draw 25 | labelMarkerOrder = False) 26 | 27 | # Set up motion map for ball 2 28 | motionMap2 = MotionMap(ball2, 10, # expected end time in seconds 29 | 10, # number of markers to draw 30 | labelMarkerOrder = False) 31 | 32 | # Set timer in top right of screen 33 | timerDisplay = PhysTimer(1, 1) # timer position (units are in meters) 34 | 35 | 36 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 37 | # ---------------------------------------------------------------------------------------- 38 | 39 | # Define parameters 40 | 41 | ball1.m = 0.5 # mass of ball in kg 42 | ball1.pos = vector(-1, 1, 0) # initial position of the ball in(x, y, z) form, units are in meters 43 | ball1.v = vector(0, 0, 0) - ball1.pos # set the direction of the velocity vector toward the origin 44 | ball1.v.mag = 0.5 # set the magnitude of the velocity vector 45 | 46 | ball2.m = 2.0 # mass of ball in kg 47 | ball2.pos = vector(-0.7, -0.5, 0) # initial position of the ball in(x, y, z) form, units are in meters 48 | ball2.v = vector(0, 0, 0) - ball2.pos # set the direction of the velocity vector toward the origin 49 | ball2.v.mag = 0.3 # set the magnitude of the velocity vector 50 | 51 | # Define time parameters 52 | t = 0 # starting time 53 | deltat = 0.001 # time step units are s 54 | 55 | 56 | ### CALCULATION LOOP; perform physics updates and drawing 57 | # ------------------------------------------------------------------------------------ 58 | 59 | while mag(ball1.pos) < 2 and mag(ball2.pos) < 2 : # while the balls are within 2 meters of the origin 60 | 61 | # Required to make animation visible / refresh smoothly (keeps program from running faster 62 | # than 1000 frames/s) 63 | rate(1000) 64 | 65 | # Compute Net Force 66 | Fnet = vector(0, 0, 0) 67 | 68 | # Newton's 2nd Law 69 | ball1.v = ball1.v + (Fnet/ball1.m * deltat) 70 | ball2.v = ball2.v + (Fnet/ball2.m * deltat) 71 | 72 | # Position update 73 | ball1.pos = ball1.pos + ball1.v * deltat 74 | ball2.pos = ball2.pos + ball2.v * deltat 75 | 76 | # check if the balls collided 77 | if mag(ball1.pos - ball2.pos) < ((ball1.radius + ball2.radius) / 2): 78 | # calculate the total momentum 79 | totalMomentum = (ball1.m * ball1.v) + (ball2.m * ball2.v) 80 | 81 | # calculate the velocity of the combined ball 82 | ball1.v = ball2.v = totalMomentum / (ball1.m + ball2.m) 83 | 84 | 85 | # Update motion map, timer 86 | motionMap1.update(t, ball1.m * ball1.v) 87 | motionMap2.update(t, ball2.m * ball2.v) 88 | timerDisplay.update(t) 89 | 90 | # Time update 91 | t = t + deltat 92 | 93 | 94 | ### OUTPUT 95 | # -------------------------------------------------------------------------------------- 96 | 97 | # Print the final time and the ball's final position 98 | print t 99 | -------------------------------------------------------------------------------- /circular motion/circularMotion.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | 10 | ### FUNCTIONS 11 | # ------------------------------------------------------------------------ 12 | 13 | # Calculates the net force vector for an object of mass m moving in uniform circular motion with 14 | # angular velocity w and linear velocity v 15 | def centripetalForce(m, w, v): 16 | return m * (cross(w, v)) 17 | 18 | 19 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 20 | # ------------------------------------------------------------------------ 21 | 22 | # Set window title 23 | scene.title = "Circular Motion Particle Model" 24 | 25 | # Make scene background black 26 | scene.background = color.black 27 | 28 | # Define scene objects (units are in meters) 29 | string = cylinder(pos = vector(0, 0, 0), axis = (1, 0, 0), length = 1, radius = 0.01, 30 | color = color.green) 31 | 32 | ball = sphere(radius = 0.1, color = color.blue) 33 | 34 | # Set up trail to mark the ball's trajectory 35 | trail = curve(color = color.yellow, radius = 0.01) # units are in meters 36 | 37 | # Set up motion map for ball's velocity 38 | vMotionMap = MotionMap(ball, 1, # expected end time in seconds 39 | 10, # number of markers to draw 40 | markerScale = 0.1, # scale the vector so it fits on the screen 41 | labelMarkerOrder = False) 42 | 43 | # Set up motion map for ball's acceleration 44 | aMotionMap = MotionMap(ball, 1, # expected end time in seconds 45 | 10, # number of markers to draw 46 | markerScale = 0.01, # scale the vector so it fits on the screen 47 | markerColor = color.orange, 48 | labelMarkerOrder = False) 49 | 50 | 51 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 52 | # ---------------------------------------------------------------------------------------- 53 | 54 | # Define parameters 55 | 56 | period = 1.0 # units in seconds 57 | 58 | ball.m = 0.1 # mass of ball in kg 59 | ball.pos = string.pos + string.axis # initial position of the ball is at the end of the string, units are in meters 60 | ball.w = (0, 0, 2 * pi / period) # angular velocity vector 61 | ball.v = cross(ball.w, string.axis) 62 | 63 | # Define time parameters 64 | t = 0 # starting time 65 | deltat = 0.001 # time step units are s 66 | 67 | 68 | ### CALCULATION LOOP; perform physics updates and drawing 69 | # ------------------------------------------------------------------------------------ 70 | 71 | while t < period : # run for 10 seconds 72 | 73 | # Required to make animation visible / refresh smoothly (keeps program from running faster 74 | # than 1000 frames/s) 75 | rate(1000) 76 | 77 | # Compute Net Force 78 | Fnet = centripetalForce(ball.m, ball.w, ball.v) 79 | 80 | # Newton's 2nd Law 81 | ball.v = ball.v + (Fnet/ball.m * deltat) 82 | 83 | # Position update 84 | ball.pos = ball.pos + ball.v * deltat 85 | 86 | # Update the orientation of the string so it stays connected to the ball :) 87 | string.axis = rotate(string.axis, angle=(mag(ball.w) * deltat)) 88 | 89 | # Update motion maps and trail 90 | trail.append(pos = ball.pos) 91 | vMotionMap.update(t, ball.v) 92 | aMotionMap.update(t, Fnet/ball.m) 93 | 94 | # Time update 95 | t = t + deltat 96 | 97 | 98 | ### OUTPUT 99 | # -------------------------------------------------------------------------------------- 100 | 101 | # Print the final time and the ball's final position 102 | print t 103 | print Fnet 104 | -------------------------------------------------------------------------------- /buoyancy/buoyancy.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### FUNCTIONS 10 | # ------------------------------------------------------------------------ 11 | 12 | # Calculates the volume of the specified objecdt 13 | def volumeSubmerged(object, fluid): 14 | topOfFluid = fluid.pos.y + fluid.size.y/2 15 | topOfObject = object.pos.y + object.size.y/2 16 | bottomOfObject = object.pos.y - object.size.y/2 17 | 18 | if topOfObject <= topOfFluid: 19 | heightSubmerged = object.size.y 20 | elif bottomOfObject >= topOfFluid: 21 | heightSubmerged = 0 22 | else: 23 | heightSubmerged = (topOfFluid - bottomOfObject) 24 | 25 | return (object.size.x * heightSubmerged * object.size.z) 26 | 27 | 28 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 29 | # ------------------------------------------------------------------------ 30 | 31 | # Set window title 32 | scene.title = "Buoyancy" 33 | 34 | # Make scene background black 35 | scene.background = color.black 36 | 37 | # Define scene objects (units are in meters) 38 | fluid = box(size = (2, 2, .2), color = color.blue, opacity = 0.3) 39 | object = box(color = color.red) 40 | 41 | # Set up graph with three plots 42 | graphs = PhysGraph(2) 43 | 44 | 45 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 46 | # ---------------------------------------------------------------------------------------- 47 | 48 | # Define parameters 49 | 50 | dragCoefficient = -5.0 51 | 52 | fluid.density = 1000 # density of the fluid in units of kg/m^3 53 | 54 | object.density = 500 # density of the object in units of kg/m^3 55 | object.pos = vector(0, 0, 0) # initial position of the mass in (x, y, z) form, units are in meters 56 | object.size = size = (0.4, 0.4, 0.1) # size of the object in (x, y, z) form, units are in meters 57 | object.v = vector(0, 0, 0) # initial velocity of mass in (vx, vy, vz) form, units are m/s 58 | 59 | g = -9.8 # acceleration due to gravity; units are m/s/s 60 | 61 | # Define time parameters 62 | t = 0 # starting time 63 | deltat = 0.001 # time step units are s 64 | 65 | 66 | ### CALCULATION LOOP; perform physics updates and drawing 67 | # ------------------------------------------------------------------------------------ 68 | 69 | while t < 20 and object.pos.y > (fluid.pos.y - fluid.size.y/2) : # run for one second 70 | 71 | # Required to make animation visible / refresh smoothly (keeps program from running faster 72 | # than 1000 frames/s) 73 | rate(1000) 74 | 75 | # compute the force on the object by the fluid (buoyant force) 76 | Fbuoyant = fluid.density * (-g) * volumeSubmerged(object, fluid) 77 | 78 | # compute the force on the object by the gravitational field 79 | mass = object.density * object.size.x * object.size.y * object.size.z 80 | Fgravity = mass * g 81 | 82 | # compute the drag force on the object 83 | Fdrag = dragCoefficient * object.v.y 84 | 85 | # Compute Net Force 86 | Fnet = vector(0, Fbuoyant + Fgravity + Fdrag, 0) 87 | 88 | # Newton's 2nd Law 89 | object.v = object.v + (Fnet/mass * deltat) 90 | 91 | # Position update 92 | object.pos = object.pos + object.v * deltat 93 | 94 | # Update graphs 95 | graphs.plot(t, Fbuoyant, Fgravity) # plot energies 96 | 97 | # Time update 98 | t = t + deltat 99 | 100 | 101 | ### OUTPUT 102 | # -------------------------------------------------------------------------------------- 103 | 104 | # Print the final time and the cart's final position 105 | print t 106 | -------------------------------------------------------------------------------- /inclined plane/inclinedPlane.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "Incline Plane" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | scene.center = (1, 1, 0) 18 | 19 | # Define scene objects (units are in meters) 20 | inclinedPlane = box(pos = vector(1, 0, 0), size = (2, 0.02, 0.2), color = color.green, opacity = 0.3) 21 | cart = box(size = (0.2, 0.06, 0.06), color = color.blue) 22 | 23 | # Set up graph with two plots 24 | posgraph = PhysGraph() 25 | velgraph = PhysGraph() 26 | accelgraph = PhysGraph() 27 | 28 | # Set up trail to mark the cart's trajectory 29 | trail = curve(color = color.yellow, radius = 0.01) # units are in meters 30 | 31 | # Set up motion map for cart 32 | motionMap = MotionMap(cart, 1, # expected end time in seconds 33 | 10, # number of markers to draw 34 | markerType = "breadcrumbs", 35 | dropTime = True) 36 | 37 | # Set timer in top right of screen 38 | timerDisplay = PhysTimer(2, 2) # timer position (units are in meters) 39 | 40 | 41 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 42 | # ---------------------------------------------------------------------------------------- 43 | 44 | # Define parameters 45 | cart.m = 0.5 # mass of cart in kg 46 | cart.pos = vector(1.9, 0.04, 0.08) # initial position of the cart in(x, y, z) form, units are in meters 47 | cart.v = vector(0, 0, 0) # initial velocity of car in (vx, vy, vz) form, units are m/s 48 | 49 | # angle of inclined plane relative to the horizontal 50 | theta = pi/8.0 51 | 52 | # rotate the cart and the inclined plane based on the specified angle 53 | inclinedPlane.rotate(angle = theta, origin = (0, 0, 0), axis = (0,0,1)) 54 | cart.rotate(angle = theta, origin = (0, 0, 0), axis = (0,0,1)) 55 | 56 | g = -9.8 # acceleration due to gravity; units are m/s/s 57 | 58 | # Define time parameters 59 | t = 0 # starting time 60 | deltat = 0.0005 # time step units are s 61 | 62 | 63 | ### CALCULATION LOOP; perform physics updates and drawing 64 | # ------------------------------------------------------------------------------------ 65 | 66 | while cart.pos.y > 0 : # while the cart's y-position is greater than 0 (above the ground) 67 | 68 | # Required to make animation visible / refresh smoothly (keeps program from running faster 69 | # than 1000 frames/s) 70 | rate(1000) 71 | 72 | # Compute Net Force 73 | # set the direction of the net force along the inclined plane 74 | Fnet = norm(inclinedPlane.axis) 75 | # set the magnitude to the component of the gravitational force parallel to the inclined plane 76 | Fnet.mag = cart.m * g * sin(theta) 77 | 78 | # Newton's 2nd Law 79 | cart.v = cart.v + (Fnet/cart.m * deltat) 80 | 81 | # Position update 82 | cart.pos = cart.pos + cart.v * deltat 83 | 84 | # Update motion map, graph, timer, and trail 85 | motionMap.update(t) 86 | posgraph.plot(t, mag(cart.pos)) # plot position (along inclined plane) vs. time 87 | velgraph.plot(t, mag(cart.v)) # plot velocity (along inclined plane) vs. time 88 | accelgraph.plot(t, mag(Fnet) / cart.m) # plot acceleration (along inclined plane) vs. time 89 | trail.append(pos = cart.pos) 90 | timerDisplay.update(t) 91 | 92 | # Time update 93 | t = t + deltat 94 | 95 | ### OUTPUT 96 | # -------------------------------------------------------------------------------------- 97 | 98 | # Print the final time and the cart's final position 99 | print t 100 | print cart.pos 101 | -------------------------------------------------------------------------------- /kinematics/PMPM lab iterative.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "PMPM Lab Model" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | 18 | # Define scene objects (units are in meters) 19 | field = box(pos = vector(1.5, 0, 0), size = (3, .10, 1), color = color.green, opacity = 0.3) 20 | ball = sphere(radius = .05, color = color.blue) 21 | 22 | # Define axis marks the field with a specified number of tick marks 23 | xaxis = PhysAxis(field, 10, length = 4.5) # 10 tick marks 24 | yaxis = PhysAxis(field, 5, # 5 tick marks 25 | axisType = "y", 26 | labelOrientation = "left", 27 | startPos = vector(0, 0, 0), # start the y axis at the left edge of the scene 28 | length = 1) # units are in meters 29 | 30 | # Set up graph with two plots 31 | posgraph = PhysGraph(1) 32 | 33 | # Set up trail to mark the ball's trajectory 34 | trail = curve(color = color.yellow, radius = .01) # units are in meters 35 | 36 | # Set timer in top right of screen 37 | timerDisplay = PhysTimer(2.0, 1.50) # timer position (units are in meters) 38 | 39 | 40 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 41 | # ---------------------------------------------------------------------------------------- 42 | 43 | # Define parameters 44 | theta = 20; # angle in degrees 45 | v = 4.1; # initial launcher velocity in m/s 46 | targetRange = 1.75; 47 | ball.m = 0.6 # mass of ball in kg 48 | 49 | while (ball.pos.x < targetRange - 0.04) or (ball.pos.x > targetRange + 0.04) : 50 | 51 | # Increment the launch angle 52 | theta += 2; 53 | 54 | # set (reset) the initial position and velocity 55 | ball.pos = vector(0, 1.17, 0) # initial position of the ball in(x, y, z) form, units are in meters 56 | ball.v = vector(v*cos(radians(theta)), v*sin(radians(theta)), 0) # initial velocity of car in (vx, vy, vz) form, units are m/s 57 | 58 | g = vector(0, -9.8, 0) # acceleration due to gravity; units are m/s/s 59 | 60 | # Define time parameters 61 | t = 0 # starting time 62 | deltat = 0.001 # time step units are s 63 | 64 | 65 | ### CALCULATION LOOP; perform physics updates and drawing 66 | # ------------------------------------------------------------------------------------ 67 | 68 | while ball.pos.y >= 0 : #while the ball's y-position is greater than 0 (above the ground) 69 | 70 | # Required to make animation visible / refresh smoothly (keeps program from running faster 71 | # than 1000 frames/s) 72 | rate(1000) 73 | 74 | # Compute Net Force 75 | Fnet = ball.m * g 76 | 77 | # Newton's 2nd Law 78 | ball.v = ball.v + (Fnet/ball.m * deltat) 79 | 80 | # Position update 81 | ball.pos = ball.pos + ball.v * deltat 82 | 83 | # Update motion map, graph, timer, and trail 84 | posgraph.plot(ball.pos.x, ball.pos.y) # plot x and y position vs. time 85 | trail.append(pos = ball.pos) 86 | timerDisplay.update(t) 87 | 88 | # Time update 89 | t = t + deltat 90 | 91 | 92 | ### OUTPUT 93 | # -------------------------------------------------------------------------------------- 94 | 95 | # Print the final time and the ball's final position 96 | print t 97 | print ball.pos 98 | 99 | # Print the final time and the ball's final position 100 | print t 101 | print ball.pos 102 | print theta 103 | -------------------------------------------------------------------------------- /satellite motion/binary.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | 10 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 11 | # ------------------------------------------------------------------------ 12 | 13 | # Set window title 14 | scene.title = "Satellite Motion" 15 | 16 | # Make scene background black 17 | scene.background = color.black 18 | 19 | # Define scene objects (units are in meters) 20 | earth1 = sphere(radius = 6.378e6, color = color.blue) 21 | earth2 = sphere(radius = 6.378e6, color = color.blue) 22 | 23 | satellite = sphere(radius = 6.378e6, color = color.green) # r = 10 24 | 25 | # Set up trail to mark the satellite's trajectory 26 | trail = curve(color = color.yellow, radius = 5e5) # units are in meters 27 | 28 | # Set up motion map for satellite's velocity 29 | vMotionMap = MotionMap(satellite, 100000, # expected end time in seconds 30 | 10, # number of markers to draw 31 | markerScale = 5e3, # scale the vector so it fits on the screen 32 | labelMarkerOrder = False) 33 | 34 | # Set up motion map for satellite's acceleration 35 | aMotionMap = MotionMap(satellite, 100000, # expected end time in seconds 36 | 10, # number of markers to draw 37 | markerScale = 5e7, # scale the vector so it fits on the screen 38 | markerColor = color.orange, 39 | labelMarkerOrder = False) 40 | 41 | 42 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 43 | # ---------------------------------------------------------------------------------------- 44 | 45 | # Define parameters 46 | 47 | earth1.m = 1*5.972e24 # mass of the earth in kg 48 | earth2.m = 1 * 5.972e24 49 | earth2.pos = vector(2 * 4.23e7, 0, 0) 50 | satellite.m = 1000 # mass of satellite in kg 51 | satellite.pos = vector(5*4.23e7, 3*4.23e7, 0) # initial position of the satellite, units are in meters 52 | satellite.v = vector(-.0*3.07e3, -.4*3.07e3, 0) # initial velocity of the satellite 53 | 54 | # Define time parameters 55 | t = 0 # starting time 56 | deltat = 36 # time step units are s 57 | 58 | 59 | ### CALCULATION LOOP; perform physics updates and drawing 60 | # ------------------------------------------------------------------------------------ 61 | 62 | while t < 5000000 : 63 | 64 | # Required to make animation visible / refresh smoothly (keeps program from running faster 65 | # than 1000 frames/s) 66 | rate(1000) # 1000 67 | 68 | # Note: This model makes the false assumption that the stars are stationary 69 | #in space 70 | 71 | # Force on satellite by both stars 72 | Fg1 = (6.673e-11) * satellite.m * earth1.m / ((earth1.pos.x - satellite.pos.x)**2 + (earth1.pos.y - satellite.pos.y)**2) 73 | Fg2 = (6.673e-11) * satellite.m * earth2.m / ((earth2.pos.x - satellite.pos.x)**2 + (earth2.pos.y - satellite.pos.y)**2) 74 | 75 | 76 | # Fnet1 = vector(Fg1*(earth1.pos.x - satellite.pos.x), 77 | # Fg1*(earth1.pos.y - satellite.pos.y),0) 78 | # Fnet2 = vector(Fg2*(earth2.pos.x - satellite.pos.x), 79 | # Fg2*(earth2.pos.y - satellite.pos.y),0) 80 | 81 | Fnet1 = vector((earth1.pos.x - satellite.pos.x), 82 | (earth1.pos.y - satellite.pos.y),0) 83 | Fnet1.mag = Fg1 84 | 85 | Fnet2 = vector((earth2.pos.x - satellite.pos.x), 86 | (earth2.pos.y - satellite.pos.y),0) 87 | Fnet2.mag = Fg2 88 | 89 | Fnet = Fnet1 + Fnet2 90 | 91 | # Arctan can be undefined if x = 0,while it's unlickily, it's still possible 92 | # if Fnet.x == 0: 93 | # Fnet.mag = Fg1 +Fg2 94 | # else: 95 | # Fnet.mag = (Fg1 +Fg2) * math.sin(math.atan(math.fabs(Fnet.y/Fnet.x))) 96 | 97 | 98 | # Newton's 2nd Law 99 | satellite.v = satellite.v + (Fnet/satellite.m * deltat) 100 | 101 | # Position update 102 | satellite.pos = satellite.pos + satellite.v * deltat 103 | 104 | # Update motion maps and trail 105 | trail.append(pos = satellite.pos) 106 | #vMotionMap.update(t, satellite.v) 107 | #aMotionMap.update(t, Fnet/satellite.m) 108 | 109 | # Time update 110 | t = t + deltat 111 | 112 | 113 | ### OUTPUT 114 | # -------------------------------------------------------------------------------------- 115 | 116 | # Print the final time and the satellite's final position 117 | print t 118 | print satellite.v 119 | print Fnet/satellite.m 120 | -------------------------------------------------------------------------------- /inclined plane/inclinedPlane52.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "Incline Plane" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | scene.center = (5, 1, 0) # location at which the camera looks 18 | 19 | # Define scene objects (units are in meters) 20 | 21 | # 10-m long inclined plane whose center is at 5 m 22 | inclinedPlane = box(pos = vector(5, 0, 0), size = (10, 0.02, 0.2), 23 | color = color.green, opacity = 0.3) 24 | 25 | # 20-cm long cart on the inclined plane 26 | cart = box(size = (0.2, 0.06, 0.06), color = color.blue) 27 | 28 | # Set up graph with two plots 29 | posgraph = PhysGraph() 30 | velgraph = PhysGraph() 31 | accelgraph = PhysGraph() 32 | 33 | # Set up trail to mark the cart's trajectory 34 | trail = curve(color = color.yellow, radius = 0.01) # units are in meters 35 | 36 | # Set up motion map for cart 37 | motionMap = MotionMap(cart, 3, # expected end time in seconds 38 | 10, # number of markers to draw 39 | markerType = "breadcrumbs", 40 | dropTime = False) 41 | 42 | # Set timer in top right of screen 43 | timerDisplay = PhysTimer(9, 5) # timer position (units are in meters) 44 | 45 | 46 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 47 | # ---------------------------------------------------------------------------------------- 48 | 49 | # Define parameters 50 | cart.m = 0.5 # mass of cart in kg 51 | 52 | # initial position of the cart in(x, y, z) form, units are in meters 53 | # cart is positioned on the inclined plane at the far right end 54 | cart.pos = vector(9.1, 0.04, 0.08) 55 | 56 | cart.v = vector(0, 0, 0) # initial velocity of car in (vx, vy, vz) form, units are m/s 57 | 58 | # angle of inclined plane relative to the horizontal 59 | theta = 22.0 * (pi / 180.0) 60 | 61 | # rotate the cart and the inclined plane based on the specified angle (counterclockwise) 62 | inclinedPlane.rotate(angle = theta, origin = (0, 0, 0), axis = (0,0,1)) 63 | cart.rotate(angle = theta, origin = (0, 0, 0), axis = (0,0,1)) 64 | 65 | g = 9.8 # acceleration due to gravity; units are m/s/s 66 | 67 | # Define time parameters 68 | t = 0 # starting time 69 | deltat = 0.0005 # time step units are s 70 | 71 | print "initial cart position (m): ", cart.pos 72 | 73 | 74 | ### CALCULATION LOOP; perform physics updates and drawing 75 | # ------------------------------------------------------------------------------------ 76 | 77 | while cart.pos.y > 0.04 : # while the cart's y-position is greater than 0 (above the ground) 78 | 79 | # Required to make animation visible / refresh smoothly (keeps program from running faster 80 | # than 1000 frames/s) 81 | rate(1000) 82 | 83 | # Compute Net Force 84 | # set the direction of the net force along the inclined plane 85 | Fnet = norm(inclinedPlane.axis) 86 | # set the magnitude to the component of the gravitational force parallel to the inclined plane 87 | Fnet.mag = -(cart.m * g * sin(theta)) 88 | 89 | # Newton's 2nd Law 90 | cart.v = cart.v + (Fnet/cart.m * deltat) 91 | 92 | # Position update 93 | cart.pos = cart.pos + cart.v * deltat 94 | 95 | # Update motion map, graph, timer, and trail 96 | motionMap.update(t) 97 | posgraph.plot(t, mag(cart.pos)) # plot position (along inclined plane) vs. time 98 | velgraph.plot(t, mag(cart.v)) # plot velocity (along inclined plane) vs. time 99 | accelgraph.plot(t, mag(Fnet) / cart.m) # plot acceleration (along inclined plane) vs. time 100 | trail.append(pos = cart.pos) 101 | timerDisplay.update(t) 102 | 103 | # Time update 104 | t = t + deltat 105 | 106 | ### OUTPUT 107 | # -------------------------------------------------------------------------------------- 108 | 109 | # Print the final time and the cart's final position 110 | print "final time (s): ", t 111 | print "final cart position (m): ", cart.pos 112 | print "final cart velocity (m/s): ", cart.v 113 | print "final cart speed (m/s): ", mag(cart.v) 114 | print "final cart acceleration (m/s/s): ", (mag(Fnet) / cart.m) 115 | 116 | -------------------------------------------------------------------------------- /inclined plane/inclinedPlane53.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "Incline Plane" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | scene.center = (1, 1, 0) # location at which the camera looks 18 | 19 | # Define scene objects (units are in meters) 20 | 21 | # 2-m long inclined plane whose center is at 1 m 22 | inclinedPlane = box(pos = vector(1, 0, 0), size = (2, 0.02, 0.2), 23 | color = color.green, opacity = 0.3) 24 | 25 | # 20-cm long cart on the inclined plane 26 | cart = box(size = (0.2, 0.06, 0.06), color = color.blue) 27 | 28 | # Set up graph with two plots 29 | posgraph = PhysGraph() 30 | velgraph = PhysGraph() 31 | accelgraph = PhysGraph() 32 | 33 | # Set up trail to mark the cart's trajectory 34 | trail = curve(color = color.yellow, radius = 0.01) # units are in meters 35 | 36 | # Set up motion map for cart 37 | motionMap = MotionMap(cart, 2, # expected end time in seconds 38 | 10, # number of markers to draw 39 | markerType = "breadcrumbs", 40 | dropTime = False) 41 | 42 | # Set timer in top right of screen 43 | timerDisplay = PhysTimer(2, 1.5) # timer position (units are in meters) 44 | 45 | 46 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 47 | # ---------------------------------------------------------------------------------------- 48 | 49 | # Define parameters 50 | cart.m = 0.5 # mass of cart in kg 51 | 52 | # initial position of the cart in(x, y, z) form, units are in meters 53 | # cart is positioned on the inclined plane at the far left end 54 | cart.pos = vector(0, 0.04, 0.08) 55 | 56 | cart.v = vector(0, 0, 0) # initial velocity of car in (vx, vy, vz) form, units are m/s 57 | 58 | # angle of inclined plane relative to the horizontal 59 | theta = 22.0 * (pi / 180.0) 60 | 61 | # rotate the cart and the inclined plane based on the specified angle (counterclockwise) 62 | inclinedPlane.rotate(angle = theta, origin = (0, 0, 0), axis = (0,0,1)) 63 | cart.rotate(angle = theta, origin = (0, 0, 0), axis = (0,0,1)) 64 | 65 | # set the initial velocity up the ramp; units are m/s 66 | cart.v = norm(inclinedPlane.axis) 67 | cart.v.mag = 3 68 | 69 | g = 9.8 # acceleration due to gravity; units are m/s/s 70 | 71 | # Define time parameters 72 | t = 0 # starting time 73 | deltat = 0.0005 # time step units are s 74 | 75 | print "initial cart position (m): ", cart.pos 76 | 77 | 78 | ### CALCULATION LOOP; perform physics updates and drawing 79 | # ------------------------------------------------------------------------------------ 80 | 81 | while cart.pos.y > 0.03 : # while the cart's y-position is greater than 0 (above the ground) 82 | 83 | # Required to make animation visible / refresh smoothly (keeps program from running faster 84 | # than 1000 frames/s) 85 | rate(1000) 86 | 87 | # Compute Net Force 88 | # set the direction of the net force along the inclined plane 89 | Fnet = norm(inclinedPlane.axis) 90 | # set the magnitude to the component of the gravitational force parallel to the inclined plane 91 | Fnet.mag = -(cart.m * g * sin(theta)) 92 | 93 | # Newton's 2nd Law 94 | cart.v = cart.v + (Fnet/cart.m * deltat) 95 | 96 | # Position update 97 | cart.pos = cart.pos + cart.v * deltat 98 | 99 | # Update motion map, graph, timer, and trail 100 | motionMap.update(t) 101 | posgraph.plot(t, mag(cart.pos)) # plot position (along inclined plane) vs. time 102 | velgraph.plot(t, mag(cart.v)) # plot velocity (along inclined plane) vs. time 103 | accelgraph.plot(t, mag(Fnet) / cart.m) # plot acceleration (along inclined plane) vs. time 104 | trail.append(pos = cart.pos) 105 | timerDisplay.update(t) 106 | 107 | # Time update 108 | t = t + deltat 109 | 110 | ### OUTPUT 111 | # -------------------------------------------------------------------------------------- 112 | 113 | # Print the final time and the cart's final position 114 | print "final time (s): ", t 115 | print "final cart position (m): ", cart.pos 116 | print "final cart velocity (m/s): ", cart.v 117 | print "final cart speed (m/s): ", mag(cart.v) 118 | print "final cart acceleration (m/s/s): ", (mag(Fnet) / cart.m) 119 | 120 | -------------------------------------------------------------------------------- /inclined plane/inclinedPlane54.py: -------------------------------------------------------------------------------- 1 | ### INITIALIZE VPYTHON 2 | # ----------------------------------------------------------------------- 3 | 4 | from __future__ import division 5 | from visual import * 6 | from physutil import * 7 | from visual.graph import * 8 | 9 | ### SETUP ELEMENTS FOR GRAPHING, SIMULATION, VISUALIZATION, TIMING 10 | # ------------------------------------------------------------------------ 11 | 12 | # Set window title 13 | scene.title = "Incline Plane" 14 | 15 | # Make scene background black 16 | scene.background = color.black 17 | scene.center = (0.7, 1, 0) # location at which the camera looks 18 | 19 | # Define scene objects (units are in meters) 20 | 21 | # 1.4-m long inclined plane whose center is at 0.7 m 22 | inclinedPlane = box(pos = vector(0.7, 0, 0), size = (1.4, 0.02, 0.2), 23 | color = color.green, opacity = 0.3) 24 | 25 | # 20-cm long cart on the inclined plane 26 | cart = box(size = (0.2, 0.06, 0.06), color = color.blue) 27 | 28 | # Set up graph with two plots 29 | posgraph = PhysGraph() 30 | velgraph = PhysGraph() 31 | accelgraph = PhysGraph() 32 | 33 | # Set up trail to mark the cart's trajectory 34 | trail = curve(color = color.yellow, radius = 0.01) # units are in meters 35 | 36 | # Set up motion map for cart 37 | motionMap = MotionMap(cart, 2, # expected end time in seconds 38 | 10, # number of markers to draw 39 | markerType = "breadcrumbs", 40 | dropTime = False) 41 | 42 | # Set timer in top right of screen 43 | timerDisplay = PhysTimer(1.5, 1) # timer position (units are in meters) 44 | 45 | 46 | ### SETUP PARAMETERS AND INITIAL CONDITIONS 47 | # ---------------------------------------------------------------------------------------- 48 | 49 | # Define parameters 50 | cart.m = 0.5 # mass of cart in kg 51 | 52 | # initial position of the cart in(x, y, z) form, units are in meters 53 | # cart is positioned on the inclined plane at the far left end 54 | cart.pos = vector(0, 0.04, 0.08) 55 | 56 | cart.v = vector(0, 0, 0) # initial velocity of car in (vx, vy, vz) form, units are m/s 57 | 58 | # angle of inclined plane relative to the horizontal 59 | theta = 22.0 * (pi / 180.0) 60 | 61 | # rotate the cart and the inclined plane based on the specified angle (counterclockwise) 62 | inclinedPlane.rotate(angle = theta, origin = (0, 0, 0), axis = (0,0,1)) 63 | cart.rotate(angle = theta, origin = (0, 0, 0), axis = (0,0,1)) 64 | 65 | # set the initial velocity up the ramp; units are m/s 66 | cart.v = norm(inclinedPlane.axis) 67 | cart.v.mag = 3 68 | 69 | g = 9.8 # acceleration due to gravity; units are m/s/s 70 | 71 | mu = 0.20 # coefficient of friction between cart and plane 72 | 73 | # Define time parameters 74 | t = 0 # starting time 75 | deltat = 0.0005 # time step units are s 76 | 77 | print "initial cart position (m): ", cart.pos 78 | 79 | 80 | ### CALCULATION LOOP; perform physics updates and drawing 81 | # ------------------------------------------------------------------------------------ 82 | 83 | while cart.pos.y > 0.03 : # while the cart's y-position is greater than 0 (above the ground) 84 | 85 | # Required to make animation visible / refresh smoothly (keeps program from running faster 86 | # than 1000 frames/s) 87 | rate(1000) 88 | 89 | # Compute Net Force 90 | # set the direction of the net force along the inclined plane 91 | Fnet = norm(inclinedPlane.axis) 92 | # set the magnitude to the component of the gravitational force parallel to the inclined plane 93 | Fnet.mag = -(cart.m * g * sin(theta)) 94 | if cart.v.y > 0: 95 | Fnet.mag += (mu * cart.m * g * cos(theta)) 96 | else: 97 | Fnet.mag -= (mu * cart.m * g * cos(theta)) 98 | 99 | # Newton's 2nd Law 100 | cart.v = cart.v + (Fnet/cart.m * deltat) 101 | 102 | # Position update 103 | cart.pos = cart.pos + cart.v * deltat 104 | 105 | # Update motion map, graph, timer, and trail 106 | motionMap.update(t) 107 | posgraph.plot(t, mag(cart.pos)) # plot position (along inclined plane) vs. time 108 | velgraph.plot(t, mag(cart.v)) # plot velocity (along inclined plane) vs. time 109 | accelgraph.plot(t, mag(Fnet) / cart.m) # plot acceleration (along inclined plane) vs. time 110 | trail.append(pos = cart.pos) 111 | timerDisplay.update(t) 112 | 113 | # Time update 114 | t = t + deltat 115 | 116 | ### OUTPUT 117 | # -------------------------------------------------------------------------------------- 118 | 119 | # Print the final time and the cart's final position 120 | print "final time (s): ", t 121 | print "final cart position (m): ", cart.pos 122 | print "final cart velocity (m/s): ", cart.v 123 | print "final cart speed (m/s): ", mag(cart.v) 124 | print "final cart acceleration (m/s/s): ", (mag(Fnet) / cart.m) 125 | 126 | -------------------------------------------------------------------------------- /buoyancy/physutil.py: -------------------------------------------------------------------------------- 1 | # physutil.py v1.22 2 | # Copyright (c) 2011-2012 GT Physics Education Research Group 3 | # License: GPL-3.0 (http://opensource.org/licenses/GPL-3.0) 4 | 5 | # This module is built to simplify and assist high school physics students 6 | # in the construction of models for lab exercises using VPython. 7 | 8 | 9 | # Revisions by date 10 | 11 | # v1.22 24 January 2011 -- Danny Caballero 12 | # Added labelColor attribute to PhysAxis, MotionMap, and MotionMapN 13 | # controls color of text 14 | 15 | # v1.21 5 December 2011 -- Danny Caballero 16 | # Added timerColor attribute to PhysTimer 17 | # controls color of text 18 | 19 | # v1.2 19 October 2011 -- Danny Caballero 20 | # Added MotionMapN, a class that allows the placing of breadcrumbs or arrows 21 | # every "n" steps. 22 | 23 | # v1.13 26 September 2011 -- Daniel Borrero 24 | # Fixed unit test bug for PhysTimer 25 | 26 | # v1.12 30 August 2011 -- Daniel Borrero 27 | # Fixed bug in PhysTimer output 28 | # E.g., 2.00 s is now displayed as 00:00:02.00 instead of 00:00:01:100 29 | 30 | # v1.11 29 August 2011 -- Danny Caballero 31 | # Changed License to GNU 32 | 33 | # v1.1 15 August 2011 -- Daniel Borrero 34 | # Print statements made compatible with Python 3.1 35 | 36 | # v1.01 16 July 2011 -- Danny Caballero 37 | # Added ability to change PhysAxis color using axisColor 38 | 39 | # v1.0 29 April 2011 -- CS Build Team 40 | # Heavy Modification 41 | 42 | # v0.1 05 January 2011 -- Danny Caballero 43 | # Initial Build 44 | 45 | from __future__ import division 46 | import unittest 47 | 48 | """ 49 | # 50 | # 51 | # UNIT TESTING / IMPORT SETUP CODE ------------------------------------------------------------ 52 | # 53 | # 54 | """ 55 | 56 | # Determine whether we are being used as a module or just running unittests (for mock purposes this is important) 57 | if __name__ == "__main__": 58 | # If we are unit testing, set up mock objects (must be done before classes are defined below!) 59 | from visual import vector 60 | class Mock: 61 | def __init__(self, name, *args, **kwargs): 62 | self.name = name 63 | self.called = 0 64 | 65 | def __call__(self, *args, **kwargs): 66 | self.args = args 67 | self.kwargs = kwargs 68 | for name in kwargs: 69 | setattr(self, name, kwargs[name]) 70 | self.called += 1 71 | return self 72 | 73 | def reset(self): 74 | self.called = 0 75 | 76 | color = Mock("color") 77 | color.red = "red" 78 | color.green = "green" 79 | color.blue = "blue" 80 | color.yellow = "yellow" 81 | color.orange = "orange" 82 | color.cyan = "cyan" 83 | color.magenta = "magenta" 84 | color.white = "white" 85 | 86 | arrow = Mock("arrow") 87 | label = Mock("label") 88 | points = Mock("points") 89 | curve = Mock("curve") 90 | gdisplay = Mock("gdisplay") 91 | gcurve = Mock("gcurve") 92 | gcurve.plots = [] 93 | def mockPlot(pos): 94 | gcurve.plots.append(pos) 95 | gcurve.plot = mockPlot 96 | 97 | """ 98 | vector = Mock("vector") 99 | def call(x, y, z): 100 | vector.x = x 101 | vector.y = y 102 | vector.z = z 103 | vector.__call__ = call 104 | """ 105 | 106 | else: 107 | # These are the actual imports for the utility 108 | from visual import * 109 | from visual.graph import * 110 | 111 | 112 | """ 113 | # 114 | # 115 | # ACTUAL PHYSUTIL CODE FOLLOWS -------------------------------------------------- 116 | # 117 | # 118 | """ 119 | 120 | # Initialize window positions for students (if we aren't unit testing) 121 | if __name__ != "__main__": 122 | scene.x = 50 123 | scene.y = 50 124 | 125 | # Helper function for returning proper size of something 126 | def obj_size(obj): 127 | if type(obj) == box or type(obj) == pyramid: 128 | return obj.size 129 | elif type(obj) == sphere: 130 | return vector(obj.radius, obj.radius, obj.radius) 131 | 132 | class MotionMap: 133 | """ 134 | This class assists students in constructing motion maps 135 | using either arrows (measuring a quantity) or "breadcrumbs" 136 | (with timestamps). 137 | """ 138 | 139 | def __init__(self, obj, tf, numMarkers, markerType="arrow", 140 | markerScale=1, markerColor=color.red, 141 | labelMarkerOrder=True, labelMarkerOffset=vector(0,0,0), 142 | dropTime=False, timeOffset=vector(0,0,0), arrowOffset=vector(0,0,0), labelColor=color.white): 143 | # MotionMap 144 | # obj - object to track in mapping / placing markers 145 | # tf - expected tFinal, used to space marker placement over time 146 | # numMarkers - number of markers to place 147 | # markerType - determines type of motionmap; options are "arrow" or "breadcrumbs" 148 | # markerScale - replaces pSize / quantscale from motionmodule.py depending on type 149 | # markerColor - color of markers 150 | # labelMarkerOrder - drop numbers of markers? 151 | # labelMarkerOffset - amount to offset numbering by 152 | # dropTime - boolean determining whether a timestamp should be placed along with the marker 153 | # timeOffset - if dropTime is True, determines the offset, if any, of the label from the marker 154 | # arrowOffset - shift an arrow by an amount (x,y,z), useful for two arrows views 155 | 156 | self.obj = obj 157 | self.tf = tf 158 | self.numMarkers = numMarkers 159 | self.markerType = markerType 160 | self.markerScale = markerScale 161 | self.markerColor = markerColor 162 | self.labelMarkerOrder = labelMarkerOrder 163 | self.labelMarkerOffset = labelMarkerOffset 164 | self.timeOffset = timeOffset 165 | self.dropTime = dropTime 166 | self.arrowOffset = arrowOffset 167 | self.labelColor = labelColor 168 | 169 | # Calculate size of interval for each step, set initial step index 170 | try: 171 | self.interval = self.tf / self.numMarkers 172 | except TypeError as err: 173 | print("**********TYPE ERROR**********") 174 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 175 | print("******************************") 176 | print(err) 177 | raise err 178 | self.curMarker = 0 179 | 180 | 181 | def update(self, t, quantity=1): 182 | try: 183 | # Display new arrow if t has broken next threshold 184 | if t > (self.interval * self.curMarker): 185 | # Increment threshold 186 | self.curMarker += 1 187 | 188 | # Display marker! 189 | if self.markerType == "arrow": 190 | arrow(pos=self.obj.pos+self.arrowOffset, 191 | axis=self.markerScale*quantity, color=self.markerColor) 192 | elif self.markerType == "breadcrumbs": 193 | points(pos=self.obj.pos, 194 | size=10*self.markerScale*quantity, color=self.markerColor) 195 | 196 | #Also display timestamp if requested 197 | if self.dropTime is not False: 198 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 199 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 200 | 201 | # Same with order label 202 | if self.labelMarkerOrder is not False: 203 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 204 | except TypeError as err: 205 | print("**********TYPE ERROR**********") 206 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 207 | print("******************************") 208 | print(err) 209 | raise err 210 | 211 | class MotionMapN: 212 | """ 213 | This class assists students in constructing motion maps 214 | using either arrows (measuring a quantity) or "breadcrumbs" 215 | (with timestamps). 216 | """ 217 | 218 | def __init__(self, obj, dt, numSteps, markerType="arrow", 219 | markerScale=1, markerColor=color.red, 220 | labelMarkerOrder=True, labelMarkerOffset=vector(0,0,0), 221 | dropTime=False, timeOffset=vector(0,0,0), arrowOffset=vector(0,0,0), labelColor=color.white): 222 | # MotionMapN 223 | # obj - object to track in mapping / placing markers 224 | # dt - time between steps 225 | # numSteps - number of steps between markers 226 | # markerType - determines type of motionmap; options are "arrow" or "breadcrumbs" 227 | # markerScale - replaces pSize / quantscale from motionmodule.py depending on type 228 | # markerColor - color of markers 229 | # labelMarkerOrder - drop numbers of markers? 230 | # labelMarkerOffset - amount to offset numbering by 231 | # dropTime - boolean determining whether a timestamp should be placed along with the marker 232 | # timeOffset - if dropTime is True, determines the offset, if any, of the label from the markers 233 | # arrowOffset - shift an arrow by an amount (x,y,z), useful for two arrows views 234 | 235 | self.obj = obj 236 | self.dt = dt 237 | self.numSteps = numSteps 238 | self.markerType = markerType 239 | self.markerScale = markerScale 240 | self.markerColor = markerColor 241 | self.labelMarkerOrder = labelMarkerOrder 242 | self.labelMarkerOffset = labelMarkerOffset 243 | self.timeOffset = timeOffset 244 | self.dropTime = dropTime 245 | self.arrowOffset = arrowOffset 246 | self.labelColor = labelColor 247 | 248 | # Calculate size of interval for each step, set initial step index 249 | try: 250 | self.interval = self.dt * self.numSteps 251 | except TypeError as err: 252 | print("**********TYPE ERROR**********") 253 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 254 | print("******************************") 255 | print(err) 256 | raise err 257 | self.curMarker = 0 258 | 259 | 260 | def update(self, t, quantity=1): 261 | try: 262 | 263 | threshold = self.interval * self.curMarker 264 | # Display new arrow if t has broken new threshold 265 | if t >= threshold: 266 | 267 | # Increment marker count 268 | self.curMarker += 1 269 | 270 | # Display marker! 271 | if self.markerType == "arrow": 272 | arrow(pos=self.obj.pos+self.arrowOffset, 273 | axis=self.markerScale*quantity, color=self.markerColor) 274 | elif self.markerType == "breadcrumbs": 275 | points(pos=self.obj.pos, 276 | size=10*self.markerScale*quantity, color=self.markerColor) 277 | 278 | #Also display timestamp if requested 279 | if self.dropTime is not False: 280 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 281 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 282 | 283 | # Same with order label 284 | if self.labelMarkerOrder is not False: 285 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 286 | 287 | except TypeError as err: 288 | print("**********TYPE ERROR**********") 289 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 290 | print("******************************") 291 | print(err) 292 | raise err 293 | 294 | class PhysAxis: 295 | """ 296 | This class assists students in creating dynamic axes for their models. 297 | """ 298 | 299 | def __init__(self, obj, numLabels, axisType="x", axis=vector(1,0,0), startPos=None, 300 | length=None, labels = None, labelOrientation="down", axisColor=color.yellow, labelColor=color.white): 301 | # PhysAxis 302 | # obj - Object which axis is oriented based on by default 303 | # numLabels - number of labels on axis 304 | # axisType - sets whether this is a default axis of x or y, or an arbitrary axis 305 | # axis - unit vector defining the orientation of the axis to be created IF axisType = "arbitrary" 306 | # startPos - start position for the axis - defaults to (-obj_size(obj).x/2,-4*obj_size(obj).y,0) 307 | # length - length of the axis - defaults to obj_size(obj).x 308 | # labelOrientation - how labels are placed relative to axis markers - "up", "down", "left", or "right" 309 | 310 | try: 311 | self.intervalMarkers = [] 312 | self.intervalLabels = [] 313 | self.labelText = labels 314 | self.obj = obj 315 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 316 | self.numLabels = numLabels 317 | self.axisType = axisType 318 | self.axis = axis if axisType != "y" else vector(0,1,0) 319 | self.length = length if (length is not None) else obj_size(obj).x 320 | self.startPos = startPos if (startPos is not None) else vector(-obj_size(obj).x/2,-4*obj_size(obj).y,0) 321 | self.axisColor = axisColor 322 | self.labelColor = labelColor 323 | 324 | if labelOrientation == "down": 325 | self.labelShift = vector(0,-0.05*self.length,0) 326 | elif labelOrientation == "up": 327 | self.labelShift = vector(0,0.05*self.length,0) 328 | elif labelOrientation == "left": 329 | self.labelShift = vector(-0.1*self.length,0,0) 330 | elif labelOrientation == "right": 331 | self.labelShift = vector(0.1*self.length,0,0) 332 | 333 | self.__reorient() 334 | except TypeError as err: 335 | print("**********TYPE ERROR**********") 336 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 337 | print("******************************") 338 | print(err) 339 | raise err 340 | 341 | def update(self): 342 | try: 343 | # Determine if reference obj. has shifted since last update, if so shift us too 344 | if self.obj.pos != self.lastPos: 345 | diff = self.obj.pos - self.lastPos 346 | 347 | for i in range(len(self.intervalMarkers)): 348 | self.intervalMarkers[i].pos += diff 349 | self.intervalLabels[i].pos += diff 350 | self.axisCurve.pos = [x + diff for x in self.axisCurve.pos] 351 | 352 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 353 | except TypeError as err: 354 | print("**********TYPE ERROR**********") 355 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 356 | print("******************************") 357 | print(err) 358 | raise err 359 | 360 | def reorient(self, axis=None, startPos=None, length=None, labels=None, labelOrientation=None): 361 | try: 362 | # Determine which, if any, parameters are being modified 363 | self.axis = axis if axis is not None else self.axis 364 | self.startPos = startPos if startPos is not None else self.startPos 365 | self.length = length if length is not None else self.length 366 | self.labelText = labels if labels is not None else self.labels 367 | 368 | # Re-do label orientation as well, if it has been set 369 | if labelOrientation == "down": 370 | self.labelShift = vector(0,-0.05*self.length,0) 371 | elif labelOrientation == "up": 372 | self.labelShift = vector(0,0.05*self.length,0) 373 | elif labelOrientation == "left": 374 | self.labelShift = vector(-0.1*self.length,0,0) 375 | elif labelOrientation == "right": 376 | self.labelShift = vector(0.1*self.length,0,0) 377 | 378 | self.__reorient() 379 | except TypeError as err: 380 | print("**********TYPE ERROR**********") 381 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 382 | print("******************************") 383 | print(err) 384 | raise err 385 | 386 | def __reorient(self): 387 | # Actual internal axis setup code... determines first whether we are creating or updating 388 | updating = True if len(self.intervalMarkers) > 0 else False 389 | 390 | # Then determines the endpoint of the axis and the interval 391 | final = self.startPos + (self.length * self.axis) 392 | interval = (self.length / (self.numLabels-1)) * self.axis 393 | 394 | # Loop for each interval marker, setting up or updating the markers and labels 395 | i=0 396 | while i (self.interval * self.curMarker): 185 | # Increment threshold 186 | self.curMarker += 1 187 | 188 | # Display marker! 189 | if self.markerType == "arrow": 190 | arrow(pos=self.obj.pos+self.arrowOffset, 191 | axis=self.markerScale*quantity, color=self.markerColor) 192 | elif self.markerType == "breadcrumbs": 193 | points(pos=self.obj.pos, 194 | size=10*self.markerScale*quantity, color=self.markerColor) 195 | 196 | #Also display timestamp if requested 197 | if self.dropTime is not False: 198 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 199 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 200 | 201 | # Same with order label 202 | if self.labelMarkerOrder is not False: 203 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 204 | except TypeError as err: 205 | print("**********TYPE ERROR**********") 206 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 207 | print("******************************") 208 | print(err) 209 | raise err 210 | 211 | class MotionMapN: 212 | """ 213 | This class assists students in constructing motion maps 214 | using either arrows (measuring a quantity) or "breadcrumbs" 215 | (with timestamps). 216 | """ 217 | 218 | def __init__(self, obj, dt, numSteps, markerType="arrow", 219 | markerScale=1, markerColor=color.red, 220 | labelMarkerOrder=True, labelMarkerOffset=vector(0,0,0), 221 | dropTime=False, timeOffset=vector(0,0,0), arrowOffset=vector(0,0,0), labelColor=color.white): 222 | # MotionMapN 223 | # obj - object to track in mapping / placing markers 224 | # dt - time between steps 225 | # numSteps - number of steps between markers 226 | # markerType - determines type of motionmap; options are "arrow" or "breadcrumbs" 227 | # markerScale - replaces pSize / quantscale from motionmodule.py depending on type 228 | # markerColor - color of markers 229 | # labelMarkerOrder - drop numbers of markers? 230 | # labelMarkerOffset - amount to offset numbering by 231 | # dropTime - boolean determining whether a timestamp should be placed along with the marker 232 | # timeOffset - if dropTime is True, determines the offset, if any, of the label from the markers 233 | # arrowOffset - shift an arrow by an amount (x,y,z), useful for two arrows views 234 | 235 | self.obj = obj 236 | self.dt = dt 237 | self.numSteps = numSteps 238 | self.markerType = markerType 239 | self.markerScale = markerScale 240 | self.markerColor = markerColor 241 | self.labelMarkerOrder = labelMarkerOrder 242 | self.labelMarkerOffset = labelMarkerOffset 243 | self.timeOffset = timeOffset 244 | self.dropTime = dropTime 245 | self.arrowOffset = arrowOffset 246 | self.labelColor = labelColor 247 | 248 | # Calculate size of interval for each step, set initial step index 249 | try: 250 | self.interval = self.dt * self.numSteps 251 | except TypeError as err: 252 | print("**********TYPE ERROR**********") 253 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 254 | print("******************************") 255 | print(err) 256 | raise err 257 | self.curMarker = 0 258 | 259 | 260 | def update(self, t, quantity=1): 261 | try: 262 | 263 | threshold = self.interval * self.curMarker 264 | # Display new arrow if t has broken new threshold 265 | if t >= threshold: 266 | 267 | # Increment marker count 268 | self.curMarker += 1 269 | 270 | # Display marker! 271 | if self.markerType == "arrow": 272 | arrow(pos=self.obj.pos+self.arrowOffset, 273 | axis=self.markerScale*quantity, color=self.markerColor) 274 | elif self.markerType == "breadcrumbs": 275 | points(pos=self.obj.pos, 276 | size=10*self.markerScale*quantity, color=self.markerColor) 277 | 278 | #Also display timestamp if requested 279 | if self.dropTime is not False: 280 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 281 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 282 | 283 | # Same with order label 284 | if self.labelMarkerOrder is not False: 285 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 286 | 287 | except TypeError as err: 288 | print("**********TYPE ERROR**********") 289 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 290 | print("******************************") 291 | print(err) 292 | raise err 293 | 294 | class PhysAxis: 295 | """ 296 | This class assists students in creating dynamic axes for their models. 297 | """ 298 | 299 | def __init__(self, obj, numLabels, axisType="x", axis=vector(1,0,0), startPos=None, 300 | length=None, labels = None, labelOrientation="down", axisColor=color.yellow, labelColor=color.white): 301 | # PhysAxis 302 | # obj - Object which axis is oriented based on by default 303 | # numLabels - number of labels on axis 304 | # axisType - sets whether this is a default axis of x or y, or an arbitrary axis 305 | # axis - unit vector defining the orientation of the axis to be created IF axisType = "arbitrary" 306 | # startPos - start position for the axis - defaults to (-obj_size(obj).x/2,-4*obj_size(obj).y,0) 307 | # length - length of the axis - defaults to obj_size(obj).x 308 | # labelOrientation - how labels are placed relative to axis markers - "up", "down", "left", or "right" 309 | 310 | try: 311 | self.intervalMarkers = [] 312 | self.intervalLabels = [] 313 | self.labelText = labels 314 | self.obj = obj 315 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 316 | self.numLabels = numLabels 317 | self.axisType = axisType 318 | self.axis = axis if axisType != "y" else vector(0,1,0) 319 | self.length = length if (length is not None) else obj_size(obj).x 320 | self.startPos = startPos if (startPos is not None) else vector(-obj_size(obj).x/2,-4*obj_size(obj).y,0) 321 | self.axisColor = axisColor 322 | self.labelColor = labelColor 323 | 324 | if labelOrientation == "down": 325 | self.labelShift = vector(0,-0.05*self.length,0) 326 | elif labelOrientation == "up": 327 | self.labelShift = vector(0,0.05*self.length,0) 328 | elif labelOrientation == "left": 329 | self.labelShift = vector(-0.1*self.length,0,0) 330 | elif labelOrientation == "right": 331 | self.labelShift = vector(0.1*self.length,0,0) 332 | 333 | self.__reorient() 334 | except TypeError as err: 335 | print("**********TYPE ERROR**********") 336 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 337 | print("******************************") 338 | print(err) 339 | raise err 340 | 341 | def update(self): 342 | try: 343 | # Determine if reference obj. has shifted since last update, if so shift us too 344 | if self.obj.pos != self.lastPos: 345 | diff = self.obj.pos - self.lastPos 346 | 347 | for i in range(len(self.intervalMarkers)): 348 | self.intervalMarkers[i].pos += diff 349 | self.intervalLabels[i].pos += diff 350 | self.axisCurve.pos = [x + diff for x in self.axisCurve.pos] 351 | 352 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 353 | except TypeError as err: 354 | print("**********TYPE ERROR**********") 355 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 356 | print("******************************") 357 | print(err) 358 | raise err 359 | 360 | def reorient(self, axis=None, startPos=None, length=None, labels=None, labelOrientation=None): 361 | try: 362 | # Determine which, if any, parameters are being modified 363 | self.axis = axis if axis is not None else self.axis 364 | self.startPos = startPos if startPos is not None else self.startPos 365 | self.length = length if length is not None else self.length 366 | self.labelText = labels if labels is not None else self.labels 367 | 368 | # Re-do label orientation as well, if it has been set 369 | if labelOrientation == "down": 370 | self.labelShift = vector(0,-0.05*self.length,0) 371 | elif labelOrientation == "up": 372 | self.labelShift = vector(0,0.05*self.length,0) 373 | elif labelOrientation == "left": 374 | self.labelShift = vector(-0.1*self.length,0,0) 375 | elif labelOrientation == "right": 376 | self.labelShift = vector(0.1*self.length,0,0) 377 | 378 | self.__reorient() 379 | except TypeError as err: 380 | print("**********TYPE ERROR**********") 381 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 382 | print("******************************") 383 | print(err) 384 | raise err 385 | 386 | def __reorient(self): 387 | # Actual internal axis setup code... determines first whether we are creating or updating 388 | updating = True if len(self.intervalMarkers) > 0 else False 389 | 390 | # Then determines the endpoint of the axis and the interval 391 | final = self.startPos + (self.length * self.axis) 392 | interval = (self.length / (self.numLabels-1)) * self.axis 393 | 394 | # Loop for each interval marker, setting up or updating the markers and labels 395 | i=0 396 | while i (self.interval * self.curMarker): 185 | # Increment threshold 186 | self.curMarker += 1 187 | 188 | # Display marker! 189 | if self.markerType == "arrow": 190 | arrow(pos=self.obj.pos+self.arrowOffset, 191 | axis=self.markerScale*quantity, color=self.markerColor) 192 | elif self.markerType == "breadcrumbs": 193 | points(pos=self.obj.pos, 194 | size=10*self.markerScale*quantity, color=self.markerColor) 195 | 196 | #Also display timestamp if requested 197 | if self.dropTime is not False: 198 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 199 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 200 | 201 | # Same with order label 202 | if self.labelMarkerOrder is not False: 203 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 204 | except TypeError as err: 205 | print("**********TYPE ERROR**********") 206 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 207 | print("******************************") 208 | print(err) 209 | raise err 210 | 211 | class MotionMapN: 212 | """ 213 | This class assists students in constructing motion maps 214 | using either arrows (measuring a quantity) or "breadcrumbs" 215 | (with timestamps). 216 | """ 217 | 218 | def __init__(self, obj, dt, numSteps, markerType="arrow", 219 | markerScale=1, markerColor=color.red, 220 | labelMarkerOrder=True, labelMarkerOffset=vector(0,0,0), 221 | dropTime=False, timeOffset=vector(0,0,0), arrowOffset=vector(0,0,0), labelColor=color.white): 222 | # MotionMapN 223 | # obj - object to track in mapping / placing markers 224 | # dt - time between steps 225 | # numSteps - number of steps between markers 226 | # markerType - determines type of motionmap; options are "arrow" or "breadcrumbs" 227 | # markerScale - replaces pSize / quantscale from motionmodule.py depending on type 228 | # markerColor - color of markers 229 | # labelMarkerOrder - drop numbers of markers? 230 | # labelMarkerOffset - amount to offset numbering by 231 | # dropTime - boolean determining whether a timestamp should be placed along with the marker 232 | # timeOffset - if dropTime is True, determines the offset, if any, of the label from the markers 233 | # arrowOffset - shift an arrow by an amount (x,y,z), useful for two arrows views 234 | 235 | self.obj = obj 236 | self.dt = dt 237 | self.numSteps = numSteps 238 | self.markerType = markerType 239 | self.markerScale = markerScale 240 | self.markerColor = markerColor 241 | self.labelMarkerOrder = labelMarkerOrder 242 | self.labelMarkerOffset = labelMarkerOffset 243 | self.timeOffset = timeOffset 244 | self.dropTime = dropTime 245 | self.arrowOffset = arrowOffset 246 | self.labelColor = labelColor 247 | 248 | # Calculate size of interval for each step, set initial step index 249 | try: 250 | self.interval = self.dt * self.numSteps 251 | except TypeError as err: 252 | print("**********TYPE ERROR**********") 253 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 254 | print("******************************") 255 | print(err) 256 | raise err 257 | self.curMarker = 0 258 | 259 | 260 | def update(self, t, quantity=1): 261 | try: 262 | 263 | threshold = self.interval * self.curMarker 264 | # Display new arrow if t has broken new threshold 265 | if t >= threshold: 266 | 267 | # Increment marker count 268 | self.curMarker += 1 269 | 270 | # Display marker! 271 | if self.markerType == "arrow": 272 | arrow(pos=self.obj.pos+self.arrowOffset, 273 | axis=self.markerScale*quantity, color=self.markerColor) 274 | elif self.markerType == "breadcrumbs": 275 | points(pos=self.obj.pos, 276 | size=10*self.markerScale*quantity, color=self.markerColor) 277 | 278 | #Also display timestamp if requested 279 | if self.dropTime is not False: 280 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 281 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 282 | 283 | # Same with order label 284 | if self.labelMarkerOrder is not False: 285 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 286 | 287 | except TypeError as err: 288 | print("**********TYPE ERROR**********") 289 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 290 | print("******************************") 291 | print(err) 292 | raise err 293 | 294 | class PhysAxis: 295 | """ 296 | This class assists students in creating dynamic axes for their models. 297 | """ 298 | 299 | def __init__(self, obj, numLabels, axisType="x", axis=vector(1,0,0), startPos=None, 300 | length=None, labels = None, labelOrientation="down", axisColor=color.yellow, labelColor=color.white): 301 | # PhysAxis 302 | # obj - Object which axis is oriented based on by default 303 | # numLabels - number of labels on axis 304 | # axisType - sets whether this is a default axis of x or y, or an arbitrary axis 305 | # axis - unit vector defining the orientation of the axis to be created IF axisType = "arbitrary" 306 | # startPos - start position for the axis - defaults to (-obj_size(obj).x/2,-4*obj_size(obj).y,0) 307 | # length - length of the axis - defaults to obj_size(obj).x 308 | # labelOrientation - how labels are placed relative to axis markers - "up", "down", "left", or "right" 309 | 310 | try: 311 | self.intervalMarkers = [] 312 | self.intervalLabels = [] 313 | self.labelText = labels 314 | self.obj = obj 315 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 316 | self.numLabels = numLabels 317 | self.axisType = axisType 318 | self.axis = axis if axisType != "y" else vector(0,1,0) 319 | self.length = length if (length is not None) else obj_size(obj).x 320 | self.startPos = startPos if (startPos is not None) else vector(-obj_size(obj).x/2,-4*obj_size(obj).y,0) 321 | self.axisColor = axisColor 322 | self.labelColor = labelColor 323 | 324 | if labelOrientation == "down": 325 | self.labelShift = vector(0,-0.05*self.length,0) 326 | elif labelOrientation == "up": 327 | self.labelShift = vector(0,0.05*self.length,0) 328 | elif labelOrientation == "left": 329 | self.labelShift = vector(-0.1*self.length,0,0) 330 | elif labelOrientation == "right": 331 | self.labelShift = vector(0.1*self.length,0,0) 332 | 333 | self.__reorient() 334 | except TypeError as err: 335 | print("**********TYPE ERROR**********") 336 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 337 | print("******************************") 338 | print(err) 339 | raise err 340 | 341 | def update(self): 342 | try: 343 | # Determine if reference obj. has shifted since last update, if so shift us too 344 | if self.obj.pos != self.lastPos: 345 | diff = self.obj.pos - self.lastPos 346 | 347 | for i in range(len(self.intervalMarkers)): 348 | self.intervalMarkers[i].pos += diff 349 | self.intervalLabels[i].pos += diff 350 | self.axisCurve.pos = [x + diff for x in self.axisCurve.pos] 351 | 352 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 353 | except TypeError as err: 354 | print("**********TYPE ERROR**********") 355 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 356 | print("******************************") 357 | print(err) 358 | raise err 359 | 360 | def reorient(self, axis=None, startPos=None, length=None, labels=None, labelOrientation=None): 361 | try: 362 | # Determine which, if any, parameters are being modified 363 | self.axis = axis if axis is not None else self.axis 364 | self.startPos = startPos if startPos is not None else self.startPos 365 | self.length = length if length is not None else self.length 366 | self.labelText = labels if labels is not None else self.labels 367 | 368 | # Re-do label orientation as well, if it has been set 369 | if labelOrientation == "down": 370 | self.labelShift = vector(0,-0.05*self.length,0) 371 | elif labelOrientation == "up": 372 | self.labelShift = vector(0,0.05*self.length,0) 373 | elif labelOrientation == "left": 374 | self.labelShift = vector(-0.1*self.length,0,0) 375 | elif labelOrientation == "right": 376 | self.labelShift = vector(0.1*self.length,0,0) 377 | 378 | self.__reorient() 379 | except TypeError as err: 380 | print("**********TYPE ERROR**********") 381 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 382 | print("******************************") 383 | print(err) 384 | raise err 385 | 386 | def __reorient(self): 387 | # Actual internal axis setup code... determines first whether we are creating or updating 388 | updating = True if len(self.intervalMarkers) > 0 else False 389 | 390 | # Then determines the endpoint of the axis and the interval 391 | final = self.startPos + (self.length * self.axis) 392 | interval = (self.length / (self.numLabels-1)) * self.axis 393 | 394 | # Loop for each interval marker, setting up or updating the markers and labels 395 | i=0 396 | while i (self.interval * self.curMarker): 185 | # Increment threshold 186 | self.curMarker += 1 187 | 188 | # Display marker! 189 | if self.markerType == "arrow": 190 | arrow(pos=self.obj.pos+self.arrowOffset, 191 | axis=self.markerScale*quantity, color=self.markerColor) 192 | elif self.markerType == "breadcrumbs": 193 | points(pos=self.obj.pos, 194 | size=10*self.markerScale*quantity, color=self.markerColor) 195 | 196 | #Also display timestamp if requested 197 | if self.dropTime is not False: 198 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 199 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 200 | 201 | # Same with order label 202 | if self.labelMarkerOrder is not False: 203 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 204 | except TypeError as err: 205 | print("**********TYPE ERROR**********") 206 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 207 | print("******************************") 208 | print(err) 209 | raise err 210 | 211 | class MotionMapN: 212 | """ 213 | This class assists students in constructing motion maps 214 | using either arrows (measuring a quantity) or "breadcrumbs" 215 | (with timestamps). 216 | """ 217 | 218 | def __init__(self, obj, dt, numSteps, markerType="arrow", 219 | markerScale=1, markerColor=color.red, 220 | labelMarkerOrder=True, labelMarkerOffset=vector(0,0,0), 221 | dropTime=False, timeOffset=vector(0,0,0), arrowOffset=vector(0,0,0), labelColor=color.white): 222 | # MotionMapN 223 | # obj - object to track in mapping / placing markers 224 | # dt - time between steps 225 | # numSteps - number of steps between markers 226 | # markerType - determines type of motionmap; options are "arrow" or "breadcrumbs" 227 | # markerScale - replaces pSize / quantscale from motionmodule.py depending on type 228 | # markerColor - color of markers 229 | # labelMarkerOrder - drop numbers of markers? 230 | # labelMarkerOffset - amount to offset numbering by 231 | # dropTime - boolean determining whether a timestamp should be placed along with the marker 232 | # timeOffset - if dropTime is True, determines the offset, if any, of the label from the markers 233 | # arrowOffset - shift an arrow by an amount (x,y,z), useful for two arrows views 234 | 235 | self.obj = obj 236 | self.dt = dt 237 | self.numSteps = numSteps 238 | self.markerType = markerType 239 | self.markerScale = markerScale 240 | self.markerColor = markerColor 241 | self.labelMarkerOrder = labelMarkerOrder 242 | self.labelMarkerOffset = labelMarkerOffset 243 | self.timeOffset = timeOffset 244 | self.dropTime = dropTime 245 | self.arrowOffset = arrowOffset 246 | self.labelColor = labelColor 247 | 248 | # Calculate size of interval for each step, set initial step index 249 | try: 250 | self.interval = self.dt * self.numSteps 251 | except TypeError as err: 252 | print("**********TYPE ERROR**********") 253 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 254 | print("******************************") 255 | print(err) 256 | raise err 257 | self.curMarker = 0 258 | 259 | 260 | def update(self, t, quantity=1): 261 | try: 262 | 263 | threshold = self.interval * self.curMarker 264 | # Display new arrow if t has broken new threshold 265 | if t >= threshold: 266 | 267 | # Increment marker count 268 | self.curMarker += 1 269 | 270 | # Display marker! 271 | if self.markerType == "arrow": 272 | arrow(pos=self.obj.pos+self.arrowOffset, 273 | axis=self.markerScale*quantity, color=self.markerColor) 274 | elif self.markerType == "breadcrumbs": 275 | points(pos=self.obj.pos, 276 | size=10*self.markerScale*quantity, color=self.markerColor) 277 | 278 | #Also display timestamp if requested 279 | if self.dropTime is not False: 280 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 281 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 282 | 283 | # Same with order label 284 | if self.labelMarkerOrder is not False: 285 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 286 | 287 | except TypeError as err: 288 | print("**********TYPE ERROR**********") 289 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 290 | print("******************************") 291 | print(err) 292 | raise err 293 | 294 | class PhysAxis: 295 | """ 296 | This class assists students in creating dynamic axes for their models. 297 | """ 298 | 299 | def __init__(self, obj, numLabels, axisType="x", axis=vector(1,0,0), startPos=None, 300 | length=None, labels = None, labelOrientation="down", axisColor=color.yellow, labelColor=color.white): 301 | # PhysAxis 302 | # obj - Object which axis is oriented based on by default 303 | # numLabels - number of labels on axis 304 | # axisType - sets whether this is a default axis of x or y, or an arbitrary axis 305 | # axis - unit vector defining the orientation of the axis to be created IF axisType = "arbitrary" 306 | # startPos - start position for the axis - defaults to (-obj_size(obj).x/2,-4*obj_size(obj).y,0) 307 | # length - length of the axis - defaults to obj_size(obj).x 308 | # labelOrientation - how labels are placed relative to axis markers - "up", "down", "left", or "right" 309 | 310 | try: 311 | self.intervalMarkers = [] 312 | self.intervalLabels = [] 313 | self.labelText = labels 314 | self.obj = obj 315 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 316 | self.numLabels = numLabels 317 | self.axisType = axisType 318 | self.axis = axis if axisType != "y" else vector(0,1,0) 319 | self.length = length if (length is not None) else obj_size(obj).x 320 | self.startPos = startPos if (startPos is not None) else vector(-obj_size(obj).x/2,-4*obj_size(obj).y,0) 321 | self.axisColor = axisColor 322 | self.labelColor = labelColor 323 | 324 | if labelOrientation == "down": 325 | self.labelShift = vector(0,-0.05*self.length,0) 326 | elif labelOrientation == "up": 327 | self.labelShift = vector(0,0.05*self.length,0) 328 | elif labelOrientation == "left": 329 | self.labelShift = vector(-0.1*self.length,0,0) 330 | elif labelOrientation == "right": 331 | self.labelShift = vector(0.1*self.length,0,0) 332 | 333 | self.__reorient() 334 | except TypeError as err: 335 | print("**********TYPE ERROR**********") 336 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 337 | print("******************************") 338 | print(err) 339 | raise err 340 | 341 | def update(self): 342 | try: 343 | # Determine if reference obj. has shifted since last update, if so shift us too 344 | if self.obj.pos != self.lastPos: 345 | diff = self.obj.pos - self.lastPos 346 | 347 | for i in range(len(self.intervalMarkers)): 348 | self.intervalMarkers[i].pos += diff 349 | self.intervalLabels[i].pos += diff 350 | self.axisCurve.pos = [x + diff for x in self.axisCurve.pos] 351 | 352 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 353 | except TypeError as err: 354 | print("**********TYPE ERROR**********") 355 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 356 | print("******************************") 357 | print(err) 358 | raise err 359 | 360 | def reorient(self, axis=None, startPos=None, length=None, labels=None, labelOrientation=None): 361 | try: 362 | # Determine which, if any, parameters are being modified 363 | self.axis = axis if axis is not None else self.axis 364 | self.startPos = startPos if startPos is not None else self.startPos 365 | self.length = length if length is not None else self.length 366 | self.labelText = labels if labels is not None else self.labels 367 | 368 | # Re-do label orientation as well, if it has been set 369 | if labelOrientation == "down": 370 | self.labelShift = vector(0,-0.05*self.length,0) 371 | elif labelOrientation == "up": 372 | self.labelShift = vector(0,0.05*self.length,0) 373 | elif labelOrientation == "left": 374 | self.labelShift = vector(-0.1*self.length,0,0) 375 | elif labelOrientation == "right": 376 | self.labelShift = vector(0.1*self.length,0,0) 377 | 378 | self.__reorient() 379 | except TypeError as err: 380 | print("**********TYPE ERROR**********") 381 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 382 | print("******************************") 383 | print(err) 384 | raise err 385 | 386 | def __reorient(self): 387 | # Actual internal axis setup code... determines first whether we are creating or updating 388 | updating = True if len(self.intervalMarkers) > 0 else False 389 | 390 | # Then determines the endpoint of the axis and the interval 391 | final = self.startPos + (self.length * self.axis) 392 | interval = (self.length / (self.numLabels-1)) * self.axis 393 | 394 | # Loop for each interval marker, setting up or updating the markers and labels 395 | i=0 396 | while i (self.interval * self.curMarker): 185 | # Increment threshold 186 | self.curMarker += 1 187 | 188 | # Display marker! 189 | if self.markerType == "arrow": 190 | arrow(pos=self.obj.pos+self.arrowOffset, 191 | axis=self.markerScale*quantity, color=self.markerColor) 192 | elif self.markerType == "breadcrumbs": 193 | points(pos=self.obj.pos, 194 | size=10*self.markerScale*quantity, color=self.markerColor) 195 | 196 | #Also display timestamp if requested 197 | if self.dropTime is not False: 198 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 199 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 200 | 201 | # Same with order label 202 | if self.labelMarkerOrder is not False: 203 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 204 | except TypeError as err: 205 | print("**********TYPE ERROR**********") 206 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 207 | print("******************************") 208 | print(err) 209 | raise err 210 | 211 | class MotionMapN: 212 | """ 213 | This class assists students in constructing motion maps 214 | using either arrows (measuring a quantity) or "breadcrumbs" 215 | (with timestamps). 216 | """ 217 | 218 | def __init__(self, obj, dt, numSteps, markerType="arrow", 219 | markerScale=1, markerColor=color.red, 220 | labelMarkerOrder=True, labelMarkerOffset=vector(0,0,0), 221 | dropTime=False, timeOffset=vector(0,0,0), arrowOffset=vector(0,0,0), labelColor=color.white): 222 | # MotionMapN 223 | # obj - object to track in mapping / placing markers 224 | # dt - time between steps 225 | # numSteps - number of steps between markers 226 | # markerType - determines type of motionmap; options are "arrow" or "breadcrumbs" 227 | # markerScale - replaces pSize / quantscale from motionmodule.py depending on type 228 | # markerColor - color of markers 229 | # labelMarkerOrder - drop numbers of markers? 230 | # labelMarkerOffset - amount to offset numbering by 231 | # dropTime - boolean determining whether a timestamp should be placed along with the marker 232 | # timeOffset - if dropTime is True, determines the offset, if any, of the label from the markers 233 | # arrowOffset - shift an arrow by an amount (x,y,z), useful for two arrows views 234 | 235 | self.obj = obj 236 | self.dt = dt 237 | self.numSteps = numSteps 238 | self.markerType = markerType 239 | self.markerScale = markerScale 240 | self.markerColor = markerColor 241 | self.labelMarkerOrder = labelMarkerOrder 242 | self.labelMarkerOffset = labelMarkerOffset 243 | self.timeOffset = timeOffset 244 | self.dropTime = dropTime 245 | self.arrowOffset = arrowOffset 246 | self.labelColor = labelColor 247 | 248 | # Calculate size of interval for each step, set initial step index 249 | try: 250 | self.interval = self.dt * self.numSteps 251 | except TypeError as err: 252 | print("**********TYPE ERROR**********") 253 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 254 | print("******************************") 255 | print(err) 256 | raise err 257 | self.curMarker = 0 258 | 259 | 260 | def update(self, t, quantity=1): 261 | try: 262 | 263 | threshold = self.interval * self.curMarker 264 | # Display new arrow if t has broken new threshold 265 | if t >= threshold: 266 | 267 | # Increment marker count 268 | self.curMarker += 1 269 | 270 | # Display marker! 271 | if self.markerType == "arrow": 272 | arrow(pos=self.obj.pos+self.arrowOffset, 273 | axis=self.markerScale*quantity, color=self.markerColor) 274 | elif self.markerType == "breadcrumbs": 275 | points(pos=self.obj.pos, 276 | size=10*self.markerScale*quantity, color=self.markerColor) 277 | 278 | #Also display timestamp if requested 279 | if self.dropTime is not False: 280 | epsilon = vector(0,self.markerScale*.5,0)+self.timeOffset 281 | droptimeText = label(pos=self.obj.pos+epsilon, text='t='+str(t)+'s', height=10, box=False, color=self.labelColor) 282 | 283 | # Same with order label 284 | if self.labelMarkerOrder is not False: 285 | label(pos=self.obj.pos-vector(0,self.markerScale*.5,0)+self.labelMarkerOffset, text=str(self.curMarker), height=10, box=False, color=self.labelColor) 286 | 287 | except TypeError as err: 288 | print("**********TYPE ERROR**********") 289 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 290 | print("******************************") 291 | print(err) 292 | raise err 293 | 294 | class PhysAxis: 295 | """ 296 | This class assists students in creating dynamic axes for their models. 297 | """ 298 | 299 | def __init__(self, obj, numLabels, axisType="x", axis=vector(1,0,0), startPos=None, 300 | length=None, labels = None, labelOrientation="down", axisColor=color.yellow, labelColor=color.white): 301 | # PhysAxis 302 | # obj - Object which axis is oriented based on by default 303 | # numLabels - number of labels on axis 304 | # axisType - sets whether this is a default axis of x or y, or an arbitrary axis 305 | # axis - unit vector defining the orientation of the axis to be created IF axisType = "arbitrary" 306 | # startPos - start position for the axis - defaults to (-obj_size(obj).x/2,-4*obj_size(obj).y,0) 307 | # length - length of the axis - defaults to obj_size(obj).x 308 | # labelOrientation - how labels are placed relative to axis markers - "up", "down", "left", or "right" 309 | 310 | try: 311 | self.intervalMarkers = [] 312 | self.intervalLabels = [] 313 | self.labelText = labels 314 | self.obj = obj 315 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 316 | self.numLabels = numLabels 317 | self.axisType = axisType 318 | self.axis = axis if axisType != "y" else vector(0,1,0) 319 | self.length = length if (length is not None) else obj_size(obj).x 320 | self.startPos = startPos if (startPos is not None) else vector(-obj_size(obj).x/2,-4*obj_size(obj).y,0) 321 | self.axisColor = axisColor 322 | self.labelColor = labelColor 323 | 324 | if labelOrientation == "down": 325 | self.labelShift = vector(0,-0.05*self.length,0) 326 | elif labelOrientation == "up": 327 | self.labelShift = vector(0,0.05*self.length,0) 328 | elif labelOrientation == "left": 329 | self.labelShift = vector(-0.1*self.length,0,0) 330 | elif labelOrientation == "right": 331 | self.labelShift = vector(0.1*self.length,0,0) 332 | 333 | self.__reorient() 334 | except TypeError as err: 335 | print("**********TYPE ERROR**********") 336 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 337 | print("******************************") 338 | print(err) 339 | raise err 340 | 341 | def update(self): 342 | try: 343 | # Determine if reference obj. has shifted since last update, if so shift us too 344 | if self.obj.pos != self.lastPos: 345 | diff = self.obj.pos - self.lastPos 346 | 347 | for i in range(len(self.intervalMarkers)): 348 | self.intervalMarkers[i].pos += diff 349 | self.intervalLabels[i].pos += diff 350 | self.axisCurve.pos = [x + diff for x in self.axisCurve.pos] 351 | 352 | self.lastPos = vector(self.obj.pos.x, self.obj.pos.y, self.obj.pos.z) 353 | except TypeError as err: 354 | print("**********TYPE ERROR**********") 355 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 356 | print("******************************") 357 | print(err) 358 | raise err 359 | 360 | def reorient(self, axis=None, startPos=None, length=None, labels=None, labelOrientation=None): 361 | try: 362 | # Determine which, if any, parameters are being modified 363 | self.axis = axis if axis is not None else self.axis 364 | self.startPos = startPos if startPos is not None else self.startPos 365 | self.length = length if length is not None else self.length 366 | self.labelText = labels if labels is not None else self.labels 367 | 368 | # Re-do label orientation as well, if it has been set 369 | if labelOrientation == "down": 370 | self.labelShift = vector(0,-0.05*self.length,0) 371 | elif labelOrientation == "up": 372 | self.labelShift = vector(0,0.05*self.length,0) 373 | elif labelOrientation == "left": 374 | self.labelShift = vector(-0.1*self.length,0,0) 375 | elif labelOrientation == "right": 376 | self.labelShift = vector(0.1*self.length,0,0) 377 | 378 | self.__reorient() 379 | except TypeError as err: 380 | print("**********TYPE ERROR**********") 381 | print("Please check that you are not passing in a variable of the wrong type (e.g. a scalar as a vector, or vice-versa)!") 382 | print("******************************") 383 | print(err) 384 | raise err 385 | 386 | def __reorient(self): 387 | # Actual internal axis setup code... determines first whether we are creating or updating 388 | updating = True if len(self.intervalMarkers) > 0 else False 389 | 390 | # Then determines the endpoint of the axis and the interval 391 | final = self.startPos + (self.length * self.axis) 392 | interval = (self.length / (self.numLabels-1)) * self.axis 393 | 394 | # Loop for each interval marker, setting up or updating the markers and labels 395 | i=0 396 | while i