import "./PhysicsSimulationBox.scss"; import { FieldView, FieldViewProps } from './FieldView'; import React = require('react'); import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { observer } from 'mobx-react'; import "./PhysicsSimulationBox.scss"; import Weight from "./PhysicsSimulationWeight"; import Wall from "./PhysicsSimulationWall" import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CheckBox } from "../search/CheckBox"; 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; height: number; x1: number; y1: number; x2: number; y2: number; 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() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); } constructor(props: any) { super(props); } // 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[] = []; 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 }); // 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; // Used for review mode this.dataDoc.answerInputFields = this.dataDoc.answerInputFields ??
; 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; // 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(prevProps, prevState) { 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 = ( coefficient: number, width: number = this.wedgeWidth, height: number = this.wedgeHeight ) => { const normalForce: IForce = { description: "Normal Force", 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 * 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 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); yForce += frictionForce.magnitude * Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); if (yForce > 0) { frictionForce.magnitude = (-normalForce.magnitude * Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + 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 = [gravityForce, normalForce, frictionForce]; this.dataDoc.updatedForces = [gravityForce, normalForce, frictionForce]; this.dataDoc.componentForces = [ frictionForceComponent, normalForceComponent, gravityParallel, gravityPerpendicular, ]; } else { this.dataDoc.startForces = [gravityForce, normalForce]; this.dataDoc.updatedForces = [gravityForce, normalForce]; this.dataDoc.componentForces = [ normalForceComponent, gravityParallel, gravityPerpendicular, ]; } }; // Change wedge height and width and weight position to match new wedge angle changeWedgeBasedOnNewAngle = (angle: number) => { let width = 0; let height = 0; if (angle < 50) { width = 400; height = Math.tan((angle * Math.PI) / 180) * 400; this.dataDoc.wedgeWidth = width; this.dataDoc.wedgeHeight = height; } else if (angle < 70) { width = 200; height = Math.tan((angle * Math.PI) / 180) * 200; this.dataDoc.wedgeWidth = width; this.dataDoc.wedgeHeight = height; } else { 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 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 = Math.round((this.xMax * 0.5 - 200) * 10) / 10; this.dataDoc.startPosY = this.getDisplayYPos(yPos); if (this.dataDoc.mode == "Freeform") { this.updateForcesWithFriction( Number(this.dataDoc.coefficientOfStaticFriction), width, height ); } }; // 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); }; // 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.reviewStaticMagnitude = (friction); 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 = (
); }; // 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(
Gravity magnitude

} lowerBound={0} changeValue={this.dataDoc.reviewGravityMagnitude} step={0.1} unit={"N"} upperBound={50} value={this.dataDoc.reviewGravityMagnitude} showIcon={showIcon} correctValue={answers[i]} labelWidth={"7em"} />
); } else if (question.answerParts[i] == "angle of gravity") { this.dataDoc.reviewGravityAngle = (0); answerInput.push(
Gravity angle

} lowerBound={0} changeValue={this.dataDoc.reviewGravityAngle} step={1} unit={"°"} upperBound={360} value={this.dataDoc.reviewGravityAngle} radianEquivalent={true} showIcon={showIcon} correctValue={answers[i]} labelWidth={"7em"} />
); } else if (question.answerParts[i] == "normal force") { this.dataDoc.reviewNormalMagnitude = (0); answerInput.push(
Normal force magnitude

} lowerBound={0} changeValue={this.dataDoc.reviewNormalMagnitude} step={0.1} unit={"N"} upperBound={50} value={this.dataDoc.reviewNormalMagnitude} showIcon={showIcon} correctValue={answers[i]} labelWidth={"7em"} />
); } else if (question.answerParts[i] == "angle of normal force") { this.dataDoc.reviewNormalAngle = (0); answerInput.push(
Normal force angle

} lowerBound={0} changeValue={this.dataDoc.reviewNormalAngle} step={1} unit={"°"} upperBound={360} value={this.dataDoc.reviewNormalAngle} radianEquivalent={true} showIcon={showIcon} correctValue={answers[i]} labelWidth={"7em"} />
); } else if (question.answerParts[i] == "force of static friction") { this.dataDoc.reviewStaticMagnitude = (0); answerInput.push(
Static friction magnitude

} lowerBound={0} changeValue={this.dataDoc.reviewStaticMagnitude} step={0.1} unit={"N"} upperBound={50} value={this.dataDoc.reviewStaticMagnitude} showIcon={showIcon} correctValue={answers[i]} labelWidth={"7em"} />
); } else if (question.answerParts[i] == "angle of static friction") { this.dataDoc.reviewStaticAngle = (0); answerInput.push(
Static friction angle

} lowerBound={0} changeValue={this.dataDoc.reviewStaticAngle} step={1} unit={"°"} upperBound={360} value={this.dataDoc.reviewStaticAngle} radianEquivalent={true} showIcon={showIcon} correctValue={answers[i]} labelWidth={"7em"} />
); } else if (question.answerParts[i] == "coefficient of static friction") { this.updateReviewForcesBasedOnCoefficient(0); answerInput.push(
μs } lowerBound={0} changeValue={this.dataDoc.coefficientOfStaticFriction} step={0.1} unit={""} upperBound={1} value={this.dataDoc.coefficientOfStaticFriction} effect={this.updateReviewForcesBasedOnCoefficient} showIcon={showIcon} correctValue={answers[i]} />
); } else if (question.answerParts[i] == "wedge angle") { this.updateReviewForcesBasedOnAngle(0); answerInput.push(
θ} 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]} />
); } } this.dataDoc.answerInputFields = (
{answerInput}
); }; render () { }