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

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

(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 f27843ab0..3ae281177 100644
--- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
@@ -198,7 +198,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi
     this.dataDoc.mass2 = this.dataDoc.mass2 ?? 1;
   }
 
-  componentDidUpdate() {
+  componentDidUpdate(prevProps, prevState) {
     this.xMax = this.layoutDoc._width;
     this.yMax = this.layoutDoc._height;
     this.radius = 0.1*this.layoutDoc._height;
@@ -436,6 +436,410 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi
     this.dataDoc.reviewStaticAngle = (180 - angle);
   };
 
+  // Solve for the correct answers to the generated problem
+  getAnswersToQuestion = (
+    question: QuestionTemplate,
+    questionVars: number[]
+  ) => {
+    const solutions: number[] = [];
+
+    let theta: number = Number(this.dataDoc.wedgeAngle);
+    let index = question.variablesForQuestionSetup.indexOf("theta - max 45");
+    if (index >= 0) {
+      theta = questionVars[index];
+    }
+    let muS: number = Number(this.dataDoc.coefficientOfStaticFriction);
+    index = question.variablesForQuestionSetup.indexOf(
+      "coefficient of static friction"
+    );
+    if (index >= 0) {
+      muS = questionVars[index];
+    }
+
+    for (let i = 0; i < question.answerSolutionDescriptions.length; i++) {
+      const description = question.answerSolutionDescriptions[i];
+      if (!isNaN(Number(description))) {
+        solutions.push(Number(description));
+      } else if (description == "solve normal force angle from wedge angle") {
+        solutions.push(90 - theta);
+      } else if (
+        description == "solve normal force magnitude from wedge angle"
+      ) {
+        solutions.push(Math.abs(this.dataDoc.gravity) * Math.cos((theta / 180) * Math.PI));
+      } else if (
+        description ==
+        "solve static force magnitude from wedge angle given equilibrium"
+      ) {
+        let normalForceMagnitude =
+          Math.abs(this.dataDoc.gravity) * Math.cos((theta / 180) * Math.PI);
+        let normalForceAngle = 90 - theta;
+        let frictionForceAngle = 180 - theta;
+        let frictionForceMagnitude =
+          (-normalForceMagnitude *
+            Math.sin((normalForceAngle * Math.PI) / 180) +
+            Math.abs(this.dataDoc.gravity)) /
+          Math.sin((frictionForceAngle * Math.PI) / 180);
+        solutions.push(frictionForceMagnitude);
+      } else if (
+        description ==
+        "solve static force angle from wedge angle given equilibrium"
+      ) {
+        solutions.push(180 - theta);
+      } else if (
+        description ==
+        "solve minimum static coefficient from wedge angle given equilibrium"
+      ) {
+        let normalForceMagnitude =
+          Math.abs(this.dataDoc.gravity) * Math.cos((theta / 180) * Math.PI);
+        let normalForceAngle = 90 - theta;
+        let frictionForceAngle = 180 - theta;
+        let frictionForceMagnitude =
+          (-normalForceMagnitude *
+            Math.sin((normalForceAngle * Math.PI) / 180) +
+            Math.abs(this.dataDoc.gravity)) /
+          Math.sin((frictionForceAngle * Math.PI) / 180);
+        let frictionCoefficient = frictionForceMagnitude / normalForceMagnitude;
+        solutions.push(frictionCoefficient);
+      } else if (
+        description ==
+        "solve maximum wedge angle from coefficient of static friction given equilibrium"
+      ) {
+        solutions.push((Math.atan(muS) * 180) / Math.PI);
+      }
+    }
+    this.dataDoc.selectedSolutions = (solutions);
+    return solutions;
+  };
+
+  // In review mode, check if input answers match correct answers and optionally generate alert
+  checkAnswers = (showAlert: boolean = true) => {
+    let error: boolean = false;
+    let epsilon: number = 0.01;
+    if (this.dataDoc.selectedQuestion) {
+      for (let i = 0; i < this.dataDoc.selectedQuestion.answerParts.length; i++) {
+        if (this.dataDoc.selectedQuestion.answerParts[i] == "force of gravity") {
+          if (
+            Math.abs(this.dataDoc.reviewGravityMagnitude - this.dataDoc.selectedSolutions[i]) > epsilon
+          ) {
+            error = true;
+          }
+        } else if (this.dataDoc.selectedQuestion.answerParts[i] == "angle of gravity") {
+          if (Math.abs(this.dataDoc.reviewGravityAngle - this.dataDoc.selectedSolutions[i]) > epsilon) {
+            error = true;
+          }
+        } else if (this.dataDoc.selectedQuestion.answerParts[i] == "normal force") {
+          if (
+            Math.abs(this.dataDoc.reviewNormalMagnitude - this.dataDoc.selectedSolutions[i]) > epsilon
+          ) {
+            error = true;
+          }
+        } else if (this.dataDoc.selectedQuestion.answerParts[i] == "angle of normal force") {
+          if (Math.abs(this.dataDoc.reviewNormalAngle - this.dataDoc.selectedSolutions[i]) > epsilon) {
+            error = true;
+          }
+        } else if (
+          this.dataDoc.selectedQuestion.answerParts[i] == "force of static friction"
+        ) {
+          if (
+            Math.abs(this.dataDoc.reviewStaticMagnitude - this.dataDoc.selectedSolutions[i]) > epsilon
+          ) {
+            error = true;
+          }
+        } else if (
+          this.dataDoc.selectedQuestion.answerParts[i] == "angle of static friction"
+        ) {
+          if (Math.abs(this.dataDoc.reviewStaticAngle - this.dataDoc.selectedSolutions[i]) > epsilon) {
+            error = true;
+          }
+        } else if (
+          this.dataDoc.selectedQuestion.answerParts[i] == "coefficient of static friction"
+        ) {
+          if (
+            Math.abs(
+              Number(this.dataDoc.coefficientOfStaticFriction) - this.dataDoc.selectedSolutions[i]
+            ) > epsilon
+          ) {
+            error = true;
+          }
+        } else if (this.dataDoc.selectedQuestion.answerParts[i] == "wedge angle") {
+          if (Math.abs(Number(this.dataDoc.wedgeAngle) - this.dataDoc.selectedSolutions[i]) > epsilon) {
+            error = true;
+          }
+        }
+      }
+    }
+    if (showAlert) {
+      if (!error) {
+        this.dataDoc.simulationPaused = (false);
+        setTimeout(() => {
+          this.dataDoc.simulationPaused = (true);
+        }, 3000);
+      } else {
+        this.dataDoc.simulationPaused = (false);
+        setTimeout(() => {
+          this.dataDoc.simulationPaused = (true);
+        }, 3000);
+      }
+    }
+    if (this.dataDoc.selectedQuestion.goal == "noMovement") {
+      if (!error) {
+        this.dataDoc.noMovement = (true);
+      } else {
+        this.dataDoc.roMovement = (false);
+      }
+    }
+  };
+
+  // Reset all review values to default
+  resetReviewValuesToDefault = () => {
+    this.dataDoc.reviewGravityMagnitude = (0);
+    this.dataDoc.reviewGravityAngle = (0);
+    this.dataDoc.reviewNormalMagnitude = (0);
+    this.dataDoc.reviewNormalAngle = (0);
+    this.dataDoc.reviewStaticMagnitude = (0);
+    this.dataDoc.reviewStaticAngle = (0);
+    this.dataDoc.coefficientOfKineticFriction = (0);
+    this.dataDoc.simulationPaused = (true);
+    this.dataDoc.answerInputFields = (<div></div>);
+  };
+
+  // In review mode, reset problem variables and generate a new question
+  generateNewQuestion = () => {
+    this.resetReviewValuesToDefault();
+
+    const vars: number[] = [];
+    let question: QuestionTemplate = questions.inclinePlane[0];
+
+    if (this.dataDoc.simulationType == "Inclined Plane") {
+      if (this.dataDoc.questionNumber == questions.inclinePlane.length - 1) {
+        this.dataDoc.questionNumber = (0);
+      } else {
+        this.dataDoc.questionNumber =(questionNumber + 1);
+      }
+      question = questions.inclinePlane[this.dataDoc.questionNumber];
+
+      let coefficient = 0;
+      let wedgeAngle = 0;
+
+      for (let i = 0; i < question.variablesForQuestionSetup.length; i++) {
+        if (question.variablesForQuestionSetup[i] == "theta - max 45") {
+          let randValue = Math.floor(Math.random() * 44 + 1);
+          vars.push(randValue);
+          wedgeAngle = randValue;
+        } else if (
+          question.variablesForQuestionSetup[i] ==
+          "coefficient of static friction"
+        ) {
+          let randValue = Math.round(Math.random() * 1000) / 1000;
+          vars.push(randValue);
+          coefficient = randValue;
+        }
+      }
+      this.dataDoc.wedgeAngle = (wedgeAngle);
+      this.changeWedgeBasedOnNewAngle(wedgeAngle);
+      this.dataDoc.coefficientOfStaticFriction = (coefficient);
+      this.dataDoc.reviewCoefficient = coefficient;
+    }
+    let q = "";
+    for (let i = 0; i < question.questionSetup.length; i++) {
+      q += question.questionSetup[i];
+      if (i != question.questionSetup.length - 1) {
+        q += vars[i];
+        if (question.variablesForQuestionSetup[i].includes("theta")) {
+          q +=
+            " degree (≈" +
+            Math.round((1000 * (vars[i] * Math.PI)) / 180) / 1000 +
+            " rad)";
+        }
+      }
+    }
+    this.dataDoc.questionVariables = vars;
+    this.dataDoc.selectedQuestion = (question);
+    this.dataDoc.questionPartOne = (q);
+    this.dataDoc.questionPartTwo = (question.question);
+    const answers = this.getAnswersToQuestion(question, vars);
+    this.generateInputFieldsForQuestion(false, question, answers);
+    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
+  };
+
+  // Generate answerInputFields for new review question
+  generateInputFieldsForQuestion = (
+    showIcon: boolean = false,
+    question: QuestionTemplate = this.dataDoc.selectedQuestion,
+    answers: number[] = this.dataDoc.selectedSolutions
+  ) => {
+    let answerInput = [];
+    const d = new Date();
+    for (let i = 0; i < question.answerParts.length; i++) {
+      if (question.answerParts[i] == "force of gravity") {
+        this.dataDoc.reviewGravityMagnitude = (0);
+        answerInput.push(
+          <div key={i + d.getTime()}>
+            <InputField
+              label={<p>Gravity magnitude</p>}
+              lowerBound={0}
+              changeValue={this.dataDoc.reviewGravityMagnitude}
+              step={0.1}
+              unit={"N"}
+              upperBound={50}
+              value={this.dataDoc.reviewGravityMagnitude}
+              showIcon={showIcon}
+              correctValue={answers[i]}
+              labelWidth={"7em"}
+            />
+          </div>
+        );
+      } else if (question.answerParts[i] == "angle of gravity") {
+        this.dataDoc.reviewGravityAngle = (0);
+        answerInput.push(
+          <div key={i + d.getTime()}>
+            <InputField
+              label={<p>Gravity angle</p>}
+              lowerBound={0}
+              changeValue={this.dataDoc.reviewGravityAngle}
+              step={1}
+              unit={"°"}
+              upperBound={360}
+              value={this.dataDoc.reviewGravityAngle}
+              radianEquivalent={true}
+              showIcon={showIcon}
+              correctValue={answers[i]}
+              labelWidth={"7em"}
+            />
+          </div>
+        );
+      } else if (question.answerParts[i] == "normal force") {
+        this.dataDoc.reviewNormalMagnitude = (0);
+        answerInput.push(
+          <div key={i + d.getTime()}>
+            <InputField
+              label={<p>Normal force magnitude</p>}
+              lowerBound={0}
+              changeValue={this.dataDoc.reviewNormalMagnitude}
+              step={0.1}
+              unit={"N"}
+              upperBound={50}
+              value={this.dataDoc.reviewNormalMagnitude}
+              showIcon={showIcon}
+              correctValue={answers[i]}
+              labelWidth={"7em"}
+            />
+          </div>
+        );
+      } else if (question.answerParts[i] == "angle of normal force") {
+        this.dataDoc.reviewNormalAngle = (0);
+        answerInput.push(
+          <div key={i + d.getTime()}>
+            <InputField
+              label={<p>Normal force angle</p>}
+              lowerBound={0}
+              changeValue={this.dataDoc.reviewNormalAngle}
+              step={1}
+              unit={"°"}
+              upperBound={360}
+              value={this.dataDoc.reviewNormalAngle}
+              radianEquivalent={true}
+              showIcon={showIcon}
+              correctValue={answers[i]}
+              labelWidth={"7em"}
+            />
+          </div>
+        );
+      } else if (question.answerParts[i] == "force of static friction") {
+        this.dataDoc.reviewStaticMagnitude = (0);
+        answerInput.push(
+          <div key={i + d.getTime()}>
+            <InputField
+              label={<p>Static friction magnitude</p>}
+              lowerBound={0}
+              changeValue={this.dataDoc.reviewStaticMagnitude}
+              step={0.1}
+              unit={"N"}
+              upperBound={50}
+              value={this.dataDoc.reviewStaticMagnitude}
+              showIcon={showIcon}
+              correctValue={answers[i]}
+              labelWidth={"7em"}
+            />
+          </div>
+        );
+      } else if (question.answerParts[i] == "angle of static friction") {
+        this.dataDoc.reviewStaticAngle = (0);
+        answerInput.push(
+          <div key={i + d.getTime()}>
+            <InputField
+              label={<p>Static friction angle</p>}
+              lowerBound={0}
+              changeValue={this.dataDoc.reviewStaticAngle}
+              step={1}
+              unit={"°"}
+              upperBound={360}
+              value={this.dataDoc.reviewStaticAngle}
+              radianEquivalent={true}
+              showIcon={showIcon}
+              correctValue={answers[i]}
+              labelWidth={"7em"}
+            />
+          </div>
+        );
+      } else if (question.answerParts[i] == "coefficient of static friction") {
+        this.updateReviewForcesBasedOnCoefficient(0);
+        answerInput.push(
+          <div key={i + d.getTime()}>
+            <InputField
+              label={
+                <Box>
+                  &mu;<sub>s</sub>
+                </Box>
+              }
+              lowerBound={0}
+              changeValue={this.dataDoc.coefficientOfStaticFriction}
+              step={0.1}
+              unit={""}
+              upperBound={1}
+              value={this.dataDoc.coefficientOfStaticFriction}
+              effect={this.updateReviewForcesBasedOnCoefficient}
+              showIcon={showIcon}
+              correctValue={answers[i]}
+            />
+          </div>
+        );
+      } else if (question.answerParts[i] == "wedge angle") {
+        this.updateReviewForcesBasedOnAngle(0);
+        answerInput.push(
+          <div key={i + d.getTime()}>
+            <InputField
+              label={<Box>&theta;</Box>}
+              lowerBound={0}
+              changeValue={this.dataDoc.qedgeAngle}
+              step={1}
+              unit={"°"}
+              upperBound={49}
+              value={this.dataDoc.wedgeAngle}
+              effect={(val: number) => {
+                this.changeWedgeBasedOnNewAngle(val);
+                this.updateReviewForcesBasedOnAngle(val);
+              }}
+              radianEquivalent={true}
+              showIcon={showIcon}
+              correctValue={answers[i]}
+            />
+          </div>
+        );
+      }
+    }
+
+    this.dataDoc.answerInputFields = (
+      <div
+        style={{ display: "flex", flexDirection: "column", alignItems: "left" }}
+      >
+        {answerInput}
+      </div>
+    );
+  };
+  
+
+
 
   render () { 
   }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

