From abeb2b59b46e2c6de224d53b341495c162c75c7a Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Mon, 1 May 2023 14:34:04 -0400
Subject: add box

---
 .../nodes/PhysicsBox/PhysicsSimulationBox.tsx      | 1302 ++++++++++++++++++++
 1 file changed, 1302 insertions(+)

(limited to 'src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx')

diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
index 88338d9b8..101cf1d4a 100644
--- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
@@ -1178,7 +1178,1309 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi
     this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
   };
 
+  // Helper function used for tutorial and review mode
+  getForceFromJSON = (
+    json: {
+      description: string;
+      magnitude: number;
+      directionInDegrees: number;
+      component: boolean;
+    }[]
+  ): IForce[] => {
+    const forces: IForce[] = [];
+    for (let i = 0; i < json.length; i++) {
+      const force: IForce = {
+        description: json[i].description,
+        magnitude: json[i].magnitude,
+        directionInDegrees: json[i].directionInDegrees,
+        component: json[i].component,
+      };
+      forces.push(force);
+    }
+    return forces;
+  };
+
+  // Handle force change in review mode
+  updateReviewModeValues = () => {
+    const forceOfGravityReview: IForce = {
+      description: "Gravity",
+      magnitude: this.dataDoc.reviewGravityMagnitude,
+      directionInDegrees: this.dataDoc.reviewGravityAngle,
+      component: false,
+    };
+    const normalForceReview: IForce = {
+      description: "Normal Force",
+      magnitude: this.dataDoc.reviewNormalMagnitude,
+      directionInDegrees: this.dataDoc.reviewNormalAngle,
+      component: false,
+    };
+    const staticFrictionForceReview: IForce = {
+      description: "Static Friction Force",
+      magnitude: this.dataDoc.reviewStaticMagnitude,
+      directionInDegrees: this.dataDoc.reviewStaticAngle,
+      component: false,
+    };
+    this.dataDoc.startForces = ([
+      forceOfGravityReview,
+      normalForceReview,
+      staticFrictionForceReview,
+    ]);
+    this.dataDoc.updatedForces = ([
+      forceOfGravityReview,
+      normalForceReview,
+      staticFrictionForceReview,
+    ]);
+  }
+
+  // Timer for animating the simulation, update every 0.05 seconds
+  setInterval(() => {
+    setTimer(timer + 1);
+  }, 50);
+
 
 
   render () { 
+    <div className="physicsSimApp">
+    <div className="mechanicsSimulationContainer">
+      <div
+        className="mechanicsSimulationContentContainer"
+      >
+        <div className="mechanicsSimulationButtonsAndElements">
+          <div className="mechanicsSimulationButtons">
+            {!this.dataDoc.simulationPaused && (
+              <div
+                style={{
+                  position: "fixed",
+                  left: "10vw",
+                  top: "95vh",
+                  width: "50vw",
+                }}
+              >
+                <LinearProgress />
+              </div>
+            )}
+            <div
+              style={{
+                position: "fixed",
+                top: 1 + "em",
+                left: xMin + 12 + "px",
+              }}
+            >
+              <div className="dropdownMenu">
+                <select
+                  value={this.dataDoc.simulationType}
+                  onChange={(event) => {
+                    this.dataDoc.simulationType = (event.target.value);
+                    // TODO change simulation type based on mode/type
+                  }}
+                  style={{ height: "2em", width: "100%", fontSize: "16px" }}
+                >
+                  <option value="One Weight">Projectile</option>
+                  <option value="Inclined Plane">Inclined Plane</option>
+                  <option value="Pendulum">Pendulum</option>
+                  <option value="Spring">Spring</option>
+                  <option value="Circular Motion">Circular Motion</option>
+                  <option value="Pulley">Pulley</option>
+                  <option value="Suspension">Suspension</option>
+                </select>
+              </div>
+            </div>
+          </div>
+          <div className="mechanicsSimulationElements">
+            <Weight
+              dataDoc={this.dataDoc}
+              adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
+              gravity={this.dataDoc.gravity}
+              circularMotionRadius={this.dataDoc.circularMotionRadius}
+              componentForces={this.dataDoc.componentForces}
+              showComponentForces={this.dataDoc.showComponentForces}
+              color={"red"}
+              coefficientOfKineticFriction={Number(
+                this.dataDoc.coefficientOfKineticFriction
+              )}
+              displayXVelocity={this.dataDoc.velocityXDisplay}
+              displayYVelocity={this.dataDoc.velocityYDisplay}
+              elasticCollisions={this.dataDoc.elasticCollisions}
+              incrementTime={this.dataDoc.timer}
+              mass={this.dataDoc.mass}
+              mode={this.dataDoc.mode}
+              noMovement={this.dataDoc.noMovement}
+              paused={this.dataDoc.simulationPaused}
+              pendulumAngle={this.dataDoc.pendulumAngle}
+              pendulumLength={this.dataDoc.pendulumLength}
+              radius={this.radius}
+              reset={this.dataDoc.simulationReset}
+              simulationSpeed={this.dataDoc.simulationSpeed}
+              startPendulumAngle={this.dataDoc.startPendulumAngle}
+              showAcceleration={this.dataDoc.showAcceleration}
+              showForceMagnitudes={this.dataDoc.showForceMagnitudes}
+              showForces={this.dataDoc.showForces}
+              showVelocity={this.dataDoc.showVelocity}
+              simulationType={this.dataDoc.simulationType}
+              springConstant={this.dataDoc.springConstant}
+              springStartLength={this.dataDoc.springStartLength}
+              springRestLength={this.dataDoc.springRestLength}
+              startForces={this.dataDoc.startForces}
+              startPosX={this.dataDoc.startPosX}
+              startPosY={this.dataDoc.startPosY}
+              startVelX={this.dataDoc.startVelX}
+              startVelY={this.dataDoc.startVelY}
+              timestepSize={0.05}
+              updateDisplay={this.dataDoc.displayChange}
+              updatedForces={this.dataDoc.updatedForces}
+              wedgeHeight={this.dataDoc.wedgeHeight}
+              wedgeWidth={this.dataDoc.wedgeWidth}
+              xMax={this.xMax}
+              xMin={this.xMin}
+              yMax={this.yMax}
+              yMin={this.yMin}
+            />
+            {this.dataDoc.simulationType == "Pulley" && (
+              <Weight
+                dataDoc={this.dataDoc}
+                adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
+                circularMotionRadius={this.dataDoc.circularMotionRadius}
+                gravity={this.dataDoc.gravity}
+                componentForces={this.dataDoc.componentForces}
+                showComponentForces={this.dataDoc.showComponentForces}
+                color={"blue"}
+                coefficientOfKineticFriction={Number(
+                  this.dataDoc.coefficientOfKineticFriction
+                )}
+                displayXVelocity={this.dataDoc.velocityXDisplay2}
+                displayYVelocity={this.dataDoc.velocityYDisplay2}
+                elasticCollisions={this.dataDoc.elasticCollisions}
+                incrementTime={this.dataDoc.timer}
+                mass={this.dataDoc.mass2}
+                mode={this.dataDoc.mode}
+                noMovement={this.dataDoc.noMovement}
+                paused={this.dataDoc.simulationPaused}
+                pendulumAngle={this.dataDoc.pendulumAngle}
+                pendulumLength={this.dataDoc.pendulumLength}
+                radius={this.dataDoc.radius}
+                reset={this.dataDoc.simulationReset}
+                simulationSpeed={this.dataDoc.simulationSpeed}
+                startPendulumAngle={this.dataDoc.startPendulumAngle}
+                showAcceleration={this.dataDoc.showAcceleration}
+                showForceMagnitudes={this.dataDoc.showForceMagnitudes}
+                showForces={this.dataDoc.showForces}
+                showVelocity={this.dataDoc.showVelocity}
+                simulationType={this.dataDoc.simulationType}
+                springConstant={this.dataDoc.springConstant}
+                springStartLength={this.dataDoc.springStartLength}
+                springRestLength={this.dataDoc.springRestLength}
+                startForces={this.dataDoc.startForces2}
+                startPosX={this.dataDoc.startPosX2}
+                startPosY={this.dataDoc.startPosY2}
+                startVelX={this.dataDoc.startVelX}
+                startVelY={this.dataDoc.startVelY}
+                timestepSize={0.05}
+                updateDisplay={this.dataDoc.displayChange2}
+                updatedForces={this.dataDoc.updatedForces2}
+                wedgeHeight={this.dataDoc.wedgeHeight}
+                wedgeWidth={this.dataDoc.wedgeWidth}
+                xMax={this.xMax}
+                xMin={this.xMin}
+                yMax={this.yMax}
+                yMin={this.yMin}
+              />
+            )}
+          </div>
+          <div>
+            {(this.dataDoc.simulationType == "One Weight" ||
+              this.dataDoc.simulationType == "Inclined Plane") &&
+              this.wallPositions.map((element, index) => {
+                return (
+                  <Wall
+                    key={index}
+                    length={element.length}
+                    xPos={element.xPos}
+                    yPos={element.yPos}
+                    angleInDegrees={element.angleInDegrees}
+                  />
+                );
+              })}
+          </div>
+        </div>
+      </div>
+      <div className="mechanicsSimulationEquationContainer">
+        <div className="mechanicsSimulationControls">
+          <Stack direction="row" spacing={1}>
+            {this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && (
+              <IconButton
+                onClick={() => {
+                  this.dataDoc.simulationPaused = (false);
+                }}
+              >
+                <PlayArrowIcon />
+              </IconButton>
+            )}
+            {!this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && (
+              <IconButton
+                onClick={() => {
+                  this.dataDoc.simulationPaused = (true);
+                }}
+              >
+                <PauseIcon />
+              </IconButton>
+            )}
+            {this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && (
+              <IconButton
+                onClick={() => {
+                  this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
+                }}
+              >
+                <ReplayIcon />
+              </IconButton>
+            )}
+          </Stack>
+          <div className="dropdownMenu">
+            <select
+              value={mode}
+              onChange={(event) => {
+                this.dataDoc.mode = (event.target.value);
+
+                // TODO setup simulation based on type and mode
+              }}
+              style={{ height: "2em", width: "100%", fontSize: "16px" }}
+            >
+              <option value="Tutorial">Tutorial Mode</option>
+              <option value="Freeform">Freeform Mode</option>
+              <option value="Review">Review Mode</option>
+            </select>
+          </div>
+        </div>
+        {this.dataDoc.mode == "Review" && this.dataDoc.simulationType != "Inclined Plane" && (
+          <div className="wordProblemBox">
+            <p>{this.dataDoc.simulationType} review problems in progress!</p>
+          </div>
+        )}
+        {this.dataDoc.mode == "Review" && this.dataDoc.simulationType == "Inclined Plane" && (
+          <div>
+            {!this.dataDoc.hintDialogueOpen && (
+              <IconButton
+                onClick={() => {
+                  this.dataDoc.hintDialogueOpen = (true);
+                }}
+                sx={{
+                  position: "fixed",
+                  left: xMax - 50 + "px",
+                  top: yMin + 14 + "px",
+                }}
+              >
+                <QuestionMarkIcon />
+              </IconButton>
+            )}
+            <Dialog
+              maxWidth={"sm"}
+              fullWidth={true}
+              open={this.dataDoc.hintDialogueOpen}
+              onClose={() => this.dataDoc.hintDialogueOpen = (false)}
+            >
+              <DialogTitle>Hints</DialogTitle>
+              <DialogContent>
+                {this.dataDoc.selectedQuestion.hints.map((hint, index) => {
+                  return (
+                    <div key={index}>
+                      <DialogContentText>
+                        <details>
+                          <summary>
+                            <b>
+                              Hint {index + 1}: {hint.description}
+                            </b>
+                          </summary>
+                          {hint.content}
+                        </details>
+                      </DialogContentText>
+                    </div>
+                  );
+                })}
+              </DialogContent>
+              <DialogActions>
+                <Button
+                  onClick={() => {
+                    this.dataDoc.hintDialogueOpen = (false);
+                  }}
+                >
+                  Close
+                </Button>
+              </DialogActions>
+            </Dialog>
+            <div className="wordProblemBox">
+              <div className="question">
+                <p>{this.dataDoc.questionPartOne}</p>
+                <p>{this.dataDoc.questionPartTwo}</p>
+              </div>
+              <div className="answer">{this.dataDoc.answerInputFields}</div>
+            </div>
+          </div>
+        )}
+        {this.dataDoc.mode == "Tutorial" && (
+          <div className="wordProblemBox">
+            <div className="question">
+              <h2>Problem</h2>
+              <p>{this.dataDoc.selectedTutorial.question}</p>
+            </div>
+            <div
+              style={{
+                display: "flex",
+                justifyContent: "spaceBetween",
+                width: "100%",
+              }}
+            >
+              <IconButton
+                onClick={() => {
+                  let step = this.dataDoc.stepNumber - 1;
+                  step = Math.max(step, 0);
+                  step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1);
+                  this.dataDoc.stepNumber = (step);
+                  this.dataDoc.startForces = (
+                    this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
+                  );
+                  this.dataDoc.updatedForces = (
+                    this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
+                  );
+                  this.dataDoc.showForceMagnitudes = (
+                    this.dataDoc.selectedTutorial.steps[step].showMagnitude
+                  );
+                }}
+                disabled={stepNumber == 0}
+              >
+                <ArrowLeftIcon />
+              </IconButton>
+              <div>
+                <h3>
+                  Step {this.dataDoc.stepNumber + 1}:{" "}
+                  {this.dataDoc.selectedTutorial.steps[stepNumber].description}
+                </h3>
+                <p>{this.dataDoc.selectedTutorial.steps[stepNumber].content}</p>
+              </div>
+              <IconButton
+                onClick={() => {
+                  let step = this.dataDoc.stepNumber + 1;
+                  step = Math.max(step, 0);
+                  step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1);
+                  this.dataDoc.stepNumber = (step);
+                  this.dataDoc.startForces = (
+                    this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
+                  );
+                  this.dataDoc.updatedForces = (
+                    this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
+                  );
+                  this.dataDoc.showForceMagnitudes = (
+                    this.dataDoc.selectedTutorial.steps[step].showMagnitude
+                  );
+                }}
+                disabled={this.dataDoc.stepNumber == this.dataDoc.selectedTutorial.steps.length - 1}
+              >
+                <ArrowRightIcon />
+              </IconButton>
+            </div>
+            <div>
+              {(this.dataDoc.simulationType == "One Weight" ||
+                this.dataDoc.simulationType == "Inclined Plane" ||
+                this.dataDoc.simulationType == "Pendulum") && <p>Resources</p>}
+              {this.dataDoc.simulationType == "One Weight" && (
+                <ul>
+                  <li>
+                    <a
+                      href="https://www.khanacademy.org/science/physics/one-dimensional-motion"
+                      target="_blank"
+                      rel="noreferrer"
+                      style={{
+                        color: "blue",
+                        textDecoration: "underline",
+                      }}
+                    >
+                      Khan Academy - One Dimensional Motion
+                    </a>
+                  </li>
+                  <li>
+                    <a
+                      href="https://www.khanacademy.org/science/physics/two-dimensional-motion"
+                      target="_blank"
+                      rel="noreferrer"
+                      style={{
+                        color: "blue",
+                        textDecoration: "underline",
+                      }}
+                    >
+                      Khan Academy - Two Dimensional Motion
+                    </a>
+                  </li>
+                </ul>
+              )}
+              {this.dataDoc.simulationType == "Inclined Plane" && (
+                <ul>
+                  <li>
+                    <a
+                      href="https://www.khanacademy.org/science/physics/forces-newtons-laws#normal-contact-force"
+                      target="_blank"
+                      rel="noreferrer"
+                      style={{
+                        color: "blue",
+                        textDecoration: "underline",
+                      }}
+                    >
+                      Khan Academy - Normal Force
+                    </a>
+                  </li>
+                  <li>
+                    <a
+                      href="https://www.khanacademy.org/science/physics/forces-newtons-laws#inclined-planes-friction"
+                      target="_blank"
+                      rel="noreferrer"
+                      style={{
+                        color: "blue",
+                        textDecoration: "underline",
+                      }}
+                    >
+                      Khan Academy - Inclined Planes
+                    </a>
+                  </li>
+                </ul>
+              )}
+              {this.dataDoc.simulationType == "Pendulum" && (
+                <ul>
+                  <li>
+                    <a
+                      href="https://www.khanacademy.org/science/physics/forces-newtons-laws#tension-tutorial"
+                      target="_blank"
+                      rel="noreferrer"
+                      style={{
+                        color: "blue",
+                        textDecoration: "underline",
+                      }}
+                    >
+                      Khan Academy - Tension
+                    </a>
+                  </li>
+                </ul>
+              )}
+            </div>
+          </div>
+        )}
+        {this.dataDoc.mode == "Review" && this.dataDoc.simulationType == "Inclined Plane" && (
+          <div
+            style={{
+              display: "flex",
+              justifyContent: "space-between",
+              marginTop: "10px",
+            }}
+          >
+            <p
+              style={{
+                color: "blue",
+                textDecoration: "underline",
+                cursor: "pointer",
+              }}
+              onClick={() => this.dataDoc.mode = ("Tutorial")}
+            >
+              {" "}
+              Go to walkthrough{" "}
+            </p>
+            <div style={{ display: "flex", flexDirection: "column" }}>
+              <Button
+                onClick={() => {
+                  this.dataDoc.simulationReset= (!this.dataDoc.simulationReset);
+                  this.checkAnswers();
+                  this.generateInputFieldsForQuestion(true);
+                }}
+                variant="outlined"
+              >
+                <p>Submit</p>
+              </Button>
+              <Button
+                onClick={() => this.generateNewQuestion()}
+                variant="outlined"
+              >
+                <p>New question</p>
+              </Button>
+            </div>
+          </div>
+        )}
+        {this.dataDoc.mode == "Freeform" && (
+          <div className="vars">
+            <FormControl component="fieldset">
+              <FormGroup>
+                {this.dataDoc.simulationType == "One Weight" && (
+                  <FormControlLabel
+                    control={
+                      <Checkbox
+                        checked={this.dataDoc.elasticCollisions}
+                        onChange={() =>
+                          this.dataDoc.elasticCollisions= (!this.dataDoc.elasticCollisions)
+                        }
+                      />
+                    }
+                    label="Make collisions elastic"
+                    labelPlacement="start"
+                  />
+                )}
+                <FormControlLabel
+                  control={
+                    <Checkbox
+                      checked={this.dataDoc.showForces}
+                      onChange={() => this.dataDoc.showForces = (!this.dataDoc.showForces)}
+                    />
+                  }
+                  label="Show force vectors"
+                  labelPlacement="start"
+                />
+                {(this.dataDoc.simulationType == "Inclined Plane" ||
+                  this.dataDoc.simulationType == "Pendulum") && (
+                  <FormControlLabel
+                    control={
+                      <Checkbox
+                        checked={this.dataDoc.showForces}
+                        onChange={() =>
+                          this.dataDoc.showComponentForces = (!this.dataDoc.showComponentForces)
+                        }
+                      />
+                    }
+                    label="Show component force vectors"
+                    labelPlacement="start"
+                  />
+                )}
+                <FormControlLabel
+                  control={
+                    <Checkbox
+                      checked={this.dataDoc.showAcceleration}
+                      onChange={() => this.dataDoc.showAcceleration = (!this.dataDoc.showAcceleration)}
+                    />
+                  }
+                  label="Show acceleration vector"
+                  labelPlacement="start"
+                />
+                <FormControlLabel
+                  control={
+                    <Checkbox
+                      checked={this.dataDoc.showVelocity}
+                      onChange={() => this.dataDoc.showVelocity = (!this.dataDoc.showVelocity)}
+                    />
+                  }
+                  label="Show velocity vector"
+                  labelPlacement="start"
+                />
+
+                <InputField
+                  label={<Box>Speed</Box>}
+                  lowerBound={1}
+                  changeValue={setSimulationSpeed}
+                  step={1}
+                  unit={"x"}
+                  upperBound={10}
+                  value={simulationSpeed}
+                  labelWidth={"5em"}
+                />
+                {simulationPaused && simulationType != "Circular Motion" && (
+                  <InputField
+                    label={<Box>Gravity</Box>}
+                    lowerBound={-30}
+                    changeValue={setGravity}
+                    step={0.01}
+                    unit={"m/s2"}
+                    upperBound={0}
+                    value={gravity}
+                    effect={(val: number) => {
+                      setResetAll(!resetAll);
+                    }}
+                    labelWidth={"5em"}
+                  />
+                )}
+                {simulationPaused && simulationType != "Pulley" && (
+                  <InputField
+                    label={<Box>Mass</Box>}
+                    lowerBound={1}
+                    changeValue={setMass}
+                    step={0.1}
+                    unit={"kg"}
+                    upperBound={5}
+                    value={mass}
+                    effect={(val: number) => {
+                      setResetAll(!resetAll);
+                    }}
+                    labelWidth={"5em"}
+                  />
+                )}
+                {simulationPaused && simulationType == "Pulley" && (
+                  <InputField
+                    label={<Box>Red mass</Box>}
+                    lowerBound={1}
+                    changeValue={setMass}
+                    step={0.1}
+                    unit={"kg"}
+                    upperBound={5}
+                    value={mass}
+                    effect={(val: number) => {
+                      setResetAll(!resetAll);
+                    }}
+                    labelWidth={"5em"}
+                  />
+                )}
+                {simulationPaused && simulationType == "Pulley" && (
+                  <InputField
+                    label={<Box>Blue mass</Box>}
+                    lowerBound={1}
+                    changeValue={setMass2}
+                    step={0.1}
+                    unit={"kg"}
+                    upperBound={5}
+                    value={mass2}
+                    effect={(val: number) => {
+                      setResetAll(!resetAll);
+                    }}
+                    labelWidth={"5em"}
+                  />
+                )}
+                {simulationPaused && simulationType == "Circular Motion" && (
+                  <InputField
+                    label={<Box>Rod length</Box>}
+                    lowerBound={100}
+                    changeValue={setCircularMotionRadius}
+                    step={5}
+                    unit={"kg"}
+                    upperBound={250}
+                    value={circularMotionRadius}
+                    effect={(val: number) => {
+                      setResetAll(!resetAll);
+                    }}
+                    labelWidth={"5em"}
+                  />
+                )}
+              </FormGroup>
+            </FormControl>
+            {simulationType == "Spring" && simulationPaused && (
+              <div>
+                <InputField
+                  label={
+                    <Typography color="inherit">Spring stiffness</Typography>
+                  }
+                  lowerBound={0.1}
+                  changeValue={setSpringConstant}
+                  step={1}
+                  unit={"N/m"}
+                  upperBound={500}
+                  value={springConstant}
+                  effect={(val: number) => {
+                    setSimulationReset(!simulationReset);
+                  }}
+                  radianEquivalent={false}
+                  mode={"Freeform"}
+                  labelWidth={"7em"}
+                />
+                <InputField
+                  label={<Typography color="inherit">Rest length</Typography>}
+                  lowerBound={10}
+                  changeValue={setSpringRestLength}
+                  step={100}
+                  unit={""}
+                  upperBound={500}
+                  value={springRestLength}
+                  effect={(val: number) => {
+                    setSimulationReset(!simulationReset);
+                  }}
+                  radianEquivalent={false}
+                  mode={"Freeform"}
+                  labelWidth={"7em"}
+                />
+                <InputField
+                  label={
+                    <Typography color="inherit">
+                      Starting displacement
+                    </Typography>
+                  }
+                  lowerBound={-(springRestLength - 10)}
+                  changeValue={(val: number) => {}}
+                  step={10}
+                  unit={""}
+                  upperBound={springRestLength}
+                  value={springStartLength - springRestLength}
+                  effect={(val: number) => {
+                    setStartPosY(springRestLength + val);
+                    setSpringStartLength(springRestLength + val);
+                    setSimulationReset(!simulationReset);
+                  }}
+                  radianEquivalent={false}
+                  mode={"Freeform"}
+                  labelWidth={"7em"}
+                />
+              </div>
+            )}
+            {simulationType == "Inclined Plane" && simulationPaused && (
+              <div>
+                <InputField
+                  label={<Box>&theta;</Box>}
+                  lowerBound={0}
+                  changeValue={setWedgeAngle}
+                  step={1}
+                  unit={"°"}
+                  upperBound={49}
+                  value={wedgeAngle}
+                  effect={(val: number) => {
+                    changeWedgeBasedOnNewAngle(val);
+                    setSimulationReset(!simulationReset);
+                  }}
+                  radianEquivalent={true}
+                  mode={"Freeform"}
+                  labelWidth={"2em"}
+                />
+                <InputField
+                  label={
+                    <Box>
+                      &mu;<sub>s</sub>
+                    </Box>
+                  }
+                  lowerBound={0}
+                  changeValue={setCoefficientOfStaticFriction}
+                  step={0.1}
+                  unit={""}
+                  upperBound={1}
+                  value={coefficientOfStaticFriction}
+                  effect={(val: number) => {
+                    updateForcesWithFriction(val);
+                    if (val < Number(coefficientOfKineticFriction)) {
+                      setCoefficientOfKineticFriction(val);
+                    }
+                    setSimulationReset(!simulationReset);
+                  }}
+                  mode={"Freeform"}
+                  labelWidth={"2em"}
+                />
+                <InputField
+                  label={
+                    <Box>
+                      &mu;<sub>k</sub>
+                    </Box>
+                  }
+                  lowerBound={0}
+                  changeValue={setCoefficientOfKineticFriction}
+                  step={0.1}
+                  unit={""}
+                  upperBound={Number(coefficientOfStaticFriction)}
+                  value={coefficientOfKineticFriction}
+                  effect={(val: number) => {
+                    setSimulationReset(!simulationReset);
+                  }}
+                  mode={"Freeform"}
+                  labelWidth={"2em"}
+                />
+              </div>
+            )}
+            {simulationType == "Inclined Plane" && !simulationPaused && (
+              <Typography>
+                &theta;: {Math.round(Number(wedgeAngle) * 100) / 100}° ≈{" "}
+                {Math.round(((Number(wedgeAngle) * Math.PI) / 180) * 100) /
+                  100}{" "}
+                rad
+                <br />
+                &mu; <sub>s</sub>: {coefficientOfStaticFriction}
+                <br />
+                &mu; <sub>k</sub>: {coefficientOfKineticFriction}
+              </Typography>
+            )}
+            {simulationType == "Pendulum" && !simulationPaused && (
+              <Typography>
+                &theta;: {Math.round(pendulumAngle * 100) / 100}° ≈{" "}
+                {Math.round(((pendulumAngle * Math.PI) / 180) * 100) / 100}{" "}
+                rad
+              </Typography>
+            )}
+            {simulationType == "Pendulum" && simulationPaused && (
+              <div>
+                <InputField
+                  label={<Box>Angle</Box>}
+                  lowerBound={0}
+                  changeValue={setPendulumAngle}
+                  step={1}
+                  unit={"°"}
+                  upperBound={59}
+                  value={pendulumAngle}
+                  effect={(value) => {
+                    setStartPendulumAngle(value);
+                    if (simulationType == "Pendulum") {
+                      const mag =
+                        mass *
+                        Math.abs(gravity) *
+                        Math.cos((value * Math.PI) / 180);
+
+                      const forceOfTension: IForce = {
+                        description: "Tension",
+                        magnitude: mag,
+                        directionInDegrees: 90 - value,
+                        component: false,
+                      };
+
+                      const tensionComponent: IForce = {
+                        description: "Tension",
+                        magnitude: mag,
+                        directionInDegrees: 90 - value,
+                        component: true,
+                      };
+                      const gravityParallel: IForce = {
+                        description: "Gravity Parallel Component",
+                        magnitude:
+                          Math.abs(gravity) *
+                          Math.cos((value * Math.PI) / 180),
+                        directionInDegrees: 270 - value,
+                        component: true,
+                      };
+                      const gravityPerpendicular: IForce = {
+                        description: "Gravity Perpendicular Component",
+                        magnitude:
+                          Math.abs(gravity) *
+                          Math.sin((value * Math.PI) / 180),
+                        directionInDegrees: -value,
+                        component: true,
+                      };
+
+                      const length = pendulumLength;
+                      const x =
+                        length * Math.cos(((90 - value) * Math.PI) / 180);
+                      const y =
+                        length * Math.sin(((90 - value) * Math.PI) / 180);
+                      const xPos = xMax / 2 - x - radius;
+                      const yPos = y - radius - 5;
+                      setStartPosX(xPos);
+                      setStartPosY(yPos);
+
+                      setStartForces([
+                        {
+                          description: "Gravity",
+                          magnitude: Math.abs(gravity) * mass,
+                          directionInDegrees: 270,
+                          component: false,
+                        },
+                        forceOfTension,
+                      ]);
+                      setUpdatedForces([
+                        {
+                          description: "Gravity",
+                          magnitude: Math.abs(gravity) * mass,
+                          directionInDegrees: 270,
+                          component: false,
+                        },
+                        forceOfTension,
+                      ]);
+                      setComponentForces([
+                        tensionComponent,
+                        gravityParallel,
+                        gravityPerpendicular,
+                      ]);
+                      setAdjustPendulumAngle({
+                        angle: value,
+                        length: pendulumLength,
+                      });
+                      setSimulationReset(!simulationReset);
+                    }
+                  }}
+                  radianEquivalent={true}
+                  mode={"Freeform"}
+                  labelWidth={"5em"}
+                />
+                <InputField
+                  label={<Box>Rod length</Box>}
+                  lowerBound={0}
+                  changeValue={setPendulumLength}
+                  step={1}
+                  unit={"m"}
+                  upperBound={400}
+                  value={Math.round(pendulumLength)}
+                  effect={(value) => {
+                    if (simulationType == "Pendulum") {
+                      setAdjustPendulumAngle({
+                        angle: pendulumAngle,
+                        length: value,
+                      });
+                      setSimulationReset(!simulationReset);
+                    }
+                  }}
+                  radianEquivalent={false}
+                  mode={"Freeform"}
+                  labelWidth={"5em"}
+                />
+              </div>
+            )}
+          </div>
+        )}
+        <div className="mechanicsSimulationEquation">
+          {mode == "Freeform" && (
+            <table>
+              <tbody>
+                <tr>
+                  <td>{simulationType == "Pulley" ? "Red Weight" : ""}</td>
+                  <td>X</td>
+                  <td>Y</td>
+                </tr>
+                <tr>
+                  <td
+                    style={{ cursor: "help" }}
+                    onClick={() => {
+                      window.open(
+                        "https://www.khanacademy.org/science/physics/two-dimensional-motion"
+                      );
+                    }}
+                  >
+                    <Box>Position</Box>
+                  </td>
+                  {(!simulationPaused ||
+                    simulationType == "Inclined Plane" ||
+                    simulationType == "Suspension" ||
+                    simulationType == "Circular Motion" ||
+                    simulationType == "Pulley") && (
+                    <td style={{ cursor: "default" }}>
+                      {positionXDisplay} m
+                    </td>
+                  )}{" "}
+                  {simulationPaused &&
+                    simulationType != "Inclined Plane" &&
+                    simulationType != "Suspension" &&
+                    simulationType != "Circular Motion" &&
+                    simulationType != "Pulley" && (
+                      <td
+                        style={{
+                          cursor: "default",
+                        }}
+                      >
+                        <InputField
+                          lowerBound={0}
+                          changeValue={setPositionXDisplay}
+                          step={1}
+                          unit={"m"}
+                          upperBound={xMax - 110}
+                          value={positionXDisplay}
+                          effect={(value) => {
+                            setDisplayChange({
+                              xDisplay: value,
+                              yDisplay: positionYDisplay,
+                            });
+                          }}
+                          small={true}
+                          mode={"Freeform"}
+                        />
+                      </td>
+                    )}{" "}
+                  {(!simulationPaused ||
+                    simulationType == "Inclined Plane" ||
+                    simulationType == "Suspension" ||
+                    simulationType == "Circular Motion" ||
+                    simulationType == "Pulley") && (
+                    <td style={{ cursor: "default" }}>
+                      {positionYDisplay} m
+                    </td>
+                  )}{" "}
+                  {simulationPaused &&
+                    simulationType != "Inclined Plane" &&
+                    simulationType != "Suspension" &&
+                    simulationType != "Circular Motion" &&
+                    simulationType != "Pulley" && (
+                      <td
+                        style={{
+                          cursor: "default",
+                        }}
+                      >
+                        <InputField
+                          lowerBound={0}
+                          changeValue={setPositionYDisplay}
+                          step={1}
+                          unit={"m"}
+                          upperBound={yMax - 110}
+                          value={positionYDisplay}
+                          effect={(value) => {
+                            setDisplayChange({
+                              xDisplay: positionXDisplay,
+                              yDisplay: value,
+                            });
+                          }}
+                          small={true}
+                          mode={"Freeform"}
+                        />
+                      </td>
+                    )}{" "}
+                </tr>
+                <tr>
+                  <td
+                    style={{ cursor: "help" }}
+                    onClick={() => {
+                      window.open(
+                        "https://www.khanacademy.org/science/physics/two-dimensional-motion"
+                      );
+                    }}
+                  >
+                    <Box>Velocity</Box>
+                  </td>
+                  {(!simulationPaused ||
+                    (simulationType != "One Weight" &&
+                      simulationType != "Circular Motion")) && (
+                    <td style={{ cursor: "default" }}>
+                      {velocityXDisplay} m/s
+                    </td>
+                  )}{" "}
+                  {simulationPaused &&
+                    (simulationType == "One Weight" ||
+                      simulationType == "Circular Motion") && (
+                      <td
+                        style={{
+                          cursor: "default",
+                        }}
+                      >
+                        <InputField
+                          lowerBound={-50}
+                          changeValue={setVelocityXDisplay}
+                          step={1}
+                          unit={"m/s"}
+                          upperBound={50}
+                          value={velocityXDisplay}
+                          effect={(value) => {
+                            setStartVelX(value);
+                            setSimulationReset(!simulationReset);
+                          }}
+                          small={true}
+                          mode={"Freeform"}
+                        />
+                      </td>
+                    )}{" "}
+                  {(!simulationPaused || simulationType != "One Weight") && (
+                    <td style={{ cursor: "default" }}>
+                      {velocityYDisplay} m/s
+                    </td>
+                  )}{" "}
+                  {simulationPaused && simulationType == "One Weight" && (
+                    <td
+                      style={{
+                        cursor: "default",
+                      }}
+                    >
+                      <InputField
+                        lowerBound={-50}
+                        changeValue={setVelocityYDisplay}
+                        step={1}
+                        unit={"m/s"}
+                        upperBound={50}
+                        value={velocityYDisplay}
+                        effect={(value) => {
+                          setStartVelY(-value);
+                          setDisplayChange({
+                            xDisplay: positionXDisplay,
+                            yDisplay: positionYDisplay,
+                          });
+                        }}
+                        small={true}
+                        mode={"Freeform"}
+                      />
+                    </td>
+                  )}{" "}
+                </tr>
+                <tr>
+                  <td
+                    style={{ cursor: "help" }}
+                    onClick={() => {
+                      window.open(
+                        "https://www.khanacademy.org/science/physics/two-dimensional-motion"
+                      );
+                    }}
+                  >
+                    <Box>Acceleration</Box>
+                  </td>
+                  <td style={{ cursor: "default" }}>
+                    {accelerationXDisplay} m/s<sup>2</sup>
+                  </td>
+                  <td style={{ cursor: "default" }}>
+                    {accelerationYDisplay} m/s<sup>2</sup>
+                  </td>
+                </tr>
+                <tr>
+                  <td>
+                    <Box>Momentum</Box>
+                  </td>
+                  <td>
+                    {Math.round(velocityXDisplay * mass * 10) / 10} kg*m/s
+                  </td>
+                  <td>
+                    {Math.round(velocityYDisplay * mass * 10) / 10} kg*m/s
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          )}
+          {mode == "Freeform" && simulationType == "Pulley" && (
+            <table>
+              <tbody>
+                <tr>
+                  <td>Blue Weight</td>
+                  <td>X</td>
+                  <td>Y</td>
+                </tr>
+                <tr>
+                  <td>
+                    <Box>Position</Box>
+                  </td>
+                  <td style={{ cursor: "default" }}>{positionXDisplay2} m</td>
+                  <td style={{ cursor: "default" }}>{positionYDisplay2} m</td>
+                </tr>
+                <tr>
+                  <td>
+                    <Box>Velocity</Box>
+                  </td>
+                  <td style={{ cursor: "default" }}>
+                    {velocityXDisplay2} m/s
+                  </td>
+
+                  <td style={{ cursor: "default" }}>
+                    {velocityYDisplay2} m/s
+                  </td>
+                </tr>
+                <tr>
+                  <td>
+                    <Box>Acceleration</Box>
+                  </td>
+                  <td style={{ cursor: "default" }}>
+                    {accelerationXDisplay2} m/s<sup>2</sup>
+                  </td>
+                  <td style={{ cursor: "default" }}>
+                    {accelerationYDisplay2} m/s<sup>2</sup>
+                  </td>
+                </tr>
+                <tr>
+                  <td>
+                    <Box>Momentum</Box>
+                  </td>
+                  <td>
+                    {Math.round(velocityXDisplay2 * mass * 10) / 10} kg*m/s
+                  </td>
+                  <td>
+                    {Math.round(velocityYDisplay2 * mass * 10) / 10} kg*m/s
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          )}
+        </div>
+        {simulationType != "Pendulum" && simulationType != "Spring" && (
+          <div>
+            <p>Kinematic Equations</p>
+            <ul>
+              <li>
+                Position: x<sub>1</sub>=x<sub>0</sub>+v<sub>0</sub>t+
+                <sup>1</sup>&frasl;
+                <sub>2</sub>at
+                <sup>2</sup>
+              </li>
+              <li>
+                Velocity: v<sub>1</sub>=v<sub>0</sub>+at
+              </li>
+              <li>Acceleration: a = F/m</li>
+            </ul>
+          </div>
+        )}
+        {simulationType == "Spring" && (
+          <div>
+            <p>Harmonic Motion Equations: Spring</p>
+            <ul>
+              <li>
+                Spring force: F<sub>s</sub>=kd
+              </li>
+              <li>
+                Spring period: T<sub>s</sub>=2&pi;&#8730;<sup>m</sup>&frasl;
+                <sub>k</sub>
+              </li>
+              <li>Equilibrium displacement for vertical spring: d = mg/k</li>
+              <li>
+                Elastic potential energy: U<sub>s</sub>=<sup>1</sup>&frasl;
+                <sub>2</sub>kd<sup>2</sup>
+              </li>
+              <ul>
+                <li>
+                  Maximum when system is at maximum displacement, 0 when
+                  system is at 0 displacement
+                </li>
+              </ul>
+              <li>
+                Translational kinetic energy: K=<sup>1</sup>&frasl;
+                <sub>2</sub>mv<sup>2</sup>
+              </li>
+              <ul>
+                <li>
+                  Maximum when system is at maximum/minimum velocity (at 0
+                  displacement), 0 when velocity is 0 (at maximum
+                  displacement)
+                </li>
+              </ul>
+            </ul>
+          </div>
+        )}
+        {simulationType == "Pendulum" && (
+          <div>
+            <p>Harmonic Motion Equations: Pendulum</p>
+            <ul>
+              <li>
+                Pendulum period: T<sub>p</sub>=2&pi;&#8730;<sup>l</sup>&frasl;
+                <sub>g</sub>
+              </li>
+            </ul>
+          </div>
+        )}
+      </div>
+    </div>
+    <div
+      style={{
+        position: "fixed",
+        top: window.innerHeight - 120 + 20 + "px",
+        left: xMin + 90 - 80 + "px",
+        zIndex: -10000,
+      }}
+    >
+      <svg width={100 + "px"} height={100 + "px"}>
+        <defs>
+          <marker
+            id="miniArrow"
+            markerWidth="20"
+            markerHeight="20"
+            refX="0"
+            refY="3"
+            orient="auto"
+            markerUnits="strokeWidth"
+          >
+            <path d="M0,0 L0,6 L9,3 z" fill={"#000000"} />
+          </marker>
+        </defs>
+        <line
+          x1={20}
+          y1={70}
+          x2={70}
+          y2={70}
+          stroke={"#000000"}
+          strokeWidth="2"
+          markerEnd="url(#miniArrow)"
+        />
+        <line
+          x1={20}
+          y1={70}
+          x2={20}
+          y2={20}
+          stroke={"#000000"}
+          strokeWidth="2"
+          markerEnd="url(#miniArrow)"
+        />
+      </svg>
+      <p
+        style={{
+          position: "fixed",
+          top: window.innerHeight - 120 + 40 + "px",
+          left: xMin + 90 - 80 + "px",
+        }}
+      >
+        {simulationType == "Circular Motion" ? "Z" : "Y"}
+      </p>
+      <p
+        style={{
+          position: "fixed",
+          top: window.innerHeight - 120 + 80 + "px",
+          left: xMin + 90 - 40 + "px",
+        }}
+      >
+        X
+      </p>
+    </div>
+  </div>
   }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

