From f327a27d664f45c10a90a4464cd0fa5edec59b68 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Mon, 1 May 2023 12:51:12 -0400
Subject: start adding box code

---
 .../nodes/PhysicsBox/PhysicsSimulationBox.tsx      | 745 ++++++++++-----------
 1 file changed, 346 insertions(+), 399 deletions(-)

(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 d0e854263..f27843ab0 100644
--- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
@@ -6,22 +6,41 @@ import { observer } from 'mobx-react';
 import "./PhysicsSimulationBox.scss";
 import Weight from "./PhysicsSimulationWeight";
 import Wall  from "./PhysicsSimulationWall"
-import Wedge from "./PhysicsSimulationWedge"
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { CheckBox } from "../search/CheckBox";
-export interface IForce {
-  description: string;
-  magnitude: number;
-  directionInDegrees: number;
-}
-export interface IWallProps {
-  length: number;
-  xPos: number;
-  yPos: number;
-  angleInDegrees: number;
-}
-
-interface PhysicsVectorTemplate {
+import PauseIcon from "@mui/icons-material/Pause";
+import PlayArrowIcon from "@mui/icons-material/PlayArrow";
+import ReplayIcon from "@mui/icons-material/Replay";
+import QuestionMarkIcon from "@mui/icons-material/QuestionMark";
+import ArrowLeftIcon from "@mui/icons-material/ArrowLeft";
+import ArrowRightIcon from "@mui/icons-material/ArrowRight";
+import EditIcon from "@mui/icons-material/Edit";
+import EditOffIcon from "@mui/icons-material/EditOff";
+import {
+  Box,
+  Button,
+  Checkbox,
+  Dialog,
+  DialogTitle,
+  DialogContent,
+  DialogContentText,
+  DialogActions,
+  FormControl,
+  FormControlLabel,
+  FormGroup,
+  IconButton,
+  LinearProgress,
+  Stack,
+} from "@mui/material";
+import Typography from "@mui/material/Typography";
+import React, { useEffect, useState } from "react";
+import "./App.scss";
+import { InputField } from "./InputField";
+import questions from "./PhysicsSimulationQuestions.json";
+import tutorials from "./PhysicsSimulationTutorial.json";
+import { IWallProps, Wall } from "./Wall";
+import { IForce, Weight } from "./Weight";
+interface VectorTemplate {
   top: number;
   left: number;
   width: number;
@@ -33,118 +52,191 @@ interface PhysicsVectorTemplate {
   weightX: number;
   weightY: number;
 }
+interface QuestionTemplate {
+  questionSetup: string[];
+  variablesForQuestionSetup: string[];
+  question: string;
+  answerParts: string[];
+  answerSolutionDescriptions: string[];
+  goal: string;
+  hints: { description: string; content: string }[];
+}
+
+interface TutorialTemplate {
+  question: string;
+  steps: {
+    description: string;
+    content: string;
+    forces: {
+      description: string;
+      magnitude: number;
+      directionInDegrees: number;
+      component: boolean;
+    }[];
+    showMagnitude: boolean;
+  }[];
+}
 
 @observer
 export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
   public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }
 
-  // Constants
-  gravityMagnitude = 9.81;
-  forceOfGravity: IForce = {
-    description: "Gravity",
-    magnitude: this.gravityMagnitude,
-    directionInDegrees: 270,
-  };
-  xMin = 0;
-  yMin = 0;
-  xMax = 300;
-  yMax = 300;
-  color = `rgba(0,0,0,0.5)`;
-  radius = 0.1*this.yMax
-  update = true
-  menuIsOpen = false
-
   constructor(props: any) {
     super(props);
   }
 
-  // Add one weight to the simulation
-  addWeight () {
-    this.dataDoc.weight = true;
-    this.dataDoc.wedge = false;
-    this.dataDoc.pendulum = false;
-    this.addWalls();
-  };
+  // Constants
+  const xMin = 0;
+  const yMin = 0;
+  const xMax = window.innerWidth * 0.7;
+  const yMax = window.innerHeight * 0.8;
+  const color = `rgba(0,0,0,0.5)`;
+  const radius = 50;
+  const wallPositions: IWallProps[] = [];
 
-  // Set weight defaults
-  setToWeightDefault () {
-    this.dataDoc.startPosY = this.yMin+this.radius;
-    this.dataDoc.startPosX = (this.xMax+this.xMin-this.radius)/2;
-    this.dataDoc.updatedForces = [this.forceOfGravity];
-    this.dataDoc.startForces = [this.forceOfGravity];
-  }
 
-  // Add a wedge with a One Weight to the simulation
-  addWedge () {
-    this.dataDoc.weight = true;
-    this.dataDoc.wedge = true;
-    this.dataDoc.pendulum = false;
-    this.addWalls();
-  };
+  componentDidMount() {
+    this.wallPositions.push({ length: 70, xPos: 0, yPos: 0, angleInDegrees: 0 });
+    this.wallPositions.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 });
+    this.wallPositions.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 });
+    this.wallPositions.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 });
 
-  // Set wedge defaults
-  setToWedgeDefault () {
-    this.changeWedgeBasedOnNewAngle(26);
-    this.updateForcesWithFriction(this.dataDoc.coefficientOfStaticFriction);
-  }
+    // Used throughout sims
+    this.xMax = this.layoutDoc._width;
+    this.yMax = this.layoutDoc._height;
+    this.radius = 0.1*this.layoutDoc._height;
+    this.dataDoc.reviewCoefficient = this.dataDoc.reviewCoefficient ?? 0;
+    this.dataDoc.questionVariables = this.dataDoc.questionVariables ?? [];
+    this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0;
+    this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0;
+    this.dataDoc.componentForces = this.dataDoc.componentForces ?? [];
+    this.dataDoc.displayChange = this.dataDoc.displayChange ?? { xDisplay: 0, yDisplay: 0 };
+    this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false;
+    this.dataDoc.gravity = this.dataDoc.gravity ?? -9.81;
+    this.dataDoc.mass = this.dataDoc.mass ?? 1;
+    this.dataDoc.mode = this.dataDoc.mode ?? "Freeform";
+    this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0;
+    this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0;
+    this.dataDoc.resetAll = this.dataDoc.resetAll ?? true;
+    this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false;
+    this.dataDoc.showComponentForces = this.dataDoc.showComponentForces ?? false;
+    this.dataDoc.showForces = this.dataDoc.showForces ?? true;
+    this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? true;
+    this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false;
+    this.dataDoc.simulationPaused = this.dataDoc.simulationPaused ?? true;
+    this.dataDoc.simulationReset = this.dataDoc.simulationReset ?? false;
+    this.dataDoc.simulationSpeed = this.dataDoc.simulationSpeed ?? 2;
+    this.dataDoc.simulationType = this.dataDoc.simulationType ?? "Inclined Plane";
+    this.dataDoc.startForces = this.dataDoc.startForces ?? [];
+    this.dataDoc.startPosX = this.dataDoc.startPosX ?? 0;
+    this.dataDoc.startPosY = this.dataDoc.startPosY ?? 0;
+    this.dataDoc.startVelX = this.dataDoc.startVelX ?? 0;
+    this.dataDoc.startVelY = this.dataDoc.startVelY ?? 0;
+    this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0;
+    this.dataDoc.timer = this.dataDoc.timer ?? 0;
+    this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [];
+    this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0;
+    this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0;
 
-  // Add a simple pendulum to the simulation
-  addPendulum = () => {
-    this.dataDoc.weight = true;
-    this.dataDoc.wedge = false;
-    this.dataDoc.pendulum = true;
-    this.removeWalls();
-    let angle = this.dataDoc.pendulumAngle;
-    let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
-    let forceOfTension: IForce = {
-      description: "Tension",
-      magnitude: mag,
-      directionInDegrees: 90 - angle,
-    };
-    this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension];
-    this.dataDoc.startForces = [this.forceOfGravity, forceOfTension];
-  };
+    // Used for review mode
+    this.dataDoc.answerInputFields = this.dataDoc.answerInputFields ?? <div></div>;
+    this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? null;
+    this.dataDoc.deleteMode = this.dataDoc.deleteMode ?? false;
+    this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? [];
+    this.dataDoc.hintDialogueOpen = this.dataDoc.hintDialogueOpen ?? false;
+    this.dataDoc.noMovement = this.dataDoc.noMovement ?? false;
+    this.dataDoc.questionNumber = this.dataDoc.questionNumber ?? 0;
+    this.dataDoc.questionPartOne = this.dataDoc.questionPartOne ?? "";
+    this.dataDoc.questionPartTwo = this.dataDoc.questionPartTwo ?? "";
+    this.dataDoc.reviewGravityAngle = this.dataDoc.reviewGravityAngle ?? 0;
+    this.dataDoc.reviewGravityMagnitude = this.dataDoc.reviewGravityMagnitude ?? 0;
+    this.dataDoc.reviewNormalAngle = this.dataDoc.reviewNormalAngle ?? 0;
+    this.dataDoc.reviewNormalMagnitude = this.dataDoc.reviewNormalMagnitude ?? 0;
+    this.dataDoc.reviewStaticAngle = this.dataDoc.reviewStaticAngle ?? 0;
+    this.dataDoc.reviewStaticMagnitude = this.dataDoc.reviewStaticMagnitude ?? 0;
+    this.dataDoc.selectedSolutions = this.dataDoc.selectedSolutions ?? [];
+    this.dataDoc.selectedQuestion = this.dataDoc.selectedQuestion ?? questions.inclinePlane[0];
+    this.dataDoc.sketching = this.dataDoc.sketching ?? false;
+
+    // Used for tutorial mode
+    this.dataDoc.selectedTutorial = this.dataDoc.selectedTutorial ?? tutorials.inclinePlane;
 
-  // Set pendulum defaults
-  setToPendulumDefault () {
-    let length = this.xMax*0.7;
-    let angle = 35;
-    let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
-    let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
-    let xPos = this.xMax / 2 - x - this.radius;
-    let yPos = y - this.radius;
-    this.dataDoc.startPosX = xPos;
-    this.dataDoc.startPosY = yPos;
-    let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
-    this.dataDoc.pendulumAngle = angle;
-    this.dataDoc.pendulumLength = length;
-    this.dataDoc.startPendulumAngle = angle;
-    this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle;
+    // Used for uniform circular motion
+    this.dataDoc.circularMotionRadius = this.dataDoc.circularMotionRadius ?? 150;
+
+    // Used for spring simulation
+    this.dataDoc.springConstant = this.dataDoc.springConstant ?? 0.5;
+    this.dataDoc.springRestLength = this.dataDoc.springRestLength ?? 200;
+    this.dataDoc.springStartLength = this.dataDoc.springStartLength ?? 200;
+
+    // Used for pendulum simulation
+    this.dataDoc.adjustPendulumAngle = this.dataDoc.adjustPendulumAngle ?? { angle: 0, length: 0 };
+    this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 0;
+    this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300;
+    this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0;
+
+    // Used for wedge simulation
+    this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0;
+    this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0;
+    this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26;
+    this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * 400;
+    this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? 400;
+
+    // Used for pulley simulation
+    this.dataDoc.positionXDisplay2 = this.dataDoc.positionXDisplay2 ?? 0;
+    this.dataDoc.velocityXDisplay2 = this.dataDoc.velocityXDisplay2 ?? 0;
+    this.dataDoc.accelerationXDisplay2 = this.dataDoc.accelerationXDisplay2 ?? 0;
+    this.dataDoc.positionYDisplay2 = this.dataDoc.positionYDisplay2 ?? 0;
+    this.dataDoc.velocityYDisplay2 = this.dataDoc.velocityYDisplay2 ?? 0;
+    this.dataDoc.accelerationYDisplay2 = this.dataDoc.accelerationYDisplay2 ?? 0;
+    this.dataDoc.startPosX2 = this.dataDoc.startPosX2 ?? 0;
+    this.dataDoc.startPosY2 = this.dataDoc.startPosY2 ?? 0;
+    this.dataDoc.displayChange2 = this.dataDoc.displayChange2 ?? { xDisplay: 0, yDisplay: 0 };
+    this.dataDoc.startForces2 = this.dataDoc.startForces2 ?? [];
+    this.dataDoc.updatedForces2 = this.dataDoc.updatedForces2 ?? [];
+    this.dataDoc.mass2 = this.dataDoc.mass2 ?? 1;
+  }
+
+  componentDidUpdate() {
+    this.xMax = this.layoutDoc._width;
+    this.yMax = this.layoutDoc._height;
+    this.radius = 0.1*this.layoutDoc._height;
   }
 
+  // Helper function to go between display and real values
+  getDisplayYPos = (yPos: number) => {
+    return this.yMax - this.dataDoc.yPos - 2 * this.radius + 5;
+  };
+  getYPosFromDisplay = (yDisplay: number) => {
+    return this.yMax - this.dataDoc.yDisplay - 2 * this.radius + 5;
+  };
+
   // Update forces when coefficient of static friction changes in freeform mode
-  updateForcesWithFriction (
+  updateForcesWithFriction = (
     coefficient: number,
-    width: number = this.dataDoc.wedgeWidth,
-    height: number = this.dataDoc.wedgeHeight
-  ) {
-    let normalForce = {
+    width: number = this.wedgeWidth,
+    height: number = this.wedgeHeight
+  ) => {
+    const normalForce: IForce = {
       description: "Normal Force",
-      magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)),
+      magnitude: Math.abs(this.gravity) * Math.cos(Math.atan(height / width)) * this.mass,
       directionInDegrees:
         180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
+      component: false,
     };
     let frictionForce: IForce = {
       description: "Static Friction Force",
       magnitude:
         coefficient *
-        this.forceOfGravity.magnitude *
-        Math.cos(Math.atan(height / width)),
+        Math.abs(this.gravity) *
+        Math.cos(Math.atan(height / width)) *
+        this.mass,
       directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
+      component: false,
     };
-    // reduce magnitude of friction force if necessary such that block cannot slide up plane
-    let yForce = -this.forceOfGravity.magnitude;
+    // reduce magnitude or friction force if necessary such that block cannot slide up plane
+    let yForce = -Math.abs(this.gravity) * this.mass;
     yForce +=
       normalForce.magnitude *
       Math.sin((normalForce.directionInDegrees * Math.PI) / 180);
@@ -155,15 +247,65 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi
       frictionForce.magnitude =
         (-normalForce.magnitude *
           Math.sin((normalForce.directionInDegrees * Math.PI) / 180) +
-          this.forceOfGravity.magnitude) /
+          Math.abs(this.gravity) * this.mass) /
         Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
     }
+    const frictionForceComponent: IForce = {
+      description: "Static Friction Force",
+      magnitude:
+        coefficient * Math.abs(this.gravity) * Math.cos(Math.atan(height / width)),
+      directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
+      component: true,
+    };
+    const normalForceComponent: IForce = {
+      description: "Normal Force",
+      magnitude: Math.abs(this.gravity) * Math.cos(Math.atan(height / width)),
+      directionInDegrees:
+        180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
+      component: true,
+    };
+    const gravityParallel: IForce = {
+      description: "Gravity Parallel Component",
+      magnitude:
+      this.mass *
+        Math.abs(this.gravity) *
+        Math.sin(Math.PI / 2 - Math.atan(height / width)),
+      directionInDegrees:
+        180 - 90 - (Math.atan(height / width) * 180) / Math.PI + 180,
+      component: true,
+    };
+    const gravityPerpendicular: IForce = {
+      description: "Gravity Perpendicular Component",
+      magnitude:
+      this.mass *
+        Math.abs(this.gravity) *
+        Math.cos(Math.PI / 2 - Math.atan(height / width)),
+      directionInDegrees: 360 - (Math.atan(height / width) * 180) / Math.PI,
+      component: true,
+    };
+    const gravityForce: IForce = {
+      description: "Gravity",
+      magnitude: this.mass * Math.abs(this.gravity),
+      directionInDegrees: 270,
+      component: false,
+    };
     if (coefficient != 0) {
-      this.dataDoc.startForces = [this.forceOfGravity, normalForce, frictionForce];
-      this.dataDoc.updatedForces = [this.forceOfGravity, normalForce, frictionForce];
+      this.dataDoc.startForces = [gravityForce, normalForce, frictionForce];
+      this.dataDoc.updatedForces = [gravityForce, normalForce, frictionForce];
+      this.dataDoc.componentForces = [
+        frictionForceComponent,
+        normalForceComponent,
+        gravityParallel,
+        gravityPerpendicular,
+      ];
     } else {
-      this.dataDoc.startForces = [this.forceOfGravity, normalForce];
-      this.dataDoc.updatedForces = [this.forceOfGravity, normalForce];
+      this.dataDoc.startForces = [gravityForce, normalForce];
+      this.dataDoc.updatedForces = [gravityForce, normalForce];
+      this.dataDoc.componentForces = [
+        normalForceComponent,
+        gravityParallel,
+        gravityPerpendicular,
+      ];
     }
   };
 
@@ -172,323 +314,128 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi
     let width = 0;
     let height = 0;
     if (angle < 50) {
-      width = this.xMax*0.6;
-      height = Math.tan((angle * Math.PI) / 180) * width;
+      width = 400;
+      height = Math.tan((angle * Math.PI) / 180) * 400;
       this.dataDoc.wedgeWidth = width;
       this.dataDoc.wedgeHeight = height;
     } else if (angle < 70) {
-      width = this.xMax*0.3;
-      height = Math.tan((angle * Math.PI) / 180) * width;
+      width = 200;
+      height = Math.tan((angle * Math.PI) / 180) * 200;
       this.dataDoc.wedgeWidth = width;
       this.dataDoc.wedgeHeight = height;
     } else {
-      width = this.xMax*0.15;
-      height = Math.tan((angle * Math.PI) / 180) * width;
-      this.dataDoc.wedgeWidth =  width;
+      width = 100;
+      height = Math.tan((angle * Math.PI) / 180) * 100;
+      this.dataDoc.wedgeWidth = width;
       this.dataDoc.wedgeHeight = height;
     }
 
     // update weight position based on updated wedge width/height
-    let xPos = (this.xMax * 0.2)-this.radius;
-    let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius;
+    let yPos = (width - this.radius) * Math.tan((angle * Math.PI) / 180);
+    if (angle < 40) {
+      yPos += Math.sqrt(angle);
+    } else if (angle < 58) {
+      yPos += angle / 2;
+    } else if (angle < 68) {
+      yPos += angle;
+    } else if (angle < 70) {
+      yPos += angle * 1.3;
+    } else if (angle < 75) {
+      yPos += angle * 1.5;
+    } else if (angle < 78) {
+      yPos += angle * 2;
+    } else if (angle < 79) {
+      yPos += angle * 2.25;
+    } else if (angle < 80) {
+      yPos += angle * 2.6;
+    } else {
+      yPos += angle * 3;
+    }
 
-    this.dataDoc.startPosX = xPos;
+    this.dataDoc.startPosX = Math.round((this.xMax * 0.5 - 200) * 10) / 10;
     this.dataDoc.startPosY = this.getDisplayYPos(yPos);
-    this.updateForcesWithFriction(
-      Number(this.dataDoc.coefficientOfStaticFriction),
-      width,
-      height
-    );
-    this.dataDoc['updateDisplay'] = !this.dataDoc['updateDisplay']
-  };
-
-  // Helper function to go between display and real values
-  getDisplayYPos = (yPos: number) => {
-    return this.yMax - yPos - 2 * 50 + 5;
-  };
-
-  // In review mode, edit force arrow sketch on mouse movement
-  editForce = (element: PhysicsVectorTemplate) => {
-    if (!this.dataDoc.sketching) {
-      let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element);
-      this.dataDoc.forceSketches = sketches;
-      this.dataDoc.currentForceSketch = element;
-      this.dataDoc.sketching = true;
+    if (this.dataDoc.mode == "Freeform") {
+      this.updateForcesWithFriction(
+        Number(this.dataDoc.coefficientOfStaticFriction),
+        width,
+        height
+      );
     }
   };
 
-  // In review mode, used to delete force arrow sketch on SHIFT+click
-  deleteForce = (element: PhysicsVectorTemplate) => {
-    if (!this.dataDoc.sketching) {
-      let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element);
-      this.dataDoc.forceSketches = sketches;
+  // In review mode, update forces when coefficient of static friction changed
+  updateReviewForcesBasedOnCoefficient = (coefficient: number) => {
+    let theta: number = Number(this.dataDoc.wedgeAngle);
+    let index =
+      this.dataDoc.selectedQuestion.variablesForQuestionSetup.indexOf("theta - max 45");
+    if (index >= 0) {
+      theta = this.dataDoc.questionVariables[index];
     }
+    if (isNaN(theta)) {
+      return;
+    }
+    this.dataDoc.reviewGravityMagnitude = (Math.abs(this.dataDoc.gravity));
+    this.dataDoc.reviewGravityAngle = (270);
+    this.dataDoc.reviewNormalMagnitude = (
+      Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180)
+    );
+    this.dataDoc.reviewNormalAngle = (90 - theta);
+    let yForce = -Math.abs(this.dataDoc.gravity);
+    yForce +=
+      Math.abs(this.dataDoc.gravity) *
+      Math.cos((theta * Math.PI) / 180) *
+      Math.sin(((90 - theta) * Math.PI) / 180);
+    yForce +=
+      coefficient *
+      Math.abs(this.dataDoc.gravity) *
+      Math.cos((theta * Math.PI) / 180) *
+      Math.sin(((180 - theta) * Math.PI) / 180);
+    let friction =
+      coefficient * Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180);
+    if (yForce > 0) {
+      friction =
+        (-(Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180)) *
+          Math.sin(((90 - theta) * Math.PI) / 180) +
+          Math.abs(this.dataDoc.gravity)) /
+        Math.sin(((180 - theta) * Math.PI) / 180);
+    }
+    this.dataDoc.reviewStaticMagnitude = (friction);
+    this.dataDoc.reviewStaticAngle = (180 - theta);
   };
 
-  // Remove floor and walls from simulation
-  removeWalls = () => {
-    this.dataDoc.wallPositions = []
-  };
-
-  // Add floor and walls to simulation
-  addWalls = () => {
-    let walls = [];
-    walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 });
-    walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 });
-    walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 });
-    this.dataDoc.wallPositions = walls
-  };
-
-
-  componentDidMount() {
-    this.xMax = this.layoutDoc._width;
-    this.yMax = this.layoutDoc._height;
-    this.radius = 0.1*this.layoutDoc._height;
-
-    // Add weight
-    if (this.dataDoc.simulationType == "Inclined Plane") {
-      this.addWedge()
-    } else if (this.dataDoc.simulationType == "Pendulum") {
-      this.addPendulum()
-    } else {
-      this.dataDoc.simulationType = "Free Weight"
-      this.addWeight()
+  // In review mode, update forces when wedge angle changed
+  updateReviewForcesBasedOnAngle = (angle: number) => {
+    this.dataDoc.reviewGravityMagnitude = (Math.abs(this.dataDoc.gravity));
+    this.dataDoc.reviewGravityAngle = (270);
+    this.dataDoc.reviewNormalMagnitude = (
+      Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180)
+    );
+    this.dataDoc.reviewNormalAngle = (90 - angle);
+    let yForce = -Math.abs(this.dataDoc.gravity);
+    yForce +=
+      Math.abs(this.dataDoc.gravity) *
+      Math.cos((Number(angle) * Math.PI) / 180) *
+      Math.sin(((90 - Number(angle)) * Math.PI) / 180);
+    yForce +=
+      this.dataDoc.reviewCoefficient *
+      Math.abs(this.dataDoc.gravity) *
+      Math.cos((Number(angle) * Math.PI) / 180) *
+      Math.sin(((180 - Number(angle)) * Math.PI) / 180);
+    let friction =
+      this.dataDoc.reviewCoefficient *
+      Math.abs(this.dataDoc.gravity) *
+      Math.cos((Number(angle) * Math.PI) / 180);
+    if (yForce > 0) {
+      friction =
+        (-(Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180)) *
+          Math.sin(((90 - Number(angle)) * Math.PI) / 180) +
+          Math.abs(this.dataDoc.gravity)) /
+        Math.sin(((180 - Number(angle)) * Math.PI) / 180);
     }
-    this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0;
-    this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0;
-    this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0;
-    this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0;
-    this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? [];
-    this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false;
-    this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? [];
-    this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 26;
-    this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300;
-    this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0;
-    this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0;
-    this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false;
-    this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? false;
-    this.dataDoc.showForces = this.dataDoc.showForces ?? false;
-    this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false;
-    this.dataDoc.startForces = this.dataDoc.startForces ?? [this.forceOfGravity];
-    this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0;
-    this.dataDoc.startPosX = this.dataDoc.startPosX ?? 50;
-    this.dataDoc.startPosY = this.dataDoc.startPosY ?? 50;
-    this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0;
-    this.dataDoc.updateDisplay = this.dataDoc.updateDisplay ?? false;
-    this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [this.forceOfGravity];
-    this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0;
-    this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0;
-    this.dataDoc.wallPositions = this.dataDoc.wallPositions ?? [];
-    this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26;
-    this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * this.xMax*0.6;
-    this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? this.xMax*0.6;
-
-    this.dataDoc.adjustPendulumAngle = true;
-    this.dataDoc.simulationPaused = true;
-    this.dataDoc.simulationReset = false;
+    this.dataDoc.reviewStaticMagnitude = (friction);
+    this.dataDoc.reviewStaticAngle = (180 - angle);
+  };
 
-    // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
-    document.addEventListener("keydown", (e) => {
-      if (e.shiftKey) {
-        this.dataDoc.deleteMode = true;
-      }
-    });
-    document.addEventListener("keyup", (e) => {
-      if (e.shiftKey) {
-        this.dataDoc.deleteMode = false;
-      }
-    });
-  }
-
-  componentDidUpdate() {
-    this.xMax = this.layoutDoc._width;
-    this.yMax = this.layoutDoc._height;
-    this.radius = 0.1*this.layoutDoc._height;
-  }
 
   render () { 
-    return (
-      <div>
-        <div className="mechanicsSimulationContainer">
-          <div className="mechanicsSimulationContentContainer">
-            <div className="mechanicsSimulationButtonsAndElements">
-              <div className="mechanicsSimulationElements">
-                {this.dataDoc.weight && (
-                  <Weight
-                    adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
-                    color={"red"}
-                    dataDoc={this.dataDoc}
-                    mass={1}
-                    radius={this.radius}
-                    simulationReset={this.dataDoc.simulationReset}
-                    startPosX={this.dataDoc.startPosX}
-                    startPosY={this.dataDoc.startPosY}
-                    timestepSize={0.002}
-                    updateDisplay={this.dataDoc.updateDisplay}
-                    walls={this.dataDoc.wallPositions}
-                    wedge={this.dataDoc.wedge}
-                    wedgeWidth={this.dataDoc.wedgeWidth}
-                    wedgeHeight={this.dataDoc.wedgeHeight}
-                    xMax={this.xMax}
-                    xMin={this.xMin}
-                    yMax={this.yMax}
-                    yMin={this.yMin}
-                  />
-                )}
-                {this.dataDoc.wedge && (
-                  <Wedge
-                    startWidth={this.dataDoc.wedgeWidth}
-                    startHeight={this.dataDoc.wedgeHeight}
-                    startLeft={this.xMax * 0.2}
-                    xMax={this.xMax}
-                    yMax={this.yMax}
-                  />
-                )}
-              </div>
-              <div>
-                {(this.dataDoc.wallPositions ?? []).map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
-                    return (
-                      <div key={index}>
-                        <Wall
-                          length={element.length}
-                          xPos={element.xPos}
-                          yPos={element.yPos}
-                          angleInDegrees={element.angleInDegrees}
-                        />
-                      </div>
-                    );
-                  })}
-              </div>
-            </div>
-          </div>
-          <div style = {{width: this.layoutDoc._width+'px', height: this.layoutDoc._height+'px'}}>
-            {this.menuIsOpen && (
-              <div className="mechanicsSimulationSettingsMenu">
-                <div className="close-button" onClick={() => {this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}>
-                    <FontAwesomeIcon icon={'times'} color="black" size={'lg'} />
-                </div>
-                <h4>Simulation Settings</h4>
-                <div className="mechanicsSimulationSettingsMenuRow">
-                   <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Show forces</p></div>
-                   <div><input type="checkbox" checked={this.dataDoc.showForces} onClick={() => {this.dataDoc.showForces = !this.dataDoc.showForces}}/></div>
-                </div>
-                <div className="mechanicsSimulationSettingsMenuRow">
-                  <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Show acceleration</p></div>
-                  <div><input type="checkbox" checked={this.dataDoc.showAcceleration}  onClick={() => {this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/></div>
-                </div>
-                <div className="mechanicsSimulationSettingsMenuRow">
-                <div className="mechanicsSimulationSettingsMenuRowDescription">
-                  <p>Show velocity</p></div>
-                  <div><input type="checkbox" checked={this.dataDoc.showVelocity} onClick={() => {this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/></div>
-                </div>
-                <hr/>
-                {this.dataDoc.simulationType == "Free Weight" && <div className="mechanicsSimulationSettingsMenuRow">
-                  <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Elastic collisions </p></div>
-                  <div><input type="checkbox" checked={this.dataDoc.elasticCollisions} onClick={() => {this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/></div>
-                </div>}
-                {this.dataDoc.simulationType == "Pendulum" && <div className="mechanicsSimulationSettingsMenuRow">
-                  <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Pendulum start angle</p></div>
-                  <div>
-                    <input 
-                      type="number" 
-                      value={this.dataDoc.startPendulumAngle} 
-                      max={35} 
-                      min={0} 
-                      step={1} 
-                      onInput={(e) => {
-                        let angle = e.target.value;
-                        if (angle > 35) {
-                          angle = 35
-                        }
-                        if (angle < 0) {
-                          angle = 0
-                        }
-                        let length = this.xMax*0.7;
-                        let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
-                        let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
-                        let xPos = this.xMax / 2 - x - this.radius;
-                        let yPos = y - this.radius;
-                        this.dataDoc.startPosX = xPos;
-                        this.dataDoc.startPosY = yPos;
-                        let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
-                        this.dataDoc.pendulumAngle = angle;
-                        this.dataDoc.pendulumLength = length;
-                        this.dataDoc.startPendulumAngle = angle;
-                        this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle;
-                      }}
-                    />
-                  </div>
-                </div>}
-                {this.dataDoc.simulationType == "Inclined Plane" && <div className="mechanicsSimulationSettingsMenuRow">
-                  <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Inclined plane angle</p></div>
-                  <div>
-                    <input 
-                      type="number" 
-                      value={this.dataDoc.wedgeAngle} 
-                      max={70} 
-                      min={0} 
-                      step={1} 
-                      onInput={(e) => {
-                        let angle = e.target.value ?? 0
-                        if (angle > 70) {
-                          angle = 70
-                        } 
-                        if (angle < 0) {
-                          angle = 0
-                        }
-                        this.dataDoc.wedgeAngle = angle
-                        this.changeWedgeBasedOnNewAngle(angle)
-                      }}
-                    />
-                  </div>
-                </div>}
-              </div>
-            )}
-          </div>
-          <div className="mechanicsSimulationEquationContainer">
-            <div className="mechanicsSimulationControls">
-            <div>
-                {this.dataDoc.simulationPaused && (
-                <button onClick={() => {
-                  this.dataDoc.simulationPaused = false}
-                } >START</button>
-                )}
-                {!this.dataDoc.simulationPaused && (
-                <button onClick={() => {
-                  this.dataDoc.simulationPaused = true}
-                } >PAUSE</button>
-                )}
-                {this.dataDoc.simulationPaused && (
-                <button onClick={() => {
-                  this.dataDoc.simulationReset = !this.dataDoc.simulationReset}
-                } >RESET</button>
-                )}
-                {this.dataDoc.simulationPaused && ( <button onClick={() => {
-                  if (!this.dataDoc.pendulum && !this.dataDoc.wedge) {
-                    this.addWedge()
-                    this.setToWedgeDefault()
-                    this.dataDoc.simulationType = "Inclined Plane"
-                    this.dataDoc.elasticCollisions = false
-                  }
-                  else if (!this.dataDoc.pendulum && this.dataDoc.wedge) {
-                    this.setToPendulumDefault()
-                    this.addPendulum()
-                    this.dataDoc.simulationType = "Pendulum"
-                    this.dataDoc.elasticCollisions = false
-                  }
-                  else {
-                    this.setToWeightDefault()
-                    this.addWeight()
-                    this.dataDoc.simulationType = "Free Weight"
-                  }
-                  this.dataDoc.simulationReset = !this.dataDoc.simulationReset
-                }} >TYPE</button>)}
-                <button onClick={() => {this.menuIsOpen=true; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}>MENU</button>
-                </div>
-            </div>
-          </div>
-        </div>
-      </div>
-      );
-    }
   }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

