aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx406
1 files changed, 405 insertions, 1 deletions
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