diff options
author | brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> | 2023-05-01 12:51:12 -0400 |
---|---|---|
committer | brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> | 2023-05-01 12:51:12 -0400 |
commit | f327a27d664f45c10a90a4464cd0fa5edec59b68 (patch) | |
tree | 2d5ede56c23493101f2f67a8c64be519dd6c298b /src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx | |
parent | 0cda1a8f8b4e3d79c30291685456c7cb62fd7e8e (diff) |
start adding box code
Diffstat (limited to 'src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx')
-rw-r--r-- | src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx | 745 |
1 files changed, 346 insertions, 399 deletions
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 |