(*by Nasser M. Abbasi, version: 8/8/2012*)

Manipulate[
 gTick;
 Module[{g1, wasHit = False, r0 = 0.2(*bob radius, fixed*), 
   L0 = R0/2.0(*relaxed length of the spring*)},
  
  If[setIC,
   setIC = False;
   If[initialBobX > R0, initialBobX = R0];
   simulationTime = 0;
   list@setIC[{initialBobX, initialBobSpeed, initialTheta, 
      initialThetaDot, 2 m0 initialBobSpeed  initialThetaDot}];
   isRelaxedSpring = 
    If[Abs[initialBobX - R0/2] <= $MachineEpsilon, True, False]
   ];
  
  If[runningState == "RUNNING" || runningState == "STEP",
   
   wasHit = solver@step[m0, R0, L0, k, M0, delT, wallType];
   (*this logic below so that we do not animate a hit on the edge \
unless last time it was no hit*)
   If[wasHit,
    If[wasHitLastTime == True,
     wasHit = False,
     wasHitLastTime = True
     ]
    ,
    wasHitLastTime = False
    ];
   
   simulationTime = Mod[simulationTime + delT, 1000];
   If[runningState == "STEP", runningState = "STOP", gTick += del]
   ];
  
  (*all done, display the animation on the screen*)
  
  g1 = display@
    makeDisplay[simulationTime, plotType, m0, M0, R0, r0, wasHit, k, 
     showPlots, showCounters, showCoriolisForce, trace];
  FinishDynamic[];
  g1
  ],
 (*---------- control layout ------------*)
 Grid[{
   {Grid[{{
       Button[
        Text[Style["run", 12]], {If[
          Not[plotType == "velocity/acceleration"], 
          runningState = "RUNNING"]; gTick += del}, 
        ImageSize -> {55, 35}],
       Button[
        Text[Style["stop", 12]], {If[
          Not[plotType == "velocity/acceleration"], 
          runningState = "STOP"]; gTick += del}, ImageSize -> {55, 35}]
       },
      {
       Button[
        Text[Style["step", 12]], {If[
          Not[plotType == "velocity/acceleration"], 
          runningState = "STEP"]; gTick += del}, 
        ImageSize -> {55, 35}],
       
       Button[
        Text[Style["reset", 
          12]],(*bring simulation back to initial conditions*)
       \
 {
         setIC = True;
         runningState = "STOP";
         gTick += del
         }, ImageSize -> {55, 35}]
       }}, Spacings -> {0.5, .2}
     ]},
   
   {Text@Style["simulation parameters", 12]},
   {Grid[
     {
      {"simulation speed",
       Manipulator[Dynamic[delT, {delT = #} &], {0.01, 5, 0.01}, 
        ImageSize -> Tiny, ContinuousAction -> False],
       Text@Style[Dynamic@padIt2[delT, {3, 2}], 11]
       },
      
      {"disk mass",
       Manipulator[Dynamic[M0,
         {M0 = #;
           setIC = True;
           gTick += del
           } &], {1, 500, 1}, ImageSize -> Tiny, 
        ContinuousAction -> False],
       Text@Style[Dynamic@padIt2[M0, 3], 11]
       },
      
      {"disk radius",
       Manipulator[Dynamic[R0,
         {R0 = #;
           setIC = True;
           gTick += del
           } &], {1, 4, 0.1}, ImageSize -> Tiny, 
        ContinuousAction -> False],
       Text@Style[Dynamic@padIt2[R0, {2, 1}], 11]
       },
      
      {"bob mass",
       Manipulator[Dynamic[m0,
         {m0 = #;
           setIC = True;
           gTick += del
           } &], {0, 99, 0.1}, ImageSize -> Tiny, 
        ContinuousAction -> False],
       Text@Style[Dynamic@padIt2[m0, {3, 1}], 11]
       },
      
      {"spring stiffness",
       Manipulator[Dynamic[k,
         {k = #;
           setIC = True;
           gTick += del
           } &], {0.1, 9, .1}, ImageSize -> Tiny, 
        ContinuousAction -> False],
       Text@Style[Dynamic@padIt2[k, {2, 1}], 11]
       },
      {Grid[{{"disk edge",
          RadioButtonBar[Dynamic[wallType,
            {wallType = #;
              setIC = True;
              gTick += del
              } &], {"elastic" -> "elastic", 
            "inelastic" -> "inelastic"}]
          }}], SpanFromLeft
       }
      }, Spacings -> {.6, .5}, Alignment -> Left, Frame -> True, 
     FrameStyle -> Directive[Thickness[.005], Gray]
     ]
    },
   
   {Text@Style["initial conditions", 12]},
   {Grid[{
      {"angular velocity",
       Manipulator[Dynamic[initialThetaDot,
         {initialThetaDot = #;
           setIC = True;
           gTick += del
           } &], {-0.1, 0.1, .01}, ImageSize -> Tiny, 
        ContinuousAction -> False],
       Text@Style[Dynamic@padIt1[initialThetaDot, {2, 2}], 11]
       },
      {"angle (degree)",
       Manipulator[Dynamic[initialTheta,
         {initialTheta = #;
           setIC = True;
           gTick += del
           } &], {0, 2 Pi, 2 Pi/100.}, ImageSize -> Tiny, 
        ContinuousAction -> False],
       Text@Style[Dynamic@padIt2[initialTheta*180.0/Pi, {4, 1}], 11]
       },
      {"bob position",
       Manipulator[Dynamic[initialBobX,
         {initialBobX = #;
           setIC = True;
           gTick += del
           } &], {0, 4, 0.1}, ImageSize -> Tiny, 
        ContinuousAction -> False],
       Text@Style[Dynamic@padIt2[initialBobX, {2, 1}], 11]
       },
      {
       Grid[{{
          Row[{"relax", Spacer[2],
            Checkbox[Dynamic[isRelaxedSpring,
              {isRelaxedSpring = #;
                initialBobX = R0/2; 
                setIC = True;
                gTick += del
                } &]]}],
          Row[{"trace", Spacer[2],
            Checkbox[Dynamic[trace,
              {trace = #;
                If[#, list@clearTrace[]];
                gTick += del
                } &]]}],
          Row[{"show coriolis force", Spacer[2],
            Checkbox[Dynamic[showCoriolisForce,
              {showCoriolisForce = #;
                gTick += del
                } &]]}]
          }}, Spacings -> {0.4, 0}], SpanFromLeft
       },
      {"bob speed",
       Manipulator[Dynamic[initialBobSpeed,
         {initialBobSpeed = #;
           setIC = True;
           gTick += del
           } &], {-0.1, 0.1, 0.01}, ImageSize -> Tiny, 
        ContinuousAction -> False],
       Text@Style[Dynamic@padIt1[initialBobSpeed, {2, 2}], 11]
       }
      }, Spacings -> {.6, .3}, Alignment -> Left, Frame -> True, 
     FrameStyle -> Directive[Thickness[.005], Gray]
     ]
    },
   {Grid[{
      {Text@Style["plot type", 12], Text@Style["test case", 12]},
      {
       PopupMenu[Dynamic[plotType, {plotType = #; 
           If[plotType == "velocity/acceleration",
            {
             If[runningState == "RUNNING",
              runningState = "SUSPEND_RUNNING"
              ]
             },
            {
             
             If[runningState == "SUSPEND_RUNNING", 
              runningState = "RUNNING"]
             }
            ]; gTick += del} &],
        { 
         "disk angular velocity" -> 
          Text@Style["disk angular velocity", 12],
          "disk angle" -> Text@Style["disk angle", 12],
          "bob position" -> Text@Style["bob position", 12],
          "bob velocity" -> Text@Style["bob velocity", 12],
         "Coriolis force" -> Text@Style["Coriolis force", 12]
         }, ImageSize -> All, ContinuousAction -> False, 
        Enabled -> Dynamic[showPlots]]
       ,
       PopupMenu[Dynamic[testCase, {testCase = #;
           runningState = "STOP";
           Which[testCase == 1,
            (
             isRelaxedSpring = False; delT = 1; m0 = 40; k = 1; 
             R0 = 3.9;
             initialThetaDot = 0.09; initialTheta = 206 Degree; 
             initialBobX = 0.5; initialBobSpeed = 0; M0 = 10; 
             trace = True;
             setIC = True;
             runningState = "STOP";
             plotType = "bob position"
             ),
            testCase == 2,
            (
             isRelaxedSpring = False; delT = 5; m0 = 16; k = 3; R0 = 2;
             initialThetaDot = 0.01; initialTheta = 45 Degree; 
             initialBobX = 1.4; initialBobSpeed = 0; M0 = 100; 
             trace = True;
             setIC = True;
             runningState = "STOP";
             plotType = "disk angular velocity"
             ),
            testCase == 3,
            (
             isRelaxedSpring = True; delT = 5; m0 = 50; k = 0.5; 
             M0 = 100; R0 = 3; trace = False;
             initialThetaDot = 0; initialTheta = 270 Degree; 
             initialBobX = 1.5; initialBobSpeed = 0.1;
             setIC = True;
             runningState = "STOP";
             plotType = "disk angular velocity"
             )
            ];
           gTick += del} &],
        { 
         1 -> Text@Style["1", 12], 2 -> Text@Style["2", 12], 
         3 -> Text@Style["3", 12]
         }, ImageSize -> All, ContinuousAction -> False]
       },
      
      {Grid[{
         {
          
          Row[{"show plot ", Spacer[4], 
            Checkbox[
             Dynamic[showPlots, {showPlots = #; gTick += del} &]]}], 
          Spacer[12],
          
          Row[{"show counters ", Spacer[4], 
            Checkbox[
             Dynamic[
              showCounters, {showCounters = #; gTick += del} &]]}], 
          SpanFromLeft
          }
         }
        ], SpanFromLeft
       },
      
      {Grid[{
         {"plot x-scale",
          Manipulator[Dynamic[xScale,
            {xScale = #;
              list@setSize[xScale];
              setIC = True;
              gTick += del
              } &], {10, 1000, 1}, ImageSize -> Tiny, 
           ContinuousAction -> False, Enabled -> Dynamic[showPlots]],
          Text@Style[Dynamic@padIt2[xScale, 4], 11]
          }
         }], SpanFromLeft
       }
      
      }, Frame -> True, 
     FrameStyle -> Directive[Thickness[.005], Gray]
     ]
    }
   }, Spacings -> {0, {2 -> 1, 4 -> 1, 6 -> 0.5, 8 -> 0}}, 
  Alignment -> Center, Frame -> None],
 (*----control variables--*)
 {{m0, 40}, None},
 {{M0, 10}, None},
 {{R0, 3.9}, None},
 {{delT, 1}, None},
 {{k, 1}, None},
 {{initialThetaDot, 0.09}, None},
 {{initialTheta, 45 Degree}, None},
 {{initialBobX, 1.5}, None},
 {{initialBobSpeed, 0}, None},
 {{isRelaxedSpring, False}, None},
 {{plotType, "bob position"}, None},
 {{testCase, 1}, None},
 {{wallType, "elastic"}, None},
 {{showPlots, False}, None},
 {{showCounters, True}, None},
 {{xScale, 400}, None},
 {{showCoriolisForce, False}, None},
 {{trace, True}, None},
 {{setIC, False}, None},
 
 (*----- refresh control ---*)
 {{gTick, 0}, ControlType -> None},
 {{del, $MachineEpsilon}, None},
 
 (*----- state variables for sim---*)
 {{runningState, "STOP"}, 
  None},(*"RUNNING","STEP","SUSPEND","STOP"*)
 {{simulationTime, 0}, 
  None},
 {{wasHitLastTime, False}, None},
 
 
 TrackedSymbols :> {gTick},
 ControlPlacement -> Left,
 SynchronousUpdating -> False,
 SynchronousInitialization -> True,
 ContinuousAction -> False,
 Alignment -> Center,
 ImageMargins -> 0,
 FrameMargins -> 0,
 Paneled -> True,
 Frame -> False,
 Initialization :>
  {
   (*definitions used for parameter checking*)
   
   integerStrictPositive = (IntegerQ[#] && # > 0 &);
   integerPositive = (IntegerQ[#] && # >= 0 &);
   numericStrictPositive = (Element[#, Reals] && # > 0 &);
   numericPositive = (Element[#, Reals] && # >= 0 &);
   numericStrictNegative = (Element[#, Reals] && # < 0 &);
   numericNegative = (Element[#, Reals] && # <= 0 &);
   bool = (Element[#, Booleans] &);
   numeric = (Element[#, Reals] &);
   integer = (Element[#, Integers] &);
   
   (* This list object is used to store and the manage the time \
series generated during running of the simulation so that display \
object can use it to make plots and the animation *)
   
   listClass[$size_?integer(*maximum size of the list*)] :=
    
    Module[{size, lists, self},
     (*lists are in this order x,v,\[Theta],\[Omega],force,
     trace*)
     
     self@getSize[] := size;
     self@setSize[n_] := ( size = n; 
       lists = Table[{0, Table[0, {n}]}, {6}] );
     
     self@
       add[{x_?numeric,(*bob position*)
         
         v_?numeric,(*bob speed*)
         \[Theta]_?
          numeric,(*disk angle*)
         \[Omega]_?
          numeric,(*disk angular speed*)
         force_?numeric(* 
         coriolis force*)}
        ] := Module[{},
       MapThread[Function[{e, idx},
         lists[[idx, 1]]++;
         If[lists[[idx, 1]] > size, lists[[idx, 1]] = 1];
         lists[[ idx, 2, lists[[idx, 1]]  ]] = e
         ],
        {{x, v, \[Theta], \[Omega], 
          force, {x*Cos[\[Theta]], x*Sin[\[Theta]]}}, 
         Range[1, Length[lists]]}
        ]
       ];
     
     self@
       setIC[{x_?numeric, 
         v_?numeric, \[Theta]_?numeric, \[Omega]_?numeric, 
         force_?numeric}] := (
       list@clear[];
       list@add[{x, v, \[Theta], \[Omega], force}]
       );
     
     self@getCurrent[] := 
      lists[[ #, 2, lists[[#, 1]] ]] & /@ Range[1, Length[lists]];
     self@clear[] := (lists[[#, 1]] = 0) & /@ 
       Range[1, Length[lists]];
     self@clearTrace[] := lists[[6, 1]] = 0;
     
     self@getPositionList[] := 
      Module[{len = lists[[1, 1]]}, lists[[ 1, 2, 1 ;; len]]  ] ;
     self@getSpeedList[] := 
      Module[{len = lists[[2, 1]]}, lists[[ 2, 2, 1 ;; len]]  ] ;
     self@getThetaList[] := 
      Module[{len = lists[[3, 1]]}, lists[[ 3, 2, 1 ;; len]]  ] ;
     self@getOmegaList[] := 
      Module[{len = lists[[4, 1]]}, lists[[ 4, 2, 1 ;; len]]  ] ;
     self@getCoriolisForceList[] := 
      Module[{len = lists[[5, 1]]}, lists[[ 5, 2, 1 ;; len]]  ] ;
     self@getTraceData[] := 
      Module[{len = lists[[6, 1]]}, lists[[ 6, 2, 1 ;; len]]  ] ;
     
     (*--- constructor---*)
     self@setSize[$size];
     self
     ];
   (*-----------------------------------------------------------*)
   
   solverClass[] :=
    Module[{self},
     
     (* uses NDSolve to integrate equations of motion for given time \
step*)
     
     self@step[m0_?numericPositive,(*bob mass*)
        
        R0_?numericStrictPositive,(*disk radius*)
        
        L0_?numericStrictPositive,(*relaxed spring length, 
        measured from the origin*)
        
        k_?numericStrictPositive,(*spring k*)
        
        M0_?numericStrictPositive,(*disk mass*)
        
        delT_?numericStrictPositive,(*time length to integrate over \
for NDSolve*)
        wallType_String(* 
        wall type is either elastic or inelastic*)
        ] := 
      Module[{ic, eq1, eq2, t, x, \[Theta], maxDistance = R0, 
        minDistance = 0, currentSolution, currentX, currentV, 
        current\[Theta], currentOmega, 
        wasHit = 
         False, $currentX, $currentV, $current\[Theta], \
$currentOmega, $force, trace},
       
       {$currentX, $currentV, $current\[Theta], $currentOmega, $force,
          trace} = list@getCurrent[];
       
       currentX = $currentX;
       currentV = $currentV;
       
       If[ Abs[m0] <= $MachineEpsilon,
        currentSolution = 
         First@NDSolve[{\[Theta]''[t] == 0, \[Theta][0] == 
             
             Mod[$current\[Theta], 2 Pi], \[Theta]'[
              0] == $currentOmega}, {\[Theta], \[Theta]'}, {t, 0, 
            delT}, MaxSteps -> Infinity];
        current\[Theta] = (\[Theta] /. currentSolution)[delT];
        currentOmega = (\[Theta]' /. currentSolution)[delT]
        ,
        eq1 = (x^\[Prime]\[Prime])[t] == (-k (x[t] - L0))/m0 + 
           x[t] \[Theta]'[t]^2;
        eq2 = \[Theta]''[t] == (-4 m0 x[t] x'[t] \[Theta]'[t])/(
          M0 R0^2 + 2 m0 x[t]^2);
        
        ic = {x[0] == $currentX, 
          x'[0] == $currentV, \[Theta][0] == 
           Mod[$current\[Theta], 2 Pi], \[Theta]'[0] == $currentOmega};
        
        currentSolution = 
         First@Quiet@
           NDSolve[
            Flatten@{eq1, eq2, ic}, {x, x', \[Theta], \[Theta]'}, {t, 
             0, delT}, MaxSteps -> Infinity];
        currentX = (x /. currentSolution)[delT];
        currentV = (x' /. currentSolution)[delT];
        current\[Theta] = (\[Theta] /. currentSolution)[delT];
        currentOmega = (\[Theta]' /. currentSolution)[delT];
        
        (* 
        if bob hits the edge of the disk or the base of the spring, 
        fix speed and reset things*)
        
        If[currentX > maxDistance || currentX < minDistance,
         currentV = 0;
         If[wallType == "elastic",
          If[currentX > maxDistance, wasHit = True];
          currentV = -$currentV
          ];
         currentX = $currentX;
         current\[Theta] = $current\[Theta];
         currentOmega = $currentOmega
         ]
        ];
       
       (*save current solution in the list object so that display can \
use it*)
       
       list@add[{currentX, currentV, current\[Theta], currentOmega, 
          2 m0 currentOmega currentV}];
       wasHit
       ];
     
     self
     ];
   (*--------- displayClass ---------------------------------------*)

      displayClass[] := 
    Module[{makeCounters, makeDiskDiagram, makePlot, self},
     
     (*--------- private ---------------------------------------*)
   
       makeCounters[simulationTime_?numericPositive,
       m0_?numericPositive,
       M0_?numericStrictPositive,
       R0_?numericStrictPositive,
       k_?numericStrictPositive] := 
      Module[{h1, h2, currentMomentOfInertia, x, 
        v, \[Theta], \[Omega], currentCoriolisForce, PE, KE, trace},
       {x, v, \[Theta], \[Omega], currentCoriolisForce, trace} = 
        list@getCurrent[];
       currentMomentOfInertia = M0/2*R0^2 + m0*x^2;
       PE = 0.5*k*(x - R0/2)^2;
       KE = 1/4 M0 R0^2 \[Omega]^2 + 1/2 m0 (v^2 + x^2 \[Omega]^2);
       
       h1 = Text@Style[Grid[{
            {Text["disk \[Theta]"],
             Text["disk \[Omega]"],
             Text["bob position"],
             Text["bob velocity"],
             Text[Style["\[CapitalIota]", Italic]],
             Text["energy"]
             },
            {Text["(degree)"],
             Text["(rad/sec)"],
             Text["(meter)"],
             Text["(meter/sec)"],
             Text["(kg \!\(\*SuperscriptBox[\(meter\), \(2\)]\))"],
             Text[Row[{"(", Style["J", Italic], ")"}]]
             },
            { padIt2[180./Pi*\[Theta], {5, 2}],
             padIt2[\[Omega], {7, 6}],
             padIt2[x, {3, 2}],
             padIt1[v, {6, 3}],
             padIt2[currentMomentOfInertia, {5, 2}],
             padIt2[PE + KE, {4, 3}]
             }
            },
           
           Frame -> {All, 
             None, { {{1, 2}, {1, 6}} -> True , {{3, 3}, {1, 6}} -> 
               True}},
           FrameStyle -> Gray,
           Spacings -> 1,
           ItemSize -> {{All, 2 ;; -1} -> 5},
           Alignment -> Center], 12];
       
       h2 = Text@Style[Grid[{
            {Text["time (sec)"],
             
             Text["\[CapitalIota]\[InvisibleSpace] \[InvisibleSpace]\
\[Omega] (joule second)"],
             Text@Row[{"Coriolis force (", Style["N", Italic], ")"}],
             Text@Row[{"P.E. (", Style["J", Italic], ")"}],
             Text@Row[{"K.E. (", Style["J", Italic], ")"}]
             },
            { padIt2[simulationTime, {5, 2}],
             padIt2[currentMomentOfInertia*\[Omega], {6, 4}],
             padIt1[currentCoriolisForce, {5, 4}],
             padIt2[PE, {5, 4}],
             padIt2[KE, {5, 4}]
             }},
           Frame -> All,
           FrameStyle -> Gray,
           Spacings -> 1,
           ItemSize -> {{All, 2 ;; -1} -> 6},
           Alignment -> Center], 12];
       
       Grid[{{h1}, {h2}}, Spacings -> {0, .1}]
       ];
     (*---------------private----------------------------------*)
    
      makeDiskDiagram[m0_?numericPositive,
       R0_?numericStrictPositive,
       r_?numericStrictPositive,
       wasHit_?bool,
       {w_?numericStrictPositive, h_?numericStrictPositive},
       showCoriolisForce_?bool,
       trace_?bool] := 
      Module[{x, y, splash, xx, v, \[Theta], \[Omega], force, 
        traceData, currentTrace},
       
       {xx, v, \[Theta], \[Omega], force, currentTrace} = 
        list@getCurrent[];
       force = force/(4*1.25) + 0.25*Sign[force];
       
       x = xx*Cos[\[Theta]];
       y = xx*Sin[\[Theta]];
       traceData = list@getTraceData[];
       
       splash = If[wasHit, {
          { Dotted, Red, 
           Rotate[Line[{{R0, 0}, {1.2 R0, 0}}], \[Theta], {0, 0}]},
          {Dotted, Red, 
           Rotate[Line[{{R0, 0}, {1.2 R0, .2 R0}}], \[Theta], {0, 0}]},
          {Dotted, Red, 
           Rotate[Line[{{R0, 0}, {1.2 R0, .1 R0}}], \[Theta], {0, 0}]},
          {Dotted, Red, 
           Rotate[Line[{{R0, 0}, {1.2 R0, -.2 R0}}], \[Theta], {0, 
             0}]},
          {Dotted, Red, 
           Rotate[Line[{{R0, 0}, {1.2 R0, -.1 R0}}], \[Theta], {0, 0}]}
          },
         Sequence @@ {}
         ];
       
       Graphics[{
         {EdgeForm[{Thick, Blue}], FaceForm@RGBColor[.75, .97, .97], 
          Disk[{0, 0}, R0 ]},
         If[showCoriolisForce && Abs[force] > $MachineEpsilon,
          {Dotted, Black, 
           Rotate[Arrow[{{xx, 
               Sign[force]*
                r}, {xx, (force + Sign[force]*r)}}], \[Theta], {0, 
             0}]}, Sequence @@ {}
          ],
         If[trace, {Dotted, Darker@Red, Line[traceData]}, 
          Sequence @@ {}],
         If[m0 <= $MachineEpsilon, 
          Sequence @@ {}, { Red, Disk[{x, y}, r]}],
         {Black, 
          Line@makeSpring[0, 
            0, (xx - r) Cos[\[Theta]], (xx - r) Sin[\[Theta]], 0.8*r]},
         
         (*relaxed position indicator*)
         {Dashed, Gray, 
          Rotate[Line[{{R0/2, -r}, {R0/2, -2 r}}], \[Theta], {0, 
            0}]},
         {Dashed, Gray, 
          Rotate[Line[{{R0/2, r}, {R0/2, 2 r}}], \[Theta], {0, 0}]},
         
         (* 
         inertial frames*)
         {Gray, Dashed, 
          Rotate[Line[{{-R0, 0}, {0, 0}}], \[Theta], {0, 0}]},
         {Gray, Dashed, 
          Rotate[Line[{{0, -R0}, {0, R0}}], \[Theta], {0, 0}]},
         splash
         },
        ImageSize -> {w, h},
        ImagePadding -> {{10, 10}, {10, 10}},
        PlotRange -> {{-R0 - r, R0 + r}, {-R0 - r, R0 + r}},
        ImageMargins -> 1,
        AspectRatio -> 1
        ]
       ];
     (*-------------------- private -----------------------------*)
  
        makePlot[plotType_String,
       R0_?numericStrictPositive] := 
      Module[{plotTitle, data, n = list@getSize[]},
       
       Which[plotType == "disk angular velocity",
        data = list@getOmegaList[];
        If[Length[data] == 0, data = {0}];
        plotTitle = {{Text@Style["\[Omega] (rad/sec)", 12], 
           None}, {Text@Style["time"], 
           Text@Style["disk angular velocity vs. time", 12]}};
        plotRange = {{1, n}, All}
        ,
        plotType == "disk angle",
        data = 180.0/Pi*list@getThetaList[];
        If[Length[data] == 0, data = {0}];
        plotTitle = {{Text@Style["\[Theta] (deg)", 12], 
           None}, {Text@Style["time"], 
           Text@Style["disk angle vs. time", 12]}};
        plotRange = {{1, n}, {0, 360}}
        ,
        plotType == "bob position",
        data = list@getPositionList[];
        If[Length[data] == 0, data = {0}];
        plotTitle = {{Text@
            Style[Row[{"position (", Style["m", Italic], ")"}], 12], 
           None}, {Text@Style["time"], 
           Text@Style["bob position vs. time", 12]}};
        plotRange = {{1, n}, {0, R0}}
        ,
        plotType == "bob velocity",
        data = list@getSpeedList[];
        If[Length[data] == 0, data = {0}];
        plotTitle = {{Text@
            Style[Row[{"velocity (", Style["m/s", Italic], ")"}], 12],
            None}, {Text@Style["time"], 
           Text@Style["bob velocity vs. time", 12]}};
        plotRange = {{1, n}, All}
        ,
        plotType == "Coriolis force",
        data = list@getCoriolisForceList[];
        If[Length[data] == 0, data = {0}];
        plotTitle = {{Text@
            
            Style[Row[{"Coriolis force (", Style["N", Italic], ")"}], 
             12], None}, {Text@Style["time"], 
           Text@Style["Coriolis force vs. time", 12]}};
        plotRange = {{1, n}, All}
        ];
       
       ListPlot[ data,
        PlotRange -> plotRange, 
        AxesOrigin -> {0, 0},
        Joined -> True,
        Frame -> True,
        GridLines -> Automatic, 
        ImageSize -> {330, 160},
        ImagePadding -> {{60, 10}, {30, 25}},
        ImageMargins -> {{2, 1}, {1, 1}},
        Axes -> False,
        FrameLabel -> plotTitle,
        PlotStyle -> Red,
        AspectRatio -> 0.27]
       ];
     (*------- public ----------------------------------*)
     
     self@makeDisplay[simulationTime_?numericPositive,
        plotType_String,
        m0_?numericPositive,
        M0_?numericStrictPositive,
        R0_?numericStrictPositive,
        r0_?numericStrictPositive,
        wasHit_?bool,
        k_?numericStrictPositive,
        showPlots_?bool,
        showCounters_?bool,
        showCoriolisForce_?bool,
        trace_?bool] :=
      If[showPlots,
       If[showCounters,
        Grid[{
          {makeCounters[simulationTime, m0, M0, R0, k]},
          {makePlot[plotType, R0]},
          {makeDiskDiagram[m0, R0, r0, 
            wasHit, {1.4 ContentSizeW, 0.515 ContentSizeH}, 
            showCoriolisForce, trace]}
          }, Spacings -> 0]
        ,
        Grid[{
          {makePlot[plotType, R0]},
          {makeDiskDiagram[m0, R0, r0, 
            wasHit, {1.4 ContentSizeW, 0.787 ContentSizeH}, 
            showCoriolisForce, trace]}
          }, Spacings -> 0]
        ],
       If[showCounters,
        Grid[{
          {makeCounters[simulationTime, m0, M0, R0, k]},
          {makeDiskDiagram[m0, R0, r0, 
            wasHit, {1.4 ContentSizeW, 0.93 ContentSizeH}, 
            showCoriolisForce, trace]}
          }, Spacings -> 0]
        ,
        Grid[{
          {makeDiskDiagram[m0, R0, r0, 
            wasHit, {1.4 ContentSizeW, 1.2 ContentSizeH}, 
            showCoriolisForce, trace]}
          }, Spacings -> 0]
        ]
       ];
     
     self
     ];
   (*--------------------------------------------*)
   (* 
   helper function for formatting             *)
   (*--------------------------------------------*)

      padIt1[v_?numeric, f_List] := 
    AccountingForm[Chop[v] , f, NumberSigns -> {"-", "+"}, 
     NumberPadding -> {"0", "0"}, SignPadding -> True];
   (*--------------------------------------------*)
   (* 
   helper function for formatting             *)
   (*--------------------------------------------*)

      padIt2[v_?numeric, f_List] := 
    AccountingForm[Chop[v] , f, NumberSigns -> {"", ""}, 
     NumberPadding -> {"0", "0"}, SignPadding -> True];
   padIt2[v_?numeric, f_Integer] := 
    AccountingForm[Chop[v] , f, NumberSigns -> {"", ""}, 
     NumberPadding -> {"0", "0"}, SignPadding -> True];
   
   (*This function is called to make spring,
   based on code by Arpad Kosa from WRI demo*)(*at Wolfram web site \
modified by me.This returns a Line which is the spring*)
   (*szel, 
   larger number means bigger spring width*)
   
   makeSpring[xFirst_?numeric, yFirst_?numeric, xEnd_?numeric, 
     yEnd_?numeric, szel_?numeric] := 
    Module[{hx, veghossz, hossz, hy, dh, tbl},
     hx = xEnd - xFirst;
     If[Abs[hx] <= $MachineEpsilon, hx = 10^-6];
     hy = yEnd - yFirst;
     If[Abs[hy] <= $MachineEpsilon, hy = 10^-6];
     
     veghossz = 0.03;
     hossz = Sqrt[hx^2 + hy^2];
     dh = (hossz - 2*veghossz)/20;
     tbl = 
      Table[If[
        OddQ[i], {xFirst + hx*(i*dh + veghossz)/hossz + hy*szel/hossz,
          yFirst + hy*(i*dh + veghossz)/hossz - 
          hx*szel/hossz}, {xFirst + hx*(i*dh + veghossz)/hossz - 
          hy*szel/hossz, 
         yFirst + hy*(i*dh + veghossz)/hossz + hx*szel/hossz}], {i, 2,
         18}];
     {{xFirst, yFirst}}~
      Join~{{xFirst + hx*(dh + veghossz)/hossz, 
        yFirst + hy*(dh + veghossz)/hossz}}~Join~tbl~
      Join~{{xFirst + hx*(19*dh + veghossz)/hossz, 
        yFirst + hy*(19*dh + veghossz)/hossz}}~Join~{{xEnd, yEnd}}
     ];
   
   (*--- constant parameters size and width of display ---*)
   
   ContentSizeW = 260;
   ContentSizeH = 405;
   
   (* objects used by the simulation. 
   These must be here in the initialization section *)
   
   list = listClass[400];
   list@add[{1.5, 0.0, Pi/4, 0.09, 0.0}];
   solver = solverClass[];
   display = displayClass[];
   }
 ]