Home
Gravity Sim logo
About
About
Screenshots
Camera Lens
Docs
INFO

Gravity Sim CODE ( Netlogo environment )

; GravitySim 1.5 (and NetLogo 5.0.4)
; Original version 1.0 release date: 20 November 2012.
; v 1.1 -- 01 December 2012 { Fixed typographical errors in dialog boxes. }
; v 1.2 -- 27 January 2013 { Added "Software test" simulation; fixed reference frame synchronous rotation animation in sims; updated some text. }
; v 1.3 -- 27 March 2013 { Added BIG switch (increases size of trace dots by 1 pixel). }
; v 1.4 -- 15 May 2013 { Improved presentation of text in the general message box. }
; v 1.5 -- 24 August 2013 { Improved the communication in some text messages. Slight improvements to initial demonstration ([← Show Me] button) interface and 'Empty space' simulation interface. }
; NOTE: btnShowMe routine is NOT tick-based; Netlogo "view updates" mode must be set to "continuous".

extensions [sound] ; only 2 sounds exist (startup sound: ./GSrsc/astronaut40s.au, LRO/Apollo sound: ./GSrsc/OneSmallStep8s.au)

;=========================================================================================================================================================================================
; variable definitions
;=========================================================================================================================================================================================
turtles-own
[ My-ax            ; acceleration x-component
  My-ay            ; acceleration y-component
  My-vx            ; velocity x-component
  My-vy            ; velocity y-component
  My-px            ; position x-component
  My-py            ; position y-component
  My-fx            ; frame x-coordinate (plotted)
  My-fy            ; frame y-coordinate (plotted)
  MyRadius         ; distance from origin (GM)
  MyRelDistance    ; distance from the centroid (i.e., orange ball)
  MyRelVelocity    ; velocity relative to the centroid
  EnergyStart      ; kinetic energy + gravitational potential energy *relative to the centroid (i.e., the orange ball)*
  EnergyNow        ; ideally, should be identical to EnergyStart when operating in empty space, but not so when the orange ball orbits a source mass
  MyPhaseInit      ; initial phase angle in orbit in degrees
  MyOmega          ; angular velocity applicable iif the ball has a known circular orbit
  MyPhaseDeg       ; phase angle in orbit in degrees (iif the ball has a known circular orbit)
]

globals
[ 
  ; stored values of the orange reference ball
  OrangeMy-px
  OrangeMy-py
  OrangeMy-vx
  OrangeMy-vy
  OrangeMyRadius
  OrangeMyPhaseDeg


  ; interface reporters (brown boxes)
  ; inside left frame
  OrbitalPeriodShow
  OrbitalSpeedShow
  OrbitalRadiusShow
  cShowGM
  
  ; main controls
  Orange_Ball_MassShow
  Simulation_IntervalShow
  Time_IntervalMultiplier ; not shown, but related to Simulation_IntervalShow (time interval in seconds = Simulation_Interval: * Time_IntervalMultiplier)
  Test_Mass_Separation*:_Units
  
  ; top right
  FrameDimensionsShow
  GridSquareDimensionsShow
  Trace_IntervalShow
  Trace_IntervalMultShow ; what the slider units are being multiplied by
  TraceSecondsMultiplier ; not shown, but related to units: if minutes (60), if hours (3600), if years (3.15569E7)
  
  ; Dashboard  
  Real-timeShow
  Run-timeShow
  SimulationSpeed
  DistanceChange
  Arcseconds
  fre     ; fractional range error
  avg-fre 
  sum-fre ; not reported, used to calculate avg-fre = (sum-fre / ticks)
  MaxRangeShow
  MaxVelocityShow
  
  ; values for shown values, above
  MaxRange         ; maximum distance of a ball relative to the orange ball
  MaxRangeColor    ; color of the ball
  MaxVelocity      ; maximum velocity of a ball relative to the orange ball
  MaxVelocityColor ; color of the ball
  
  
  ; lock control values at start of simulation
  LockSynchronous_Rotation
  LockR
  LockChoose_Simulation:
  LockOrange_Ball_Mass:
  LockTest_Mass_Separation*:
  LockSimulation_Interval:
  LockOrbit_Stops_At:  
  LockFrame_Dimension:
  Lockx1
  LockTrace_Interval:
  LockTimePerTick     ; = LockSimulation_Interval: * Time_IntervalMultiplier
    
; switches
  bShowMe             ; tells setup-2-Graphics that it was called by btnShowMe, not by startup or btnReset
  bNoSplash           ; tells setup-2-Graphics not to use splash screens — we about to run a simulation
  bSetUpButtonLocked  ; when running (= true), user cannot click the setup button before a reset
  bShowOrbitClicked   ; stops the current simulation (but user should toggle [Run Simulation] instead)
  bSetUpButtonClicked ; btnShowMe should not work afterwards
  bFreeFall           ; user chose "Radial free fall" simulation
  bEarthExists        ; user chose "Empty space (no Earth)" simulation
  bEndOfSimuation     ; Orbit_Stops_At: was reached
  bResetTimer         ; used in btnRun to start the Run-time timer
  bPreciseColors      ; if false (default) "lime" is reported as "green"; "sky" is reported as "blue"
  
; screen size management
  bNotHD              ; true if this is not the HD version; set in setup-0-Clear&Reset
  ScreenScale
  Screen_dx
  Screen_dy
  OrbitRadius
  CenterX
  GyroOffset


; check values for max values
  CheckMaxRange          ; checking maximum distance
  CheckMaxRangeColor     ; color of the ball
  CheckMaxVelocity       ; checking max velocity
  CheckMaxVelocityColor  ; maximum velocity of a ball relative to the orange ball


; set constants
  cSourceBodyGM       ; set to the JPL HORIZONS value for the Earth (or the Moon)
  OrbitalPeriod       ; depends on orbit selected; set in setup-2-Graphics
  cOrbitalSpeed       ; depends on orbit selected; set in setup-2-Graphics

; calculated constants
  OrbitalRadius       ; calculated per orbital mechanics assuming an idealized zero eccentricity
  CentroidGM          ; = G * LockOrange_Ball_Mass:
  cPixelsPerMeter     ; = 400 / LockFrame_Dimension:

; calculated simulation variables (physics)
  Real-time           ; LockTime_Interval * ticks
  FrameIdealTheta     ; = Real-time / OrbitalPeriod * 360 (i.e., if Real-time = OrbitalPeriod, then FrameIdealTheta = 360)
  dx-correction       ; the x position correction of the orange ball to be applied to all other balls
  dy-correction       ; the y position correction of the orange ball to be applied to all other balls
  ffv-correction      ; free fall velocity correction
  
; miscellaneous
  LastOutput     ; what was last typed to output
  LastAlert      ; what was last temporarily displayed in output
  LastReport     ; time in seconds that the last report was written to output
  OutputHeader   ; text description of simulation to run
  PadLeftSpaces  ; used by repNumber, which pads PadLeftSpaces to the left of numbers
  SimSettings    ; Text of the settinf for output
  AutoStopAngle  ; the angle correlated to Orbit_Stops_At: value
  Run-Time       ; used to calculate Run-timeShow
  LastRun-time   ; used to calculate SimulationSpeed
  ShowM51        ; compare simulation to M51
  
  ; names of display turtles for easy reference
  tOrbitalSpeedCalc ; used to display data via its label
  tOrbitalSpeedSim  ; used to display data via its label
  tOrbitalRadius    ; used to display data via its label
  tOrbitalPeriod    ; used to display data via its label
  tPartOfT          ; used to display (PhaseAngle / 360)
  tGM               ; used to display data via its label
  tOrangeMass       ; used to display data via its label
  tTraceInterval    ; used to display data via its label
  
 ; names of other turtles for easy reference
  tMarker           ; used for drawing stuff and copyright notice on exported view
  tMessage          ; used to display a message via its label.
  tMessage2         ; used to display a message via its label (second line).
  
  tReferenceFrame   ; the little reference frame that moves
  tGyroOrange       ; magnified orange ball for [← Show Me] button
  tGyroRed          ; the red ball for [← Show Me] button
  tGyroGreen        ; the green ball for [← Show Me] button
  tLittleGyroRed    ; the red ball inside the orbiting frame for [← Show Me] button
  tLittleGyroGreen  ; the green ball inside the orbiting frame for [← Show Me] button
  tOrangeBall       ; center test mass

  ; corner test masses
  tRedBall_TL
  tGreenBall_TR
  tMagentaBall_BL
  tYellowBall_BR
  
  ; radial test masses (top/bottom center)
  tBlueBall_TC
  tVioletBall_BC
  
  ; lateral test masses (middle left/right)
  tPinkBall_ML
  tWhiteBall_MR
]

breed [ OrbitData OrbitDatum ] ; the display turtles in the left pane
breed [ radials radial ]       ; the two radial balls (blue / violet)
breed [ laterals lateral ]     ; the two lateral balls (pink / white)
breed [ corners corner ]       ; the four corner balls

to testme ; place to test message output
;  let MsgPhrase ""
; let OutputPhrase ""
clear-output


end

;=========================================================================================================================================================================================
; physics
;=========================================================================================================================================================================================
; *** START OF ALL THE PHYSICS *** *** START OF ALL THE PHYSICS *** *** START OF ALL THE PHYSICS *** *** START OF ALL THE PHYSICS *** *** START OF ALL THE PHYSICS ***

; This section has been put at the top to make technical code review easy.
; Everthing seen in the simulations is controlled exclusively by this code.

; This is the only calling application for the physics routines, below.
; It is called exclusively by the <btnRun> routine, PART 4: Simulation.
to physics-0-sequence
  physics-1-position       ; new position = old position + (old velocity * Δt)
  physics-2-position-fix   ; Correct position of frame based on perfect knowledge of orange ball dynamics (given a circular orbit at fixed angular velocity).
  physics-3-velocity       ; new velocity = old velocity + (old acceleration * Δt)
  physics-4-velocity-fix   ; *Only if free falling*, correct the velocity of the frame based on energy conservation calculated from total Δr from original starting position.
  physics-5-properties     ; Update the properties of the test masses (but not the orange ball) here.
  physics-6-accel          ; new acceleration = acceleration of Earth on orange ball at new position {MyRadius} (set in physics-5-properties)
end                        ;                    + any acceleration of orange ball on test masses at there new positions in the frame


to physics-1-position
  ; new position = old position + (old velocity * Δt)
  set My-px (My-px + (My-vx * LockTimePerTick))
  set My-py (My-py + (My-vy * LockTimePerTick))
end


; After each tick, we know exactly where the orange ball (i.e., the reference frame centroid) should be.
; This routine shifts the entire frame (and the relative locations of all test masses) to the correct location.
; By doing this, the very small error incurred over each tick does not add up over the simulation.
to physics-2-position-fix
  if not bFreeFall and bEarthExists
  [ if self = turtle tOrangeBall ; always gets set first in btnRun
    [ let RoughRadius (sqrt(My-px ^ 2 + My-py ^ 2))
      set fre ((RoughRadius - OrbitalRadius) / OrbitalRadius)
      set sum-fre sum-fre + fre
      set avg-fre (sum-fre / (ticks + 1))
      let idealX OrbitalRadius * cos repMathAngle FrameIdealTheta
      let idealY OrbitalRadius * sin repMathAngle FrameIdealTheta
      set dx-correction idealX - My-px
      set dy-correction idealY - My-py
      set MyPhaseDeg FrameIdealTheta ; the orange ball is always corrected to the ideal phase angle
    ]
    set My-px My-px + dx-correction
    set My-py My-py + dy-correction
  ]
end


to physics-3-velocity
  ifelse self != turtle tOrangeBall and MyRelDistance = 0
  [ ; This test mass has been absorbed by the orange ball and is hidden.
    set My-vx OrangeMy-vx
    set My-vy OrangeMy-vy
  ]
  [
    ; new velocity = old velocity + (old acceleration * Δt)
    set My-vx (My-vx + (My-ax * LockTimePerTick))
    set My-vy (My-vy + (My-ay * LockTimePerTick))
  ]
end


; In the case of radial free fall, we know exactly how fast the orange ball should be moving for its range based on energy conservation.
; This routine calculates the difference between the simulated velocity and the known actual value and corrects the velocitues of all the balls accordingly.
; By doing this, the small error incurred over each tick does not add up over the simulation.
to physics-4-velocity-fix
  if bFreeFall ; Energy conservation in free fall allows for this correction.
  [ if ( (int(Real-time) != LastReport) and (remainder int(Real-time) (LockTrace_Interval: * TraceSecondsMultiplier) = 0) ) or ( MyRadius < (6371 * 2 * 1000) ) ; trace intervals and within 2 Earth radii
    [ if self = turtle tOrangeBall ; always gets set first in btnRun
      [ let ffEnergyCalcV 0 - sqrt( 2 * cSourceBodyGM * ( 1 / My-py - 1 / OrbitalRadius) ) ; This is the known velocity at this range from energy considerations; 0 for tick 0.
        set ffv-correction ffEnergyCalcV - My-vy        
      ]
    set My-vy My-vy + ffv-correction
    
    if bFreeFall and ( self = turtle tOrangeBall or self = turtle tBlueBall_TC or self = turtle tVioletBall_BC)
    [ set My-vx 0 ] ; Free-falling *radial* balls never have any x-velocity, so don't introduce any tiny errors induced by the "atan" function.
    ]
  ]
  
  if not bEarthExists and self != turtle tOrangeBall
  [ ; At periapsis, the body tends to swing out too wide, so we bring it in to the correct radius based on constant energy.
    ; We need to pre-update these three values, but not the energy.
    set MyRadius sqrt(My-px ^ 2 + My-py ^ 2)
    if MyRadius < 10
    [ set MyRelDistance MyRadius
      set MyRelVelocity sqrt( My-vx ^ 2 + My-vy ^ 2)
      let MyKineticEnergy ( 0.0005 *  MyRelVelocity ^ 2)                  ; = (0.5 * m * v^2) in joules *relative to the orange ball*
      let MyPotentialEnergy (0 - ( CentroidGM * 0.001 / MyRelDistance )) ; - (GMm / r) in joules *relative to the orange ball*
      let RoughEnergyNow MyKineticEnergy + MyPotentialEnergy              ; This should = EnergyStart.
      let EnergyError RoughEnergyNow - EnergyStart
      if EnergyError != 0
      [ let CorrectPotentialEnergy  MyPotentialEnergy - EnergyError
        let CorrectRadius abs (CentroidGM * 0.001 / CorrectPotentialEnergy)
        let CorrectionFactor CorrectRadius / MyRadius
        set My-px My-px * CorrectionFactor
        set My-py My-py * CorrectionFactor
      ]
    ]
  ]
end


to physics-5-properties
  ifelse self = turtle tOrangeBall
  [ ; orange ball only:
    ; First, get the changes, based on the old values.; how far did it move from last position?
    if ticks > 0 ; We can't calculate this on the 0th tick.
    [ set DistanceChange uCenterText22 (repNumber (sqrt((My-px - OrangeMy-px) ^ 2 + (My-py - OrangeMy-py) ^ 2) / 1000) 6) 
      ifelse bFreeFall [ set Arcseconds uCenterText22 "N/A" ][ set Arcseconds uCenterText22 (repNumber ((MyPhaseDeg - OrangeMyPhaseDeg) * 3600) 6) ]
    ]
    
    ; Now that we have the changes, above, update the orange ball values for reference by the other balls.
    set OrangeMy-px My-px
    set OrangeMy-py My-py
    set OrangeMy-vx My-vx
    set OrangeMy-vy My-vy
    set OrangeMyRadius MyRadius
    set OrangeMyPhaseDeg MyPhaseDeg            
    if bFreeFall [ set MyRadius sqrt(My-px ^ 2 + My-py ^ 2) ] ; otherwise, it is a constant
  ]
  [ ; test masses only:
    set MyRadius sqrt(My-px ^ 2 + My-py ^ 2)
    set MyRelDistance sqrt( (My-px - OrangeMy-px) ^ 2 + (My-py - OrangeMy-py) ^ 2)
    set MyRelVelocity sqrt( (My-vx - OrangeMy-vx) ^ 2 + (My-vy - OrangeMy-vy) ^ 2)
    set EnergyNow (( 0.0005 *  MyRelVelocity ^ 2) - ( CentroidGM * 0.001 / MyRelDistance )) ; = (0.5 * m * v^2) - (GMm / r) in joules *relative to the orange ball*
  ]
end


; Determine acceleration vectors using inverse square law *based on MyRadius* .
to physics-6-accel
  let angle 0
  let EarthAccelerationX 0
  let EarthAccelerationY 0
  if bEarthExists
  [ set angle repMathAngle atan My-px My-py
    ; new acceleration is calculated from new radius relative to Earth
    set EarthAccelerationX 0 - (cos angle * (cSourceBodyGM / MyRadius ^ 2))
    set EarthAccelerationY 0 - (sin angle * (cSourceBodyGM / MyRadius ^ 2))
  ]
  
  ; If it has mass, what is the gravitational acceleration of the orange ball on a local test mass?
  let CentroidAccelerationX 0
  let CentroidAccelerationY 0
  if self != turtle tOrangeBall
  [ ; What is the position of the test mass in the frame relative to the orange ball?
    let RelativeX My-px - OrangeMy-px
    let RelativeY My-py - OrangeMy-py
    let RadiusToCentroid sqrt(RelativeX ^ 2 + RelativeY ^ 2)
    ifelse RadiusToCentroid <= 1
    [ ; Test mass has crashed into the orange ball and is absorbed.
      set MyRelDistance 0 ; The ball hit the orange centroid ball and is absorbed by it; it dies.
      set My-px OrangeMy-px
      set My-py OrangeMy-py
      die
    ]
    [ 
      ; Based on its relative position, this is the acceleration of the orange ball on the test mass.
      set angle repMathAngle atan RelativeX RelativeY
      set CentroidAccelerationX 0 - cos angle * (CentroidGM / RadiusToCentroid ^ 2)  ; the "toy model" acceleration of the orange ball
      set CentroidAccelerationY 0 - sin angle * (CentroidGM / RadiusToCentroid ^ 2)  ; the "toy model" acceleration of the orange ball
    ]
  ]
  
  ; new acceleration = linear combination of Earth acceleration and orange ball acceleration
  set My-ax EarthAccelerationX + CentroidAccelerationX
  set My-ay EarthAccelerationY + CentroidAccelerationY
end ; physics-6-accel

; *** END OF ALL THE PHYSICS *** *** END OF ALL THE PHYSICS *** *** END OF ALL THE PHYSICS *** *** END OF ALL THE PHYSICS *** *** END OF ALL THE PHYSICS ***
;=========================================================================================================================================================================================
; BUTTONS
;=========================================================================================================================================================================================

to btnShowMe ; This routine is NOT tick-based; Netlogo "view updates" mode must be set to "continuous".
  if hStartupHalt [  user-message "[ Halt ] clicked during startup; restart required.\n\n"  stop ]
  
  if bEndOfSimuation
  [                let MsgPhrase "This button can be only used after\n"
    set MsgPhrase word MsgPhrase "clicking [ Show This Orbit ].\n\n"
    display ; always call display before a dialog box
    user-message MsgPhrase
    stop
  ]
  
  if bSetUpButtonClicked
  [                let MsgPhrase "Click [ Run Simulation ] instead.\n\n"
    set MsgPhrase word MsgPhrase "This button can be only used after\n"
    set MsgPhrase word MsgPhrase "clicking [ Show This Orbit ].\n\n"
    display ; always call display before a dialog box
    user-message MsgPhrase
    stop
  ]
  if bEarthExists and R != LockR 
  [                let MsgPhrase "The orbit setting (R) is different from the displayed orbit.\n"
    set MsgPhrase word MsgPhrase "To change orbits, first click [ Show This Orbit ].\n\n"
    display ; always call display before a dialog box
    user-message MsgPhrase

    set bNoSplash false
    stop
  ]  

  if R = 1 or R = 10
  [                let MsgPhrase "This button does not function for the ISS or LRO orbits;\n"
    set MsgPhrase word MsgPhrase "the reference frame icon is too small.\n\n"
    display ; always call display before a dialog box
    user-message MsgPhrase
    stop
  ]
  set bShowMe true

  uPark-tMessage ; just in case this is right after a sim
  ask turtle tOrangeBall [ hide-turtle ]
  ask turtle tGyroOrange [ show-turtle ]
  import-drawing "./GSrsc/spacecraft.png"
  ask turtle tReferenceFrame [ set shape "spacecraft" ]

  set FrameDimensionsShow uCenterText22 "~ 3 m × 3 m"
  set GridSquareDimensionsShow uCenterText22 "N/A"  
  
  let OutputPhrase "*** A gyroscope suspended in space maintains its orientation relative to the ‘fixed quasars.’ ***\n\n"
  set OutputPhrase word OutputPhrase "Note that the spacecraft is represented in miniature at the 12 o'clock position in the left frame.\n"
  set OutputPhrase word OutputPhrase "Thus, this gyroscope (orange ball) always points in the general direction of the North Star (Polaris).\n\n"
  set OutputPhrase word OutputPhrase "The ‘spacecraft’ is idealized in that it exerts no forces whatsoever on the gyroscope and the gyro is ideally\n"
  set OutputPhrase word OutputPhrase "located at the spacecraft’s center of mass; thus, this gyro never translates in x, y, or z from the origin.\n"
  clear-output
  beep
  output-type OutputPhrase

  let MsgPhrase "* This will be a demonstration, not a simulation. *\n\n"
  set MsgPhrase word MsgPhrase "EXPERTS:\n"
  set MsgPhrase word MsgPhrase "Be patient; Part IV communicates the key concept.\n"
  set MsgPhrase word MsgPhrase "*** It demonstrates behavior that is not intuitive. ***\n\n"
  set MsgPhrase word MsgPhrase "Please read the important information newly posted\n"
  set MsgPhrase word MsgPhrase "to the general message box. If it is partially obscured,\n"
  set MsgPhrase word MsgPhrase "you may drag this dialog box out of the way.\n\n"
  display ; always call display before a dialog box
  user-message MsgPhrase
      
  set Synchronous_Rotation true
  set MsgPhrase "I. Center-of-mass gyro :  ↕Synchronous_Rotation -On-\n\n"
  set MsgPhrase word MsgPhrase "In this case, the reference frame keeps the same ‘face’\n"
  set MsgPhrase word MsgPhrase "pointing Earthward like a typical satellite. This implies\n"
  set MsgPhrase word MsgPhrase "that a free-floating gyroscope will rotate in the frame.\n"
  set MsgPhrase word MsgPhrase "Thus, this is *not* an inertial reference frame because\n"
  set MsgPhrase word MsgPhrase "internal objects are subject to centripetal acceleration.\n\n"
  set MsgPhrase word MsgPhrase "DEFINITION:\nThe “inertial reference frame” of an object is an idealized\n"
  set MsgPhrase word MsgPhrase "reference frame in which the object experiences no forces.\n\n"
  set MsgPhrase word MsgPhrase "NOTE:\nHold mouse-down inside the frame to stop action;\n"
  set MsgPhrase word MsgPhrase "3, 6, and 9 o'clock positions are most helpful.\n\n"
  display ; always call display before a dialog box
  user-message MsgPhrase
  
  let DoNext false
  while [ not DoNext ]
  [ drawOrbit
    set DoNext user-yes-or-no? "Continue with the next part?\n(Click 'No' to repeat the last demo.)\n\n"
  ]
  wait 0.5

  set Synchronous_Rotation false

  set OutputPhrase word OutputPhrase "\n"
  set OutputPhrase word OutputPhrase "=============================================================================================================\n"
  set OutputPhrase word OutputPhrase "If the gyroscope does not rotate, an internal observer without a window does not know that the spacecraft\n"
  set OutputPhrase word OutputPhrase "is in orbital motion, at least not by consulting the orientation of a gyroscope.\n\n"
  beep
  output-type OutputPhrase
    
                  set MsgPhrase "II. Center-of-mass gyro :  ↕Synchronous_Rotation -Off-\n\n"
  set MsgPhrase word MsgPhrase "The spacecraft will now behave naturally; similar to the\n"
  set MsgPhrase word MsgPhrase "gyroscope, it will keep the same orientation relative to\n"
  set MsgPhrase word MsgPhrase "the ‘fixed quasars’ over its orbit.\n\n"
  set MsgPhrase word MsgPhrase "The free-floating gyroscope does not transate or rotate;\n"
  set MsgPhrase word MsgPhrase "this is then the gyroscope’s *inertial reference frame* .\n"
  set MsgPhrase word MsgPhrase "See additional detail in the general message box.\n\n"
  set MsgPhrase word MsgPhrase "NOTE:\n"
  set MsgPhrase word MsgPhrase "The fact that the same side of the Moon always faces the\n"
  set MsgPhrase word MsgPhrase "Earth is due to “gravitational tidal locking” caused by a\n"
  set MsgPhrase word MsgPhrase "mass asymmetry; if one side of the Moon were not more\n"
  set MsgPhrase word MsgPhrase "massive than the other, this would not occur.\n\n"
  display ; always call display before a dialog box
  user-message MsgPhrase

  set DoNext false
  while [ not DoNext ]
  [ drawOrbit
    set DoNext user-yes-or-no? "Continue with the next part?\n(Click 'No' to repeat the last demo.)\n\n"
  ]
  wait 0.5
    
  ask turtle tLittleGyroRed [ show-turtle ]
  ask turtle tLittleGyroGreen [ show-turtle ]
  
  display ; always call display before a dialog box
                let YNphrase "Two gyroscopes (small red and green circles) have been\n"
  set YNphrase word YNphrase " added to the miniature orbiting spacecraft on the left.\n\n"
  set YNphrase word YNphrase "Are both of them adequately visible?\n\n"
  ifelse not user-yes-or-no? YNphrase
  [ ask turtle tLittleGyroRed [ set size 4 ]
    ask turtle tLittleGyroGreen [ set size 4 ]
    ask turtle tReferenceFrame [ set shape "spacecraft2" ]
    ; In this case, they appear the same size (40), not a little larger (43).
    ask turtle tGyroRed [ set size 40 * ScreenScale ]
    ask turtle tGyroGreen [ set size 40 * ScreenScale ]
                   set MsgPhrase "They are now bigger; you should see them clearly.\n\n"
    set MsgPhrase word MsgPhrase "Click [ OK ]; the same gyroscopes will appear on the right…\n\n"
    user-message MsgPhrase
  ]
  [
    user-message "Click [ OK ]; the same gyroscopes will appear on the right…\n\n"    
  ]

  ask turtle tGyroRed [ show-turtle ]
  ask turtle tGyroGreen [ show-turtle ]
  
  
  set Synchronous_Rotation true
  set OutputPhrase word OutputPhrase "=============================================================================================================\n"
  set OutputPhrase word OutputPhrase "The red and green gyros are on the same ideal circular orbit as the orange gyro and slightly out of phase.\n"
  set OutputPhrase word OutputPhrase "This ‘experiment’ assumes the idealization that the spacecraft environment has no effect on the behavior\n"
  set OutputPhrase word OutputPhrase "of any gyroscope; it simply functions as a convenient visual reference frame in which to observe them.\n"
  set OutputPhrase word OutputPhrase "Therefore, the only modeled force acting on the three gyroscopes is the inverse-square gravitational force\n"
  set OutputPhrase word OutputPhrase "of an idealized ‘point-mass’ Earth.\n\n\n"
  beep
  output-type OutputPhrase

  
                 set MsgPhrase "III. Multiple gyros :  ↕Synchronous_Rotation -On-\n\n"
  set MsgPhrase word MsgPhrase "Please read the important information newly posted\n"
  set MsgPhrase word MsgPhrase "to the general message box.\n\n"
  display ; always call display before a dialog box
  user-message MsgPhrase

  set DoNext false
  while [ not DoNext ]
  [ drawOrbit ; calls display
    set DoNext user-yes-or-no? "Continue with the next part?\n(Click 'No' to repeat the last demo.)\n\n"
  ]
  wait 0.5
  
  set Synchronous_Rotation false
  set MsgPhrase "IV. Multiple gyros :  ↕Synchronous_Rotation -Off-\n\n"
  set MsgPhrase word MsgPhrase "The conditions are identical to those in Part II, in which\n"
  set MsgPhrase word MsgPhrase "the orange gyroscope at the center of mass is immobile;\n"
  set MsgPhrase word MsgPhrase "this is the orange gyro’s *inertial reference frame* .\n\n"
  set MsgPhrase word MsgPhrase "The other two gyroscopes are on the identical orbit;\n"
  set MsgPhrase word MsgPhrase "how do you expect them to behave over the orbit\n"
  set MsgPhrase word MsgPhrase "from the perspective of this frame of reference, in\n"
  set MsgPhrase word MsgPhrase "which the orange gyro experiences zero net force?\n\n"
  set MsgPhrase word MsgPhrase "This demonstration will make it obvious. Be sure \n"
  set MsgPhrase word MsgPhrase "to closely observe the gyros shown on the left —\n"
  set MsgPhrase word MsgPhrase "hold mouse-down inside the frame to stop action.\n\n"
  display ; always call display before a dialog box
  user-message MsgPhrase
  
  set DoNext false
  while [ not DoNext ]
  [ drawOrbit ; calls display
    set DoNext user-yes-or-no? "Continue? (Click 'No' to repeat the last demo.)\n\n"
  ]
  wait 0.5
  
                 set MsgPhrase "KEY CONCEPT:\n"
  set MsgPhrase word MsgPhrase "It is a general principle of nature that a collection of\n"
  set MsgPhrase word MsgPhrase "objects, which orbits *another object*, will ‘wind up.’\n\n"
  set MsgPhrase word MsgPhrase "----------------------------------------------\n\n"
  set MsgPhrase word MsgPhrase "This principle is independent of scale; it is just as true\n"
  set MsgPhrase word MsgPhrase "for a “toy model” consisting of a few marbles orbiting\n"
  set MsgPhrase word MsgPhrase "the Earth as for a collection of billions of stars in a\n"
  set MsgPhrase word MsgPhrase "spiral galaxy disk, which, as a collective unit, orbits\n"
  set MsgPhrase word MsgPhrase "some distant barycenter within the host cluster.\n\n"
  set MsgPhrase word MsgPhrase "This proves to be relevant to the “dark matter problem”\n"
  set MsgPhrase word MsgPhrase "as concerns interpreting spiral galaxy rotation curves.\n\n"
  display ; always call display before a dialog box
  user-message MsgPhrase
  
  if R = 3 ; default startup orbit
    [                set MsgPhrase "It may be instructive to switch to a different orbit\n"
      set MsgPhrase word MsgPhrase "(e.g., “Moon”) and run this demonstration again.\n"
      set MsgPhrase word MsgPhrase "Any illusion that the proximity of the Earth is\n"
      set MsgPhrase word MsgPhrase "somehow related to the observed phenomena\n"
      set MsgPhrase word MsgPhrase "will be dispelled.\n\n"
      set MsgPhrase word MsgPhrase "AFTER you click [ OK ] in the *following* dialog box:\n"
      set MsgPhrase word MsgPhrase "1. Move the small red tab on the vertical green slider\n"
      set MsgPhrase word MsgPhrase "    (R, far left) to “Moon” (the next-to-highest position).\n"
      set MsgPhrase word MsgPhrase "2. Click [ Show This Orbit ] to change orbits.\n"
      set MsgPhrase word MsgPhrase "3. Click [ ← Show Me ] to run this demo again.\n\n"
      user-message MsgPhrase
    ]
  
                 set MsgPhrase "This brief demonstration is now concluded.\n\n"
  set MsgPhrase word MsgPhrase "After running this demo any number of times you wish,\n"
  set MsgPhrase word MsgPhrase "read “WHAT NEXT?” under the | Info | link (top of screen).\n\n"
  user-message MsgPhrase 
  
  uPark-tMessage
  ; Return all turtles to their original size.
  ask turtle tLittleGyroRed [ set size 3  hide-turtle ] 
  ask turtle tLittleGyroGreen [ set size 3  hide-turtle ]
  ask turtle tGyroRed [ set size 43 * ScreenScale  hide-turtle ]
  ask turtle tGyroGreen [ set size 43 * ScreenScale hide-turtle ]
  ask turtle tReferenceFrame [ set shape "frame" ]
  
  ask turtle tGyroOrange [ hide-turtle ]
  ask turtle tOrangeBall [ show-turtle ]
  
  beep
  ifelse LastOutput = ""
    [
      clear-output
      output-type "\n\n\n Click the | Info | link at the top of the screen for more information and instructions.\n"
    ]
    [ output-type LastOutput ]
  
  set Draw_Graph_Paper false ; turn off graph paper
  set bNoSplash true
  setup-2-Graphics
  set bNoSplash false  
  set bShowMe false
  
  ; Only here, show x and y axes alone to match icon on the left.
  ask turtle tMarker
    [ set color gray
      set pen-size 1
      repeat 2
      [ 
        setxy 4 * ScreenScale 0
        set heading 90
        pen-down
        fd 400 * ScreenScale
        pen-up
        setxy CenterX -200 * ScreenScale
        set heading 0
        pen-down
        fd 400 * ScreenScale
        pen-up  
      ]
    ]
  uPark-tMarker
  display ; must call this after <Setup-2-Graphics>
end ; btnShowMe


to btnShowOrbit
  if hSim_Running
  [               let YNphrase "Clicking [ No ] will destroy the current simulation.\n\n"
    set YNphrase word YNphrase "Did you click [ Show This Orbit ] by mistake?\n\n"
    display ; always call display before a dialog box
    if user-yes-or-no? YNphrase [ stop ]
    set bSetUpButtonClicked false ; Don't show next dialog.
  ]

  if bSetUpButtonClicked
  [               let YNphrase "You have set up a new simulation.\n\n"
    set YNphrase word YNphrase "Did you actually mean to click the\n"
    set YNphrase word YNphrase "[Run Simulation] button instead?\n"
    set YNphrase word YNphrase "If so, click [ Yes ] and do that.\n\n"
    display ; always call display before a dialog box
    if user-yes-or-no? YNphrase [ stop ]
  ]
    
  if R = 0 [ set R 5 ] ; After "Empty space," go to GPS.
  
  set hInteractive false ; reset "Match the image"
  set hMatch_Galaxy 1    ; reset "Match the image"
   
  setup-0-Clear&Reset ; calls no-display
  setup-1-Initialize  ; sets OrbitalRadius and Lock[Control] values
  setup-2-Graphics    ; calls no-display
  drawOrbit           ; calls display at end
  
  if LockR = 10 [ if user-yes-or-no? "Is it OK to play an 8-second sound?\n\n" [ sound:play-sound-and-wait "./GSrsc/OneSmallStep8s.au" ] ]
end


to btnSetup ; I want to set up a sim for the scenareo I am looking at, selected with the [Show This Orbit] button.
  if hStartupHalt [ user-message "[Halt] clicked during startup; restart required.\n\n"  stop ]
  if bEarthExists and R != LockR 
  [                let MsgPhrase "The orbit setting (R) is different from the displayed orbit.\n"
    set MsgPhrase word MsgPhrase "To change orbits, first click [ Show This Orbit ].\n\n"
    display ; always call display before a dialog box
    user-message MsgPhrase
    set bNoSplash false
    stop
  ]  
  
  if hSim_Running and not hInteractive and not (LockChoose_Simulation: = "Empty space")
  [ display ; always call display before a dialog box
    if not user-yes-or-no? "End the existing simulation and restart immediately?" [ stop ]
  ]
  
  if Choose_Simulation: != LockChoose_Simulation: [ set Orange_Ball_Mass: 0 ] ; ensures that we dont start a new simulation with mass from a previous simulation
  if (Choose_Simulation: = "Circular orbit" or Choose_Simulation: = "Match the image") and Orbit_Stops_At: = "N/A" [ set Orbit_Stops_At: "Never" ] ; "N/A" is not an option for "Circular orbit"
  
  if R = 0 [ set R 5 ] ; After "Empty space," go to GPS.
  
  setup-0-Clear&Reset ; calls no-display
  
  ; switches
  set bSetUpButtonClicked true
  set bResetTimer true
  set bNoSplash true  
  if Choose_Simulation: = "Radial free fall    (start here)" [ set bFreeFall true ]
  if Choose_Simulation: = "Empty space" [ set bEarthExists false ]
  set radial:blue/violet false
  set lateral:white/pink false
  set corners:red/green false
  
  let AskQuestion true
  If bFreeFall and (hUser_Response = 1 or hUser_Response = 3 or hUser_Response = 5 or hUser_Response = 7) [ set AskQuestion false ]
  If Choose_Simulation: = "Circular orbit" and (hUser_Response = 2 or hUser_Response = 3 or hUser_Response = 6 or hUser_Response = 7) [ set AskQuestion false ]
  If Choose_Simulation: = "Software test" or Choose_Simulation: = "Match the image" [ set AskQuestion false ]
  If not bEarthExists and (hUser_Response = 4 or hUser_Response = 5 or hUser_Response = 6 or hUser_Response = 7) [ set AskQuestion false ]
  let UseDefault false
  if AskQuestion
  [ display ; always call display before a dialog box
    set UseDefault user-yes-or-no? (word "SIMULATION: " (remove "    (start here)" Choose_Simulation:) "\n\nIs this your first time running this simulation choice?\n\n")
  ]
  If Choose_Simulation: = "Software test" or Choose_Simulation: = "Match the image" [ set UseDefault true ] ; always uses default settings, not configurable by the user
                                                                                                            ; set hMatch_Galaxy 3 ; comment out unless testing angles
  ifelse not UseDefault
    [ ; user wants to use current settings
      if bFreeFall and  (R = 1 or R = 3 or R = 10)
      [                let MsgPhrase "The altitude of this orbit is too low for this simulation;\n"
        set MsgPhrase word MsgPhrase "choose a higher altitude.\n\n"
        display ; always call display before a dialog box
        user-message MsgPhrase
        set bSetUpButtonClicked false
        set bNoSplash false
        stop
      ]
    ] 
    [                let MsgPhrase "The recommended default orbit and control\n"
      set MsgPhrase word MsgPhrase "settings for this simulation will be set.\n\n"
      display ; always call display before a dialog box
      user-message MsgPhrase
      set x1 1
      if bFreeFall
      [ set Synchronous_Rotation false
        set R 7
        
        set Orange_Ball_Mass: 0
        set Test_Mass_Separation*: 4
        set Simulation_Interval: 5
        set Orbit_Stops_At: "N/A"
        
        set Frame_Dimension: 100
        set Trace_Interval: 5 ; 5 minutes
        set lateral:white/pink true
        set radial:blue/violet true
        set corners:red/green true
        set Draw_Graph_Paper true
      ]

      if Choose_Simulation: = "Software test" 
      [ set R 5
        set Frame_Dimension: 150

                       set MsgPhrase "Each ball’s independent initial velocity is\n"
        set MsgPhrase word MsgPhrase "set to place it in an ideal circular orbit;\n"
        set MsgPhrase word MsgPhrase "the following are then known sim checks:\n\n"
        set MsgPhrase word MsgPhrase "If ↕Synchronous_Rotation is -Off- ,\n"
        set MsgPhrase word MsgPhrase "pink & white balls rotate in a circle;\n"
        set MsgPhrase word MsgPhrase "top & bottom row trajectories are curvilinear.\n\n"
        set MsgPhrase word MsgPhrase "If ↕Synchronous_Rotation is -On- ,\n"
        set MsgPhrase word MsgPhrase "pink & white balls are stationary;\n"
        set MsgPhrase word MsgPhrase "top & bottom row trajectories are linear.\n\n"
        
        if hTestInit
        [ set Synchronous_Rotation false
          set Frame_Dimension: 100
          set MsgPhrase word MsgPhrase "*** DO NOT terminate test sim manually! ***\n\n"
        ]

        ifelse Synchronous_Rotation
        [ set MsgPhrase word MsgPhrase "Status: ↕Synchronous_Rotation is now -On-.\n\n" ]
        [ set MsgPhrase word MsgPhrase "Status: ↕Synchronous_Rotation is now -Off-.\n\n" ]
        
        user-message MsgPhrase
                
        set Orange_Ball_Mass: 0
        set Test_Mass_Separation*: 10
        set Simulation_Interval: 5
        set Orbit_Stops_At: "1.00T (360°)"
        
        set Trace_Interval: 10
        set lateral:white/pink true
        set radial:blue/violet true
        set corners:red/green true
        set Draw_Graph_Paper true
      ]
            
      if Choose_Simulation: = "Circular orbit" 
      [ set Synchronous_Rotation false
        set R 5
                        set MsgPhrase "All nine balls are initially at relative rest;\n"
        set MsgPhrase word MsgPhrase "Thus, each ball has the same initial velocity\n"
        set MsgPhrase word MsgPhrase "(i.e., the velocity of the reference frame).\n\n"
        set MsgPhrase word MsgPhrase "Note that the center orange ball has a mass\n"
        set MsgPhrase word MsgPhrase "of ~12.5 tonnes in the default simulation.\n\n"
        user-message MsgPhrase
        
        set Orange_Ball_Mass: 6
        set Test_Mass_Separation*: 6
        set Simulation_Interval: 5
        set Orbit_Stops_At: "1.40T"
        
        set Frame_Dimension: 350
        set Trace_Interval: 10
        set lateral:white/pink true
        set radial:blue/violet true
        set corners:red/green true
        set Draw_Graph_Paper false
        set ShowM51 true
      ]
      
      if Choose_Simulation: = "Match the image"
      [ if hMatch_Galaxy = 2 ; M51
        [ set Synchronous_Rotation false
          set R 5
          
          set Orange_Ball_Mass: 6
          set Test_Mass_Separation*: 6
          set Simulation_Interval: 10 ; 1.0 second
          set Orbit_Stops_At: "Never"
          
          set Frame_Dimension: 350
          set Trace_Interval: 10 ; 1.0 minute
          set lateral:white/pink true
          set radial:blue/violet true
          set corners:red/green true
          set Draw_Graph_Paper false
        ]
        
        if hMatch_Galaxy = 1 ; NGC 1097
        [ set Synchronous_Rotation false
          set R 3
          
          set Orange_Ball_Mass: 1
          set Test_Mass_Separation*: 4
          set Simulation_Interval: 2 ; 0.2 second
          set Orbit_Stops_At: "Never"
          
          set Frame_Dimension: 200
          set Trace_Interval: 5 ; 0.5 minutes
          set lateral:white/pink true
          set radial:blue/violet true
          set corners:red/green true
          set Draw_Graph_Paper false
        ]
      
        if hMatch_Galaxy < 1 or hMatch_Galaxy > 2
        [ display ; always call display before a dialog box
          user-message "Error in <btnSetup>; no such hMatch_Galaxy"
          stop
        ]
      ]
      
      if not bEarthExists
      [ set Synchronous_Rotation false
        ; 'set R 0' is a general condition for (not bEarthExists); set below
        
        set Orange_Ball_Mass: 3
        set Simulation_Interval: 10
        set Test_Mass_Separation*: 5
        set Orbit_Stops_At: "N/A"
        
        set Frame_Dimension: 100
        set Trace_Interval: 3 ; 3 hours
        set lateral:white/pink false
        set radial:blue/violet false
        set corners:red/green false
        set Draw_Graph_Paper false
        
                       set MsgPhrase "The test masses are given random initial velocities in both\n"
        set MsgPhrase word MsgPhrase "direction and speed at up to 90% of escape velocity.\n\n"
        set MsgPhrase word MsgPhrase "Click [Set Up Simulation] to refresh a *running* simulation.\n\n"
        set MsgPhrase word MsgPhrase "• The orange ball absorbs any collisions with it.\n"
        set MsgPhrase word MsgPhrase "• The plotter is inactive for this simulation.\n"
        set MsgPhrase word MsgPhrase "• Click [ Show This Orbit ] to return to Earth.\n\n"
        set MsgPhrase word MsgPhrase "Ideally, each ball’s Total Energy should remain constant;\n"
        set MsgPhrase word MsgPhrase "high periapsis velocity may cause minor simulation error.\n\n"
        set MsgPhrase word MsgPhrase "One purpose of this simulation is to demonstrate that the\n"
        set MsgPhrase word MsgPhrase "identical code used to the produce the other simulations\n"
        set MsgPhrase word MsgPhrase "(see “physics”) yields stable Keplerian elliptical orbits.\n\n"
        set MsgPhrase word MsgPhrase "Switch Trace Controls On/Off at will during the simulations.\n\n"
        display ; always call display before a dialog box
        user-message MsgPhrase
      ]
    ]
  
  ; Always show M51 if the basic default conditions are met.
  if R = 5 and Orange_Ball_Mass: = 6 and Test_Mass_Separation*: = 6 and Orbit_Stops_At: = "1.40T" and Frame_Dimension: = 350 and x1 = 1 and Trace_Interval: <= 12 and lateral:white/pink and radial:blue/violet and corners:red/green [ set ShowM51 true ]
  
  ; This tracks which of the three basic simulations have been tried using the defaults.
  if bFreeFall and hUser_Response != 1 and hUser_Response != 3 and hUser_Response != 5 and hUser_Response != 7 [ set hUser_Response hUser_Response + 1 ]
  if Choose_Simulation: = "Circular orbit" and hUser_Response != 2 and hUser_Response != 3 and hUser_Response != 6 and hUser_Response != 7 [ set hUser_Response hUser_Response + 2 ]
  if not bEarthExists and hUser_Response != 4 and hUser_Response != 5 and hUser_Response != 6 and hUser_Response != 7 [ set hUser_Response hUser_Response + 4 ]
  
  if bFreeFall
  [ ask turtle  tPartOfT  [ set label "t = N/A" ]
    if Synchronous_Rotation
    [ display ; always call display before a dialog box
      user-message "↕Synchronous_Rotation -On-\nis not meaningful for radial freefall.\n\n"

      set Synchronous_Rotation false
    ]
  ]
  
  if not bEarthExists
  [ set R 0
    if Orange_Ball_Mass: = 0
    [                let MsgPhrase "For ‘Empty space,’ the minimum allowed value\n"
      set MsgPhrase word MsgPhrase "of ||Orange_Ball_Mass is 1.\n\n"
      display ; always call display before a dialog box
      user-message MsgPhrase 
      set Orange_Ball_Mass: 1
    ]
  ]
  
  setup-1-Initialize ; sets OrbitalRadius and Lock[Control] values
  setup-2-Graphics   ; calls no-display
  display
  
  set CheckMaxRange 0
  set CheckMaxVelocity 0
  set CheckMaxRangeColor ""
  set CheckMaxVelocityColor ""
  set LastReport -1 ; first report at Real-time = 0 != LastReport
  ask turtle tOrangeBall [ Turtles-Plot ]
  ask radials [ Turtles-Plot ]
  ask laterals [ Turtles-Plot ]
  ask corners [ Turtles-Plot ]
  
  mainShowMax
  
  let bLabelColorBlack false
  if Choose_Simulation: = "Match the image"
  [ if not hInteractive ; first pass
    [ set hInteractive true
                     let MsgPhrase "The goal here is to stop the simulation by clicking the\n"
      set MsgPhrase word MsgPhrase "mouse (inside the frame) when the trace trails match\n"
      set MsgPhrase word MsgPhrase "the complete extent of the galaxy’s spiral arms.\n\n"
      set MsgPhrase word MsgPhrase "Note the time required to do so, expressed as a fraction\n"
      set MsgPhrase word MsgPhrase "(n) of the orbital period (“t = nT”) in green.\n\n"
      display ; always call display before a dialog box
      user-message MsgPhrase
    ]
  ]
  
  ask turtle tMessage
  [ set color black
    set label-color orange
    ifelse LockOrange_Ball_Mass: > 0
    [ ifelse LockChoose_Simulation: = "Empty space"
      [ ifelse bNotHD
        [ set label "Interaction is exclusively with the mass of the orange ball;"
          setxy (229) (- 138)
        ]
        [ 
          set label "Interaction is exclusively with the mass of the orange ball; no interactions occur between any of the 1-gram test masses."
          setxy (384) (- 194)
        ]
      ]
      [ ifelse bNotHD
        [ set label "Interaction is exclusively with the mass of the Earth and the orange ball;"
          setxy (215) (- 138)
        ]
        [ 
          set label "Interaction is exclusively with the mass of the Earth and the orange ball; no interactions occur between the eight 1-gram test masses."
          setxy (395) (- 194)
        ]
      ]
    ]
    [ 
      ifelse bNotHD
      [ set label "Interaction is exclusively with the mass of the Earth;"
        ifelse bLabelColorBlack [ set color 7  set label-color black ][ set label-color 86 ] ; same as GM label
        setxy (156) (- 138)
      ]
      [
        set label "Interaction is exclusively with the mass of the Earth; no interactions occur between the nine 1-gram test masses."
        ifelse bLabelColorBlack [ set color 7  set label-color black ][ set label-color 86 ] ; same as GM label
        setxy (369) (- 194)
      ]
    ]
    show-turtle
  ]
  
  if bNotHD
  [ ask turtle tMessage2
    [ set color black
      set label-color orange
      ifelse LockOrange_Ball_Mass: > 0
      [ ifelse LockChoose_Simulation: = "Empty space"
        [ set label "no interactions occur between any of the 1-gram test masses."
          setxy (242) (- 146)
        ]
        [ set label "no interactions occur between the eight 1-gram test masses."
          setxy (184) (- 146)
        ]
      ]
      [ 
        set label "no interactions occur between the nine 1-gram test masses."
        ifelse bLabelColorBlack [ set color 7  set label-color black ][ set label-color 86 ] ; same as GM label
        setxy (181) (- 146)
      ]
      show-turtle
    ]
  ]
  
  mainOutputHeader
  
  set bShowOrbitClicked false
end ; btnSetup


to btnRun
  ; PART 1: reasons to stop running
  ;=========================================================================================================================================================================================
  if hInteractive and Mouse-down?
  [ display ; always call display before a dialog box
    
    let result "OK"
    if hMatch_Galaxy = 2 ; M51
    [ if OrangeMyPhaseDeg < 475 [ set result "TooSoon" ]
      if OrangeMyPhaseDeg > 520 [ set result "TooLate" ]
    ]
    
    if hMatch_Galaxy = 1 ; NGC 1097
    [ if OrangeMyPhaseDeg < 325 [ set result "TooSoon" ]
      if OrangeMyPhaseDeg > 370 [ set result "TooLate" ]
    ]
    let value repNumber (Real-time / OrbitalPeriod) 2
    
    if result = "test" [ user-message (word "You stopped at OrangeMyPhaseDeg: " repnumber OrangeMyPhaseDeg 2 "\n\nContinue test.\n\n") ]
    if result = "TooSoon" [ user-message "It seems that you clicked too soon;\nthe galaxy’s arms extend beyond this point.\n\n" ]
    if result = "TooLate"
    [                let MsgPhrase "It seems that you clicked too late;\n"
      set MsgPhrase word MsgPhrase "the galaxy’s arms don’t extend this far.\n\n"
      set MsgPhrase word MsgPhrase "You will need to repeat this simulation.\n\n"
      user-message MsgPhrase
      set hInteractive false
      set hSim_Running false
      set bEndOfSimuation true
      set bSetUpButtonClicked false
      stop        
    ]
    if result = "OK"
    [ let GalaxiesToShow 2
      let MsgPhrase (word "You stopped at t ≈ " value "T.\n\n")
      if hMatch_Galaxy < GalaxiesToShow [ set MsgPhrase word MsgPhrase "Let’s do the same thing with another galaxy…\n\n" ]
      user-message MsgPhrase
      ifelse hMatch_Galaxy < GalaxiesToShow
      [ set hMatch_Galaxy hMatch_Galaxy + 1
        no-display
        set R LockR ; Don't let a disallowed change in the R control cause a dialog box.
        btnSetup    ; hInteractive = true supresses dialog boxes and last display
      ]
      [
                       set MsgPhrase "KEY CONCEPT:\n"
        set MsgPhrase word MsgPhrase "A larger fraction of an orbit produces a longer spiral.\n"
        set MsgPhrase word MsgPhrase "---------------------------------------------\n\n"
        set MsgPhrase word MsgPhrase "For elliptic orbits, T = 2⋅π⋅Sqrt[ a^3 / μ ];\n"
        set MsgPhrase word MsgPhrase "this implies that T is sensitive to the\n"
        set MsgPhrase word MsgPhrase "semi-major axis of the orbit (a).\n\n"
        set MsgPhrase word MsgPhrase "If, contrary to conventional wisdom, spiral galaxy\n"
        set MsgPhrase word MsgPhrase "morphology and rotation curves are caused by the\n"
        set MsgPhrase word MsgPhrase "modeled phenomenon (i.e., systemic galaxy orbits),\n"
        set MsgPhrase word MsgPhrase "then the plausibility of constraints on the age of\n"
        set MsgPhrase word MsgPhrase "galaxies imposed by the “Big Bang” standard\n" 
        set MsgPhrase word MsgPhrase "cosmological model must be reconsidered.\n\n"
        set MsgPhrase word MsgPhrase "See:\n"
        set MsgPhrase word MsgPhrase "Nature 487, 338 (2012); < arxiv.org/abs/1207.4196 >.\n"
        set MsgPhrase word MsgPhrase "Also see this PDF: < SensibleUniverse.com/Cosmos >.\n\n"
        user-message MsgPhrase
                         
        set hInteractive false
        set hMatch_Galaxy 1
        set hSim_Running false
        set bEndOfSimuation true
        set bSetUpButtonClicked false
        stop
      ]
    ]
  ]
  
  if not bSetUpButtonClicked ; We are prepared to run.
  [ beep
    display ; always call display before a dialog box
    user-message "Please first set up a new simulation.\n\n"
    set hSim_Running false
    stop
  ]
  
  let SkipTicks 20
  if LockR = 9 [ set SkipTicks 1000 ] ; Lunar orbit, so do things 50x faster
  ifelse ticks mod 20 = 0 [ display ][ no-display ] ; a higher value speeds up the simulation
  
  if bShowOrbitClicked
  [ set bShowOrbitClicked false
    set bEndOfSimuation true
    set bSetUpButtonClicked false
    set hSim_Running false
    stop
  ]
  
  if bEndOfSimuation 
  [ beep
    display ; always call display before a dialog box
    user-message "Cannot run simulation; first click [ Set Up Simulation ].\n\n"
    set hSim_Running false
    stop
  ]
  
  if bEarthExists and OrangeMyPhaseDeg >= AutoStopAngle
  [ ifelse bEarthExists and ticks > 0 [ mainOutputStatus ][ mainOutputStatus2 ] ; Send a final status report to output.
    beep
    display ; always call display before a dialog box      
    user-message "The simulation has stopped at the Orbit_Stops_At↓ value.\n\n"
    if ShowM51
    [ import-drawing "./GSrsc/M51.png"
      ask turtle tReferenceFrame [ hide-turtle ]
      ask OrbitData [ hide-turtle ]
      
                        let OutputPhrase "=============================================================================================================\n"
      set OutputPhrase word OutputPhrase "In physics, the purpose of a so-called “toy model” (right) is to demonstrate fundamental physical principles\n"
      set OutputPhrase word OutputPhrase "at work in real, complex physical systems (e.g., a galaxy of billions of interacting stars: M51 on the left).\n"
      set OutputPhrase word OutputPhrase "In addition to the obvious similarity in the spiral morphology, also note the periodic widening and narrowing\n"
      set OutputPhrase word OutputPhrase "of the spiral arms, which is apparent in both the model and the real galaxy, and that the Speed versus Radius\n"
      set OutputPhrase word OutputPhrase "graph shows linearly-increasing test-mass speed (i.e., tangential velocity) as a function of radial distance.\n"
      set OutputPhrase word OutputPhrase "This implies that spiral galaxies, which are not similarly isolated, cannot be expected to exhibit a velocity\n"
      set OutputPhrase word OutputPhrase "profile similar to the Solar System, where the nearest star is ~9000 times the orbital radius of Neptune.\n"
      beep
      output-type OutputPhrase
      
                     let MsgPhrase "“We are to admit no more causes of natural things\n"
      set MsgPhrase word MsgPhrase " than such as are both true and sufficient to explain\n"
      set MsgPhrase word MsgPhrase " their appearances.”   – Isaac Newton\n\n"
      set MsgPhrase word MsgPhrase "AFTER you click [ OK ]:\n"
      set MsgPhrase word MsgPhrase "Please read the important information newly posted\n"
      set MsgPhrase word MsgPhrase "to the general message box.\n\n"
      user-message MsgPhrase
    ]
    if Choose_Simulation: = "Software test" and hTestInit
    [ set hTestInit false
      set Synchronous_Rotation true
                     let MsgPhrase "↕Synchronous_Rotation has been switched -On-.\n\n"
      set MsgPhrase word MsgPhrase "Click [ Set Up Simulation ] and then run the\n"
      set MsgPhrase word MsgPhrase "the second phase of the test [ Run Simulation ].\n\n"
      user-message MsgPhrase
    ]
    set bShowOrbitClicked true
    set bEndOfSimuation true
    set bSetUpButtonClicked false
    set hSim_Running false
    stop
  ]
  
  if not mainAny-Balls_left? ; All balls crashed into the orange ball.
  [ ifelse bEarthExists and ticks > 0 [ mainOutputStatus ][ mainOutputStatus2 ] ; Send a final status report to output.
    beep
    display ; always call display before a dialog box
    let GoAgain false
    ifelse LockChoose_Simulation: = "Empty space"
    [               let YNphrase "All the other test masses have been absorbed\n"
      set YNphrase word YNphrase "by the orange ball; the simulation is over.\n\n"
      set YNphrase word YNphrase "Run another? (new random intitial velocities)\n\n"
      set GoAgain user-yes-or-no? YNphrase
    ]
    [                let MsgPhrase "All the other test masses have been absorbed\n"
      set MsgPhrase word MsgPhrase "by the orange ball; the simulation is over.\n\n"
      user-message MsgPhrase
    ]
    ifelse GoAgain
    [
      set R LockR ; Don't let a disallowed change in the R control cause a dialog box.
      btnSetup    ; "Empty space" supresses dialog box.
    ]
    [
      set bShowOrbitClicked true
      set bEndOfSimuation true
      set bSetUpButtonClicked false
      set hSim_Running false
      stop
    ]
  ]
  
  ; The radial free fall has ended when the frame drops below R = 6700 km; last report before stop.
  if bEarthExists and OrangeMyRadius < (6700 * 1000) and bFreeFall
  [ ask turtle tOrangeBall
    [ ; update the left panel display value
      let NewRadius My-py
      let Runits " km"
      let NewRadiusShow repNumber (NewRadius / 1000) 3
      if NewRadius / 1000 < 10000 [ set Runits " km  " ]
      set NewRadiusShow (word "R = " NewRadiusShow Runits)
      ask turtle tOrbitalRadius [ set label NewRadiusShow ]
      
      ifelse bEarthExists and ticks > 0 [ mainOutputStatus ][ mainOutputStatus2 ] ; Send a final status report to output.
      
                        let OutputPhrase "             # The simulation stopped; altitude is too low (approaching the atmosphere). #\n\n"
      set OutputPhrase word OutputPhrase "    NOTE: This well-known gravitational tidal force phenomenon is commonly called the “spaghetti effect.”\n"
      set OutputPhrase word OutputPhrase " ***********************************************************************************************************\n"
      set OutputPhrase word OutputPhrase " *  NEXT: Add mass to the orange ball (the selector has a log scale) and observe its gravitational effect  *\n"
      set OutputPhrase word OutputPhrase " *        on the dynamics of the other eight colored balls (i.e., 1-gram test masses). Afterwards, change  *\n"
      set OutputPhrase word OutputPhrase " *        Choose_Simulation↓ to “Circular orbit” and initially run the recommended default simulation.     *\n"
      set OutputPhrase word OutputPhrase " ***********************************************************************************************************\n"
      beep
      output-type OutputPhrase
    ]
  display
  set bShowOrbitClicked true
  set bEndOfSimuation true
  set bSetUpButtonClicked false
  set hSim_Running false
  stop
  ]
  
  
  ; PART 2: Controls cannot change during run.
  ;=========================================================================================================================================================================================
  
  if Synchronous_Rotation != LockSynchronous_Rotation
  [                let MsgPhrase "You cannot change ↕Synchronous_Rotation\n"
    set MsgPhrase word MsgPhrase "during a simulation.\n\n"
    display ; always call display before a dialog box
    user-message MsgPhrase
    set Synchronous_Rotation LockSynchronous_Rotation
  ]
  
  if LockR != R
  [ display ; always call display before a dialog box
    user-message "You cannot change the orbit during a simulation.\n\n"
    set R LockR
  ]
  
  if LockChoose_Simulation: != Choose_Simulation:
  [ display ; always call display before a dialog box
    user-message "You cannot change Choose_Simulation↓ during a simulation.\n\n"
    set Choose_Simulation: LockChoose_Simulation:
  ]
  
  if Orange_Ball_Mass: != LockOrange_Ball_Mass:
  [ display ; always call display before a dialog box
    user-message "You cannot change ||Orange_Ball_Mass during a simulation.\n\n"
    set  Orange_Ball_Mass: LockOrange_Ball_Mass:
  ]
  
  if Simulation_Interval: != LockSimulation_Interval:
  [ display ; always call display before a dialog box
    user-message "You cannot change ||Simulation_Interval\nduring a simulation.\n\n"
    set Simulation_Interval: LockSimulation_Interval:
  ]
  
  if Orbit_Stops_At: != LockOrbit_Stops_At:
  [ display ; always call display before a dialog box
    user-message "You cannot change Orbit_Stops_At↓ during a simulation.\n\n"
    set Orbit_Stops_At: LockOrbit_Stops_At:
  ]
  
  if Frame_Dimension: != LockFrame_Dimension: or x1 != Lockx1
  [ display ; always call display before a dialog box
    user-message "You cannot change ||Frame_Dimension during a simulation.\n\n"
    set Frame_Dimension: LockFrame_Dimension:
    set x1 Lockx1
  ]
  
  if Trace_Interval: != LockTrace_Interval:
  [ display ; always call display before a dialog box
    user-message "You cannot change ||Trace_Interval during a simulation.\n\n"
    set Trace_Interval: LockTrace_Interval:
  ]
  
  ; PART 3: initialize and report (btnRun)
  ;=========================================================================================================================================================================================
  
  set bSetUpButtonLocked true ; We are running, so don't let the user click the [ Set Up Simulation ] button.
  
  if bResetTimer ; resets once at tick 0 to initialize {Real-time} to 0 and to recod how long we have been running the sim via {Run-time}
  [ reset-timer
    set Real-time 0
    set bResetTimer false
    set hSim_Running true
    output-type "\n" ; Skip a line between the header and the first status report.
  ]
  
  ; Update the two timers and the simulation speed indicator at the top of the Dashboard
  set Real-timeShow uCenterText (repHumanTime Real-time) 20 ; starts off at 00:00:00 at tick 0
  
  set Run-time timer
  set Run-timeShow uCenterText22 (repHumanTime Run-time)
  if ticks mod 2500 = 0
  [ if ticks > 0 [ set SimulationSpeed uCenterText22 (precision ((2500 * LockTimePerTick) / (Run-time - lastRun-time)) 0) ]
    set LastRun-time Run-time
  ]
  ; Based on the real-time, we know the precide phase angle of the orange ball {FrameIdealTheta} and we report it as {tPartOfT}.
  if bEarthExists
  [ set FrameIdealTheta (Real-time / OrbitalPeriod) * 360 
    if not bFreeFall
      [ let value repNumber (Real-time / OrbitalPeriod) 3
        ask turtle  tPartOfT  [ set label (word "t = " value "T") ]
      ]
  ]
  
  ; Send a status report to output.
  if LockTrace_Interval: > 0
  [ if (int(Real-time) != LastReport) and (remainder int(Real-time) (LockTrace_Interval: * TraceSecondsMultiplier) = 0) [ ifelse bEarthExists [ mainOutputStatus ][ mainOutputStatus2 ] ] ]
  
  
  ; PART 4: Simulation (btnRun)
  ;=========================================================================================================================================================================================
  
  ; After reporting initial conditions at time 0, the first pass occurs at 1 * LockTimePerTick
  set Real-time (ticks + 1) * LockTimePerTick
  
  
  ; What happened to the orange ball over the last tick of time?
  ask turtle tOrangeBall ; Always update the orange ball first so that other balls can get corrected position (or velocity for free fall).
  [ ifelse bEarthExists
    [ physics-0-sequence ]; physics-5-properties sets the set of OrangeMy-<properties> and also sets DistanceChange & Arcseconds
    [
      set DistanceChange uCenterText22 "N/A"
      set Arcseconds uCenterText22 "N/A"
      ask turtle tOrbitalSpeedSim [set label "0.00000 km/s  (sim)" ]
    ]      
  ] 
  ; end of "What happened to the orange ball?"
  
  
  ; Report the speed of the orange ball in km/s {kps}.
  let kps precision (sqrt( OrangeMy-vx ^ 2 + OrangeMy-vy ^ 2) / 1000) 5
  if kps > 10 [ set kps precision kps 4 ]
  let kpsAlpha word kps ""
  let StringLength length kpsAlpha
  while [StringLength < 7 ]
  [ set kpsAlpha word kpsAlpha "0"
    set StringLength length kpsAlpha
  ]
  ask turtle tOrbitalSpeedSim [ set label (word kpsAlpha " km/s  (sim)") ]
  
  
  ; Since we know where the orange ball is, we know where the frame is and we plot its progress.
  if bEarthExists
  [ ask turtle tReferenceFrame
    [ let TimeDelta 0
      if LockTrace_Interval: > 0 [ set TimeDelta remainder int(Real-time) (LockTrace_Interval: * TraceSecondsMultiplier) ]
      ifelse TimeDelta = 0 [ pen-down ][ pen-up ]
      let fx (OrbitRadius * OrangeMyRadius / OrbitalRadius) * cos repMathAngle OrangeMyPhaseDeg - CenterX
      let fy (OrbitRadius * OrangeMyRadius / OrbitalRadius) * sin repMathAngle OrangeMyPhaseDeg
      if LockSynchronous_Rotation [ set heading OrangeMyPhaseDeg ]
      setxy fx fy
    ]
  ]
  
  ; What happened to the other balls over the last tick of time?
  set CheckMaxRange 0
  set CheckMaxVelocity 0
  
  ; sorting makes MaxVelocity and MaxRange favor red/green/blue/white
  ; ask <breed> is not deterministic, so we need to sort
  foreach sort radials
  [ ask ? [ physics-0-sequence  Turtles-Plot ] ]
  
  foreach sort laterals
  [ ask ? [ physics-0-sequence  Turtles-Plot ] ]
  
  foreach sort corners
  [ ask ? [ physics-0-sequence  Turtles-Plot ] ]
  
  mainShowMax
  
  ; end of "What happened to the other balls"
  
  tick ; Advance the time for the next pass.
end ;btnRun


to btnErase
  if Real-timeShow = 0 [ user-message "Nothing to erase.\n\n"  stop ]
                let YNphrase "Clear all current trace trails?\n\n"
  set YNphrase word YNphrase "This wll also activate changes to ↕Draw_Graph_Paper.\n\n"
  display ; always call display before a dialog box
  if user-yes-or-no? YNphrase
    [ clear-drawing
      setup-2-Graphics ; calls no-display
      display
      let OutputPhrase (word "\n\n\n*** TRACE TRAILS CLEARED AT " (remove " " Real-timeShow) " REAL-TIME ***\n\n\n\n\n")
      beep
      output-type OutputPhrase
    ]
end


to btnSave
  if hStartupHalt [ user-message "[ Halt ] clicked during startup; restart required.\n\n"  stop ]
  let NoFileName true
  let DoWrite false
  let FileName ""
  display
  while [ NoFileName = true ]
  [ display ; always call display before a dialog box
    set FileName user-new-file
    ifelse FileName = false [ set NoFileName false ]
    [ let txtFile word FileName "-GravitySim.png"
      ifelse file-exists? txtFile
      [               let YNphrase "This file name already exists and will be overwritten.\n"
        set YNphrase word YNphrase "Use a different file name? [Yes]\n"
        set YNphrase word YNphrase "CLICKING [ No ] HERE WILL OVERWRITE EXISTING FILE.\n"
        set YNphrase word YNphrase "Click [ Yes ] to use a different file name   (SAFE default).\n\n"
        display ; always call display before a dialog box
        if not user-yes-or-no? YNphrase
        [ set NoFileName false  set DoWrite true ] 
      ]
      [ set NoFileName false  set DoWrite true ]  
    ]
  ]
  if DoWrite
  [ ; Put a copyright notice and URL on the exported view
    ask turtle tMessage
    [ set color black
      setxy (- 131) (- 194)
      set label "Copyright ©2012 Alexander F. Mayer < http://GravitySim.net >"
      show-turtle
    ]
    export-view word FileName "-GravitySim.png"
    uPark-tMessage
    
    display ; always call display before a dialog box
    if user-yes-or-no? "Add a complete interface image?\n\n" [ export-interface word FileName "-interface.png" ]
    if user-yes-or-no? "Include the output text file?\n(This file is encoded UTF-8.)\n\n"
    [ let txtFile word FileName "-output.txt"
      export-output txtFile
      file-open txtFile
      file-print ""
      file-print ""
      file-print "GravitySim application ( http://GravitySim.net ) Copyright ©2012 Alexander F. Mayer"
      file-close       
    ]
  ]
end ; btnSave

;=========================================================================================================================================================================================
; startup and setup
;=========================================================================================================================================================================================

;  runs automatically at startup and initializes the application
to startup
  ; control defaults
  set hTestInit true     ; switch hidden under output
  set hStartupHalt true  ; switch hidden under output
  set hSim_Running false ; switch hidden under output
  set hInteractive false ; switch hidden under output
  set hMatch_Galaxy 1    ; slider (1 – 10) hidden under output
  set hUser_Response 20  ; slider (0 – 20) hidden under output (This setting means we are staring up and want the Startup splash screen.)
  set Synchronous_Rotation false
  set R 3 ; HST
  set LockR 3 ; must set as this is the current orbit
  set Choose_Simulation: "Radial free fall    (start here)"
  set Orange_Ball_Mass: 0
  set Test_Mass_Separation*: 5
  set Simulation_Interval: 5
  set Orbit_Stops_At: "1.00T (360°)"

  set Frame_Dimension: 50
  set x1 1
  ; set Trace_Interval: (set automatically for choice of R)
  set lateral:white/pink true
  set radial:blue/violet true
  set corners:red/green true
  set BIG false
  set Draw_Graph_Paper true

  set bShowOrbitClicked true ; supress dialog box
  set bSetUpButtonClicked false ; supress dialog box
  btnShowOrbit
  
  let MsgPhrase ""
  if false ; I like it, but probably not for everyone. Removed as of v 1.5 (for people who do not edit this line of code). 
  [
                 set MsgPhrase "In memoriam:\n"
  set MsgPhrase word MsgPhrase "Sir Arthur C. Clarke (1917 – 2008)\n\n"
  set MsgPhrase word MsgPhrase "Please click [ OK ] only when\n"
  set MsgPhrase word MsgPhrase "the sound ends (40 seconds) …\n"
  set MsgPhrase word MsgPhrase "Do not click [ Halt ]."
                let YNphrase "These dialog boxes can be dragged anywhere.\n\n"
  set YNphrase word YNphrase "Play the startup sound? (40 seconds)\n"
  set YNphrase word YNphrase "Do not click [ Halt ]."
  if user-yes-or-no? YNphrase [ sound:play-sound-and-wait "./GSrsc/astronaut40s.au"  user-message MsgPhrase ]
  ]
 
                   set MsgPhrase "Welcome to GravitySim!\n\n"
  set MsgPhrase word MsgPhrase "• If running the app locally (i.e., not in a browser):\n"
  set MsgPhrase word MsgPhrase "   – Java heap size *must* be set per the READ ME file.\n"
  set MsgPhrase word MsgPhrase "   – Adjust interface to your monitor with the Zoom menu.\n"
  set MsgPhrase word MsgPhrase "     (Zoom is not available in the Internet-based applet.)\n\n"
  set MsgPhrase word MsgPhrase "• Please note that the setting indicators under the slide\n"
  set MsgPhrase word MsgPhrase "   controls will reflect any control changes only *after*\n"
  set MsgPhrase word MsgPhrase "   you click the [ Set Up Simulation ] button.\n\n"
  set MsgPhrase word MsgPhrase "• American notation is used; a period is a decimal mark\n"
  set MsgPhrase word MsgPhrase "   (π = 3.14159…) and a comma is a digit group separator\n"
  set MsgPhrase word MsgPhrase "   (100 × 100 = 10,000).\n\n"
  set MsgPhrase word MsgPhrase "• Whenever new information is posted to the general\n"
  set MsgPhrase word MsgPhrase "   message box, you will hear an alert beep.\n\n"
  set MsgPhrase word MsgPhrase "                                      Do not click [ Halt ]."  
  user-message MsgPhrase

  let OutputPhrase "\n"
  set OutputPhrase word OutputPhrase "  The location of the NASA Jet Propoulsion Laboratory (JPL) in Pasadena, California is shown on the globe.\n"
  set OutputPhrase word OutputPhrase "  The appearance of the distinctive JPL logo does not construe that this software is in any way associated\n"
  set OutputPhrase word OutputPhrase "  with JPL. It does, however, reflect my respect for the JPL Team, whose various scientific missions serve\n"
  set OutputPhrase word OutputPhrase "  to benefit all mankind. I encourage exploration of the JPL website < www.jpl.nasa.gov > and for citizens\n"
  set OutputPhrase word OutputPhrase "  of the U.S.A. to e-mail their Congressional representatives in support of JPL’s annual budget. –A. Mayer\n\n"
  output-type OutputPhrase
  
  output-type "=============================================================================================================\n"

  set LastOutput "\n"
  set LastOutput word LastOutput "  If you are new to GravitySim, first click the [ ← Show Me ] button at the top left of the screen.\n"
  set LastOutput word LastOutput "  Afterwards, click the | Info | link at the top of the screen for more information and instructions.\n"
  set LastOutput word LastOutput "\n"
  set LastOutput word LastOutput "  NOTE: Lunar and Solar gravity are ignored; the Earth is treated as an idealized, isolated point mass.\n"
  set LastOutput word LastOutput "        -----------------------------------------------------------------------------------------------\n\n"
  beep
  output-type LastOutput
  
  set hStartupHalt false ; False means the user did not click Halt during startup and therefore saw all nessessary messages and output.

                 set MsgPhrase "AFTER you click [ OK ]:\n\n"
  set MsgPhrase word MsgPhrase "If running the application locally:\n"
  set MsgPhrase word MsgPhrase "Select menu item [Tools] → 'Hide Command Center'.\n\n"
  set MsgPhrase word MsgPhrase "Please read the entire contents of the general message\n"
  set MsgPhrase word MsgPhrase "box (below photo on the right); you will need to scroll up.\n\n"
  set MsgPhrase word MsgPhrase "Thank you.\n\n"
  display ; always call display before a dialog box
  user-message MsgPhrase
end ; startup


to setup-0-Clear&Reset
  no-display
  clear-all        ; clears all global variables and kills all turtles!
  set bNotHD false ; true if this is not the HD version
  set ScreenScale 1
  set Screen_dx 0
  set Screen_dy 0
  set OrbitRadius 180
  set CenterX 204
  set GyroOffset 100
  if bNotHD [ set ScreenScale 0.75  set Screen_dx 101  set Screen_dy 50  set OrbitRadius 135  set CenterX 153  set GyroOffset 75 ]
  
  set bShowOrbitClicked true ; we are going to display something
  set hSim_Running false
  set LockR R ; the current orbit
  
  ; other switches
  set bShowMe false             ; tells setup-2-Graphics that it was called by btnShowMe, not by startup or btnReset
  set bNoSplash false           ; tells setup-2-Graphics not to use splash screens — we about to run a simulation
  set bSetUpButtonLocked false  ; when running (= true), user cannot click the setup button before a reset
  set bSetUpButtonClicked false ; btnShowMe should not work afterwards
  set bFreeFall false           ; user chose "Radial free fall" simulation
  set bEarthExists true         ; if false, user chose "Empty space (no Earth)" simulation
  set bEndOfSimuation false     ; Orbit_Stops_At: was reached
  set bResetTimer false         ; used in btnRun to start the Run-time timer
  set bPreciseColors false      ; if false (default) "lime" is reported as "green"; "sky" is reported as "blue"
  set ShowM51 false             ; compare simulation to M51
  
  set PadLeftSpaces 0           ; used by repNumber, which pads PadLeftSpaces to the left of numbers
  set LastOutput ""
  set LastAlert ""
  
  import-drawing "./GSrsc/Columbia.png" ; screen-wide supercomputer
  
                                        ; ================================================================================================================================
  set-default-shape turtles "circle"
  let ball-diameter round (400 / Frame_Dimension:) ; pixels per 1-meter-diameter test-mass locator
  if ball-diameter < 1 [ set ball-diameter 1 ]
  
  ; ================================================================
  ; label turtles
  ; ================================================================
  
  create-OrbitData 1 
  [ set color black
    set size 4
    setxy (- 330 + Screen_dx) (193 - Screen_dy) ; top left corner
    set label "v = 0.00000 km/s (calc)"
    set label-color yellow
  ]
  set tOrbitalSpeedCalc (count turtles - 1)
  
  create-OrbitData 1 
  [ set color black
    set size 4
    setxy (- 330 + Screen_dx) (183 - Screen_dy) ; top left corner
    set label "0.00000 km/s  (sim)"
    set label-color lime
  ]
  set tOrbitalSpeedSim (count turtles - 1)
  
  ; ================================================================
  
  create-OrbitData 1
  [ set color black
    set size 4
    setxy (- 341 + Screen_dx) (- 194 + Screen_dy) ; bottom left corner (left panel)
                          ; set label "R = "
    set label-color orange
  ]
  set tOrbitalRadius (count turtles - 1)
  
  create-OrbitData 1
  [ set color black
    set size 4
    setxy (- 9) (- 194 + Screen_dy) ; bottom right corner (left panel)
                        ; set label "GM = n km^3 / s^2"
    set label-color 86
  ]
  set tGM (count turtles - 1)
  
  create-OrbitData 1
  [ set color black
    set size 4
    setxy (- 9) (193 - Screen_dy); top right corner (left panel)
                    ; set label "T = "
    set label-color yellow
  ]
  set tOrbitalPeriod (count turtles - 1)
  
  crt 1 ; We don't include this one in "OrbitData," because we want to show how many turns it took to create the spiral.
  [ set color black
    set size 4
    setxy (- 9) (183 - Screen_dy) ; top left corner (left panel)
    set label "t = 0.000T"
    set label-color lime
  ]
  set tPartOfT  (count turtles - 1)
  
  ; ================================================================
  
  create-OrbitData 1
  [ set color black
    set size 4
    setxy (- 226 + Screen_dx / 2) (193 - Screen_dy) ; top middle (left panel)
    set label "m = 1 g"
    set label-color orange
  ]
  set tOrangeMass  (count turtles - 1)
  
  create-OrbitData 1
  [ set color black
    set size 4
    setxy (- 140 + Screen_dx / 2) (193 - Screen_dy) ; top middle (left panel)
    set label "Δt = "
    set label-color orange
  ]
  set tTraceInterval  (count turtles - 1)
  
  ; ================================================================
  ; reference frame turtle (created first, thus *behind* "little gyros")
  ; ================================================================
  
  crt 1
  [ set shape "frame"                               ; set by setup-2-Graphics to "frame-small" for ISS orbit (looks better than shrinking the original with "set size")
    set size 20 * ScreenScale                       ; permanent size
    set color 26                                    ; the pen color, not the color of anything that shows
    ifelse BIG [ set pen-size 3 ][ set pen-size 2 ] ; small (but not tiny) dots
    set heading 0                                   ; parked heading
    setxy (- CenterX) OrbitRadius                   ; permanent parking spot
  ]
  set tReferenceFrame (count turtles - 1)
  
  
  ; ================================================================
  ; gyro turtles
  ; ================================================================
  
  let angle 2 ; the angle to displace the little "gyros" inside the orbiting frame
  crt 1
    [ set color red
      set size 3
      set heading 0
      setxy (- CenterX + OrbitRadius * sin (- angle)) (0 + OrbitRadius * cos (- angle)) ; permanent parking spot
      set MyPhaseInit (- angle) ; used in {drawOrbit} routine to orbit it in sycnch with tReferenceFrame
      set MyPhaseDeg (- angle)  ; not used  
      hide-turtle
    ]
  set tLittleGyroRed (count turtles - 1) 
  
  crt 1
    [ set color lime
      set size 3
      set heading 0
      setxy (- CenterX + OrbitRadius * sin angle) (0 + OrbitRadius * cos angle)         ; permanent parking spot
      set MyPhaseInit angle     ; used in {drawOrbit} routine to orbit it in sycnch with tReferenceFrame
      set MyPhaseDeg angle      ; not used
      hide-turtle
    ]
  set tLittleGyroGreen (count turtles - 1)
  
  crt 1
    [ set color orange
      set shape "gyro"
      set size 40 * ScreenScale
      set heading 0
      setxy CenterX 0         ; permanent parking spot
      hide-turtle
    ]
  set tGyroOrange (count turtles - 1) 
  
  crt 1
    [ set color red
      set shape "gyro"
      set size 43  * ScreenScale
      set heading 0
      setxy (CenterX - GyroOffset) 0 ; permanent parking spot
      hide-turtle
    ]
  set tGyroRed (count turtles - 1) 
  
  crt 1
    [ set color lime
      set shape "gyro"
      set size 43  * ScreenScale
      set heading 0
      setxy (CenterX + GyroOffset) 0 ; permanent parking spot
      hide-turtle
    ]
  set tGyroGreen (count turtles - 1) 
  
  ; ================================================================
  ; simulation turtles
  ; ================================================================
  
  crt 1
  [ set color orange ]
  set tOrangeBall (count turtles - 1)
  
  ; ================================================================
  let BallPenSize 3
  if BIG [set BallPenSize 4 ]
  if x1 = 10 [
    ifelse BIG [ set BallPenSize 2 ] [ set BallPenSize 1 ]
  ]
  
  create-corners 1
  [ set color red
    set pen-size BallPenSize
    hide-turtle
  ]
  set tRedBall_TL (count turtles - 1)
  
  create-corners 1
  [ set color lime
    set pen-size BallPenSize
    hide-turtle
  ]
  set tGreenBall_TR (count turtles - 1)
  
  create-corners 1
  [ set color magenta
    set pen-size BallPenSize
    hide-turtle
  ]
  set tMagentaBall_BL (count turtles - 1)
  
  create-corners 1
  [ set color yellow
    set pen-size BallPenSize
    hide-turtle
  ]
  set tYellowBall_BR (count turtles - 1)
  
  ; ================================================================
  
  create-radials 1
  [ set color sky
    set pen-size BallPenSize
    hide-turtle
  ]
  set tBlueBall_TC (count turtles - 1)
  
  create-radials 1
  [ set color violet
    set pen-size BallPenSize
    hide-turtle
  ]
  set tVioletBall_BC (count turtles - 1)
  
  ; ================================================================
  
  create-laterals 1
  [ set color white
    set pen-size BallPenSize
    hide-turtle
  ]
  set tWhiteBall_MR (count turtles - 1)
  
  create-laterals 1
  [ set color pink
    set pen-size BallPenSize
    hide-turtle
  ]
  set tPinkBall_ML (count turtles - 1)
  
  ; ================================================================
  ; utility turtles
  ; ================================================================
  
  crt 1
  [ set color black
    hide-turtle
  ]
  set tMarker (count turtles - 1)
  
  crt 1
  [ set color black
    hide-turtle
  ]
  set tMessage (count turtles 
- 1)
  
  crt 1
  [ set color black
    hide-turtle
  ]
  set tMessage2 (count turtles - 1)
  
  ; hide turtles and reset-ticks
  ; ================================================================================================================================
  
  ask turtle tReferenceFrame [ hide-turtle ]
  ask OrbitData [ hide-turtle ]
  ask turtle tPartOfT [ hide-turtle ]
  uPark-tMarker
  uPark-tMessage

  reset-ticks ; reset to time zero; must go last because it activates the plot area, which needs {bEarthExists}
end ; setup-0-Clear&Reset


to setup-1-Initialize
  ; Did the user choose a valid setting of the ||R slider?
  if  R != 0 and R != 1 and R != 3 and R != 5 and R != 7 and R != 9 and R != 10  ; zero is for empty space
  [ let phrase (word "The orbit setting is set between options.\nChoices for  are limited to:")
    display ; always call display before a dialog box
    let choice read-from-string first (user-one-of phrase [ "1 – International Space Station orbit (ISS)" "2 – Hubble Space Telescope orbit (HST)" "3 – Global Positioning System orbit (GPS)" "4 – Geostationary orbit (Geo)" "5 – Mean Lunar orbit (Moon)" "6 – Lunar Reconnaissance Orbiter (◗)" ])
    if choice = 1 [ set R 1 ]
    if choice = 2 [ set R 3 ]
    if choice = 3 [ set R 5 ]
    if choice = 4 [ set R 7 ]
    if choice = 5 [ set R 9 ]
    if choice = 6 [ set R 10 ]
    no-display
  ]
  
  ; standard near-Earth values (Geo and Moon different)
  set Time_IntervalMultiplier 0.1 ; 1 second max.
  set TraceSecondsMultiplier 6
  
  ; Set {OrbitalPeriod}, the fundamental physical parameter determining the orbital parameters based on ||R slider setting.
  ; {Trace_Interval:} spaces the dots in a meaningful way for the default display.
  
  ifelse R = 0 ; "Empty space" simulation
  [ set OrbitalPeriod 0
    set Time_IntervalMultiplier 1 ; 10 seconds max.
    set TraceSecondsMultiplier 3600
  ]
  [
    ifelse R = 1
    [ set OrbitalPeriod 92.8588 * 60            ; Nominal ISS value
      if not bShowMe and not bFreeFall and not bSetupButtonClicked [ set Trace_Interval: 30 ] ; [Show This Orbit] button clicked
    ]
    [
      ifelse R = 3
      [ set OrbitalPeriod 95.8146 * 60          ; Nominal HST value
        if not bShowMe and not bFreeFall and not bSetupButtonClicked [ set Trace_Interval: 30 ] ; [Show This Orbit] button clicked & * startup *
      ]
      [
        ifelse R = 5
        [ set OrbitalPeriod 717.9882 * 60       ; Nominal GPS value
          if not bShowMe and not bFreeFall and not bSetupButtonClicked [ set Trace_Interval: 30 ]
          set TraceSecondsMultiplier 60
        ]
        [
          ifelse R = 7
          [ set OrbitalPeriod 23.9344696 * 3600 ; sidereal day in seconds (Geostationary orbit)
            if not bShowMe and not bFreeFall and not bSetupButtonClicked [ set Trace_Interval: 60 ]
            set TraceSecondsMultiplier 60
          ]
          [
            ifelse R = 9
            [ set OrbitalPeriod 27.3217 * 86400 ; Lunar revolution period in seconds
              if not bShowMe and not bFreeFall and not bSetupButtonClicked [ set Trace_Interval: 24 ]
              if Frame_Dimension: < 100 and bSetupButtonClicked
              [ display ; always call display before a dialog box
                user-message "The minimum frame size for “Moon” is 100 m.\n\n"
                set Frame_Dimension: 100  ; Otherwise, balls go off-screen in "Radial free fall".
              ]
              set TraceSecondsMultiplier 3600
              
              set Time_IntervalMultiplier 1 ; 10 seconds max.              
            ]
            [
              ifelse R = 10
              [ set OrbitalPeriod 2 * pi * sqrt(1788387.1464 ^ 3 / 4902.798E9)  ; parameter sources: LRO_Mission_Baseline_Ephemeris_v11_file2.txt (avg value of a) & JPL HORIZONS (GM)
                if not bShowMe and not bFreeFall and not bSetupButtonClicked [ set Trace_Interval: 4 ]
                set TraceSecondsMultiplier 6
              ]
              [ 
                               let MsgPhrase "Error in setup-1-Initialize;\n"
                set MsgPhrase word MsgPhrase "no such orbital radius (R) setting for Earth."
                display
                user-message MsgPhrase
                stop
              ]
            ]
          ]
        ]
      ]
    ]
  ]
  if not bSetUpButtonClicked and not (hUser_Response = 20)
  [ ; make it pretty
    set Draw_Graph_Paper false
    ask turtle tOrangeBall [ hide-turtle ]
  ]
  
  set LockSynchronous_Rotation Synchronous_Rotation
  set LockR R ; this is actually already set immediately after the clear-all in setup-0
  set LockChoose_Simulation: Choose_Simulation:
  set LockOrange_Ball_Mass: Orange_Ball_Mass:
  set LockTest_Mass_Separation*: Test_Mass_Separation*:
  set LockSimulation_Interval: Simulation_Interval:  
  set LockOrbit_Stops_At: Orbit_Stops_At:
  set LockFrame_Dimension: Frame_Dimension:
  set Lockx1 x1
  set LockTrace_Interval: Trace_Interval:
  set LockTimePerTick LockSimulation_Interval: * Time_IntervalMultiplier
  
  ifelse LockOrbit_Stops_At: = "Never" or LockOrbit_Stops_At: = "N/A"
  [ set AutoStopAngle 999999999 ]
  [
    let value remove " (180°)" Orbit_Stops_At:
    set value remove " (270°)" value
    set value remove " (360°)" value
    set value remove "[ " value
    set value remove " ]" value
    set value remove "T" value
    set value read-from-string value
    set AutoStopAngle value * 360
  ]
  
  ifelse LockR = 10
  [ set cSourceBodyGM 4902.798E9 ]   ; Moon in m^3 / s^2, source: http://ssd.jpl.nasa.gov/
  [ set cSourceBodyGM 398600.440E9 ] ; Earth in m^3 / s^2, source: http://ssd.jpl.nasa.gov/
  
  set OrbitalRadius (OrbitalPeriod ^ 2 * cSourceBodyGM / (4 * pi ^ 2)) ^ (1 / 3) ; OrbitalPeriod from preceding code
  set CentroidGM 0
  if LockOrange_Ball_Mass: > 0 [ set CentroidGM (6.67384E-11 * (2.51188643150958 ^ LockOrange_Ball_Mass:) * 100) ]
  set cPixelsPerMeter 400 * ScreenScale / (LockFrame_Dimension: * Lockx1)
  
  ifelse bFreeFall or not bEarthExists
  [ set cOrbitalSpeed 0     
    set OrbitalSpeedShow "v = 0 (not an orbit)"
    set OrbitalPeriodShow "N/A"
    set fre uCenterText22 "N/A"
    set avg-fre uCenterText22 "N/A"
  ]
  [ 
    set cOrbitalSpeed sqrt(cSourceBodyGM / OrbitalRadius)
    set OrbitalSpeedShow (word "v = " repNumber (sqrt(cSourceBodyGM / OrbitalRadius) / 1000) 5 " km/s (calc)")
  ] 
  
  
  ; starting xy coordinates and Turtles-Initialize for the orange ball + the 8 test-mass balls 
  ; Turtles-Initialize needs: cSourceBodyGM, CentroidGM, cOrbitalSpeed, cPixelsPerMeter, {bFreeFall, bEarthExists}
  ;=======================================================================================================================
  ask turtle tOrangeBall
  [ set My-px 0
    set My-py OrbitalRadius
    Turtles-Initialize
    set OrangeMy-px My-px
    set OrangeMy-py My-py
    set OrangeMy-vx  My-vx
    set OrangeMy-vy  My-vy
    set OrangeMyRadius MyRadius
    set OrangeMyPhaseDeg MyPhaseDeg
    
    ; This is where we plot the orange ball. To ensure it know where it is, we reference its physical coordinates and use the same commands as Turtles-Plot
    set My-fx CenterX + (My-px - OrangeMy-px) * cPixelsPerMeter
    set My-fy (My-py - OrangeMy-py) * cPixelsPerMeter
    setxy My-fx My-fy
  ]
  
  let DoCircle false ; future use
                     ; relative to orange ball: x-coordinate identical, the y-coordinate + Test_Mass_Separation*:
  ask turtle tBlueBall_TC
  [ ifelse DoCircle
    [ set My-px 0
      set My-py OrbitalRadius + Test_Mass_Separation*:
    ]
    [
      set My-px 0
      set My-py OrbitalRadius + Test_Mass_Separation*:
    ]
  Turtles-Initialize
  ]
  
  ; relative to orange ball: x-coordinate identical, the y-coordinate - Test_Mass_Separation*:
  ask turtle tVioletBall_BC
  [ ifelse DoCircle
    [ set My-px 0
      set My-py OrbitalRadius - Test_Mass_Separation*:
    ]
    [
      set My-px 0
      set My-py OrbitalRadius - Test_Mass_Separation*:
    ]
  Turtles-Initialize
  ]
  
  ; relative to orange ball: x-coordinate - Test_Mass_Separation*:, the y-coordinate identical
  ask turtle tPinkBall_ML
  [ ifelse DoCircle
    [ set My-px 0 - Test_Mass_Separation*:
      set My-py OrbitalRadius
    ]
    [
      set My-px 0 - Test_Mass_Separation*:
      set My-py OrbitalRadius
    ]
  Turtles-Initialize
  ]
  
  ; relative to orange ball: x-coordinate + Test_Mass_Separation*:, the y-coordinate identical
  ask turtle tWhiteBall_MR
  [ ifelse DoCircle
    [ set My-px 0 + Test_Mass_Separation*:
      set My-py OrbitalRadius
    ]
    [
      set My-px 0 + Test_Mass_Separation*:
      set My-py OrbitalRadius
    ]
  Turtles-Initialize
  ]
  
  ; relative to orange ball: x-coordinate - Test_Mass_Separation*:, the y-coordinate + Test_Mass_Separation*:
  ask turtle tRedBall_TL
  [ ; top left of the circle is at 135 degrees MathAngle
    ifelse DoCircle
    [ set My-px 0 - Test_Mass_Separation*: * cos 135
      set My-py OrbitalRadius + Test_Mass_Separation*: * sin 135
    ]
    [
      set My-px 0 - Test_Mass_Separation*:
      set My-py OrbitalRadius + Test_Mass_Separation*:
    ]
    Turtles-Initialize
  ]
  
  ; relative to orange ball: x-coordinate + Test_Mass_Separation*:, the y-coordinate + Test_Mass_Separation*:
  ask turtle tGreenBall_TR
  [ ; top right of the circle is at 45 degrees MathAngle
    ifelse DoCircle
    [ set My-px 0 + Test_Mass_Separation*: * cos 45
      set My-py OrbitalRadius + Test_Mass_Separation*: * sin 45
    ]
    [
      set My-px 0 + Test_Mass_Separation*:
      set My-py OrbitalRadius + Test_Mass_Separation*:
    ]
    Turtles-Initialize
  ]
  
  ; relative to orange ball: x-coordinate - Test_Mass_Separation*:, the y-coordinate - Test_Mass_Separation*:
  ask turtle tMagentaBall_BL
  [ ; bottom left of the circle is at -135 degrees MathAngle
    ifelse DoCircle
    [ set My-px 0 - Test_Mass_Separation*: * cos (- 135)
      set My-py OrbitalRadius - Test_Mass_Separation*: * sin (- 135)
    ]
    [
      set My-px 0 - Test_Mass_Separation*:
      set My-py OrbitalRadius - Test_Mass_Separation*:
    ]
    Turtles-Initialize
  ]
  
  ; relative to orange ball: x-coordinate + Test_Mass_Separation*:, the y-coordinate - Test_Mass_Separation*:
  ask turtle tYellowBall_BR
  [ ; bottom right of the circle is at -45 degrees MathAngle
    ifelse DoCircle
    [ set My-px 0 + Test_Mass_Separation*: * cos (- 45)
      set My-py OrbitalRadius - Test_Mass_Separation*: * sin (- 45)
    ]
    [
      set My-px 0 + Test_Mass_Separation*:
      set My-py OrbitalRadius - Test_Mass_Separation*:
    ]
    Turtles-Initialize
  ]
end ; setup-1-Initialize


to setup-2-Graphics
  no-display
  clear-drawing
  
  ask turtle tMarker
  [ ; draw a fat line down the center in case we don't use an overlay
    set color gray
    setxy 0 max-pycor
    set heading 180
    set pen-size 6
    pen-down
    jump 2 * max-pycor
    
    if 1 = 2
    [ ; draw centering axes on the left (dev only)
      setxy min-pxcor  0
      set heading 90
      set color sky
      set pen-size 1
      pen-down
      jump 400
      pen-up
      setxy (- CenterX)  min-pycor
      set heading 0
      pen-down
      jump 2 * max-pycor
    ]
  ]
  uPark-tMarker
  
  
  let ImageSuffix "_Splash.png"
  if bNoSplash [ set ImageSuffix ".png" ]
  
  if Choose_Simulation: = "Match the image"
  [ if hMatch_Galaxy = 1 [ import-drawing "./GSrsc/NGC1097neg.png" ]
    if hMatch_Galaxy = 2 [ import-drawing "./GSrsc/M51neg.png" ]
    if hMatch_Galaxy < 1 or hMatch_Galaxy > 2 
    [ display ; always call display before a dialog box
      user-message "Error in setup-2-Graphics; no such hMatch_Galaxy"
      stop
    ]
  ]
  
  ask turtle tReferenceFrame [ setxy (- CenterX) OrbitRadius ] ; permanent parking spot, unless R = 0
  
  ifelse LockR = 0 ;
  [ import-drawing word "./GSrsc/EmptySpace" ImageSuffix    
    set OrbitalPeriodShow "N/A"
    ask turtle tReferenceFrame
    [ set shape "frame"
      setxy (- CenterX) 0
    ]   
  ]
  [
    ifelse LockR = 1
    [
      set OrbitalPeriodShow "92.8588 minutes"
      import-drawing word "./GSrsc/EarthISS" ImageSuffix
      ask turtle tReferenceFrame [ set shape "frame-small" ]
      
                        let OutputPhrase "This photo by Paolo Nespoli shows the Shuttle Endeavor docked to the International Space Station (ISS)\n"
      set OutputPhrase word OutputPhrase "< nasa.gov/mission_pages/station/main >.\n\n"
      if not bSetUpButtonClicked and not bShowMe [ beep  output-type OutputPhrase ]
    ]
    ;--------------------------------------------------------------------------------------------------------------------------------------------    
    
    [ ifelse LockR = 3
      [
        set OrbitalPeriodShow "95.8146 minutes"
        ifelse hUser_Response = 20
        [ import-drawing word "./GSrsc/Startup" ImageSuffix 
          set hUser_Response 0 ; 20 was the startup setting to make this happen; now we reset it.
        ]
        [ 
          import-drawing word "./GSrsc/EarthHST" ImageSuffix
          ask turtle tReferenceFrame [ set shape "frame" ]
          
                            let OutputPhrase "This photo depicts the Hubble Telescope after the installation of new solar arrays by Shuttle mission STS-61\n"
          set OutputPhrase word OutputPhrase "< nasa.gov/mission_pages/shuttle/shuttlemissions/archives/sts-61.html >.\n\n"
          if not bSetUpButtonClicked and not bShowMe [ beep  output-type OutputPhrase ]
        ]
      ]
    ;--------------------------------------------------------------------------------------------------------------------------------------------    
    
      [ ifelse LockR = 5
        [ set OrbitalPeriodShow "717.9882 minutes"
          import-drawing word "./GSrsc/EarthGPS" ImageSuffix
          ask turtle tReferenceFrame [ set shape "frame" ]
          
                            let OutputPhrase "The artist rendering depicts the Lockheed Martin GPS III next-generation Global Positioning System satellite\n"
          set OutputPhrase word OutputPhrase "< www.lockheedmartin.com/us/products/gps.html >.\n\n"
          if not bSetUpButtonClicked and not bShowMe [ beep  output-type OutputPhrase ]          
        ]
      ;--------------------------------------------------------------------------------------------------------------------------------------------    
      
        [ ifelse LockR = 7
          [ set OrbitalPeriodShow "23.9344696 hours"
            import-drawing word "./GSrsc/EarthGeo" ImageSuffix
            ask turtle tReferenceFrame [ set shape "frame" ]
            
                              let OutputPhrase "The rendering (right) employs artistic license as concerns the apparent size of the Earth; it depicts the\n"
            set OutputPhrase word OutputPhrase "Artemis telecommunications satallite, which is in a geostationary orbit ~35,786 km above the Equator\n"
            set OutputPhrase word OutputPhrase "< aerospace-technology.com/projects/artemis >.\n\n"
            if not bSetUpButtonClicked and not bShowMe [ beep  output-type OutputPhrase ]            
          ]
        ;--------------------------------------------------------------------------------------------------------------------------------------------    
        
          [ ifelse LockR = 9
            [ set OrbitalPeriodShow "27.3217 days"              
              ask turtle tReferenceFrame [ set shape "frame" ]
              
                                let OutputPhrase "This photo by the JAXA Kaguya spacecraft shows the Earth as seen from Lunar orbit\n"
              set OutputPhrase word OutputPhrase "< kaguya.jaxa.jp/index_e.htm >.\n\n"
              if not bSetUpButtonClicked and not bShowMe [ beep  output-type OutputPhrase ]
                         
              ifelse bNoSplash
              [ import-drawing word "./GSrsc/EarthMoon" ImageSuffix ]
              [ clear-drawing
                import-drawing "./GSrsc/EarthMoonX30_Splash.png"
                ask turtle tMessage
                [ set color black
                  setxy (- 220 + Screen_dx * 0.9) 12
                  set label "The mean Lunar orbit is about 30 Earth diameters."
                  show-turtle
                ]
                drawOrbit
                let TimeLeft 9
                ask turtle tMarker
                [ set color black
                  setxy (- 150 + Screen_dx / 2) 50
                  set label-color cyan
                  set label (word "Temporary Illustrative Schematic (" TimeLeft ")…")
                  show-turtle
                ]
                while [ TimeLeft > 0 ]
                [ wait 1
                  set TimeLeft TimeLeft - 1
                  ask turtle tMarker [ set label (word "Temporary Illustrative Schematic (" TimeLeft ")…") ]
                ]
                
                no-display
                uPark-tMessage
                uPark-tMarker
                clear-drawing
                import-drawing word "./GSrsc/EarthMoon" ImageSuffix                
              ]
            ]          
          ;--------------------------------------------------------------------------------------------------------------------------------------------    
          
            [ ifelse LockR = 10
              [         
                set OrbitalPeriodShow "113.1095 minutes"
                import-drawing word "./GSrsc/Moon" ImageSuffix
                ask turtle tReferenceFrame [ set shape "frame-xsmall" ]                
                
                                  let OutputPhrase "The artist rendering (right) shows the NASA Lunar Reconnaissance Orbiter (LRO) in orbit around the Moon\n"
                set OutputPhrase word OutputPhrase "< nasa.gov/mission_pages/LRO/main >. The orbital parameters shown (left) reflect the average semimajor axis\n"
                set OutputPhrase word OutputPhrase "of the LRO ephemeris as measured between JDates 2455119.502 and 2455456.489 (15 Oct. 2009 – 16 Sep. 2010).\n\n"
                set OutputPhrase word OutputPhrase "LRO launched from Cape Canaveral 18 June 2009; it was in Lunar orbit 5 days later < youtu.be/GCa_mHYK_Ik >.\n"
                set OutputPhrase word OutputPhrase "This was just under forty years after Apollo 11 when Neil Armstrong first stepped on the Moon (20 July 1969).\n\n"
                if not bSetUpButtonClicked and not bShowMe [ beep  output-type OutputPhrase ]
              ]
          ;--------------------------------------------------------------------------------------------------------------------------------------------    
                                
              [                let MsgPhrase "Error in setup-2-Graphics ;\n"
                set MsgPhrase word MsgPhrase "no such orbital radius (R) setting for Earth."
                display
                user-message MsgPhrase
                stop
              ]
            ]
          ]
        ]
      ]
    ]
  ]

  drawGraphPaper
  
  ; interface display elements 
  ;=======================================================================================================================
  ; main control area
  ifelse LockOrange_Ball_Mass: = 0
  [ 
    Ifelse bEarthExists
    [ set Orange_Ball_MassShow uCenterText22 "0.001 kg" ]
    [ set Orange_Ball_MassShow uCenterText22 "0" ]
  ]
  [ set Orange_Ball_MassShow uCenterText22 word (repNumber ((2.51188643150958 ^ LockOrange_Ball_Mass:) * 100) 0) " kg" ] ; Pogson’s formula gives a factor of 100 for 5 units on the slider with 10 being 10^7 kg.
  ask turtle tOrangeMass [ set label word "m = " remove "  " Orange_Ball_MassShow ]
  
  set Test_Mass_Separation*:_Units word LockTest_Mass_Separation*: " meters (lateral/vertical)"
  
  let unit " seconds"
  if LockTimePerTick = 1 [ set unit " second" ]
  set Simulation_IntervalShow uCenterText22 (word repNumber LockTimePerTick 1 unit)
  
  ; right stack
  set FrameDimensionsShow uCenterText22 (word (Frame_Dimension: * Lockx1) " m × " (Frame_Dimension: * Lockx1) " m")
  ; <drawGraphPaper> sets GridSquareDimensionsShow
  
  let units " ERROR"
  let coefficient 1
  set Trace_IntervalMultShow "   × 1"
  if TraceSecondsMultiplier = 6
  [ ifelse LockTrace_Interval: <= 15 ; 15 is 1.5 minutes = 90 seconds
    [ set units " seconds"
      set coefficient TraceSecondsMultiplier
    ]
    [ 
      set units " minutes"
      set coefficient 0.1
      set Trace_IntervalMultShow " ÷ 10"
    ]
  ]
  if TraceSecondsMultiplier = 60 [ set units " minutes" ]
  if TraceSecondsMultiplier = 3600 [ set units " hours" ]
  set Trace_IntervalShow uCenterText (word (precision (LockTrace_Interval: * coefficient) 1) units) 12
  ask turtle tTraceInterval [ set label word "Δt = " (remove "  " Trace_IntervalShow) ]
  
  ; bottom of left panel
  ; ORANGE
  let Runits " km"
  set OrbitalRadiusShow repNumber (OrbitalRadius / 1000) 3
  if OrbitalRadius / 1000 < 10000 [ set Runits " km  " ]
  set OrbitalRadiusShow (word "R = " OrbitalRadiusShow Runits)
  ask turtle tOrbitalRadius [ set label OrbitalRadiusShow ]
  
  ; BLUE
  set cShowGM cSourceBodyGM / 1E9 / 1E6 ; GM in ×1E6  km^3 / s^2
  ask turtle tGM [ set label (word "GM = " (cSourceBodyGM / 1E9 / 1E6) "E6  km^3 / s^2") ]
  if not bEarthExists
  [ set cShowGM CentroidGM ; GM in m^3 / s^2
    ask turtle tGM
    [
      set label (word "GM = " repNumber CentroidGM 12 " m^3 / s^2")
      set label-color orange
    ]
  ]
  
  ; top of left panel
  ; YELLOW  
  ask turtle tOrbitalSpeedCalc [ set label OrbitalSpeedShow ]           ; left
  
  ask turtle tOrbitalPeriod [ set label word "T = " OrbitalPeriodShow ] ; right
    
  ; setup-0-Clear&Reset hides these turtles, so show them now
  ask turtle tReferenceFrame [ show-turtle ]
  ask turtle tPartOfT [ show-turtle ]
  
  ifelse bEarthExists
  [ ask OrbitData [ show-turtle ] ]
  [
    ask OrbitData [ hide-turtle ]
    ask turtle tPartOfT [ hide-turtle ]
    ask turtle tTraceInterval [ hide-turtle ]
    ask turtle tGM [ show-turtle ]
    ask turtle tOrangeMass
    [ show-turtle
      setxy (- 218 + Screen_dx / 2) 0
    ]
  ]
end ; setup-2-Graphics

;=========================================================================================================================================================================================
; turtles
;=========================================================================================================================================================================================

; initialize coordinate and motion properties
; needs: cPixelsPerMeter, CentroidGM, cSourceBodyGM, cOrbitalSpeed, {bFreeFall, bEarthExists}
to Turtles-Initialize
  set size cPixelsPerMeter
  ifelse cPixelsPerMeter < 1 [ set size 1 ][ set size cPixelsPerMeter ]
  if BIG [ set size cPixelsPerMeter + 1 ]
  set MyRadius sqrt(My-px ^ 2 + My-py ^ 2) ; needed here to initialize the orange ball (also set in physics-5-properties)

  ifelse not bEarthExists and self != turtle tOrangeBall
  [ ; balls have random velocities up to separation distance escape velocity
    let MaxV 0.9 * sqrt( 2 * CentroidGM / (LockTest_Mass_Separation*: * sqrt 2) )
    let Vball random-float MaxV
    let angle random-float 360
    set My-vx Vball * cos angle
    set My-vy Vball * sin angle
  ]
  [
    ifelse Choose_Simulation: = "Software test"
    [ ; Each ball is in a perfect circular orbit.
      let Vmag sqrt(cSourceBodyGM / MyRadius)
      set My-vx Vmag * ( My-py / MyRadius )
      ifelse My-px = 0
      [ set My-vy 0 ] ; point to the right
      [         
        set My-vy 0 - (Vmag * ( My-px / MyRadius ))
      ]
    ]
    [
      ; All balls have the same initial velocity.
      set My-vx cOrbitalSpeed
      set My-vy 0
    ]
  ]
  
  physics-5-properties
  set EnergyStart EnergyNow ; This is the only time {EnergyStart} gets set (before the simulation starts).
  physics-6-accel              ; Set initial acceleration.
  
  if MyRadius > 0 ; not true for orange ball in empty space
  [ set MyPhaseInit asin(My-px / MyRadius)
    set MyOmega sqrt ( cSourceBodyGM / MyRadius ^ 3 )
    set MyPhaseDeg asin( My-px / MyRadius)
  ]
end ; Turtles-Initialize

; physics-0-sequence is at the top

to Turtles-Plot
  let TimeDelta 0
  if LockTrace_Interval: > 0 [ set TimeDelta remainder int(Real-time) (LockTrace_Interval: * TraceSecondsMultiplier) ]
  
    if lateral:white/pink
    [ ifelse ticks > 0 and TimeDelta = 0
      [ ask (turtle-set laterals) [pen-down] ]
      [ ask (turtle-set laterals) [pen-up] ]
    ]
    
    if radial:blue/violet
    [ ifelse ticks > 0 and TimeDelta = 0
      [ ask (turtle-set radials) [pen-down] ]
      [ ask (turtle-set radials) [pen-up] ]
    ]
    
    if corners:red/green ; includes magenta/yellow
    [ ifelse ticks > 0 and TimeDelta = 0
      [ ask (turtle-set corners) [pen-down] ]
      [ ask (turtle-set corners) [pen-up] ]
    ]
  ; We use My-fx, My-fy instead of built-in xcor, ycor so that turtles can live off-screen.
  ; When we multiply by cPixelsPerMeter, below, we imply [ cPixelsPerMeter pixels *per meter* ] or [ 1/cPixelsPerMeter meters *per pixel* ].
  set My-fx CenterX + (My-px - OrangeMy-px) * cPixelsPerMeter
  set My-fy (My-py - OrangeMy-py) * cPixelsPerMeter
  
  ; rotate coordinates
  if LockSynchronous_Rotation
  [ let rotation 0
    let My-fxPreRot My-fx - CenterX ; shift back to the origin to make life easy
    let My-fyPreRot My-fy
    set rotation FrameIdealTheta
    ; rotation is compass angle, so this is the coordinate transformation
    set My-fx ( (My-fxPreRot * cos rotation) - (My-fyPreRot * sin rotation) ) + CenterX ; shift back to display area
    set My-fy ( (My-fxPreRot * sin rotation) + (My-fyPreRot * cos rotation) )
  ]
  
  ifelse My-fx < max-pxcor and My-fx > 4 and abs My-fy < max-pycor
  [  ; inside reference frame boundary
    setxy My-fx My-fy
    show-turtle
  ]
  [ 
    hide-turtle
  ] ; outside reference frame boundary, so hide the ball that went off screen.
  
  if MyRelDistance > CheckMaxRange
  [ set CheckMaxRange MyRelDistance
    set CheckMaxRangeColor word repColorName color ": "
    
  ]
  if MyRelVelocity > CheckMaxVelocity
  [ set CheckMaxVelocity MyRelVelocity
    set CheckMaxVelocityColor word repColorName color ": "
  ]
end ;Turtles-Plot

;=========================================================================================================================================================================================
; main
;=========================================================================================================================================================================================

to-report mainAny-Balls_left?
  let answer false
  ask radials [ if MyRelDistance > 0 [ set answer true ] ]
  ask laterals [ if MyRelDistance > 0 [ set answer true ] ]
  ask corners [ if MyRelDistance > 0 [ set answer true ] ]
  report answer
end


to mainOutputHeader
  let OutputPhrase ""
  let WCol1 23
  let WCol2 35
  let WCol3 22
  let line ""
  let Col1 ""
  let Col2 ""
  let Col3 ""
  let Col4 ""
  
  set Col1 "SIMULATION:"
  set Col2 remove "    (start here)" LockChoose_Simulation:
  set Col3 "Orbital_Radius:"
  let detail " (ISS)"
  if LockR = 3 [ set detail " (HST)" ]
  if LockR = 5 [ set detail " (GPS)" ]
  if LockR = 7 [ set detail " (Geostationary)" ]
  if LockR = 9 [ set detail " (Moon)" ]
  if LockR = 10 [ set detail " (LRO)" ]
  set Col4 (word (remove "R = " OrbitalRadiusShow) detail)
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  set Col1 word Col1 ""
  set Col2 word Col2 ""
  set Col3 word Col3 ""
  set Col4 word Col4 ""
  set line (word (uMakeColumn Col1 WCol1) (uMakeColumn Col2 WCol2) (uMakeColumn Col3 WCol3) Col4 "\n")
  set OutputPhrase word OutputPhrase line
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  set Col1 "Synchronous_Rotation:"
  ifelse bFreeFall
  [ set Col2 "N/A" ]
  [
    ifelse Synchronous_Rotation [ set Col2 "On" ][ set Col2 "Off" ]
  ]
  set Col3 "Simulation_Interval:"
  set Col4 remove "  " Simulation_IntervalShow
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  set Col1 word Col1 ""
  set Col2 word Col2 ""
  set Col3 word Col3 ""
  set Col4 word Col4 ""  
  set line (word (uMakeColumn Col1 WCol1) (uMakeColumn Col2 WCol2) (uMakeColumn Col3 WCol3) Col4 "\n")
  set OutputPhrase word OutputPhrase line
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  set Col1 "Orange_Ball_Mass:"
  ifelse Orange_Ball_Mass: = 0
  [ set Col2 remove "  " Orange_Ball_MassShow ]
  [ set Col2 (word "*** " (remove "  " Orange_Ball_MassShow) " ***") ]
  set Col3 "Orbit_Stops_At:"
  set Col4 LockOrbit_Stops_At:
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  set Col1 word Col1 ""
  set Col2 word Col2 ""
  set Col3 word Col3 ""
  set Col4 word Col4 ""  
  set line (word (uMakeColumn Col1 WCol1) (uMakeColumn Col2 WCol2) (uMakeColumn Col3 WCol3) Col4 "\n")
  set OutputPhrase word OutputPhrase line
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  set Col1 "Test_Mass_Separation:"
  set Col2 Test_Mass_Separation*:_Units
  set Col3 ""
  set Col4 ""
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  set Col1 word Col1 ""
  set Col2 word Col2 ""
  set Col3 word Col3 ""
  set Col4 word Col4 ""  
  set line (word (uMakeColumn Col1 WCol1) (uMakeColumn Col2 WCol2) (uMakeColumn Col3 WCol3) Col4 "\n")
  set OutputPhrase word OutputPhrase line
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  set Col1 ""
  set Col2 ""
  set Col3 "Trace_Interval:"
  set Col4 remove "  " Trace_IntervalShow
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  set Col1 word Col1 ""
  set Col2 word Col2 ""
  set Col3 word Col3 ""
  set Col4 word Col4 ""  
  set line (word (uMakeColumn Col1 WCol1) (uMakeColumn Col2 WCol2) (uMakeColumn Col3 WCol3) Col4 "\n")
  set OutputPhrase word OutputPhrase line
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  set Col1 "Frame_Dimension:"
  set Col2 remove "  " FrameDimensionsShow
  set Col3 "Draw_Graph_Paper:"
  ifelse Draw_Graph_Paper [ set Col4 "On" ][ set Col4 "Off" ]
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  set Col1 word Col1 ""
  set Col2 word Col2 ""
  set Col3 word Col3 ""
  set Col4 word Col4 ""  
  set line (word (uMakeColumn Col1 WCol1) (uMakeColumn Col2 WCol2) (uMakeColumn Col3 WCol3) Col4 "\n")
  set OutputPhrase word OutputPhrase line
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  clear-output
  beep
  output-type OutputPhrase
  output-type "=============================================================================================================\n"
end ; mainOutputHeader


to mainOutputStatus
  set LastReport int(Real-time)
  let vRed ""
  let vBlue ""
  let vGreen ""
  let vPink ""
  let vWhite ""
  let vMagenta ""
  let vViolet ""
  let vYellow ""
  let Absorbed "          X              "
  let Separator "  • "
  let ColumnWidth 25
  set PadLeftSpaces 2
  ifelse is-turtle? turtle tRedBall_TL [ ask turtle tRedBall_TL [ set vRed uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator repNumber MyRelDistance 3 ) ColumnWidth ] ][ set vRed Absorbed ]
  ifelse is-turtle? turtle tBlueBall_TC [ ask turtle tBlueBall_TC [ set vBlue uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator repNumber MyRelDistance 3 ) ColumnWidth ] ][ set vBlue Absorbed ]
  ifelse is-turtle? turtle tGreenBall_TR [ ask turtle tGreenBall_TR [ set vGreen uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator repNumber MyRelDistance 3 ) ColumnWidth ] ][ set vGreen Absorbed ]
  ifelse is-turtle? turtle tPinkBall_ML [ ask turtle tPinkBall_ML [ set vPink uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator repNumber MyRelDistance 3 ) ColumnWidth ] ][ set vPink Absorbed ]
  ifelse is-turtle? turtle tWhiteBall_MR [ ask turtle tWhiteBall_MR [ set vWhite uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator repNumber MyRelDistance 3 ) ColumnWidth ] ][ set vWhite Absorbed ]
  ifelse is-turtle? turtle tMagentaBall_BL [ ask turtle tMagentaBall_BL [ set vMagenta uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator repNumber MyRelDistance 3 ) ColumnWidth ] ][ set vMagenta Absorbed ]
  ifelse is-turtle? turtle tVioletBall_BC [ ask turtle tVioletBall_BC [ set vViolet uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator repNumber MyRelDistance 3 ) ColumnWidth ] ][ set vViolet Absorbed ]
  ifelse is-turtle? turtle tYellowBall_BR [ ask turtle tYellowBall_BR [ set vYellow uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator repNumber MyRelDistance 3 ) ColumnWidth ] ][ set vYellow Absorbed ]
  set PadLeftSpaces 0
  
  let OutputPhrase word "Realtime (hh:mm:ss): " (remove "  " Real-timeShow)
  let Ender ""
  ifelse bFreeFall
    [ ask turtle tOrangeBall
      [ set OutputPhrase (word OutputPhrase ";  Geocentric range (R): " (repNumber ((My-py / 1000)) 3) " km;  Radial velocity: " (repNumber My-vy 3) " m/s.\n")
        set OutputPhrase (word OutputPhrase "Velocity correction calculated from energy conservation: " repNumber ffv-correction 7 " m/s.\n")
        
        ; update the left panel display value
        let NewRadius My-py
        let Runits " km"
        let NewRadiusShow repNumber (NewRadius / 1000) 3
        if NewRadius / 1000 < 10000 [ set Runits " km  " ]
        set NewRadiusShow (word "R = " NewRadiusShow Runits)
        ask turtle tOrbitalRadius [ set label NewRadiusShow ]
      ]
    ]
    [
      if bEarthExists [ set OutputPhrase (word OutputPhrase " (" (repNumber ( Real-time / OrbitalPeriod) 3) "T)") ]
      set OutputPhrase (word OutputPhrase ";  Max. values: " (remove "  " MaxVelocityShow) " cm/s;  " (remove "  " MaxRangeShow) " m.\n")
      set Ender "\n"
    ]
  set OutputPhrase (word OutputPhrase "Velocity (cm/s) and • Distance (m) relative to the orange ball at the centroid:\n\n")
  set OutputPhrase (word OutputPhrase "red:     " vRed)
  set OutputPhrase (word OutputPhrase "blue:   " vBlue)
  set OutputPhrase (word OutputPhrase "green:  " vGreen "\n")
  set OutputPhrase (word OutputPhrase "pink:    " vPink)
  let OrangeBallText (uMakeColumn (word "orange ball (m = " (remove "  " Orange_Ball_MassShow) ")") (ColumnWidth + 8) )
  set OutputPhrase word OutputPhrase OrangeBallText
  set OutputPhrase (word OutputPhrase "white:  " vWhite "\n")
  set OutputPhrase (word OutputPhrase "magenta: " vMagenta)
  set OutputPhrase (word OutputPhrase "violet: " vViolet)
  set OutputPhrase (word OutputPhrase "yellow: " vYellow "\n\n") 
  set OutputPhrase (word OutputPhrase Ender) 
  ; no beep
  output-type OutputPhrase ; This method gives a better presentation than a series of output-print commands.
end ; mainOutputStatus


to mainOutputStatus2
  set LastReport int(Real-time)
  let vRed ""
  let vBlue ""
  let vGreen ""
  let vPink ""
  let vWhite ""
  let vMagenta ""
  let vViolet ""
  let vYellow ""
  let Absorbed "          X               "
  let Separator "  ◊  "
  let ColumnWidth 26
  set PadLeftSpaces 2
  ifelse is-turtle? turtle tRedBall_TL [ ask turtle tRedBall_TL [ set vRed uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator (repScientific EnergyNow 4) ) ColumnWidth ] ][ set vRed Absorbed ]
  ifelse is-turtle? turtle tBlueBall_TC [ ask turtle tBlueBall_TC [ set vBlue uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator (repScientific EnergyNow 4) ) ColumnWidth ] ][ set vBlue Absorbed ]
  ifelse is-turtle? turtle tGreenBall_TR [ ask turtle tGreenBall_TR [ set vGreen uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator (repScientific EnergyNow 4) ) ColumnWidth ] ][ set vGreen Absorbed ]
  ifelse is-turtle? turtle tPinkBall_ML [ ask turtle tPinkBall_ML [ set vPink uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator (repScientific EnergyNow 4) ) ColumnWidth ] ][ set vPink Absorbed ]
  ifelse is-turtle? turtle tWhiteBall_MR [ ask turtle tWhiteBall_MR [ set vWhite uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator (repScientific EnergyNow 4) ) ColumnWidth ] ][ set vWhite Absorbed ]
  ifelse is-turtle? turtle tMagentaBall_BL [ ask turtle tMagentaBall_BL [ set vMagenta uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator (repScientific EnergyNow 4) ) ColumnWidth ] ][ set vMagenta Absorbed ]
  ifelse is-turtle? turtle tVioletBall_BC [ ask turtle tVioletBall_BC [ set vViolet uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator (repScientific EnergyNow 4) ) ColumnWidth ] ][ set vViolet Absorbed ]
  ifelse is-turtle? turtle tYellowBall_BR [ ask turtle tYellowBall_BR [ set vYellow uMakeColumn (word uPadRight (repNumber (MyRelVelocity * 100) 5) 8 Separator (repScientific EnergyNow 4) ) ColumnWidth ] ][ set vYellow Absorbed ]
  set PadLeftSpaces 0
  
  let OutputPhrase word "Realtime (hh:mm:ss): " (remove "  " Real-timeShow)
  ask turtle tOrangeBall
  [ set OutputPhrase (word OutputPhrase ";  Geocentric range (R): " (repNumber ((My-py / 1000)) 3) " km;  Radial velocity: " (repNumber My-vy 3) " m/s.\n") ] ; should be 0
  
      
  set OutputPhrase (word OutputPhrase "Velocity (cm/s) and ◊ Total Energy (J) relative to the orange ball at the centroid:\n")
  set OutputPhrase (word OutputPhrase "Inconstant Total Energy implies simulation error; reduce Δt and/or centroid mass.\n\n")
  set OutputPhrase (word OutputPhrase "red:     " vRed)
  set OutputPhrase (word OutputPhrase "blue:   " vBlue)
  set OutputPhrase (word OutputPhrase "green:  " vGreen "\n")
  set OutputPhrase (word OutputPhrase "pink:    " vPink)
  let OrangeBallText (uMakeColumn (word "orange ball (m = " (remove "  " Orange_Ball_MassShow) ")") (ColumnWidth + 8) )
  set OutputPhrase word OutputPhrase OrangeBallText
  set OutputPhrase (word OutputPhrase "white:  " vWhite "\n")
  set OutputPhrase (word OutputPhrase "magenta: " vMagenta)
  set OutputPhrase (word OutputPhrase "violet: " vViolet)
  set OutputPhrase (word OutputPhrase "yellow: " vYellow "\n\n")
  ; no beep
  output-type OutputPhrase ; This method gives a better presentation than a series of output-print commands.
end ; mainOutputStatus2


to mainShowMax
      ; Report MaxRange and MaxVelocity, which Check values are set in <Turtles-Plot>.
    if CheckMaxRange > MaxRange
      [ set MaxRange CheckMaxRange
        set MaxRangeColor CheckMaxRangeColor
      ]
    if CheckMaxVelocity > MaxVelocity
      [
        set MaxVelocity CheckMaxVelocity
        set MaxVelocityColor CheckMaxVelocityColor
      ]

    set MaxRangeShow uCenterText22 (word CheckMaxRangeColor (repNumber MaxRange 3))
    set MaxVelocityShow uCenterText22 (word CheckMaxVelocityColor (repNumber (MaxVelocity * 100) 5))
end

;=========================================================================================================================================================================================
; draw
;=========================================================================================================================================================================================

to drawGraphPaper
  ifelse not Draw_Graph_Paper
    [ set GridSquareDimensionsShow "↕Draw_Graph_Paper -Off-" ]
    [ 
      no-display ; be sure to run display at some point afterwards
      let StandardColor 2
      let HighlightColor 3
      let AxisColor gray
      
      let GridDimension 400 * ScreenScale
      let GridZero-x CenterX
      let GridZero-y 0
      let DotSpace 2000 * ScreenScale / (LockFrame_Dimension:) ; (400 pix / Frame_Dimension) * 5 m / square
      let LinesToSide int (max-pycor / DotSpace)
      if LinesToSide > 15
        [ set DotSpace 4000 * ScreenScale / (LockFrame_Dimension:) ; (400 pix / Frame_Dimension) * 10 m / square
          set LinesToSide int (max-pycor / DotSpace)
        ] 
      
      let TotalLines 1 + 2 * LinesToSide ; center line plus 2 * lines per 1/2 of screen
      
      let GridSquareDimension int (LockFrame_Dimension: * x1 / 2 / LinesToSide)
      set GridSquareDimensionsShow uCenterText22 (word GridSquareDimension " m × " GridSquareDimension " m")
      
      let FirstHighlight LinesToSide mod int(LinesToSide / 5)
      let DotColor StandardColor
      ask turtle tMarker
        [ set pen-size 1
          set color StandardColor
          pen-up
          let LinesDrawn 0
          set heading 0
          repeat TotalLines
          [ ; draw vertical lines from left to right
            setxy (GridZero-x - (DotSpace * LinesToSide) + (LinesDrawn * DotSpace)) min-pycor
            pen-down
            ifelse (LinesDrawn - FirstHighlight) mod 5 = 0 ; Highlight every 5th line from midline.
            [ set color HighlightColor ]
            [ set color StandardColor ]
            if xcor = GridZero-x [ set color AxisColor ]
            jump (2 * max-pycor)
            pen-up
            set LinesDrawn (LinesDrawn + 1)
          ]
          
          set LinesDrawn 0
          set heading 90
          repeat TotalLines
          [ ; draw horizontal lines from bottom to top
            setxy (GridZero-x - GridDimension / 2) (GridZero-y - (DotSpace * LinesToSide) + (LinesDrawn * DotSpace))
            pen-down
            ifelse (LinesDrawn - FirstHighlight) mod 5 = 0 ; Highlight every 5th line from midline.
            [ set color HighlightColor ]
            [ set color StandardColor ]
            if ycor = GridZero-y [ set color AxisColor ]
            jump (GridDimension)
            pen-up
            set LinesDrawn (LinesDrawn + 1)
          ]
          
          set color AxisColor
          ;redraw x-axis
          set heading 90
          setxy 4 0
          pen-down
          jump (GridDimension)
          pen-up
          
          ;redraw y-axis
          set heading 0
          setxy CenterX min-pycor
          pen-down
          jump (GridDimension)
          pen-up
        ]
      uPark-tMarker
    ]
end ; drawGraphPaper


to drawOrbit ; This routine is not tick-based.
  set LockSynchronous_Rotation Synchronous_Rotation
  ask turtle tReferenceFrame
    [
      let TraceAngleDelta precision (Trace_Interval: * TraceSecondsMultiplier / OrbitalPeriod * 360) 1 ; Trace_Interval: is set in minutes
      let NextTracePhase 0 ; start tracing immediately
      let PhaseAngle 0     ; starting location in NetLogo world (12 o'clock position)
      let interval 0.002
      if not bShowMe
      [
        set interval 0
        no-display
      ]
      let PenIsDown false
      while [ PhaseAngle <= 360 ]
      [ if Synchronous_Rotation != LockSynchronous_Rotation and interval != 0
        [ display ; always call display before a dialog box
          user-message "You cannot change ↕Synchronous_Rotation during an orbit."
          set Synchronous_Rotation LockSynchronous_Rotation
        ]
        every interval
        [
          if not mouse-down?
          [
            if LockSynchronous_Rotation
            [ set heading PhaseAngle 
              if bShowMe [ ask turtle tGyroOrange [ set heading (- PhaseAngle) ]
                ; These are hidden until the second phase of the demo; it doesn't matter if they rotate.
                if LockSynchronous_Rotation
                [ ask turtle tGyroRed [ set heading (- PhaseAngle) ]
                  ask turtle tGyroGreen [ set heading (- PhaseAngle) ] ; always exists with tGyroRed
                ]
              ]
            ]
            ifelse TraceAngleDelta = 0 [ pen-down ]
            [ ifelse PhaseAngle >= NextTracePhase and PhaseAngle < (NextTracePhase + 0.2)
              [ pen-down
                set PenIsDown true
              ]
              [ 
                pen-up
                if PenIsDown
                [ set PenIsDown false
                  set NextTracePhase NextTracePhase + TraceAngleDelta
                ]
              ]
            ]
            setxy ((- CenterX) + (OrbitRadius * cos repMathAngle PhaseAngle)) (OrbitRadius * sin repMathAngle PhaseAngle)
            
            if bShowMe
            [ if not LockSynchronous_Rotation
              [ ask turtle tGyroRed [ setxy (CenterX + (GyroOffset * cos repMathAngle (PhaseAngle - 90) )) (GyroOffset * sin repMathAngle (PhaseAngle - 90)) ] ; starts on the LHS of orange ball
                ask turtle tGyroGreen [ setxy (CenterX + (GyroOffset * cos repMathAngle (PhaseAngle + 90))) (GyroOffset * sin repMathAngle (PhaseAngle + 90)) ] ; starts on the RHS of orange ball
              ]
            ; These are hidden until the third phase of the demo; it doesn't matter if they rotate.
            ask turtle tLittleGyroRed [ setxy ((- CenterX) + (OrbitRadius * cos repMathAngle (MyPhaseInit + PhaseAngle))) (OrbitRadius * sin repMathAngle (MyPhaseInit + PhaseAngle)) ]   ; identical motion to tReferenceFrame, but the PhaseAngle is different
            ask turtle tLittleGyroGreen [ setxy ((- CenterX) + (OrbitRadius * cos repMathAngle (MyPhaseInit + PhaseAngle))) (OrbitRadius * sin repMathAngle (MyPhaseInit + PhaseAngle)) ] ; identical motion to tReferenceFrame, but the PhaseAngle is different
            ]
            
            let value word (precision (PhaseAngle / 360) 2) "" ; 0.50
            if length value = 3 [ set value word value "0" ]
            ask turtle  tPartOfT  [ set label (word "t = " value "T") ]
            set PhaseAngle PhaseAngle + 0.1
          ] ; every interval (end)
        ] ; not mouse-down? (end)
      ]
      pen-up
      setxy (- CenterX) OrbitRadius ; parked position
      ask turtle  tPartOfT  [ set label "t = 0.000T" ]
      display
    ]
end ; drawOrbit


;=========================================================================================================================================================================================
; utilities
;=========================================================================================================================================================================================

to-report uCenterText [ ToBeCentered MonitorWidth ]
  set ToBeCentered word ToBeCentered ""
  let TextLength length ToBeCentered
  let SpacesNeeded int(((MonitorWidth / 2) - (TextLength / 2)) * 2)
  if SpacesNeeded mod 2 != 0 [ set SpacesNeeded SpacesNeeded + 1 ] ; Always have even number of spaces so that [ remove "  " text works ].
  repeat SpacesNeeded [ set ToBeCentered word " " ToBeCentered ]
  report ToBeCentered
end

to-report uCenterText22 [ ToBeCentered ]
  set ToBeCentered word ToBeCentered ""
  let TextLength length ToBeCentered
  let SpacesNeeded int((11 - (TextLength / 2)) * 2.3)
  if SpacesNeeded mod 2 != 0 [ set SpacesNeeded SpacesNeeded + 1 ] ; Always have even number of spaces so that [ remove "  " text works ].
  repeat SpacesNeeded [ set ToBeCentered word " " ToBeCentered ]
  report ToBeCentered
end

to-report uMakeColumn [ ColumnText ColumnWidth ]
  let TextLength length ColumnText
  let SpacesNeeded ColumnWidth - TextLength
  repeat SpacesNeeded [ set ColumnText word ColumnText " " ]
  report ColumnText
end


to-report uPadRight [ ToBePadded TextLength ]
  set ToBePadded word ToBePadded ""
  let SpacesNeeded TextLength - length ToBePadded
  repeat SpacesNeeded
  [ set ToBePadded word ToBePadded " " ]
  report ToBePadded
end

to-report uPadTrailingZeros [ NumberString decimals ]
  if decimals > 0 and not is-number? position "E" NumberString ; Don't pad scientific notation.
    [ let ZeroPadding decimals
      if not is-number? position "." NumberString [ set NumberString word NumberString "." ]
      let WhereIsDecimal position "." NumberString
      set ZeroPadding decimals - (length NumberString - WhereIsDecimal - 1)
      if ZeroPadding = 1 [ set NumberString word NumberString "0" ]
      if ZeroPadding = 2 [ set NumberString word NumberString "00" ]
      if ZeroPadding = 3 [ set NumberString word NumberString "000" ]
      if ZeroPadding = 4 [ set NumberString word NumberString "0000" ]
      if ZeroPadding = 5 [ set NumberString word NumberString "00000" ]
      if ZeroPadding = 6 [ set NumberString word NumberString "000000" ]
    ]
  report NumberString
end

to uPark-tMarker
  ask turtle tMarker
  [ ; parking conditions
    hide-turtle
    pen-up
    setxy 0 0
    set color black
    set label ""
    set label-color white
  ]
end

to uPark-tMessage
  ask turtle tMessage
  [ ; parking conditions
    hide-turtle
    pen-up
    setxy 0 0 
    set color black
    set label ""
    set label-color white
  ]
  ask turtle tMessage2
  [ ; parking conditions
    hide-turtle
    pen-up
    setxy 0 0 
    set color black
    set label ""
    set label-color white
  ]
end

;=========================================================================================================================================================================================


to-report repMathAngle [h]
  report (90 - h) mod 360 ; convert NetLogo compass heading (angle) to a standard mathematical angle on the unit circle
end
       

; report the name of a color
to-report repColorName [cnum]
  let MyColor "?" 
  ifelse (cnum mod 10 = 0) [ set MyColor "black" ]
  [ ifelse ((cnum + 0.1) mod 10 = 0) [ set MyColor "white" ]
    [ ifelse (cnum < 10) [ set MyColor "gray" ]
      [ ifelse (cnum < 20) [ set MyColor "red" ]
        [ ifelse (cnum < 30) [ set MyColor "orange" ]
          [ ifelse (cnum < 40) [ set MyColor "brown" ]
            [ ifelse (cnum < 50) [ set MyColor "yellow" ]
              [ ifelse (cnum < 60) [ set MyColor "green" ]
                [ ifelse (cnum < 70) [ set MyColor "lime" ]
                  [ ifelse (cnum < 80) [ set MyColor "turquoise" ]
                    [ ifelse (cnum < 90) [ set MyColor "cyan" ]
                      [ ifelse (cnum < 100) [ set MyColor "sky" ]
                        [ ifelse (cnum < 110) [ set MyColor "blue" ]
                          [ ifelse (cnum < 120) [ set MyColor "violet" ]
                            [ ifelse (cnum < 130) [ set MyColor "magenta" ]
                              [ if (cnum < 140) [ set MyColor "pink" ]
                              ]]]]]]]]]]]]]]]
  if (MyColor != "black") and (MyColor != "white")
  [ if cnum mod 5 != 0
    [ ifelse (cnum + 2) mod 5 = 0 and cnum mod 2 = 1 [ set MyColor word "night " MyColor ]
      [ ifelse (cnum + 1) mod 5 = 0 and cnum mod 2 = 0 [ set MyColor word "dark " MyColor ]
        [ ifelse (cnum - 1) mod 5 = 0 and cnum mod 2 = 0 [ set MyColor word "light " MyColor ]
          [ ifelse (cnum - 2) mod 5 = 0 and cnum mod 2 = 1 [ set MyColor word "pastel " MyColor ]
            [ set MyColor word "other " MyColor ]
          ]]]]]
  if not bPreciseColors
  [ if MyColor = "lime" [ set MyColor "green" ]
    if MyColor = "sky" [ set MyColor "blue" ]
  ]
  report MyColor
end ; repColorName


; time in seconds returned as "y d (hh:mm:ss)"
to-report repHumanTime [TimeInSeconds]
  let years int (TimeInSeconds / 31557600) ; Julian year
  ifelse years = 0 [ set years "" ][ set years word years " y " ]
  let days int ((TimeInSeconds mod 31557600) / (24 * 3600))
  ifelse days = 0 [ set days "" ][ set days word days " d " ]
  let hours int ((TimeInSeconds mod (24 * 3600)) / 3600)
  if hours < 10 [ set hours word "0" hours ]
  let minutes int ((TimeInSeconds mod 3600) / 60)
  if minutes < 10 [ set minutes word "0" minutes ]
  let seconds int (TimeInSeconds mod 60)
  if seconds < 10 [ set seconds word "0" seconds ]
  let HumanTime (word years days hours ":" minutes ":" seconds)
  report HumanTime
end


; any number returned as string x.nnnEm where nnn is 3 decimals and m is magnitude
to-report repScientific [MyNumber decimals ]
  let magnitude 0
  let sign " "
  if MyNumber < 0 [ set sign "-" ]
  set MyNumber abs MyNumber
  ifelse MyNumber < 1 and MyNumber != 0
  [ while [ MyNumber < 1 ]
    [ set MyNumber MyNumber * 10
      set magnitude magnitude + 1
    ]
    set MyNumber word (precision MyNumber decimals) ""
    ifelse magnitude >= 10 [ set MyNumber (word (uPadTrailingZeros MyNumber decimals) "E-" magnitude) ][ set MyNumber (word (uPadTrailingZeros MyNumber decimals) "E-0" magnitude) ]
  ]
  [ ; number is >= 1
    set magnitude -1
    while [ MyNumber >= 1 ]
    [ set MyNumber MyNumber / 10
      set magnitude magnitude + 1
    ]
    if MyNumber = 0 [ set magnitude 0 ]
    set MyNumber word (precision (MyNumber * 10) decimals) ""
    ifelse magnitude >= 10 [ set MyNumber (word (uPadTrailingZeros MyNumber decimals) "E+" magnitude) ][ set MyNumber (word (uPadTrailingZeros MyNumber decimals) "E+0" magnitude) ]
  ]
  report word sign MyNumber
end


; Large numbers are returned as string with comma, if < 1E6, or scientific notation, if >= 1E6.
; This works just like the NetLogo "precision" command, except it yields a string and pads trailing zeros.
to-report repNumber [MyNumber decimals]
  let ShowNumber "0"
  let sign ""
  let LeftOfDecimal length (word (int MyNumber) "")
  ifelse abs MyNumber < 1000
  [ set ShowNumber word (precision MyNumber decimals) ""
    set ShowNumber uPadTrailingZeros ShowNumber decimals
  ]
  [
    if MyNumber < 0 [ set sign "-" ]
    set MyNumber abs MyNumber
    let HowBig int (MyNumber / 1E6)
    ifelse HowBig > 0
    [ set HowBig word HowBig ""
      let magnitude length HowBig + 5
      set ShowNumber precision (MyNumber / (10 ^ magnitude)) decimals
      set ShowNumber word ShowNumber ""
      if length ShowNumber >= (2 + decimals) [ set ShowNumber substring ShowNumber 0 (2 + decimals) ]
      set ShowNumber uPadTrailingZeros ShowNumber decimals
      set ShowNumber (word ShowNumber "E" magnitude)
      set LeftOfDecimal 1
    ]
    [
      let thousands int (MyNumber / 1000)
      let rest precision (MyNumber - (1000 * thousands)) decimals
      ifelse rest < 10 [ set rest word "00" rest ][ if rest < 100 [ set rest word "0" rest ] ]
      set ShowNumber (word thousands "," rest)
      set ShowNumber uPadTrailingZeros ShowNumber decimals
    ]
  ]
  let PadSpaces PadLeftSpaces - LeftOfDecimal
  if PadSpaces > 0
  [ repeat PadSpaces
    [ set sign word " " sign ]
  ]
  report word sign ShowNumber
end ; repNumber

; END OF CODE
; Code and interface are Copyright © 2012–2013 Alexander F. Mayer < GravitySim.net > & < SensibleUniverse.com >