aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx')
-rw-r--r--src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx4533
1 files changed, 2086 insertions, 2447 deletions
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
index aaea988a2..ab93583df 100644
--- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
@@ -1,2531 +1,2170 @@
-import "./PhysicsSimulationBox.scss";
+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 './PhysicsSimulationBox.scss';
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 "./PhysicsSimulationBox.scss";
-import InputField from "./PhysicsSimulationInputField";
-import * as questions from "./PhysicsSimulationQuestions.json";
-import * as tutorials from "./PhysicsSimulationTutorial.json";
-import Wall from "./PhysicsSimulationWall";
-import Weight from "./PhysicsSimulationWeight";
+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 './PhysicsSimulationBox.scss';
+import InputField from './PhysicsSimulationInputField';
+import * as questions from './PhysicsSimulationQuestions.json';
+import * as tutorials from './PhysicsSimulationTutorial.json';
+import Wall from './PhysicsSimulationWall';
+import Weight from './PhysicsSimulationWeight';
+import { NumCast } from '../../../../fields/Types';
+import { HeightSym, WidthSym } from '../../../../fields/Doc';
interface IWallProps {
- length: number;
- xPos: number;
- yPos: number;
- angleInDegrees: number;
+ length: number;
+ xPos: number;
+ yPos: number;
+ angleInDegrees: number;
}
interface IForce {
- description: string;
- magnitude: number;
- directionInDegrees: number;
- component: boolean;
+ description: string;
+ magnitude: number;
+ directionInDegrees: number;
+ component: boolean;
}
interface VectorTemplate {
- top: number;
- left: number;
- width: number;
- height: number;
- x1: number;
- y1: number;
- x2: number;
- y2: number;
- weightX: number;
- weightY: number;
+ 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 }[];
+ 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;
+ question: string;
+ steps: {
+ description: string;
+ content: string;
+ forces: {
+ description: string;
+ magnitude: number;
+ directionInDegrees: number;
+ component: boolean;
+ }[];
+ showMagnitude: boolean;
}[];
- showMagnitude: boolean;
- }[];
}
@observer
-export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
-
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }
-
- constructor(props: any) {
- super(props);
- }
-
- // Constants
- xMin = 0;
- yMin = 0;
- xMax = 100;
- yMax = 100;
- color = `rgba(0,0,0,0.5)`;
- radius = 50;
- wallPositions: IWallProps[] = [];
+export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+ public static LayoutString(fieldKey: string) {
+ return FieldView.LayoutString(PhysicsSimulationBox, fieldKey);
+ }
- componentDidMount() {
- // Used throughout sims
- this.layoutDoc._width = 1000;
- this.layoutDoc._height = 800;
- this.xMax = this.layoutDoc._width*0.6;
- this.yMax = this.layoutDoc._height*0.9;
- 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 = "Freeform";
- this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0;
- this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0;
- 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 ?? Math.round((this.xMax * 0.5 - 200) * 10) / 10;
- this.dataDoc.startPosY = this.dataDoc.startPosY ?? this.getDisplayYPos(
- (400 - (0.08*this.layoutDoc._height)) * Math.tan((26 * Math.PI) / 180) + Math.sqrt(26)
- );
- this.dataDoc.startVelX = this.dataDoc.startVelX ?? 0;
- this.dataDoc.startVelY = this.dataDoc.startVelY ?? 0;
- this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0;
- this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [];
- this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0;
- this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0;
+ constructor(props: any) {
+ super(props);
+ }
- // Used for review mode
- // this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? null;
- // this.dataDoc.deleteMode = this.dataDoc.deleteMode ?? false;
- // this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? [];
- this.dataDoc.answers = [];
- this.dataDoc.showIcon = false;
- this.dataDoc.hintDialogueOpen = false;
- this.dataDoc.noMovement = false;
- this.dataDoc.questionNumber = 0;
- this.dataDoc.questionPartOne = "";
- this.dataDoc.questionPartTwo = "";
- this.dataDoc.reviewGravityAngle = 0;
- this.dataDoc.reviewGravityMagnitude = 0;
- this.dataDoc.reviewNormalAngle = 0;
- this.dataDoc.reviewNormalMagnitude = 0;
- this.dataDoc.reviewStaticAngle = 0;
- this.dataDoc.reviewStaticMagnitude = 0;
- this.dataDoc.selectedSolutions = [];
- this.dataDoc.selectedQuestion = this.dataDoc.selectedQuestion ?? questions.inclinePlane[0];
- // this.dataDoc.sketching = this.dataDoc.sketching ?? false;
+ // Constants
+ xMin = 0;
+ yMin = 0;
+ xMax = 100;
+ yMax = 100;
+ color = `rgba(0,0,0,0.5)`;
+ radius = 50;
+ wallPositions: IWallProps[] = [];
- // Used for tutorial mode
- this.dataDoc.selectedTutorial = this.dataDoc.selectedTutorial ?? tutorials.inclinePlane;
+ componentDidMount() {
+ // Used throughout sims
+ this.layoutDoc._width = 1000;
+ this.layoutDoc._height = 800;
+ this.xMax = this.layoutDoc._width * 0.6;
+ this.yMax = this.layoutDoc._height * 0.9;
+ 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 = 'Freeform';
+ this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0;
+ this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0;
+ 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 ?? Math.round((this.xMax * 0.5 - 200) * 10) / 10;
+ this.dataDoc.startPosY = this.dataDoc.startPosY ?? this.getDisplayYPos((400 - 0.08 * this.layoutDoc._height) * Math.tan((26 * Math.PI) / 180) + Math.sqrt(26));
+ this.dataDoc.startVelX = this.dataDoc.startVelX ?? 0;
+ this.dataDoc.startVelY = this.dataDoc.startVelY ?? 0;
+ this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0;
+ this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [];
+ this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0;
+ this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0;
- // Used for uniform circular motion
- this.dataDoc.circularMotionRadius = this.dataDoc.circularMotionRadius ?? 150;
+ // Used for review mode
+ // this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? null;
+ // this.dataDoc.deleteMode = this.dataDoc.deleteMode ?? false;
+ // this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? [];
+ this.dataDoc.answers = [];
+ this.dataDoc.showIcon = false;
+ this.dataDoc.hintDialogueOpen = false;
+ this.dataDoc.noMovement = false;
+ this.dataDoc.questionNumber = 0;
+ this.dataDoc.questionPartOne = '';
+ this.dataDoc.questionPartTwo = '';
+ this.dataDoc.reviewGravityAngle = 0;
+ this.dataDoc.reviewGravityMagnitude = 0;
+ this.dataDoc.reviewNormalAngle = 0;
+ this.dataDoc.reviewNormalMagnitude = 0;
+ this.dataDoc.reviewStaticAngle = 0;
+ this.dataDoc.reviewStaticMagnitude = 0;
+ this.dataDoc.selectedSolutions = [];
+ this.dataDoc.selectedQuestion = this.dataDoc.selectedQuestion ?? questions.inclinePlane[0];
+ // this.dataDoc.sketching = this.dataDoc.sketching ?? false;
- // 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 tutorial mode
+ this.dataDoc.selectedTutorial = this.dataDoc.selectedTutorial ?? tutorials.inclinePlane;
- // 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 uniform circular motion
+ this.dataDoc.circularMotionRadius = this.dataDoc.circularMotionRadius ?? 150;
- // 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) * this.xMax*0.5;
- this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? this.xMax*0.5;
+ // 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 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;
+ // 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;
- // Setup simulation
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode)
+ // 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) * this.xMax * 0.5;
+ this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? this.xMax * 0.5;
- // Create walls
- let walls = []
- walls.push({ length: this.xMax / this.layoutDoc._width * 100, xPos: 0, yPos: 0, angleInDegrees: 0 });
- walls.push({ length: this.xMax / this.layoutDoc._width * 100, xPos: 0, yPos: this.yMax / this.layoutDoc._height * 100, angleInDegrees: 0 });
- walls.push({ length: this.yMax / this.layoutDoc._height * 100, xPos: 0, yPos: 0, angleInDegrees: 90 });
- walls.push({ length: this.yMax / this.layoutDoc._height * 100, xPos: this.xMax / this.layoutDoc._width * 100, yPos: 0, angleInDegrees: 90 });
- this.wallPositions = walls
- }
+ // 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() {
- if (this.xMax != this.layoutDoc._width*0.6 || this.yMax != this.layoutDoc._height*0.9) {
- this.layoutDoc._width = Math.max(this.layoutDoc._width, 800)
- this.layoutDoc._height = Math.max(this.layoutDoc._height, 600)
- this.xMax = this.layoutDoc._width*0.6;
- this.yMax = this.layoutDoc._height*0.9;
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode)
- }
- }
+ // Setup simulation
+ this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
- setupSimulation = (simulationType: string, mode: string) => {
- this.dataDoc.simulationPaused = true;
- if (simulationType != "Circular Motion") {
- this.dataDoc.startVelX = 0;
- this.dataDoc.setStartVelY = 0;
- this.dataDoc.velocityXDisplay = (0);
- this.dataDoc.velocityYDisplay = (0);
+ // Create walls
+ let walls = [];
+ walls.push({ length: (this.xMax / this.layoutDoc._width) * 100, xPos: 0, yPos: 0, angleInDegrees: 0 });
+ walls.push({ length: (this.xMax / this.layoutDoc._width) * 100, xPos: 0, yPos: (this.yMax / this.layoutDoc._height) * 100, angleInDegrees: 0 });
+ walls.push({ length: (this.yMax / this.layoutDoc._height) * 100, xPos: 0, yPos: 0, angleInDegrees: 90 });
+ walls.push({ length: (this.yMax / this.layoutDoc._height) * 100, xPos: (this.xMax / this.layoutDoc._width) * 100, yPos: 0, angleInDegrees: 90 });
+ this.wallPositions = walls;
}
- if (mode == "Freeform") {
- this.dataDoc.showForceMagnitudes = (true);
- if (simulationType == "One Weight") {
- this.dataDoc.showComponentForces = false;
- this.dataDoc.startPosY = (this.yMin + (0.08*this.layoutDoc._height));
- this.dataDoc.startPosX = ((this.xMax + this.xMin) / 2 - (0.08*this.layoutDoc._height));
- this.dataDoc.positionYDisplay = (this.getDisplayYPos(this.yMin + (0.08*this.layoutDoc._height)));
- this.dataDoc.positionXDisplay = ((this.xMax + this.xMin) / 2 - (0.08*this.layoutDoc._height));
- this.dataDoc.updatedForces = ([
- {
- description: "Gravity",
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
- directionInDegrees: 270,
- component: false,
- },
- ]);
- this.dataDoc.startForces = ([
- {
- description: "Gravity",
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
- directionInDegrees: 270,
- component: false,
- },
- ]);
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- } else if (simulationType == "Inclined Plane") {
- this.changeWedgeBasedOnNewAngle(26);
- this.dataDoc.startForces = ([
- {
- description: "Gravity",
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
- directionInDegrees: 270,
- component: false,
- },
- ]);
- this.updateForcesWithFriction(Number(this.dataDoc.coefficientOfStaticFriction));
- } else if (simulationType == "Pendulum") {
- this.setupPendulum();
- } else if (simulationType == "Spring") {
- this.setupSpring();
- } else if (simulationType == "Circular Motion") {
- this.setupCircular(0);
- } else if (simulationType == "Pulley") {
- this.setupPulley();
- } else if (simulationType == "Suspension") {
- this.setupSuspension();
- }
- } else if (mode == "Review") {
- this.dataDoc.showComponentForces = (false);
- this.dataDoc.showForceMagnitudes = (true);
- this.dataDoc.showAcceleration = (false);
- this.dataDoc.showVelocity = (false);
- this.dataDoc.showForces= (true);
- this.generateNewQuestion();
- if (simulationType == "One Weight") {
- // TODO - one weight review problems
- } else if (simulationType == "Spring") {
- this.setupSpring();
- // TODO - spring review problems
- } else if (simulationType == "Inclined Plane") {
- this.dataDoc.updatedForces = ([]);
- this.dataDoc.startForces = ([]);
- } else if (simulationType == "Pendulum") {
- this.setupPendulum();
- // TODO - pendulum review problems
- } else if (simulationType == "Circular Motion") {
- this.setupCircular(0);
- // TODO - circular motion review problems
- } else if (simulationType == "Pulley") {
- this.setupPulley();
- // TODO - pulley tutorial review problems
- } else if (simulationType == "Suspension") {
- this.setupSuspension();
- // TODO - suspension tutorial review problems
- }
- } else if (mode == "Tutorial") {
- this.dataDoc.showComponentForces = (false);
- this.dataDoc.stepNumber = (0);
- this.dataDoc.showAcceleration = (false);
- if (this.dataDoc.simulationType != "Circular Motion") {
- this.dataDoc.velocityXDisplay = (0);
- this.dataDoc.velocityYDisplay = (0);
- this.dataDoc.showVelocity = (false);
- } else {
- this.dataDoc.velocityXDisplay = (20);
- this.dataDoc.velocityYDisplay = (0);
- this.dataDoc.showVelocity = (true);
- }
- if (this.dataDoc.simulationType == "One Weight") {
- this.dataDoc.showForces = (true);
- this.dataDoc.startPosY = (this.yMax - 100);
- this.dataDoc.startPosX = ((this.xMax + this.xMin) / 2 - (0.08*this.layoutDoc._height));
- this.dataDoc.selectedTutorial = (tutorials.freeWeight);
- this.dataDoc.startForces = (this.getForceFromJSON(tutorials.freeWeight.steps[0].forces));
- this.dataDoc.showForceMagnitudes = (tutorials.freeWeight.steps[0].showMagnitude);
- } else if (this.dataDoc.simulationType == "Spring") {
- this.dataDoc.showForces = (true);
- this.setupSpring();
- this.dataDoc.startPosY = (this.yMin + 200 + 19.62);
- this.dataDoc.startPosX = ((this.xMax + this.xMin) / 2 - (0.08*this.layoutDoc._height));
- this.dataDoc.selectedTutorial = (tutorials.spring);
- this.dataDoc.startForces = (this.getForceFromJSON(tutorials.spring.steps[0].forces));
- this.dataDoc.showForceMagnitudes = (tutorials.spring.steps[0].showMagnitude);
- } else if (this.dataDoc.simulationType == "Pendulum") {
- this.dataDoc.showForces = (true);
- const length = 300;
- const angle = 30;
- const x = length * Math.cos(((90 - angle) * Math.PI) / 180);
- const y = length * Math.sin(((90 - angle) * Math.PI) / 180);
- const xPos = this.xMax / 2 - x - (0.08*this.layoutDoc._height);
- const yPos = y - (0.08*this.layoutDoc._height) - 5;
- this.dataDoc.startPosX = (xPos);
- this.dataDoc.startPosY = (yPos);
- this.dataDoc.selectedTutorial = (tutorials.pendulum);
- this.dataDoc.startForces = (this.getForceFromJSON(tutorials.pendulum.steps[0].forces));
- this.dataDoc.showForceMagnitudes = (tutorials.pendulum.steps[0].showMagnitude);
- this.dataDoc.pendulumAngle = (30);
- this.dataDoc.pendulumLength = (300);
- this.dataDoc.adjustPendulumAngle = ({ angle: 30, length: 300 });
- } else if (this.dataDoc.simulationType == "Inclined Plane") {
- this.dataDoc.showForces = (true);
- this.dataDoc.wedgeAngle = (26);
- this.changeWedgeBasedOnNewAngle(26);
- this.dataDoc.selectedTutorial = (tutorials.inclinePlane);
- this.dataDoc.startForces = (
- this.getForceFromJSON(tutorials.inclinePlane.steps[0].forces)
- );
- this.dataDoc.showForceMagnitudes = (tutorials.inclinePlane.steps[0].showMagnitude);
- } else if (this.dataDoc.simulationType == "Circular Motion") {
- this.dataDoc.showForces = (true);
- this.setupCircular(40);
- this.dataDoc.selectedTutorial = (tutorials.circular);
- this.dataDoc.startForces = (this.getForceFromJSON(tutorials.circular.steps[0].forces));
- this.dataDoc.showForceMagnitudes = (tutorials.circular.steps[0].showMagnitude);
- } else if (this.dataDoc.simulationType == "Pulley") {
- this.dataDoc.showForces = (true);
- this.setupPulley();
- this.dataDoc.selectedTutorial = (tutorials.pulley);
- this.dataDoc.startForces = (this.getForceFromJSON(tutorials.pulley.steps[0].forces));
- this.dataDoc.showForceMagnitudes = (tutorials.pulley.steps[0].showMagnitude);
- } else if (this.dataDoc.simulationType == "Suspension") {
- this.dataDoc.showForces = (true);
- this.setupSuspension();
- this.dataDoc.selectedTutorial = (tutorials.suspension);
- this.dataDoc.startForces = (this.getForceFromJSON(tutorials.suspension.steps[0].forces));
- this.dataDoc.showForceMagnitudes = (tutorials.suspension.steps[0].showMagnitude);
- }
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
+ componentDidUpdate() {
+ if (this.xMax !== this.layoutDoc[WidthSym]() * 0.6 || this.yMax != this.layoutDoc[HeightSym]() * 0.9) {
+ this.layoutDoc._width = Math.max(this.layoutDoc[WidthSym](), 800);
+ this.layoutDoc._height = Math.max(this.layoutDoc[HeightSym](), 600);
+ this.xMax = this.layoutDoc._width * 0.6;
+ this.yMax = this.layoutDoc._height * 0.9;
+ this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ }
}
- }
- // Helper function to go between display and real values
- getDisplayYPos = (yPos: number) => {
- return this.yMax - yPos - 2 * (0.08*this.layoutDoc._height) + 5;
- };
- getYPosFromDisplay = (yDisplay: number) => {
- return this.yMax - yDisplay - 2 * (0.08*this.layoutDoc._height) + 5;
- };
+ setupSimulation = (simulationType: string, mode: string) => {
+ this.dataDoc.simulationPaused = true;
+ if (simulationType != 'Circular Motion') {
+ this.dataDoc.startVelX = 0;
+ this.dataDoc.setStartVelY = 0;
+ this.dataDoc.velocityXDisplay = 0;
+ this.dataDoc.velocityYDisplay = 0;
+ }
+ if (mode == 'Freeform') {
+ this.dataDoc.showForceMagnitudes = true;
+ if (simulationType == 'One Weight') {
+ this.dataDoc.showComponentForces = false;
+ this.dataDoc.startPosY = this.yMin + 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.startPosX = (this.xMax + this.xMin) / 2 - 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.positionYDisplay = this.getDisplayYPos(this.yMin + 0.08 * this.layoutDoc[HeightSym]());
+ this.dataDoc.positionXDisplay = (this.xMax + this.xMin) / 2 - 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.updatedForces = [
+ {
+ description: 'Gravity',
+ magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ directionInDegrees: 270,
+ component: false,
+ },
+ ];
+ this.dataDoc.startForces = [
+ {
+ description: 'Gravity',
+ magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ directionInDegrees: 270,
+ component: false,
+ },
+ ];
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ } else if (simulationType == 'Inclined Plane') {
+ this.changeWedgeBasedOnNewAngle(26);
+ this.dataDoc.startForces = [
+ {
+ description: 'Gravity',
+ magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ directionInDegrees: 270,
+ component: false,
+ },
+ ];
+ this.updateForcesWithFriction(Number(this.dataDoc.coefficientOfStaticFriction));
+ } else if (simulationType == 'Pendulum') {
+ this.setupPendulum();
+ } else if (simulationType == 'Spring') {
+ this.setupSpring();
+ } else if (simulationType == 'Circular Motion') {
+ this.setupCircular(0);
+ } else if (simulationType == 'Pulley') {
+ this.setupPulley();
+ } else if (simulationType == 'Suspension') {
+ this.setupSuspension();
+ }
+ } else if (mode == 'Review') {
+ this.dataDoc.showComponentForces = false;
+ this.dataDoc.showForceMagnitudes = true;
+ this.dataDoc.showAcceleration = false;
+ this.dataDoc.showVelocity = false;
+ this.dataDoc.showForces = true;
+ this.generateNewQuestion();
+ if (simulationType == 'One Weight') {
+ // TODO - one weight review problems
+ } else if (simulationType == 'Spring') {
+ this.setupSpring();
+ // TODO - spring review problems
+ } else if (simulationType == 'Inclined Plane') {
+ this.dataDoc.updatedForces = [];
+ this.dataDoc.startForces = [];
+ } else if (simulationType == 'Pendulum') {
+ this.setupPendulum();
+ // TODO - pendulum review problems
+ } else if (simulationType == 'Circular Motion') {
+ this.setupCircular(0);
+ // TODO - circular motion review problems
+ } else if (simulationType == 'Pulley') {
+ this.setupPulley();
+ // TODO - pulley tutorial review problems
+ } else if (simulationType == 'Suspension') {
+ this.setupSuspension();
+ // TODO - suspension tutorial review problems
+ }
+ } else if (mode == 'Tutorial') {
+ this.dataDoc.showComponentForces = false;
+ this.dataDoc.stepNumber = 0;
+ this.dataDoc.showAcceleration = false;
+ if (this.dataDoc.simulationType != 'Circular Motion') {
+ this.dataDoc.velocityXDisplay = 0;
+ this.dataDoc.velocityYDisplay = 0;
+ this.dataDoc.showVelocity = false;
+ } else {
+ this.dataDoc.velocityXDisplay = 20;
+ this.dataDoc.velocityYDisplay = 0;
+ this.dataDoc.showVelocity = true;
+ }
- // Update forces when coefficient of static friction changes in freeform mode
- updateForcesWithFriction = (
- coefficient: number,
- width: number = this.dataDoc.wedgeWidth,
- height: number = this.dataDoc.wedgeHeight
- ) => {
- const normalForce: IForce = {
- description: "Normal Force",
- magnitude: Math.abs(this.dataDoc.gravity) * Math.cos(Math.atan(height / width)) * this.dataDoc.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.dataDoc.gravity) *
- Math.cos(Math.atan(height / width)) *
- this.dataDoc.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.dataDoc.gravity) * this.dataDoc.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.dataDoc.gravity) * this.dataDoc.mass) /
- Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
- }
- const frictionForceComponent: IForce = {
- description: "Static Friction Force",
- magnitude:
- coefficient * Math.abs(this.dataDoc.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.dataDoc.gravity) * Math.cos(Math.atan(height / width)),
- directionInDegrees:
- 180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
- component: true,
+ if (this.dataDoc.simulationType == 'One Weight') {
+ this.dataDoc.showForces = true;
+ this.dataDoc.startPosY = this.yMax - 100;
+ this.dataDoc.startPosX = (this.xMax + this.xMin) / 2 - 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.selectedTutorial = tutorials.freeWeight;
+ this.dataDoc.startForces = this.getForceFromJSON(tutorials.freeWeight.steps[0].forces);
+ this.dataDoc.showForceMagnitudes = tutorials.freeWeight.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulationType == 'Spring') {
+ this.dataDoc.showForces = true;
+ this.setupSpring();
+ this.dataDoc.startPosY = this.yMin + 200 + 19.62;
+ this.dataDoc.startPosX = (this.xMax + this.xMin) / 2 - 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.selectedTutorial = tutorials.spring;
+ this.dataDoc.startForces = this.getForceFromJSON(tutorials.spring.steps[0].forces);
+ this.dataDoc.showForceMagnitudes = tutorials.spring.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulationType == 'Pendulum') {
+ this.dataDoc.showForces = true;
+ const length = 300;
+ const angle = 30;
+ const x = length * Math.cos(((90 - angle) * Math.PI) / 180);
+ const y = length * Math.sin(((90 - angle) * Math.PI) / 180);
+ const xPos = this.xMax / 2 - x - 0.08 * this.layoutDoc[HeightSym]();
+ const yPos = y - 0.08 * this.layoutDoc[HeightSym]() - 5;
+ this.dataDoc.startPosX = xPos;
+ this.dataDoc.startPosY = yPos;
+ this.dataDoc.selectedTutorial = tutorials.pendulum;
+ this.dataDoc.startForces = this.getForceFromJSON(tutorials.pendulum.steps[0].forces);
+ this.dataDoc.showForceMagnitudes = tutorials.pendulum.steps[0].showMagnitude;
+ this.dataDoc.pendulumAngle = 30;
+ this.dataDoc.pendulumLength = 300;
+ this.dataDoc.adjustPendulumAngle = { angle: 30, length: 300 };
+ } else if (this.dataDoc.simulationType == 'Inclined Plane') {
+ this.dataDoc.showForces = true;
+ this.dataDoc.wedgeAngle = 26;
+ this.changeWedgeBasedOnNewAngle(26);
+ this.dataDoc.selectedTutorial = tutorials.inclinePlane;
+ this.dataDoc.startForces = this.getForceFromJSON(tutorials.inclinePlane.steps[0].forces);
+ this.dataDoc.showForceMagnitudes = tutorials.inclinePlane.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulationType == 'Circular Motion') {
+ this.dataDoc.showForces = true;
+ this.setupCircular(40);
+ this.dataDoc.selectedTutorial = tutorials.circular;
+ this.dataDoc.startForces = this.getForceFromJSON(tutorials.circular.steps[0].forces);
+ this.dataDoc.showForceMagnitudes = tutorials.circular.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulationType == 'Pulley') {
+ this.dataDoc.showForces = true;
+ this.setupPulley();
+ this.dataDoc.selectedTutorial = tutorials.pulley;
+ this.dataDoc.startForces = this.getForceFromJSON(tutorials.pulley.steps[0].forces);
+ this.dataDoc.showForceMagnitudes = tutorials.pulley.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulationType == 'Suspension') {
+ this.dataDoc.showForces = true;
+ this.setupSuspension();
+ this.dataDoc.selectedTutorial = tutorials.suspension;
+ this.dataDoc.startForces = this.getForceFromJSON(tutorials.suspension.steps[0].forces);
+ this.dataDoc.showForceMagnitudes = tutorials.suspension.steps[0].showMagnitude;
+ }
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }
};
- const gravityParallel: IForce = {
- description: "Gravity Parallel Component",
- magnitude:
- this.dataDoc.mass *
- Math.abs(this.dataDoc.gravity) *
- Math.sin(Math.PI / 2 - Math.atan(height / width)),
- directionInDegrees:
- 180 - 90 - (Math.atan(height / width) * 180) / Math.PI + 180,
- component: true,
+
+ // Helper function to go between display and real values
+ getDisplayYPos = (yPos: number) => {
+ return this.yMax - yPos - 2 * (0.08 * this.layoutDoc[HeightSym]()) + 5;
};
- const gravityPerpendicular: IForce = {
- description: "Gravity Perpendicular Component",
- magnitude:
- this.dataDoc.mass *
- Math.abs(this.dataDoc.gravity) *
- Math.cos(Math.PI / 2 - Math.atan(height / width)),
- directionInDegrees: 360 - (Math.atan(height / width) * 180) / Math.PI,
- component: true,
+ getYPosFromDisplay = (yDisplay: number) => {
+ return this.yMax - yDisplay - 2 * (0.08 * this.layoutDoc[HeightSym]()) + 5;
};
- const gravityForce: IForce = {
- description: "Gravity",
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 270,
- component: false,
+
+ // Update forces when coefficient of static friction changes in freeform mode
+ updateForcesWithFriction = (coefficient: number, width: number = this.dataDoc.wedgeWidth, height: number = this.dataDoc.wedgeHeight) => {
+ const normalForce: IForce = {
+ description: 'Normal Force',
+ magnitude: Math.abs(this.dataDoc.gravity) * Math.cos(Math.atan(height / width)) * this.dataDoc.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.dataDoc.gravity) * Math.cos(Math.atan(height / width)) * this.dataDoc.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.dataDoc.gravity) * this.dataDoc.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.dataDoc.gravity) * this.dataDoc.mass) / Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
+ }
+ const frictionForceComponent: IForce = {
+ description: 'Static Friction Force',
+ magnitude: coefficient * Math.abs(this.dataDoc.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.dataDoc.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.dataDoc.mass * Math.abs(this.dataDoc.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.dataDoc.mass * Math.abs(this.dataDoc.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.dataDoc.mass * Math.abs(this.dataDoc.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];
+ }
};
- 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) => {
- this.dataDoc.wedgeWidth = this.xMax*0.5;
- this.dataDoc.wedgeHeight = Math.tan((angle * Math.PI) / 180) * this.xMax*0.5;
+ // Change wedge height and width and weight position to match new wedge angle
+ changeWedgeBasedOnNewAngle = (angle: number) => {
+ this.dataDoc.wedgeWidth = this.xMax * 0.5;
+ this.dataDoc.wedgeHeight = Math.tan((angle * Math.PI) / 180) * this.xMax * 0.5;
- // update weight position based on updated wedge width/height
- let yPos = this.yMax - (0.08*this.layoutDoc._height*2) - Math.tan((angle * Math.PI) / 180) * this.xMax*0.5;
+ // update weight position based on updated wedge width/height
+ let yPos = this.yMax - 0.08 * this.layoutDoc[HeightSym]() * 2 - Math.tan((angle * Math.PI) / 180) * this.xMax * 0.5;
- // adjust y position
- if (angle >= 5 && angle < 10) {
- yPos += 0.08*this.layoutDoc._height*0.1
- } else if (angle >= 10 && angle < 15) {
- yPos += 0.08*this.layoutDoc._height*0.23
- } else if (angle >= 15 && angle < 20) {
- yPos += 0.08*this.layoutDoc._height*0.26
- } else if (angle >= 20 && angle < 25) {
- yPos += 0.08*this.layoutDoc._height*0.33
- } else if (angle >= 25 && angle < 30) {
- yPos += 0.08*this.layoutDoc._height*0.35
- } else if (angle >= 30 && angle < 35) {
- yPos += 0.08*this.layoutDoc._height*0.40
- } else if (angle >= 35 && angle < 40) {
- yPos += 0.08*this.layoutDoc._height*0.45
- } else if (angle >= 40 && angle < 45) {
- yPos += 0.08*this.layoutDoc._height*0.47
- } else if (angle >= 45) {
- yPos += 0.08*this.layoutDoc._height*0.52
- }
-
-
- this.dataDoc.startPosX = this.xMax*0.25;
- this.dataDoc.startPosY = yPos;
- if (this.dataDoc.mode == "Freeform") {
- this.updateForcesWithFriction(
- Number(this.dataDoc.coefficientOfStaticFriction),
- this.xMax*0.5,
- Math.tan((angle * Math.PI) / 180) * this.xMax*0.5
- );
- }
- };
+ // adjust y position
+ if (angle >= 5 && angle < 10) {
+ yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.1;
+ } else if (angle >= 10 && angle < 15) {
+ yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.23;
+ } else if (angle >= 15 && angle < 20) {
+ yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.26;
+ } else if (angle >= 20 && angle < 25) {
+ yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.33;
+ } else if (angle >= 25 && angle < 30) {
+ yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.35;
+ } else if (angle >= 30 && angle < 35) {
+ yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.4;
+ } else if (angle >= 35 && angle < 40) {
+ yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.45;
+ } else if (angle >= 40 && angle < 45) {
+ yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.47;
+ } else if (angle >= 45) {
+ yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.52;
+ }
- // 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);
- };
+ this.dataDoc.startPosX = this.xMax * 0.25;
+ this.dataDoc.startPosY = yPos;
+ if (this.dataDoc.mode == 'Freeform') {
+ this.updateForcesWithFriction(Number(this.dataDoc.coefficientOfStaticFriction), this.xMax * 0.5, Math.tan((angle * Math.PI) / 180) * this.xMax * 0.5);
+ }
+ };
- // 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);
- };
+ // 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;
+ };
- // Solve for the correct answers to the generated problem
- getAnswersToQuestion = (
- question: QuestionTemplate,
- questionVars: number[]
- ) => {
- const solutions: number[] = [];
+ // 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;
+ };
- 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];
- }
+ // Solve for the correct answers to the generated problem
+ getAnswersToQuestion = (question: QuestionTemplate, questionVars: number[]) => {
+ const solutions: number[] = [];
- 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;
- };
+ 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];
+ }
- // 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;
- }
+ 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);
+ }
}
- }
- }
- 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);
- }
- }
- };
+ this.dataDoc.selectedSolutions = solutions;
+ return solutions;
+ };
- // 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);
- };
+ // 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;
+ }
+ }
+ };
- // In review mode, reset problem variables and generate a new question
- generateNewQuestion = () => {
- this.resetReviewValuesToDefault();
+ // 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;
+ };
+
+ // In review mode, reset problem variables and generate a new question
+ generateNewQuestion = () => {
+ this.resetReviewValuesToDefault();
- const vars: number[] = [];
- let question: QuestionTemplate = questions.inclinePlane[0];
+ 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 =(this.dataDoc.questionNumber + 1);
- }
- question = questions.inclinePlane[this.dataDoc.questionNumber];
+ if (this.dataDoc.simulationType == 'Inclined Plane') {
+ if (this.dataDoc.questionNumber == questions.inclinePlane.length - 1) {
+ this.dataDoc.questionNumber = 0;
+ } else {
+ this.dataDoc.questionNumber = this.dataDoc.questionNumber + 1;
+ }
+ question = questions.inclinePlane[this.dataDoc.questionNumber];
- let coefficient = 0;
- let wedgeAngle = 0;
+ 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;
+ 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;
}
- }
- 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)";
+ 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);
- this.dataDoc.answers = this.getAnswersToQuestion(question, vars);
- //this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- };
-
- // Default setup for uniform circular motion simulation
- setupCircular = (value: number) => {
- this.dataDoc.showComponentForces = (false);
- this.dataDoc.startVelY = (0);
- this.dataDoc.startVelX = (value);
- let xPos = (this.xMax + this.xMin) / 2 - (0.08*this.layoutDoc._height);
- let yPos = (this.yMax + this.yMin) / 2 + this.dataDoc.circularMotionRadius - (0.08*this.layoutDoc._height);
- this.dataDoc.startPosY = (yPos);
- this.dataDoc.startPosX = (xPos);
- const tensionForce: IForce = {
- description: "Centripetal Force",
- magnitude: (this.dataDoc.startVelX ** 2 * this.dataDoc.mass) / this.dataDoc.circularMotionRadius,
- directionInDegrees: 90,
- component: false,
+ this.dataDoc.questionVariables = vars;
+ this.dataDoc.selectedQuestion = question;
+ this.dataDoc.questionPartOne = q;
+ this.dataDoc.questionPartTwo = question.question;
+ this.dataDoc.answers = this.getAnswersToQuestion(question, vars);
+ //this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
};
- this.dataDoc.updatedForces = ([tensionForce]);
- this.dataDoc.startForces = ([tensionForce]);
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- };
- // Default setup for pendulum simulation
- setupPendulum = () => {
- const length = 300;
- const angle = 30;
- const x = length * Math.cos(((90 - angle) * Math.PI) / 180);
- const y = length * Math.sin(((90 - angle) * Math.PI) / 180);
- const xPos = this.xMax / 2 - x - (0.08*this.layoutDoc._height);
- const yPos = y - (0.08*this.layoutDoc._height) - 5;
- this.dataDoc.startPosX = (xPos);
- this.dataDoc.startPosY = (yPos);
- const mag = this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.sin((60 * Math.PI) / 180);
- const forceOfTension: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: 90 - angle,
- component: false,
+ // Default setup for uniform circular motion simulation
+ setupCircular = (value: number) => {
+ this.dataDoc.showComponentForces = false;
+ this.dataDoc.startVelY = 0;
+ this.dataDoc.startVelX = value;
+ let xPos = (this.xMax + this.xMin) / 2 - 0.08 * this.layoutDoc[HeightSym]();
+ let yPos = (this.yMax + this.yMin) / 2 + this.dataDoc.circularMotionRadius - 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.startPosY = yPos;
+ this.dataDoc.startPosX = xPos;
+ const tensionForce: IForce = {
+ description: 'Centripetal Force',
+ magnitude: (this.dataDoc.startVelX ** 2 * this.dataDoc.mass) / this.dataDoc.circularMotionRadius,
+ directionInDegrees: 90,
+ component: false,
+ };
+ this.dataDoc.updatedForces = [tensionForce];
+ this.dataDoc.startForces = [tensionForce];
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
};
- const tensionComponent: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: 90 - angle,
- component: true,
- };
- const gravityParallel: IForce = {
- description: "Gravity Parallel Component",
- magnitude:
- this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.sin(((90 - angle) * Math.PI) / 180),
- directionInDegrees: -angle - 90,
- component: true,
- };
- const gravityPerpendicular: IForce = {
- description: "Gravity Perpendicular Component",
- magnitude:
- this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.cos(((90 - angle) * Math.PI) / 180),
- directionInDegrees: -angle,
- component: true,
- };
+ // Default setup for pendulum simulation
+ setupPendulum = () => {
+ const length = 300;
+ const angle = 30;
+ const x = length * Math.cos(((90 - angle) * Math.PI) / 180);
+ const y = length * Math.sin(((90 - angle) * Math.PI) / 180);
+ const xPos = this.xMax / 2 - x - 0.08 * this.layoutDoc[HeightSym]();
+ const yPos = y - 0.08 * this.layoutDoc[HeightSym]() - 5;
+ this.dataDoc.startPosX = xPos;
+ this.dataDoc.startPosY = yPos;
+ const mag = this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.sin((60 * Math.PI) / 180);
+ const forceOfTension: IForce = {
+ description: 'Tension',
+ magnitude: mag,
+ directionInDegrees: 90 - angle,
+ component: false,
+ };
- this.dataDoc.componentForces = ([
- tensionComponent,
- gravityParallel,
- gravityPerpendicular,
- ]);
- this.dataDoc.updatedForces = ([
- {
- description: "Gravity",
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 270,
- component: false,
- },
- forceOfTension,
- ]);
- this.dataDoc.startForces = ([
- {
- description: "Gravity",
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 270,
- component: false,
- },
- forceOfTension,
- ]);
- this.dataDoc.startPendulumAngle = (30);
- this.dataDoc.pendulumAngle = (30);
- this.dataDoc.pendulumLength = (300);
- this.dataDoc.adjustPendulumAngle = ({ angle: 30, length: 300 });
- };
+ const tensionComponent: IForce = {
+ description: 'Tension',
+ magnitude: mag,
+ directionInDegrees: 90 - angle,
+ component: true,
+ };
+ const gravityParallel: IForce = {
+ description: 'Gravity Parallel Component',
+ magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.sin(((90 - angle) * Math.PI) / 180),
+ directionInDegrees: -angle - 90,
+ component: true,
+ };
+ const gravityPerpendicular: IForce = {
+ description: 'Gravity Perpendicular Component',
+ magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.cos(((90 - angle) * Math.PI) / 180),
+ directionInDegrees: -angle,
+ component: true,
+ };
- // Default setup for spring simulation
- setupSpring = () => {
- this.dataDoc.showComponentForces = (false);
- const gravityForce: IForce = {
- description: "Gravity",
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
- directionInDegrees: 270,
- component: false,
+ this.dataDoc.componentForces = [tensionComponent, gravityParallel, gravityPerpendicular];
+ this.dataDoc.updatedForces = [
+ {
+ description: 'Gravity',
+ magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ directionInDegrees: 270,
+ component: false,
+ },
+ forceOfTension,
+ ];
+ this.dataDoc.startForces = [
+ {
+ description: 'Gravity',
+ magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ directionInDegrees: 270,
+ component: false,
+ },
+ forceOfTension,
+ ];
+ this.dataDoc.startPendulumAngle = 30;
+ this.dataDoc.pendulumAngle = 30;
+ this.dataDoc.pendulumLength = 300;
+ this.dataDoc.adjustPendulumAngle = { angle: 30, length: 300 };
};
- this.dataDoc.updatedForces = ([gravityForce]);
- this.dataDoc.startForces = ([gravityForce]);
- this.dataDoc.startPosX = (this.xMax / 2 - (0.08*this.layoutDoc._height));
- this.dataDoc.startPosY = (200);
- this.dataDoc.springConstant = (0.5);
- this.dataDoc.springRestLength = (200);
- this.dataDoc.springStartLength = (200);
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- };
- // Default setup for suspension simulation
- setupSuspension = () => {
- let xPos = (this.xMax + this.xMin) / 2 - (0.08*this.layoutDoc._height);
- let yPos = this.yMin + 200;
- this.dataDoc.startPosY = (yPos);
- this.dataDoc.startPosX = (xPos);
- this.dataDoc.positionYDisplay = (this.getDisplayYPos(yPos));
- this.dataDoc.positionXDisplay = (xPos);
- let tensionMag = (this.dataDoc.mass * Math.abs(this.dataDoc.gravity)) / (2 * Math.sin(Math.PI / 4));
- const tensionForce1: IForce = {
- description: "Tension",
- magnitude: tensionMag,
- directionInDegrees: 45,
- component: false,
- };
- const tensionForce2: IForce = {
- description: "Tension",
- magnitude: tensionMag,
- directionInDegrees: 135,
- component: false,
- };
- const grav: IForce = {
- description: "Gravity",
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 270,
- component: false,
+ // Default setup for spring simulation
+ setupSpring = () => {
+ this.dataDoc.showComponentForces = false;
+ const gravityForce: IForce = {
+ description: 'Gravity',
+ magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ directionInDegrees: 270,
+ component: false,
+ };
+ this.dataDoc.updatedForces = [gravityForce];
+ this.dataDoc.startForces = [gravityForce];
+ this.dataDoc.startPosX = this.xMax / 2 - 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.startPosY = 200;
+ this.dataDoc.springConstant = 0.5;
+ this.dataDoc.springRestLength = 200;
+ this.dataDoc.springStartLength = 200;
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
};
- this.dataDoc.updatedForces = ([tensionForce1, tensionForce2, grav]);
- this.dataDoc.startForces = ([tensionForce1, tensionForce2, grav]);
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- };
- // Default setup for pulley simulation
- setupPulley = () => {
- this.dataDoc.showComponentForces = (false);
- this.dataDoc.startPosY = ((this.yMax + this.yMin) / 2);
- this.dataDoc.startPosX = ((this.xMin + this.xMax) / 2 - 2*(0.08*this.layoutDoc._height)-5);
- this.dataDoc.positionYDisplay = (this.getDisplayYPos((this.yMax + this.yMin) / 2));
- this.dataDoc.positionXDisplay = ((this.xMin + this.xMax) / 2 - 2*(0.08*this.layoutDoc._height)-5);
- let a = (-1 * ((this.dataDoc.mass - this.dataDoc.mass2) * Math.abs(this.dataDoc.gravity))) / (this.dataDoc.mass + this.dataDoc.mass2);
- const gravityForce1: IForce = {
- description: "Gravity",
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 270,
- component: false,
- };
- const tensionForce1: IForce = {
- description: "Tension",
- magnitude: this.dataDoc.mass * a + this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 90,
- component: false,
- };
- a *= -1;
- const gravityForce2: IForce = {
- description: "Gravity",
- magnitude: this.dataDoc.mass2 * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 270,
- component: false,
- };
- const tensionForce2: IForce = {
- description: "Tension",
- magnitude: this.dataDoc.mass2 * a + this.dataDoc.mass2 * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 90,
- component: false,
+ // Default setup for suspension simulation
+ setupSuspension = () => {
+ let xPos = (this.xMax + this.xMin) / 2 - 0.08 * this.layoutDoc[HeightSym]();
+ let yPos = this.yMin + 200;
+ this.dataDoc.startPosY = yPos;
+ this.dataDoc.startPosX = xPos;
+ this.dataDoc.positionYDisplay = this.getDisplayYPos(yPos);
+ this.dataDoc.positionXDisplay = xPos;
+ let tensionMag = (this.dataDoc.mass * Math.abs(this.dataDoc.gravity)) / (2 * Math.sin(Math.PI / 4));
+ const tensionForce1: IForce = {
+ description: 'Tension',
+ magnitude: tensionMag,
+ directionInDegrees: 45,
+ component: false,
+ };
+ const tensionForce2: IForce = {
+ description: 'Tension',
+ magnitude: tensionMag,
+ directionInDegrees: 135,
+ component: false,
+ };
+ const grav: IForce = {
+ description: 'Gravity',
+ magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ directionInDegrees: 270,
+ component: false,
+ };
+ this.dataDoc.updatedForces = [tensionForce1, tensionForce2, grav];
+ this.dataDoc.startForces = [tensionForce1, tensionForce2, grav];
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
};
- this.dataDoc.updatedForces = ([gravityForce1, tensionForce1]);
- this.dataDoc.startForces = ([gravityForce1, tensionForce1]);
- this.dataDoc.startPosY2 = ((this.yMax + this.yMin) / 2);
- this.dataDoc.startPosX2 = ((this.xMin + this.xMax) / 2 + 5 );
- this.dataDoc.positionYDisplay2 = (this.getDisplayYPos((this.yMax + this.yMin) / 2));
- this.dataDoc.positionXDisplay2 = ((this.xMin + this.xMax) / 2 + 5);
- this.dataDoc.updatedForces2 = ([gravityForce2, tensionForce2]);
- this.dataDoc.startForces2 = ([gravityForce2, tensionForce2]);
-
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- };
+ // Default setup for pulley simulation
+ setupPulley = () => {
+ this.dataDoc.showComponentForces = false;
+ this.dataDoc.startPosY = (this.yMax + this.yMin) / 2;
+ this.dataDoc.startPosX = (this.xMin + this.xMax) / 2 - 2 * (0.08 * this.layoutDoc[HeightSym]()) - 5;
+ this.dataDoc.positionYDisplay = this.getDisplayYPos((this.yMax + this.yMin) / 2);
+ this.dataDoc.positionXDisplay = (this.xMin + this.xMax) / 2 - 2 * (0.08 * this.layoutDoc[HeightSym]()) - 5;
+ let a = (-1 * ((this.dataDoc.mass - this.dataDoc.mass2) * Math.abs(this.dataDoc.gravity))) / (this.dataDoc.mass + this.dataDoc.mass2);
+ const gravityForce1: IForce = {
+ description: 'Gravity',
+ magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ directionInDegrees: 270,
+ component: false,
+ };
+ const tensionForce1: IForce = {
+ description: 'Tension',
+ magnitude: this.dataDoc.mass * a + this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ directionInDegrees: 90,
+ component: false,
+ };
+ a *= -1;
+ const gravityForce2: IForce = {
+ description: 'Gravity',
+ magnitude: this.dataDoc.mass2 * Math.abs(this.dataDoc.gravity),
+ directionInDegrees: 270,
+ component: false,
+ };
+ const tensionForce2: IForce = {
+ description: 'Tension',
+ magnitude: this.dataDoc.mass2 * a + this.dataDoc.mass2 * Math.abs(this.dataDoc.gravity),
+ directionInDegrees: 90,
+ component: false,
+ };
- // Helper function used for tutorial and review mode
- getForceFromJSON = (
- json: {
- description: string;
- magnitude: number;
- directionInDegrees: number;
- component: boolean;
- }[]
- ): IForce[] => {
- const forces: IForce[] = [];
- for (let i = 0; i < json.length; i++) {
- const force: IForce = {
- description: json[i].description,
- magnitude: json[i].magnitude,
- directionInDegrees: json[i].directionInDegrees,
- component: json[i].component,
- };
- forces.push(force);
- }
- return forces;
- };
+ this.dataDoc.updatedForces = [gravityForce1, tensionForce1];
+ this.dataDoc.startForces = [gravityForce1, tensionForce1];
+ this.dataDoc.startPosY2 = (this.yMax + this.yMin) / 2;
+ this.dataDoc.startPosX2 = (this.xMin + this.xMax) / 2 + 5;
+ this.dataDoc.positionYDisplay2 = this.getDisplayYPos((this.yMax + this.yMin) / 2);
+ this.dataDoc.positionXDisplay2 = (this.xMin + this.xMax) / 2 + 5;
+ this.dataDoc.updatedForces2 = [gravityForce2, tensionForce2];
+ this.dataDoc.startForces2 = [gravityForce2, tensionForce2];
- // Handle force change in review mode
- updateReviewModeValues = () => {
- const forceOfGravityReview: IForce = {
- description: "Gravity",
- magnitude: this.dataDoc.reviewGravityMagnitude,
- directionInDegrees: this.dataDoc.reviewGravityAngle,
- component: false,
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
};
- const normalForceReview: IForce = {
- description: "Normal Force",
- magnitude: this.dataDoc.reviewNormalMagnitude,
- directionInDegrees: this.dataDoc.reviewNormalAngle,
- component: false,
+
+ // Helper function used for tutorial and review mode
+ getForceFromJSON = (
+ json: {
+ description: string;
+ magnitude: number;
+ directionInDegrees: number;
+ component: boolean;
+ }[]
+ ): IForce[] => {
+ const forces: IForce[] = [];
+ for (let i = 0; i < json.length; i++) {
+ const force: IForce = {
+ description: json[i].description,
+ magnitude: json[i].magnitude,
+ directionInDegrees: json[i].directionInDegrees,
+ component: json[i].component,
+ };
+ forces.push(force);
+ }
+ return forces;
};
- const staticFrictionForceReview: IForce = {
- description: "Static Friction Force",
- magnitude: this.dataDoc.reviewStaticMagnitude,
- directionInDegrees: this.dataDoc.reviewStaticAngle,
- component: false,
+
+ // Handle force change in review mode
+ updateReviewModeValues = () => {
+ const forceOfGravityReview: IForce = {
+ description: 'Gravity',
+ magnitude: this.dataDoc.reviewGravityMagnitude,
+ directionInDegrees: this.dataDoc.reviewGravityAngle,
+ component: false,
+ };
+ const normalForceReview: IForce = {
+ description: 'Normal Force',
+ magnitude: this.dataDoc.reviewNormalMagnitude,
+ directionInDegrees: this.dataDoc.reviewNormalAngle,
+ component: false,
+ };
+ const staticFrictionForceReview: IForce = {
+ description: 'Static Friction Force',
+ magnitude: this.dataDoc.reviewStaticMagnitude,
+ directionInDegrees: this.dataDoc.reviewStaticAngle,
+ component: false,
+ };
+ this.dataDoc.startForces = [forceOfGravityReview, normalForceReview, staticFrictionForceReview];
+ this.dataDoc.updatedForces = [forceOfGravityReview, normalForceReview, staticFrictionForceReview];
};
- this.dataDoc.startForces = ([
- forceOfGravityReview,
- normalForceReview,
- staticFrictionForceReview,
- ]);
- this.dataDoc.updatedForces = ([
- forceOfGravityReview,
- normalForceReview,
- staticFrictionForceReview,
- ]);
- }
- render () {
- return (
- <div className="physicsSimApp">
- <div className="mechanicsSimulationContainer">
- <div
- className="mechanicsSimulationContentContainer"
- >
- <div className="mechanicsSimulationButtonsAndElements">
- <div className="mechanicsSimulationButtons">
- {!this.dataDoc.simulationPaused && (
- <div
- style={{
- position: "fixed",
- left: 0.10*this.layoutDoc._width + "px",
- top: 0.95*this.layoutDoc._height + "px",
- width: 0.50*this.layoutDoc._width + "px",
- }}
- >
- <LinearProgress />
- </div>
- )}
- </div>
- <div className="mechanicsSimulationElements">
- <Weight
- dataDoc={this.dataDoc}
- layoutDoc={this.layoutDoc}
- wallPositions={this.wallPositions}
- adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
- gravity={this.dataDoc.gravity}
- circularMotionRadius={this.dataDoc.circularMotionRadius}
- componentForces={this.dataDoc.componentForces}
- showComponentForces={this.dataDoc.showComponentForces}
- color={"red"}
- coefficientOfKineticFriction={Number(
- this.dataDoc.coefficientOfKineticFriction
- )}
- displayXVelocity={this.dataDoc.velocityXDisplay}
- displayYVelocity={this.dataDoc.velocityYDisplay}
- elasticCollisions={this.dataDoc.elasticCollisions}
- mass={this.dataDoc.mass}
- mode={this.dataDoc.mode}
- noMovement={this.dataDoc.noMovement}
- paused={this.dataDoc.simulationPaused}
- pendulumAngle={this.dataDoc.pendulumAngle}
- pendulumLength={this.dataDoc.pendulumLength}
- radius={(0.08*this.layoutDoc._height)}
- reset={this.dataDoc.simulationReset}
- simulationSpeed={this.dataDoc.simulationSpeed}
- startPendulumAngle={this.dataDoc.startPendulumAngle}
- showAcceleration={this.dataDoc.showAcceleration}
- showForceMagnitudes={this.dataDoc.showForceMagnitudes}
- showForces={this.dataDoc.showForces}
- showVelocity={this.dataDoc.showVelocity}
- simulationType={this.dataDoc.simulationType}
- springConstant={this.dataDoc.springConstant}
- springStartLength={this.dataDoc.springStartLength}
- springRestLength={this.dataDoc.springRestLength}
- startForces={this.dataDoc.startForces}
- startPosX={this.dataDoc.startPosX}
- startPosY={this.dataDoc.startPosY ?? 0}
- startVelX={this.dataDoc.startVelX}
- startVelY={this.dataDoc.startVelY}
- timestepSize={0.05}
- updateDisplay={this.dataDoc.displayChange}
- updatedForces={this.dataDoc.updatedForces}
- wedgeHeight={this.dataDoc.wedgeHeight}
- wedgeWidth={this.dataDoc.wedgeWidth}
- xMax={this.xMax}
- xMin={this.xMin}
- yMax={this.yMax}
- yMin={this.yMin}
- />
- {this.dataDoc.simulationType == "Pulley" && (
- <Weight
- dataDoc={this.dataDoc}
- layoutDoc={this.layoutDoc}
- wallPositions={this.wallPositions}
- adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
- circularMotionRadius={this.dataDoc.circularMotionRadius}
- gravity={this.dataDoc.gravity}
- componentForces={this.dataDoc.componentForces}
- showComponentForces={this.dataDoc.showComponentForces}
- color={"blue"}
- coefficientOfKineticFriction={Number(
- this.dataDoc.coefficientOfKineticFriction
- )}
- displayXVelocity={this.dataDoc.velocityXDisplay2}
- displayYVelocity={this.dataDoc.velocityYDisplay2}
- elasticCollisions={this.dataDoc.elasticCollisions}
- mass={this.dataDoc.mass2}
- mode={this.dataDoc.mode}
- noMovement={this.dataDoc.noMovement}
- paused={this.dataDoc.simulationPaused}
- pendulumAngle={this.dataDoc.pendulumAngle}
- pendulumLength={this.dataDoc.pendulumLength}
- radius={(0.08*this.layoutDoc._height)}
- reset={this.dataDoc.simulationReset}
- simulationSpeed={this.dataDoc.simulationSpeed}
- startPendulumAngle={this.dataDoc.startPendulumAngle}
- showAcceleration={this.dataDoc.showAcceleration}
- showForceMagnitudes={this.dataDoc.showForceMagnitudes}
- showForces={this.dataDoc.showForces}
- showVelocity={this.dataDoc.showVelocity}
- simulationType={this.dataDoc.simulationType}
- springConstant={this.dataDoc.springConstant}
- springStartLength={this.dataDoc.springStartLength}
- springRestLength={this.dataDoc.springRestLength}
- startForces={this.dataDoc.startForces2}
- startPosX={this.dataDoc.startPosX2}
- startPosY={this.dataDoc.startPosY2}
- startVelX={this.dataDoc.startVelX}
- startVelY={this.dataDoc.startVelY}
- timestepSize={0.05}
- updateDisplay={this.dataDoc.displayChange2}
- updatedForces={this.dataDoc.updatedForces2}
- wedgeHeight={this.dataDoc.wedgeHeight}
- wedgeWidth={this.dataDoc.wedgeWidth}
- xMax={this.xMax}
- xMin={this.xMin}
- yMax={this.yMax}
- yMin={this.yMin}
- />
- )}
- </div>
- <div>
- {(this.dataDoc.simulationType == "One Weight" ||
- this.dataDoc.simulationType == "Inclined Plane") && this.wallPositions &&
- this.wallPositions.map((element, index) => {
- return (
- <Wall
- key={index}
- length={element.length}
- xPos={element.xPos}
- yPos={element.yPos}
- angleInDegrees={element.angleInDegrees}
- />
- );
- })}
- </div>
- </div>
- </div>
- <div className="mechanicsSimulationEquationContainer">
- <div className="mechanicsSimulationControls">
- <Stack direction="row" spacing={1}>
- {this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && (
- <IconButton
- onClick={() => {
- this.dataDoc.simulationPaused = (false);
- }}
- >
- <PlayArrowIcon />
- </IconButton>
- )}
- {!this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && (
- <IconButton
- onClick={() => {
- this.dataDoc.simulationPaused = (true);
- }}
- >
- <PauseIcon />
- </IconButton>
- )}
- {this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && (
- <IconButton
- onClick={() => {
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- }}
- >
- <ReplayIcon />
- </IconButton>
- )}
- </Stack>
- <div className="dropdownMenu">
- <select
- value={this.dataDoc.simulationType}
- onChange={(event) => {
- this.dataDoc.simulationType = (event.target.value);
- this.setupSimulation(event.target.value, this.dataDoc.mode)
- }}
- style={{ height: "2em", width: "100%", fontSize: "16px" }}
- >
- <option value="One Weight">Projectile</option>
- <option value="Inclined Plane">Inclined Plane</option>
- <option value="Pendulum">Pendulum</option>
- <option value="Spring">Spring</option>
- <option value="Circular Motion">Circular Motion</option>
- <option value="Pulley">Pulley</option>
- <option value="Suspension">Suspension</option>
- </select>
- </div>
- <div className="dropdownMenu">
- <select
- value={this.dataDoc.mode}
- onChange={(event) => {
- this.dataDoc.mode = (event.target.value);
- this.setupSimulation(this.dataDoc.simulationType, event.target.value)
- }}
- style={{ height: "2em", width: "100%", fontSize: "16px" }}
- >
- <option value="Tutorial">Tutorial Mode</option>
- <option value="Freeform">Freeform Mode</option>
- <option value="Review">Review Mode</option>
- </select>
- </div>
- </div>
- {this.dataDoc.mode == "Review" && this.dataDoc.simulationType != "Inclined Plane" && (
- <div className="wordProblemBox">
- <p>{this.dataDoc.simulationType} review problems in progress!</p>
- <hr/>
- </div>
- )}
- {this.dataDoc.mode == "Review" && this.dataDoc.simulationType == "Inclined Plane" && (
- <div>
- {!this.dataDoc.hintDialogueOpen && (
- <IconButton
- onClick={() => {
- this.dataDoc.hintDialogueOpen = (true);
- }}
- sx={{
- position: "fixed",
- left: this.xMax - 50 + "px",
- top: this.yMin + 14 + "px",
- }}
- >
- <QuestionMarkIcon />
- </IconButton>
- )}
- <Dialog
- maxWidth={"sm"}
- fullWidth={true}
- open={this.dataDoc.hintDialogueOpen}
- onClose={() => this.dataDoc.hintDialogueOpen = (false)}
- >
- <DialogTitle>Hints</DialogTitle>
- <DialogContent>
- {this.dataDoc.selectedQuestion.hints && (this.dataDoc.selectedQuestion.hints.map((hint, index) => {
- return (
- <div key={index}>
- <DialogContentText>
- <details>
- <summary>
- <b>
- Hint {index + 1}: {hint.description}
- </b>
- </summary>
- {hint.content}
- </details>
- </DialogContentText>
- </div>
- );
- }))}
- </DialogContent>
- <DialogActions>
- <Button
- onClick={() => {
- this.dataDoc.hintDialogueOpen = (false);
- }}
- >
- Close
- </Button>
- </DialogActions>
- </Dialog>
- <div className="wordProblemBox">
- <div className="question">
- <p>{this.dataDoc.questionPartOne}</p>
- <p>{this.dataDoc.questionPartTwo}</p>
- </div>
- <div className="answers">
- {this.dataDoc.selectedQuestion.answerParts.includes("force of gravity") && (
- <InputField
- label={<p>Gravity magnitude</p>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'reviewGravityMagnitude'}
- step={0.1}
- unit={"N"}
- upperBound={50}
- value={this.dataDoc.reviewGravityMagnitude}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf("force of gravity")]}
- labelWidth={"7em"}
- />
- )}
- {this.dataDoc.selectedQuestion.answerParts.includes("angle of gravity") && (
- <InputField
- label={<p>Gravity angle</p>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'reviewGravityAngle'}
- step={1}
- unit={"°"}
- upperBound={360}
- value={this.dataDoc.reviewGravityAngle}
- radianEquivalent={true}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf("angle of gravity")]}
- labelWidth={"7em"}
- />
- )}
- {this.dataDoc.selectedQuestion.answerParts.includes("normal force") && (
- <InputField
- label={<p>Normal force magnitude</p>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'reviewNormalMagnitude'}
- step={0.1}
- unit={"N"}
- upperBound={50}
- value={this.dataDoc.reviewNormalMagnitude}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf("normal force")]}
- labelWidth={"7em"}
- />
- )}
- {this.dataDoc.selectedQuestion.answerParts.includes("angle of normal force") && (
- <InputField
- label={<p>Normal force angle</p>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'reviewNormalAngle'}
- step={1}
- unit={"°"}
- upperBound={360}
- value={this.dataDoc.reviewNormalAngle}
- radianEquivalent={true}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf("angle of normal force")]}
- labelWidth={"7em"}
- />
- )}
- {this.dataDoc.selectedQuestion.answerParts.includes("force of static friction") && (
- <InputField
- label={<p>Static friction magnitude</p>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'reviewStaticMagnitude'}
- step={0.1}
- unit={"N"}
- upperBound={50}
- value={this.dataDoc.reviewStaticMagnitude}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf("force of static friction")]}
- labelWidth={"7em"}
- />
- )}
- {this.dataDoc.selectedQuestion.answerParts.includes("angle of static friction") && (
- <InputField
- label={<p>Static friction angle</p>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'reviewStaticAngle'}
- step={1}
- unit={"°"}
- upperBound={360}
- value={this.dataDoc.reviewStaticAngle}
- radianEquivalent={true}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf("angle of static friction")]}
- labelWidth={"7em"}
- />
- )}
- {this.dataDoc.selectedQuestion.answerParts.includes("coefficient of static friction") && (
- <InputField
- label={
- <Box>
- &mu;<sub>s</sub>
- </Box>
- }
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'coefficientOfStaticFriction'}
- step={0.1}
- unit={""}
- upperBound={1}
- value={this.dataDoc.coefficientOfStaticFriction}
- effect={this.updateReviewForcesBasedOnCoefficient}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf("coefficient of static friction")]}
- />
- )}
- {this.dataDoc.selectedQuestion.answerParts.includes("wedge angle") && (
- <InputField
- label={<Box>&theta;</Box>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'wedgeAngle'}
- step={1}
- unit={"°"}
- upperBound={49}
- value={this.dataDoc.wedgeAngle ?? 26}
- effect={(val: number) => {
- this.changeWedgeBasedOnNewAngle(val);
- this.updateReviewForcesBasedOnAngle(val);
- }}
- radianEquivalent={true}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf("wedge angle")]}
- />
- )}
- </div>
- </div>
- </div>
- )}
- {this.dataDoc.mode == "Tutorial" && (
- <div className="wordProblemBox">
- <div className="question">
- <h2>Problem</h2>
- <p>{this.dataDoc.selectedTutorial.question}</p>
- </div>
- <div
- style={{
- display: "flex",
- justifyContent: "spaceBetween",
- width: "100%",
- }}
- >
- <IconButton
- onClick={() => {
- let step = this.dataDoc.stepNumber - 1;
- step = Math.max(step, 0);
- step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1);
- this.dataDoc.stepNumber = (step);
- this.dataDoc.startForces = (
- this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
- );
- this.dataDoc.updatedForces = (
- this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
- );
- this.dataDoc.showForceMagnitudes = (
- this.dataDoc.selectedTutorial.steps[step].showMagnitude
- );
- }}
- disabled={this.dataDoc.stepNumber == 0}
- >
- <ArrowLeftIcon />
- </IconButton>
- <div>
- <h3>
- Step {this.dataDoc.stepNumber + 1}:{" "}
- {this.dataDoc.selectedTutorial.steps[this.dataDoc.stepNumber].description}
- </h3>
- <p>{this.dataDoc.selectedTutorial.steps[this.dataDoc.stepNumber].content}</p>
- </div>
- <IconButton
- onClick={() => {
- let step = this.dataDoc.stepNumber + 1;
- step = Math.max(step, 0);
- step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1);
- this.dataDoc.stepNumber = (step);
- this.dataDoc.startForces = (
- this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
- );
- this.dataDoc.updatedForces = (
- this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
- );
- this.dataDoc.showForceMagnitudes = (
- this.dataDoc.selectedTutorial.steps[step].showMagnitude
- );
- }}
- disabled={this.dataDoc.stepNumber == this.dataDoc.selectedTutorial.steps.length - 1}
- >
- <ArrowRightIcon />
- </IconButton>
- </div>
- <div>
- {(this.dataDoc.simulationType == "One Weight" ||
- this.dataDoc.simulationType == "Inclined Plane" ||
- this.dataDoc.simulationType == "Pendulum") && <p>Resources</p>}
- {this.dataDoc.simulationType == "One Weight" && (
- <ul>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/one-dimensional-motion"
- target="_blank"
- rel="noreferrer"
- style={{
- color: "blue",
- textDecoration: "underline",
- }}
- >
- Khan Academy - One Dimensional Motion
- </a>
- </li>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/two-dimensional-motion"
- target="_blank"
- rel="noreferrer"
- style={{
- color: "blue",
- textDecoration: "underline",
- }}
- >
- Khan Academy - Two Dimensional Motion
- </a>
- </li>
- </ul>
- )}
- {this.dataDoc.simulationType == "Inclined Plane" && (
- <ul>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/forces-newtons-laws#normal-contact-force"
- target="_blank"
- rel="noreferrer"
- style={{
- color: "blue",
- textDecoration: "underline",
- }}
- >
- Khan Academy - Normal Force
- </a>
- </li>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/forces-newtons-laws#inclined-planes-friction"
- target="_blank"
- rel="noreferrer"
- style={{
- color: "blue",
- textDecoration: "underline",
- }}
- >
- Khan Academy - Inclined Planes
- </a>
- </li>
- </ul>
- )}
- {this.dataDoc.simulationType == "Pendulum" && (
- <ul>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/forces-newtons-laws#tension-tutorial"
- target="_blank"
- rel="noreferrer"
- style={{
- color: "blue",
- textDecoration: "underline",
- }}
- >
- Khan Academy - Tension
- </a>
- </li>
- </ul>
- )}
- </div>
- </div>
- )}
- {this.dataDoc.mode == "Review" && this.dataDoc.simulationType == "Inclined Plane" && (
- <div
- style={{
- display: "flex",
- justifyContent: "space-between",
- marginTop: "10px",
- }}
- >
- <p
- style={{
- color: "blue",
- textDecoration: "underline",
- cursor: "pointer",
- }}
- onClick={() => this.dataDoc.mode = ("Tutorial")}
- >
- {" "}
- Go to walkthrough{" "}
- </p>
- <div style={{ display: "flex", flexDirection: "column" }}>
- <Button
- onClick={() => {
- this.dataDoc.simulationReset= (!this.dataDoc.simulationReset);
- this.checkAnswers();
- this.dataDoc.showIcon = true;
- }}
- variant="outlined"
- >
- <p>Submit</p>
- </Button>
- <Button
- onClick={() => {
- this.generateNewQuestion();
- this.dataDoc.showIcon = false;
- }}
- variant="outlined"
- >
- <p>New question</p>
- </Button>
- </div>
- </div>
- )}
- {this.dataDoc.mode == "Freeform" && (
- <div className="vars">
- <FormControl component="fieldset">
- <FormGroup>
- {this.dataDoc.simulationType == "One Weight" && (
- <FormControlLabel
- control={
- <Checkbox
- checked={this.dataDoc.elasticCollisions}
- onChange={() =>
- this.dataDoc.elasticCollisions= (!this.dataDoc.elasticCollisions)
- }
- />
- }
- label="Make collisions elastic"
- labelPlacement="start"
- />
- )}
- <FormControlLabel
- control={
- <Checkbox
- checked={this.dataDoc.showForces}
- onChange={() => this.dataDoc.showForces = (!this.dataDoc.showForces)}
- />
- }
- label="Show force vectors"
- labelPlacement="start"
- />
- {(this.dataDoc.simulationType == "Inclined Plane" ||
- this.dataDoc.simulationType == "Pendulum") && (
- <FormControlLabel
- control={
- <Checkbox
- checked={this.dataDoc.showForces}
- onChange={() =>
- this.dataDoc.showComponentForces = (!this.dataDoc.showComponentForces)
- }
- />
- }
- label="Show component force vectors"
- labelPlacement="start"
- />
- )}
- <FormControlLabel
- control={
- <Checkbox
- checked={this.dataDoc.showAcceleration}
- onChange={() => this.dataDoc.showAcceleration = (!this.dataDoc.showAcceleration)}
- />
- }
- label="Show acceleration vector"
- labelPlacement="start"
- />
- <FormControlLabel
- control={
- <Checkbox
- checked={this.dataDoc.showVelocity}
- onChange={() => this.dataDoc.showVelocity = (!this.dataDoc.showVelocity)}
- />
- }
- label="Show velocity vector"
- labelPlacement="start"
- />
- <InputField
- label={<Box>Speed</Box>}
- lowerBound={1}
- dataDoc={this.dataDoc}
- prop={'simulationSpeed'}
- step={1}
- unit={"x"}
- upperBound={10}
- value={this.dataDoc.simulationSpeed ?? 2}
- labelWidth={"5em"}
- />
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType != "Circular Motion" && (
- <InputField
- label={<Box>Gravity</Box>}
- lowerBound={-30}
- dataDoc={this.dataDoc}
- prop={'gravity'}
- step={0.01}
- unit={"m/s2"}
- upperBound={0}
- value={this.dataDoc.gravity ?? -9.81}
- effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode)
- }}
- labelWidth={"5em"}
- />
- )}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType != "Pulley" && (
- <InputField
- label={<Box>Mass</Box>}
- lowerBound={1}
- dataDoc={this.dataDoc}
- prop={'mass'}
- step={0.1}
- unit={"kg"}
- upperBound={5}
- value={this.dataDoc.mass ?? 1}
- effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode)
- }}
- labelWidth={"5em"}
- />
- )}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "Pulley" && (
- <InputField
- label={<Box>Red mass</Box>}
- lowerBound={1}
- dataDoc={this.dataDoc}
- prop={'mass'}
- step={0.1}
- unit={"kg"}
- upperBound={5}
- value={this.dataDoc.mass ?? 1}
- effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode)
- }}
- labelWidth={"5em"}
- />
- )}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "Pulley" && (
- <InputField
- label={<Box>Blue mass</Box>}
- lowerBound={1}
- dataDoc={this.dataDoc}
- prop={'mass2'}
- step={0.1}
- unit={"kg"}
- upperBound={5}
- value={this.dataDoc.mass2 ?? 1}
- effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode)
- }}
- labelWidth={"5em"}
- />
- )}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "Circular Motion" && (
- <InputField
- label={<Box>Rod length</Box>}
- lowerBound={100}
- dataDoc={this.dataDoc}
- prop={'circularMotionRadius'}
- step={5}
- unit={"m"}
- upperBound={250}
- value={this.dataDoc.circularMotionRadius ?? 100}
- effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode)
- }}
- labelWidth={"5em"}
- />
- )}
- </FormGroup>
- </FormControl>
- {this.dataDoc.simulationType == "Spring" && this.dataDoc.simulationPaused && (
- <div>
- <InputField
- label={
- <Typography color="inherit">Spring stiffness</Typography>
- }
- lowerBound={0.1}
- dataDoc={this.dataDoc}
- prop={'springConstant'}
- step={1}
- unit={"N/m"}
- upperBound={500}
- value={this.dataDoc.springConstant ?? 0.5}
- effect={(val: number) => {
- this.dataDoc.simulationReset(!this.dataDoc.simulationReset);
- }}
- radianEquivalent={false}
- mode={"Freeform"}
- labelWidth={"7em"}
- />
- <InputField
- label={<Typography color="inherit">Rest length</Typography>}
- lowerBound={10}
- dataDoc={this.dataDoc}
- prop={'springRestLength'}
- step={100}
- unit={""}
- upperBound={500}
- value={this.dataDoc.springRestLength ?? 200}
- effect={(val: number) => {
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- }}
- radianEquivalent={false}
- mode={"Freeform"}
- labelWidth={"7em"}
- />
- <InputField
- label={
- <Typography color="inherit">
- Starting displacement
- </Typography>
- }
- lowerBound={-(this.dataDoc.springRestLength - 10)}
- dataDoc={this.dataDoc}
- prop={""}
- step={10}
- unit={""}
- upperBound={this.dataDoc.springRestLength}
- value={this.dataDoc.springStartLength - this.dataDoc.springRestLength ?? 0}
- effect={(val: number) => {
- this.dataDoc.startPosY = (this.dataDoc.springRestLength + val);
- this.dataDoc.springStartLength = (this.dataDoc.springRestLength + val);
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- }}
- radianEquivalent={false}
- mode={"Freeform"}
- labelWidth={"7em"}
- />
- </div>
- )}
- {this.dataDoc.simulationType == "Inclined Plane" && this.dataDoc.simulationPaused && (
- <div>
- <InputField
- label={<Box>&theta;</Box>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'wedgeAngle'}
- step={1}
- unit={"°"}
- upperBound={49}
- value={this.dataDoc.wedgeAngle ?? 26}
- effect={(val: number) => {
- this.changeWedgeBasedOnNewAngle(val);
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- }}
- radianEquivalent={true}
- mode={"Freeform"}
- labelWidth={"2em"}
- />
- <InputField
- label={
- <Box>
- &mu;<sub>s</sub>
- </Box>
- }
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'coefficientOfStaticFriction'}
- step={0.1}
- unit={""}
- upperBound={1}
- value={this.dataDoc.coefficientOfStaticFriction ?? 0}
- effect={(val: number) => {
- this.updateForcesWithFriction(val);
- if (val < Number(this.dataDoc.coefficientOfKineticFriction)) {
- this.dataDoc.soefficientOfKineticFriction = (val);
- }
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- }}
- mode={"Freeform"}
- labelWidth={"2em"}
- />
- <InputField
- label={
- <Box>
- &mu;<sub>k</sub>
- </Box>
- }
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'coefficientOfKineticFriction'}
- step={0.1}
- unit={""}
- upperBound={Number(this.dataDoc.coefficientOfStaticFriction)}
- value={this.dataDoc.coefficientOfKineticFriction ?? 0}
- effect={(val: number) => {
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- }}
- mode={"Freeform"}
- labelWidth={"2em"}
- />
- </div>
- )}
- {this.dataDoc.simulationType == "Inclined Plane" && !this.dataDoc.simulationPaused && (
- <Typography>
- &theta;: {Math.round(Number(this.dataDoc.wedgeAngle) * 100) / 100}° ≈{" "}
- {Math.round(((Number(this.dataDoc.wedgeAngle) * Math.PI) / 180) * 100) /
- 100}{" "}
- rad
- <br />
- &mu; <sub>s</sub>: {this.dataDoc.coefficientOfStaticFriction}
- <br />
- &mu; <sub>k</sub>: {this.dataDoc.coefficientOfKineticFriction}
- </Typography>
- )}
- {this.dataDoc.simulationType == "Pendulum" && !this.dataDoc.simulationPaused && (
- <Typography>
- &theta;: {Math.round(this.dataDoc.pendulumAngle * 100) / 100}° ≈{" "}
- {Math.round(((this.dataDoc.pendulumAngle * Math.PI) / 180) * 100) / 100}{" "}
- rad
- </Typography>
- )}
- {this.dataDoc.simulationType == "Pendulum" && this.dataDoc.simulationPaused && (
- <div>
- <InputField
- label={<Box>Angle</Box>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'pendulumAngle'}
- step={1}
- unit={"°"}
- upperBound={59}
- value={this.dataDoc.pendulumAngle ?? 30}
- effect={(value) => {
- this.dataDoc.startPendulumAngle = (value);
- if (this.dataDoc.simulationType == "Pendulum") {
- const mag =
- this.dataDoc.mass *
- Math.abs(this.dataDoc.gravity) *
- Math.cos((value * Math.PI) / 180);
+ render() {
+ return (
+ <div className="physicsSimApp">
+ <div className="mechanicsSimulationContainer">
+ <div className="mechanicsSimulationContentContainer">
+ <div className="mechanicsSimulationButtonsAndElements">
+ <div className="mechanicsSimulationButtons">
+ {!this.dataDoc.simulationPaused && (
+ <div
+ style={{
+ position: 'fixed',
+ left: 0.1 * this.layoutDoc[WidthSym]() + 'px',
+ top: 0.95 * this.layoutDoc[HeightSym]() + 'px',
+ width: 0.5 * this.layoutDoc[WidthSym]() + 'px',
+ }}>
+ <LinearProgress />
+ </div>
+ )}
+ </div>
+ <div className="mechanicsSimulationElements">
+ <Weight
+ dataDoc={this.dataDoc}
+ layoutDoc={this.layoutDoc}
+ wallPositions={this.wallPositions}
+ adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
+ gravity={this.dataDoc.gravity}
+ circularMotionRadius={this.dataDoc.circularMotionRadius}
+ componentForces={this.dataDoc.componentForces}
+ showComponentForces={this.dataDoc.showComponentForces}
+ color={'red'}
+ coefficientOfKineticFriction={Number(this.dataDoc.coefficientOfKineticFriction)}
+ displayXVelocity={this.dataDoc.velocityXDisplay}
+ displayYVelocity={this.dataDoc.velocityYDisplay}
+ elasticCollisions={this.dataDoc.elasticCollisions}
+ mass={this.dataDoc.mass}
+ mode={this.dataDoc.mode}
+ noMovement={this.dataDoc.noMovement}
+ paused={this.dataDoc.simulationPaused}
+ pendulumAngle={this.dataDoc.pendulumAngle}
+ pendulumLength={this.dataDoc.pendulumLength}
+ radius={0.08 * this.layoutDoc[HeightSym]()}
+ reset={this.dataDoc.simulationReset}
+ simulationSpeed={this.dataDoc.simulationSpeed}
+ startPendulumAngle={this.dataDoc.startPendulumAngle}
+ showAcceleration={this.dataDoc.showAcceleration}
+ showForceMagnitudes={this.dataDoc.showForceMagnitudes}
+ showForces={this.dataDoc.showForces}
+ showVelocity={this.dataDoc.showVelocity}
+ simulationType={this.dataDoc.simulationType}
+ springConstant={this.dataDoc.springConstant}
+ springStartLength={this.dataDoc.springStartLength}
+ springRestLength={this.dataDoc.springRestLength}
+ startForces={this.dataDoc.startForces}
+ startPosX={this.dataDoc.startPosX}
+ startPosY={this.dataDoc.startPosY ?? 0}
+ startVelX={this.dataDoc.startVelX}
+ startVelY={this.dataDoc.startVelY}
+ timestepSize={0.05}
+ updateDisplay={this.dataDoc.displayChange}
+ updatedForces={this.dataDoc.updatedForces}
+ wedgeHeight={this.dataDoc.wedgeHeight}
+ wedgeWidth={this.dataDoc.wedgeWidth}
+ xMax={this.xMax}
+ xMin={this.xMin}
+ yMax={this.yMax}
+ yMin={this.yMin}
+ />
+ {this.dataDoc.simulationType == 'Pulley' && (
+ <Weight
+ dataDoc={this.dataDoc}
+ layoutDoc={this.layoutDoc}
+ wallPositions={this.wallPositions}
+ adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
+ circularMotionRadius={this.dataDoc.circularMotionRadius}
+ gravity={this.dataDoc.gravity}
+ componentForces={this.dataDoc.componentForces}
+ showComponentForces={this.dataDoc.showComponentForces}
+ color={'blue'}
+ coefficientOfKineticFriction={Number(this.dataDoc.coefficientOfKineticFriction)}
+ displayXVelocity={this.dataDoc.velocityXDisplay2}
+ displayYVelocity={this.dataDoc.velocityYDisplay2}
+ elasticCollisions={this.dataDoc.elasticCollisions}
+ mass={this.dataDoc.mass2}
+ mode={this.dataDoc.mode}
+ noMovement={this.dataDoc.noMovement}
+ paused={this.dataDoc.simulationPaused}
+ pendulumAngle={this.dataDoc.pendulumAngle}
+ pendulumLength={this.dataDoc.pendulumLength}
+ radius={0.08 * this.layoutDoc[HeightSym]()}
+ reset={this.dataDoc.simulationReset}
+ simulationSpeed={this.dataDoc.simulationSpeed}
+ startPendulumAngle={this.dataDoc.startPendulumAngle}
+ showAcceleration={this.dataDoc.showAcceleration}
+ showForceMagnitudes={this.dataDoc.showForceMagnitudes}
+ showForces={this.dataDoc.showForces}
+ showVelocity={this.dataDoc.showVelocity}
+ simulationType={this.dataDoc.simulationType}
+ springConstant={this.dataDoc.springConstant}
+ springStartLength={this.dataDoc.springStartLength}
+ springRestLength={this.dataDoc.springRestLength}
+ startForces={this.dataDoc.startForces2}
+ startPosX={this.dataDoc.startPosX2}
+ startPosY={this.dataDoc.startPosY2}
+ startVelX={this.dataDoc.startVelX}
+ startVelY={this.dataDoc.startVelY}
+ timestepSize={0.05}
+ updateDisplay={this.dataDoc.displayChange2}
+ updatedForces={this.dataDoc.updatedForces2}
+ wedgeHeight={this.dataDoc.wedgeHeight}
+ wedgeWidth={this.dataDoc.wedgeWidth}
+ xMax={this.xMax}
+ xMin={this.xMin}
+ yMax={this.yMax}
+ yMin={this.yMin}
+ />
+ )}
+ </div>
+ <div>
+ {(this.dataDoc.simulationType == 'One Weight' || this.dataDoc.simulationType == 'Inclined Plane') &&
+ this.wallPositions &&
+ this.wallPositions.map((element, index) => {
+ return <Wall key={index} length={element.length} xPos={element.xPos} yPos={element.yPos} angleInDegrees={element.angleInDegrees} />;
+ })}
+ </div>
+ </div>
+ </div>
+ <div className="mechanicsSimulationEquationContainer">
+ <div className="mechanicsSimulationControls">
+ <Stack direction="row" spacing={1}>
+ {this.dataDoc.simulationPaused && this.dataDoc.mode != 'Tutorial' && (
+ <IconButton
+ onClick={() => {
+ this.dataDoc.simulationPaused = false;
+ }}>
+ <PlayArrowIcon />
+ </IconButton>
+ )}
+ {!this.dataDoc.simulationPaused && this.dataDoc.mode != 'Tutorial' && (
+ <IconButton
+ onClick={() => {
+ this.dataDoc.simulationPaused = true;
+ }}>
+ <PauseIcon />
+ </IconButton>
+ )}
+ {this.dataDoc.simulationPaused && this.dataDoc.mode != 'Tutorial' && (
+ <IconButton
+ onClick={() => {
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }}>
+ <ReplayIcon />
+ </IconButton>
+ )}
+ </Stack>
+ <div className="dropdownMenu">
+ <select
+ value={this.dataDoc.simulationType}
+ onChange={event => {
+ this.dataDoc.simulationType = event.target.value;
+ this.setupSimulation(event.target.value, this.dataDoc.mode);
+ }}
+ style={{ height: '2em', width: '100%', fontSize: '16px' }}>
+ <option value="One Weight">Projectile</option>
+ <option value="Inclined Plane">Inclined Plane</option>
+ <option value="Pendulum">Pendulum</option>
+ <option value="Spring">Spring</option>
+ <option value="Circular Motion">Circular Motion</option>
+ <option value="Pulley">Pulley</option>
+ <option value="Suspension">Suspension</option>
+ </select>
+ </div>
+ <div className="dropdownMenu">
+ <select
+ value={this.dataDoc.mode}
+ onChange={event => {
+ this.dataDoc.mode = event.target.value;
+ this.setupSimulation(this.dataDoc.simulationType, event.target.value);
+ }}
+ style={{ height: '2em', width: '100%', fontSize: '16px' }}>
+ <option value="Tutorial">Tutorial Mode</option>
+ <option value="Freeform">Freeform Mode</option>
+ <option value="Review">Review Mode</option>
+ </select>
+ </div>
+ </div>
+ {this.dataDoc.mode == 'Review' && this.dataDoc.simulationType != 'Inclined Plane' && (
+ <div className="wordProblemBox">
+ <p>{this.dataDoc.simulationType} review problems in progress!</p>
+ <hr />
+ </div>
+ )}
+ {this.dataDoc.mode == 'Review' && this.dataDoc.simulationType == 'Inclined Plane' && (
+ <div>
+ {!this.dataDoc.hintDialogueOpen && (
+ <IconButton
+ onClick={() => {
+ this.dataDoc.hintDialogueOpen = true;
+ }}
+ sx={{
+ position: 'fixed',
+ left: this.xMax - 50 + 'px',
+ top: this.yMin + 14 + 'px',
+ }}>
+ <QuestionMarkIcon />
+ </IconButton>
+ )}
+ <Dialog maxWidth={'sm'} fullWidth={true} open={this.dataDoc.hintDialogueOpen} onClose={() => (this.dataDoc.hintDialogueOpen = false)}>
+ <DialogTitle>Hints</DialogTitle>
+ <DialogContent>
+ {this.dataDoc.selectedQuestion.hints &&
+ this.dataDoc.selectedQuestion.hints.map((hint: any, index: number) => {
+ return (
+ <div key={index}>
+ <DialogContentText>
+ <details>
+ <summary>
+ <b>
+ Hint {index + 1}: {hint.description}
+ </b>
+ </summary>
+ {hint.content}
+ </details>
+ </DialogContentText>
+ </div>
+ );
+ })}
+ </DialogContent>
+ <DialogActions>
+ <Button
+ onClick={() => {
+ this.dataDoc.hintDialogueOpen = false;
+ }}>
+ Close
+ </Button>
+ </DialogActions>
+ </Dialog>
+ <div className="wordProblemBox">
+ <div className="question">
+ <p>{this.dataDoc.questionPartOne}</p>
+ <p>{this.dataDoc.questionPartTwo}</p>
+ </div>
+ <div className="answers">
+ {this.dataDoc.selectedQuestion.answerParts.includes('force of gravity') && (
+ <InputField
+ label={<p>Gravity magnitude</p>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'reviewGravityMagnitude'}
+ step={0.1}
+ unit={'N'}
+ upperBound={50}
+ value={this.dataDoc.reviewGravityMagnitude}
+ showIcon={this.dataDoc.showIcon}
+ correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('force of gravity')]}
+ labelWidth={'7em'}
+ />
+ )}
+ {this.dataDoc.selectedQuestion.answerParts.includes('angle of gravity') && (
+ <InputField
+ label={<p>Gravity angle</p>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'reviewGravityAngle'}
+ step={1}
+ unit={'°'}
+ upperBound={360}
+ value={this.dataDoc.reviewGravityAngle}
+ radianEquivalent={true}
+ showIcon={this.dataDoc.showIcon}
+ correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('angle of gravity')]}
+ labelWidth={'7em'}
+ />
+ )}
+ {this.dataDoc.selectedQuestion.answerParts.includes('normal force') && (
+ <InputField
+ label={<p>Normal force magnitude</p>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'reviewNormalMagnitude'}
+ step={0.1}
+ unit={'N'}
+ upperBound={50}
+ value={this.dataDoc.reviewNormalMagnitude}
+ showIcon={this.dataDoc.showIcon}
+ correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('normal force')]}
+ labelWidth={'7em'}
+ />
+ )}
+ {this.dataDoc.selectedQuestion.answerParts.includes('angle of normal force') && (
+ <InputField
+ label={<p>Normal force angle</p>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'reviewNormalAngle'}
+ step={1}
+ unit={'°'}
+ upperBound={360}
+ value={this.dataDoc.reviewNormalAngle}
+ radianEquivalent={true}
+ showIcon={this.dataDoc.showIcon}
+ correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('angle of normal force')]}
+ labelWidth={'7em'}
+ />
+ )}
+ {this.dataDoc.selectedQuestion.answerParts.includes('force of static friction') && (
+ <InputField
+ label={<p>Static friction magnitude</p>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'reviewStaticMagnitude'}
+ step={0.1}
+ unit={'N'}
+ upperBound={50}
+ value={this.dataDoc.reviewStaticMagnitude}
+ showIcon={this.dataDoc.showIcon}
+ correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('force of static friction')]}
+ labelWidth={'7em'}
+ />
+ )}
+ {this.dataDoc.selectedQuestion.answerParts.includes('angle of static friction') && (
+ <InputField
+ label={<p>Static friction angle</p>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'reviewStaticAngle'}
+ step={1}
+ unit={'°'}
+ upperBound={360}
+ value={this.dataDoc.reviewStaticAngle}
+ radianEquivalent={true}
+ showIcon={this.dataDoc.showIcon}
+ correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('angle of static friction')]}
+ labelWidth={'7em'}
+ />
+ )}
+ {this.dataDoc.selectedQuestion.answerParts.includes('coefficient of static friction') && (
+ <InputField
+ label={
+ <Box>
+ &mu;<sub>s</sub>
+ </Box>
+ }
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'coefficientOfStaticFriction'}
+ step={0.1}
+ unit={''}
+ upperBound={1}
+ value={this.dataDoc.coefficientOfStaticFriction}
+ effect={this.updateReviewForcesBasedOnCoefficient}
+ showIcon={this.dataDoc.showIcon}
+ correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('coefficient of static friction')]}
+ />
+ )}
+ {this.dataDoc.selectedQuestion.answerParts.includes('wedge angle') && (
+ <InputField
+ label={<Box>&theta;</Box>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'wedgeAngle'}
+ step={1}
+ unit={'°'}
+ upperBound={49}
+ value={this.dataDoc.wedgeAngle ?? 26}
+ effect={(val: number) => {
+ this.changeWedgeBasedOnNewAngle(val);
+ this.updateReviewForcesBasedOnAngle(val);
+ }}
+ radianEquivalent={true}
+ showIcon={this.dataDoc.showIcon}
+ correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('wedge angle')]}
+ />
+ )}
+ </div>
+ </div>
+ </div>
+ )}
+ {this.dataDoc.mode == 'Tutorial' && (
+ <div className="wordProblemBox">
+ <div className="question">
+ <h2>Problem</h2>
+ <p>{this.dataDoc.selectedTutorial.question}</p>
+ </div>
+ <div
+ style={{
+ display: 'flex',
+ justifyContent: 'spaceBetween',
+ width: '100%',
+ }}>
+ <IconButton
+ onClick={() => {
+ let step = this.dataDoc.stepNumber - 1;
+ step = Math.max(step, 0);
+ step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1);
+ this.dataDoc.stepNumber = step;
+ this.dataDoc.startForces = this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces);
+ this.dataDoc.updatedForces = this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces);
+ this.dataDoc.showForceMagnitudes = this.dataDoc.selectedTutorial.steps[step].showMagnitude;
+ }}
+ disabled={this.dataDoc.stepNumber == 0}>
+ <ArrowLeftIcon />
+ </IconButton>
+ <div>
+ <h3>
+ Step {this.dataDoc.stepNumber + 1}: {this.dataDoc.selectedTutorial.steps[this.dataDoc.stepNumber].description}
+ </h3>
+ <p>{this.dataDoc.selectedTutorial.steps[this.dataDoc.stepNumber].content}</p>
+ </div>
+ <IconButton
+ onClick={() => {
+ let step = this.dataDoc.stepNumber + 1;
+ step = Math.max(step, 0);
+ step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1);
+ this.dataDoc.stepNumber = step;
+ this.dataDoc.startForces = this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces);
+ this.dataDoc.updatedForces = this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces);
+ this.dataDoc.showForceMagnitudes = this.dataDoc.selectedTutorial.steps[step].showMagnitude;
+ }}
+ disabled={this.dataDoc.stepNumber == this.dataDoc.selectedTutorial.steps.length - 1}>
+ <ArrowRightIcon />
+ </IconButton>
+ </div>
+ <div>
+ {(this.dataDoc.simulationType == 'One Weight' || this.dataDoc.simulationType == 'Inclined Plane' || this.dataDoc.simulationType == 'Pendulum') && <p>Resources</p>}
+ {this.dataDoc.simulationType == 'One Weight' && (
+ <ul>
+ <li>
+ <a
+ href="https://www.khanacademy.org/science/physics/one-dimensional-motion"
+ target="_blank"
+ rel="noreferrer"
+ style={{
+ color: 'blue',
+ textDecoration: 'underline',
+ }}>
+ Khan Academy - One Dimensional Motion
+ </a>
+ </li>
+ <li>
+ <a
+ href="https://www.khanacademy.org/science/physics/two-dimensional-motion"
+ target="_blank"
+ rel="noreferrer"
+ style={{
+ color: 'blue',
+ textDecoration: 'underline',
+ }}>
+ Khan Academy - Two Dimensional Motion
+ </a>
+ </li>
+ </ul>
+ )}
+ {this.dataDoc.simulationType == 'Inclined Plane' && (
+ <ul>
+ <li>
+ <a
+ href="https://www.khanacademy.org/science/physics/forces-newtons-laws#normal-contact-force"
+ target="_blank"
+ rel="noreferrer"
+ style={{
+ color: 'blue',
+ textDecoration: 'underline',
+ }}>
+ Khan Academy - Normal Force
+ </a>
+ </li>
+ <li>
+ <a
+ href="https://www.khanacademy.org/science/physics/forces-newtons-laws#inclined-planes-friction"
+ target="_blank"
+ rel="noreferrer"
+ style={{
+ color: 'blue',
+ textDecoration: 'underline',
+ }}>
+ Khan Academy - Inclined Planes
+ </a>
+ </li>
+ </ul>
+ )}
+ {this.dataDoc.simulationType == 'Pendulum' && (
+ <ul>
+ <li>
+ <a
+ href="https://www.khanacademy.org/science/physics/forces-newtons-laws#tension-tutorial"
+ target="_blank"
+ rel="noreferrer"
+ style={{
+ color: 'blue',
+ textDecoration: 'underline',
+ }}>
+ Khan Academy - Tension
+ </a>
+ </li>
+ </ul>
+ )}
+ </div>
+ </div>
+ )}
+ {this.dataDoc.mode == 'Review' && this.dataDoc.simulationType == 'Inclined Plane' && (
+ <div
+ style={{
+ display: 'flex',
+ justifyContent: 'space-between',
+ marginTop: '10px',
+ }}>
+ <p
+ style={{
+ color: 'blue',
+ textDecoration: 'underline',
+ cursor: 'pointer',
+ }}
+ onClick={() => (this.dataDoc.mode = 'Tutorial')}>
+ {' '}
+ Go to walkthrough{' '}
+ </p>
+ <div style={{ display: 'flex', flexDirection: 'column' }}>
+ <Button
+ onClick={() => {
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.checkAnswers();
+ this.dataDoc.showIcon = true;
+ }}
+ variant="outlined">
+ <p>Submit</p>
+ </Button>
+ <Button
+ onClick={() => {
+ this.generateNewQuestion();
+ this.dataDoc.showIcon = false;
+ }}
+ variant="outlined">
+ <p>New question</p>
+ </Button>
+ </div>
+ </div>
+ )}
+ {this.dataDoc.mode == 'Freeform' && (
+ <div className="vars">
+ <FormControl component="fieldset">
+ <FormGroup>
+ {this.dataDoc.simulationType == 'One Weight' && (
+ <FormControlLabel
+ control={<Checkbox checked={this.dataDoc.elasticCollisions} onChange={() => (this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions)} />}
+ label="Make collisions elastic"
+ labelPlacement="start"
+ />
+ )}
+ <FormControlLabel control={<Checkbox checked={this.dataDoc.showForces} onChange={() => (this.dataDoc.showForces = !this.dataDoc.showForces)} />} label="Show force vectors" labelPlacement="start" />
+ {(this.dataDoc.simulationType == 'Inclined Plane' || this.dataDoc.simulationType == 'Pendulum') && (
+ <FormControlLabel
+ control={<Checkbox checked={this.dataDoc.showForces} onChange={() => (this.dataDoc.showComponentForces = !this.dataDoc.showComponentForces)} />}
+ label="Show component force vectors"
+ labelPlacement="start"
+ />
+ )}
+ <FormControlLabel
+ control={<Checkbox checked={this.dataDoc.showAcceleration} onChange={() => (this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration)} />}
+ label="Show acceleration vector"
+ labelPlacement="start"
+ />
+ <FormControlLabel control={<Checkbox checked={this.dataDoc.showVelocity} onChange={() => (this.dataDoc.showVelocity = !this.dataDoc.showVelocity)} />} label="Show velocity vector" labelPlacement="start" />
+ <InputField label={<Box>Speed</Box>} lowerBound={1} dataDoc={this.dataDoc} prop={'simulationSpeed'} step={1} unit={'x'} upperBound={10} value={this.dataDoc.simulationSpeed ?? 2} labelWidth={'5em'} />
+ {this.dataDoc.simulationPaused && this.dataDoc.simulationType != 'Circular Motion' && (
+ <InputField
+ label={<Box>Gravity</Box>}
+ lowerBound={-30}
+ dataDoc={this.dataDoc}
+ prop={'gravity'}
+ step={0.01}
+ unit={'m/s2'}
+ upperBound={0}
+ value={this.dataDoc.gravity ?? -9.81}
+ effect={(val: number) => {
+ this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ }}
+ labelWidth={'5em'}
+ />
+ )}
+ {this.dataDoc.simulationPaused && this.dataDoc.simulationType != 'Pulley' && (
+ <InputField
+ label={<Box>Mass</Box>}
+ lowerBound={1}
+ dataDoc={this.dataDoc}
+ prop={'mass'}
+ step={0.1}
+ unit={'kg'}
+ upperBound={5}
+ value={this.dataDoc.mass ?? 1}
+ effect={(val: number) => {
+ this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ }}
+ labelWidth={'5em'}
+ />
+ )}
+ {this.dataDoc.simulationPaused && this.dataDoc.simulationType == 'Pulley' && (
+ <InputField
+ label={<Box>Red mass</Box>}
+ lowerBound={1}
+ dataDoc={this.dataDoc}
+ prop={'mass'}
+ step={0.1}
+ unit={'kg'}
+ upperBound={5}
+ value={this.dataDoc.mass ?? 1}
+ effect={(val: number) => {
+ this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ }}
+ labelWidth={'5em'}
+ />
+ )}
+ {this.dataDoc.simulationPaused && this.dataDoc.simulationType == 'Pulley' && (
+ <InputField
+ label={<Box>Blue mass</Box>}
+ lowerBound={1}
+ dataDoc={this.dataDoc}
+ prop={'mass2'}
+ step={0.1}
+ unit={'kg'}
+ upperBound={5}
+ value={this.dataDoc.mass2 ?? 1}
+ effect={(val: number) => {
+ this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ }}
+ labelWidth={'5em'}
+ />
+ )}
+ {this.dataDoc.simulationPaused && this.dataDoc.simulationType == 'Circular Motion' && (
+ <InputField
+ label={<Box>Rod length</Box>}
+ lowerBound={100}
+ dataDoc={this.dataDoc}
+ prop={'circularMotionRadius'}
+ step={5}
+ unit={'m'}
+ upperBound={250}
+ value={this.dataDoc.circularMotionRadius ?? 100}
+ effect={(val: number) => {
+ this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ }}
+ labelWidth={'5em'}
+ />
+ )}
+ </FormGroup>
+ </FormControl>
+ {this.dataDoc.simulationType == 'Spring' && this.dataDoc.simulationPaused && (
+ <div>
+ <InputField
+ label={<Typography color="inherit">Spring stiffness</Typography>}
+ lowerBound={0.1}
+ dataDoc={this.dataDoc}
+ prop={'springConstant'}
+ step={1}
+ unit={'N/m'}
+ upperBound={500}
+ value={this.dataDoc.springConstant ?? 0.5}
+ effect={(val: number) => {
+ this.dataDoc.simulationReset(!this.dataDoc.simulationReset);
+ }}
+ radianEquivalent={false}
+ mode={'Freeform'}
+ labelWidth={'7em'}
+ />
+ <InputField
+ label={<Typography color="inherit">Rest length</Typography>}
+ lowerBound={10}
+ dataDoc={this.dataDoc}
+ prop={'springRestLength'}
+ step={100}
+ unit={''}
+ upperBound={500}
+ value={this.dataDoc.springRestLength ?? 200}
+ effect={(val: number) => {
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }}
+ radianEquivalent={false}
+ mode={'Freeform'}
+ labelWidth={'7em'}
+ />
+ <InputField
+ label={<Typography color="inherit">Starting displacement</Typography>}
+ lowerBound={-(this.dataDoc.springRestLength - 10)}
+ dataDoc={this.dataDoc}
+ prop={''}
+ step={10}
+ unit={''}
+ upperBound={this.dataDoc.springRestLength}
+ value={this.dataDoc.springStartLength - this.dataDoc.springRestLength ?? 0}
+ effect={(val: number) => {
+ this.dataDoc.startPosY = this.dataDoc.springRestLength + val;
+ this.dataDoc.springStartLength = this.dataDoc.springRestLength + val;
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }}
+ radianEquivalent={false}
+ mode={'Freeform'}
+ labelWidth={'7em'}
+ />
+ </div>
+ )}
+ {this.dataDoc.simulationType == 'Inclined Plane' && this.dataDoc.simulationPaused && (
+ <div>
+ <InputField
+ label={<Box>&theta;</Box>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'wedgeAngle'}
+ step={1}
+ unit={'°'}
+ upperBound={49}
+ value={this.dataDoc.wedgeAngle ?? 26}
+ effect={(val: number) => {
+ this.changeWedgeBasedOnNewAngle(val);
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }}
+ radianEquivalent={true}
+ mode={'Freeform'}
+ labelWidth={'2em'}
+ />
+ <InputField
+ label={
+ <Box>
+ &mu;<sub>s</sub>
+ </Box>
+ }
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'coefficientOfStaticFriction'}
+ step={0.1}
+ unit={''}
+ upperBound={1}
+ value={this.dataDoc.coefficientOfStaticFriction ?? 0}
+ effect={(val: number) => {
+ this.updateForcesWithFriction(val);
+ if (val < Number(this.dataDoc.coefficientOfKineticFriction)) {
+ this.dataDoc.soefficientOfKineticFriction = val;
+ }
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }}
+ mode={'Freeform'}
+ labelWidth={'2em'}
+ />
+ <InputField
+ label={
+ <Box>
+ &mu;<sub>k</sub>
+ </Box>
+ }
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'coefficientOfKineticFriction'}
+ step={0.1}
+ unit={''}
+ upperBound={Number(this.dataDoc.coefficientOfStaticFriction)}
+ value={this.dataDoc.coefficientOfKineticFriction ?? 0}
+ effect={(val: number) => {
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }}
+ mode={'Freeform'}
+ labelWidth={'2em'}
+ />
+ </div>
+ )}
+ {this.dataDoc.simulationType == 'Inclined Plane' && !this.dataDoc.simulationPaused && (
+ <Typography>
+ &theta;: {Math.round(Number(this.dataDoc.wedgeAngle) * 100) / 100}° ≈ {Math.round(((Number(this.dataDoc.wedgeAngle) * Math.PI) / 180) * 100) / 100} rad
+ <br />
+ &mu; <sub>s</sub>: {this.dataDoc.coefficientOfStaticFriction}
+ <br />
+ &mu; <sub>k</sub>: {this.dataDoc.coefficientOfKineticFriction}
+ </Typography>
+ )}
+ {this.dataDoc.simulationType == 'Pendulum' && !this.dataDoc.simulationPaused && (
+ <Typography>
+ &theta;: {Math.round(this.dataDoc.pendulumAngle * 100) / 100}° ≈ {Math.round(((this.dataDoc.pendulumAngle * Math.PI) / 180) * 100) / 100} rad
+ </Typography>
+ )}
+ {this.dataDoc.simulationType == 'Pendulum' && this.dataDoc.simulationPaused && (
+ <div>
+ <InputField
+ label={<Box>Angle</Box>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'pendulumAngle'}
+ step={1}
+ unit={'°'}
+ upperBound={59}
+ value={this.dataDoc.pendulumAngle ?? 30}
+ effect={value => {
+ this.dataDoc.startPendulumAngle = value;
+ if (this.dataDoc.simulationType == 'Pendulum') {
+ const mag = this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.cos((value * Math.PI) / 180);
- const forceOfTension: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: 90 - value,
- component: false,
- };
+ const forceOfTension: IForce = {
+ description: 'Tension',
+ magnitude: mag,
+ directionInDegrees: 90 - value,
+ component: false,
+ };
- const tensionComponent: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: 90 - value,
- component: true,
- };
- const gravityParallel: IForce = {
- description: "Gravity Parallel Component",
- magnitude:
- Math.abs(this.dataDoc.gravity) *
- Math.cos((value * Math.PI) / 180),
- directionInDegrees: 270 - value,
- component: true,
- };
- const gravityPerpendicular: IForce = {
- description: "Gravity Perpendicular Component",
- magnitude:
- Math.abs(this.dataDoc.gravity) *
- Math.sin((value * Math.PI) / 180),
- directionInDegrees: -value,
- component: true,
- };
+ const tensionComponent: IForce = {
+ description: 'Tension',
+ magnitude: mag,
+ directionInDegrees: 90 - value,
+ component: true,
+ };
+ const gravityParallel: IForce = {
+ description: 'Gravity Parallel Component',
+ magnitude: Math.abs(this.dataDoc.gravity) * Math.cos((value * Math.PI) / 180),
+ directionInDegrees: 270 - value,
+ component: true,
+ };
+ const gravityPerpendicular: IForce = {
+ description: 'Gravity Perpendicular Component',
+ magnitude: Math.abs(this.dataDoc.gravity) * Math.sin((value * Math.PI) / 180),
+ directionInDegrees: -value,
+ component: true,
+ };
- const length = this.dataDoc.pendulumLength;
- const x =
- length * Math.cos(((90 - value) * Math.PI) / 180);
- const y =
- length * Math.sin(((90 - value) * Math.PI) / 180);
- const xPos = this.xMax / 2 - x - this.dataDoc.radius;
- const yPos = y - this.dataDoc.radius - 5;
- this.dataDoc.startPosX = (xPos);
- this.dataDoc.startPosY= (yPos);
+ const length = this.dataDoc.pendulumLength;
+ const x = length * Math.cos(((90 - value) * Math.PI) / 180);
+ const y = length * Math.sin(((90 - value) * Math.PI) / 180);
+ const xPos = this.xMax / 2 - x - this.dataDoc.radius;
+ const yPos = y - this.dataDoc.radius - 5;
+ this.dataDoc.startPosX = xPos;
+ this.dataDoc.startPosY = yPos;
- this.dataDoc.startForces = ([
- {
- description: "Gravity",
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
- directionInDegrees: 270,
- component: false,
- },
- forceOfTension,
- ]);
- this.dataDoc.updatedForces = ([
- {
- description: "Gravity",
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
- directionInDegrees: 270,
- component: false,
- },
- forceOfTension,
- ]);
- this.dataDoc.componentForces = ([
- tensionComponent,
- gravityParallel,
- gravityPerpendicular,
- ]);
- this.dataDoc.adjustPendulumAngle = ({
- angle: value,
- length: this.dataDoc.pendulumLength,
- });
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- }
- }}
- radianEquivalent={true}
- mode={"Freeform"}
- labelWidth={"5em"}
- />
- <InputField
- label={<Box>Rod length</Box>}
- lowerBound={0}
- dataDoc={this.dataDoc}
- prop={'pendulumLength'}
- step={1}
- unit={"m"}
- upperBound={400}
- value={Math.round(this.dataDoc.pendulumLength)}
- effect={(value) => {
- if (this.dataDoc.simulationType == "Pendulum") {
- this.dataDoc.adjustPendulumAngle = ({
- angle: this.dataDoc.pendulumAngle,
- length: value,
- });
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- }
- }}
- radianEquivalent={false}
- mode={"Freeform"}
- labelWidth={"5em"}
- />
+ this.dataDoc.startForces = [
+ {
+ description: 'Gravity',
+ magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ directionInDegrees: 270,
+ component: false,
+ },
+ forceOfTension,
+ ];
+ this.dataDoc.updatedForces = [
+ {
+ description: 'Gravity',
+ magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ directionInDegrees: 270,
+ component: false,
+ },
+ forceOfTension,
+ ];
+ this.dataDoc.componentForces = [tensionComponent, gravityParallel, gravityPerpendicular];
+ this.dataDoc.adjustPendulumAngle = {
+ angle: value,
+ length: this.dataDoc.pendulumLength,
+ };
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }
+ }}
+ radianEquivalent={true}
+ mode={'Freeform'}
+ labelWidth={'5em'}
+ />
+ <InputField
+ label={<Box>Rod length</Box>}
+ lowerBound={0}
+ dataDoc={this.dataDoc}
+ prop={'pendulumLength'}
+ step={1}
+ unit={'m'}
+ upperBound={400}
+ value={Math.round(this.dataDoc.pendulumLength)}
+ effect={value => {
+ if (this.dataDoc.simulationType == 'Pendulum') {
+ this.dataDoc.adjustPendulumAngle = {
+ angle: this.dataDoc.pendulumAngle,
+ length: value,
+ };
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }
+ }}
+ radianEquivalent={false}
+ mode={'Freeform'}
+ labelWidth={'5em'}
+ />
+ </div>
+ )}
+ </div>
+ )}
+ <div className="mechanicsSimulationEquation">
+ {this.dataDoc.mode == 'Freeform' && (
+ <table>
+ <tbody>
+ <tr>
+ <td>{this.dataDoc.simulationType == 'Pulley' ? 'Red Weight' : ''}</td>
+ <td>X</td>
+ <td>Y</td>
+ </tr>
+ <tr>
+ <td
+ style={{ cursor: 'help' }}
+ // onClick={() => {
+ // window.open(
+ // "https://www.khanacademy.org/science/physics/two-dimensional-motion"
+ // );
+ // }}
+ >
+ <Box>Position</Box>
+ </td>
+ {(!this.dataDoc.simulationPaused || this.dataDoc.simulationType == 'Inclined Plane' || this.dataDoc.simulationType == 'Circular Motion' || this.dataDoc.simulationType == 'Pulley') && (
+ <td style={{ cursor: 'default' }}>{this.dataDoc.positionXDisplay} m</td>
+ )}{' '}
+ {this.dataDoc.simulationPaused && this.dataDoc.simulationType != 'Inclined Plane' && this.dataDoc.simulationType != 'Circular Motion' && this.dataDoc.simulationType != 'Pulley' && (
+ <td
+ style={{
+ cursor: 'default',
+ }}>
+ <InputField
+ lowerBound={this.dataDoc.simulationType == 'Projectile' ? 1 : (this.xMax + this.xMin) / 4 - this.radius - 15}
+ dataDoc={this.dataDoc}
+ prop={'positionXDisplay'}
+ step={1}
+ unit={'m'}
+ upperBound={this.dataDoc.simulationType == 'Projectile' ? this.xMax - 110 : (3 * (this.xMax + this.xMin)) / 4 - this.radius / 2 - 15}
+ value={this.dataDoc.positionXDisplay}
+ effect={value => {
+ this.dataDoc.displayChange = {
+ xDisplay: value,
+ yDisplay: this.dataDoc.positionYDisplay,
+ };
+ if (this.dataDoc['simulationType'] == 'Suspension') {
+ let x1rod = (this.xMax + this.xMin) / 2 - this.radius - this.yMin - 200;
+ let x2rod = (this.xMax + this.xMin) / 2 + this.yMin + 200 + this.radius;
+ let deltaX1 = value + this.radius - x1rod;
+ let deltaX2 = x2rod - (value + this.radius);
+ let deltaY = this.getYPosFromDisplay(this.dataDoc.positionYDisplay) + this.radius;
+ let dir1T = Math.PI - Math.atan(deltaY / deltaX1);
+ let dir2T = Math.atan(deltaY / deltaX2);
+ let tensionMag2 = (this.dataDoc.mass * Math.abs(this.dataDoc.gravity)) / ((-Math.cos(dir2T) / Math.cos(dir1T)) * Math.sin(dir1T) + Math.sin(dir2T));
+ let tensionMag1 = (-tensionMag2 * Math.cos(dir2T)) / Math.cos(dir1T);
+ dir1T = (dir1T * 180) / Math.PI;
+ dir2T = (dir2T * 180) / Math.PI;
+ const tensionForce1: IForce = {
+ description: 'Tension',
+ magnitude: tensionMag1,
+ directionInDegrees: dir1T,
+ component: false,
+ };
+ const tensionForce2: IForce = {
+ description: 'Tension',
+ magnitude: tensionMag2,
+ directionInDegrees: dir2T,
+ component: false,
+ };
+ const grav: IForce = {
+ description: 'Gravity',
+ magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ directionInDegrees: 270,
+ component: false,
+ };
+ this.dataDoc['updatedForces'] = [tensionForce1, tensionForce2, grav];
+ }
+ }}
+ small={true}
+ mode={'Freeform'}
+ />
+ </td>
+ )}{' '}
+ {(!this.dataDoc.simulationPaused || this.dataDoc.simulationType == 'Inclined Plane' || this.dataDoc.simulationType == 'Circular Motion' || this.dataDoc.simulationType == 'Pulley') && (
+ <td style={{ cursor: 'default' }}>{this.dataDoc.positionYDisplay} m</td>
+ )}{' '}
+ {this.dataDoc.simulationPaused && this.dataDoc.simulationType != 'Inclined Plane' && this.dataDoc.simulationType != 'Circular Motion' && this.dataDoc.simulationType != 'Pulley' && (
+ <td
+ style={{
+ cursor: 'default',
+ }}>
+ <InputField
+ lowerBound={1}
+ dataDoc={this.dataDoc}
+ prop={'positionYDisplay'}
+ step={1}
+ unit={'m'}
+ upperBound={this.yMax - 110}
+ value={this.dataDoc.positionYDisplay}
+ effect={value => {
+ this.dataDoc.displayChange = {
+ xDisplay: this.dataDoc.positionXDisplay,
+ yDisplay: value,
+ };
+ if (this.dataDoc['simulationType'] == 'Suspension') {
+ let x1rod = (this.xMax + this.xMin) / 2 - this.radius - this.yMin - 200;
+ let x2rod = (this.xMax + this.xMin) / 2 + this.yMin + 200 + this.radius;
+ let deltaX1 = this.dataDoc.positionXDisplay + this.radius - x1rod;
+ let deltaX2 = x2rod - (this.dataDoc.positionXDisplay + this.radius);
+ let deltaY = this.getYPosFromDisplay(value) + this.radius;
+ let dir1T = Math.PI - Math.atan(deltaY / deltaX1);
+ let dir2T = Math.atan(deltaY / deltaX2);
+ let tensionMag2 = (this.dataDoc.mass * Math.abs(this.dataDoc.gravity)) / ((-Math.cos(dir2T) / Math.cos(dir1T)) * Math.sin(dir1T) + Math.sin(dir2T));
+ let tensionMag1 = (-tensionMag2 * Math.cos(dir2T)) / Math.cos(dir1T);
+ dir1T = (dir1T * 180) / Math.PI;
+ dir2T = (dir2T * 180) / Math.PI;
+ const tensionForce1: IForce = {
+ description: 'Tension',
+ magnitude: tensionMag1,
+ directionInDegrees: dir1T,
+ component: false,
+ };
+ const tensionForce2: IForce = {
+ description: 'Tension',
+ magnitude: tensionMag2,
+ directionInDegrees: dir2T,
+ component: false,
+ };
+ const grav: IForce = {
+ description: 'Gravity',
+ magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ directionInDegrees: 270,
+ component: false,
+ };
+ this.dataDoc['updatedForces'] = [tensionForce1, tensionForce2, grav];
+ }
+ }}
+ small={true}
+ mode={'Freeform'}
+ />
+ </td>
+ )}{' '}
+ </tr>
+ <tr>
+ <td
+ style={{ cursor: 'help' }}
+ // onClick={() => {
+ // window.open(
+ // "https://www.khanacademy.org/science/physics/two-dimensional-motion"
+ // );
+ // }}
+ >
+ <Box>Velocity</Box>
+ </td>
+ {(!this.dataDoc.simulationPaused || (this.dataDoc.simulationType != 'One Weight' && this.dataDoc.simulationType != 'Circular Motion')) && (
+ <td style={{ cursor: 'default' }}>{this.dataDoc.velocityXDisplay} m/s</td>
+ )}{' '}
+ {this.dataDoc.simulationPaused && (this.dataDoc.simulationType == 'One Weight' || this.dataDoc.simulationType == 'Circular Motion') && (
+ <td
+ style={{
+ cursor: 'default',
+ }}>
+ <InputField
+ lowerBound={-50}
+ dataDoc={this.dataDoc}
+ prop={'velocityXDisplay'}
+ step={1}
+ unit={'m/s'}
+ upperBound={50}
+ value={this.dataDoc.velocityXDisplay}
+ effect={value => {
+ this.dataDoc.startVelX = value;
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ }}
+ small={true}
+ mode={'Freeform'}
+ />
+ </td>
+ )}{' '}
+ {(!this.dataDoc.simulationPaused || this.dataDoc.simulationType != 'One Weight') && <td style={{ cursor: 'default' }}>{this.dataDoc.velocityYDisplay} m/s</td>}{' '}
+ {this.dataDoc.simulationPaused && this.dataDoc.simulationType == 'One Weight' && (
+ <td
+ style={{
+ cursor: 'default',
+ }}>
+ <InputField
+ lowerBound={-50}
+ dataDoc={this.dataDoc}
+ prop={'velocityYDisplay'}
+ step={1}
+ unit={'m/s'}
+ upperBound={50}
+ value={this.dataDoc.velocityYDisplay}
+ effect={value => {
+ this.dataDoc.startVelY = -value;
+ this.dataDoc.displayChange = {
+ xDisplay: this.dataDoc.positionXDisplay,
+ yDisplay: this.dataDoc.positionYDisplay,
+ };
+ }}
+ small={true}
+ mode={'Freeform'}
+ />
+ </td>
+ )}{' '}
+ </tr>
+ <tr>
+ <td
+ style={{ cursor: 'help' }}
+ // onClick={() => {
+ // window.open(
+ // "https://www.khanacademy.org/science/physics/two-dimensional-motion"
+ // );
+ // }}
+ >
+ <Box>Acceleration</Box>
+ </td>
+ <td style={{ cursor: 'default' }}>
+ {this.dataDoc.accelerationXDisplay} m/s<sup>2</sup>
+ </td>
+ <td style={{ cursor: 'default' }}>
+ {this.dataDoc.accelerationYDisplay} m/s<sup>2</sup>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <Box>Momentum</Box>
+ </td>
+ <td>{Math.round(this.dataDoc.velocityXDisplay * this.dataDoc.mass * 10) / 10} kg*m/s</td>
+ <td>{Math.round(this.dataDoc.velocityYDisplay * this.dataDoc.mass * 10) / 10} kg*m/s</td>
+ </tr>
+ </tbody>
+ </table>
+ )}
+ {this.dataDoc.mode == 'Freeform' && this.dataDoc.simulationType == 'Pulley' && (
+ <table>
+ <tbody>
+ <tr>
+ <td>Blue Weight</td>
+ <td>X</td>
+ <td>Y</td>
+ </tr>
+ <tr>
+ <td>
+ <Box>Position</Box>
+ </td>
+ <td style={{ cursor: 'default' }}>{this.dataDoc.positionXDisplay2} m</td>
+ <td style={{ cursor: 'default' }}>{this.dataDoc.positionYDisplay2} m</td>
+ </tr>
+ <tr>
+ <td>
+ <Box>Velocity</Box>
+ </td>
+ <td style={{ cursor: 'default' }}>{this.dataDoc.velocityXDisplay2} m/s</td>
+
+ <td style={{ cursor: 'default' }}>{this.dataDoc.velocityYDisplay2} m/s</td>
+ </tr>
+ <tr>
+ <td>
+ <Box>Acceleration</Box>
+ </td>
+ <td style={{ cursor: 'default' }}>
+ {this.dataDoc.accelerationXDisplay2} m/s<sup>2</sup>
+ </td>
+ <td style={{ cursor: 'default' }}>
+ {this.dataDoc.accelerationYDisplay2} m/s<sup>2</sup>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <Box>Momentum</Box>
+ </td>
+ <td>{Math.round(this.dataDoc.velocityXDisplay2 * this.dataDoc.mass * 10) / 10} kg*m/s</td>
+ <td>{Math.round(this.dataDoc.velocityYDisplay2 * this.dataDoc.mass * 10) / 10} kg*m/s</td>
+ </tr>
+ </tbody>
+ </table>
+ )}
+ </div>
+ {this.dataDoc.simulationType != 'Pendulum' && this.dataDoc.simulationType != 'Spring' && (
+ <div>
+ <p>Kinematic Equations</p>
+ <ul>
+ <li>
+ Position: x<sub>1</sub>=x<sub>0</sub>+v<sub>0</sub>t+
+ <sup>1</sup>&frasl;
+ <sub>2</sub>at
+ <sup>2</sup>
+ </li>
+ <li>
+ Velocity: v<sub>1</sub>=v<sub>0</sub>+at
+ </li>
+ <li>Acceleration: a = F/m</li>
+ </ul>
+ </div>
+ )}
+ {this.dataDoc.simulationType == 'Spring' && (
+ <div>
+ <p>Harmonic Motion Equations: Spring</p>
+ <ul>
+ <li>
+ Spring force: F<sub>s</sub>=kd
+ </li>
+ <li>
+ Spring period: T<sub>s</sub>=2&pi;&#8730;<sup>m</sup>&frasl;
+ <sub>k</sub>
+ </li>
+ <li>Equilibrium displacement for vertical spring: d = mg/k</li>
+ <li>
+ Elastic potential energy: U<sub>s</sub>=<sup>1</sup>&frasl;
+ <sub>2</sub>kd<sup>2</sup>
+ </li>
+ <ul>
+ <li>Maximum when system is at maximum displacement, 0 when system is at 0 displacement</li>
+ </ul>
+ <li>
+ Translational kinetic energy: K=<sup>1</sup>&frasl;
+ <sub>2</sub>mv<sup>2</sup>
+ </li>
+ <ul>
+ <li>Maximum when system is at maximum/minimum velocity (at 0 displacement), 0 when velocity is 0 (at maximum displacement)</li>
+ </ul>
+ </ul>
+ </div>
+ )}
+ {this.dataDoc.simulationType == 'Pendulum' && (
+ <div>
+ <p>Harmonic Motion Equations: Pendulum</p>
+ <ul>
+ <li>
+ Pendulum period: T<sub>p</sub>=2&pi;&#8730;<sup>l</sup>&frasl;
+ <sub>g</sub>
+ </li>
+ </ul>
+ </div>
+ )}
+ </div>
</div>
- )}
- </div>
- )}
- <div className="mechanicsSimulationEquation">
- {this.dataDoc.mode == "Freeform" && (
- <table>
- <tbody>
- <tr>
- <td>{this.dataDoc.simulationType == "Pulley" ? "Red Weight" : ""}</td>
- <td>X</td>
- <td>Y</td>
- </tr>
- <tr>
- <td
- style={{ cursor: "help" }}
- // onClick={() => {
- // window.open(
- // "https://www.khanacademy.org/science/physics/two-dimensional-motion"
- // );
- // }}
- >
- <Box>Position</Box>
- </td>
- {(!this.dataDoc.simulationPaused ||
- this.dataDoc.simulationType == "Inclined Plane" ||
- this.dataDoc.simulationType == "Circular Motion" ||
- this.dataDoc.simulationType == "Pulley") && (
- <td style={{ cursor: "default" }}>
- {this.dataDoc.positionXDisplay} m
- </td>
- )}{" "}
- {this.dataDoc.simulationPaused &&
- this.dataDoc.simulationType != "Inclined Plane" &&
- this.dataDoc.simulationType != "Circular Motion" &&
- this.dataDoc.simulationType != "Pulley" && (
- <td
- style={{
- cursor: "default",
- }}
- >
- <InputField
- lowerBound={this.dataDoc.simulationType == "Projectile" ? 1 : (this.xMax + this.xMin) / 4 - this.radius - 15}
- dataDoc={this.dataDoc}
- prop={'positionXDisplay'}
- step={1}
- unit={"m"}
- upperBound={this.dataDoc.simulationType == "Projectile" ? this.xMax - 110 : (3 * (this.xMax + this.xMin)) / 4 - this.radius / 2 - 15}
- value={this.dataDoc.positionXDisplay}
- effect={(value) => {
- this.dataDoc.displayChange = ({
- xDisplay: value,
- yDisplay: this.dataDoc.positionYDisplay,
- });
- if (this.dataDoc['simulationType'] == "Suspension") {
- let x1rod = (this.xMax + this.xMin) / 2 - this.radius - this.yMin - 200;
- let x2rod = (this.xMax + this.xMin) / 2 + this.yMin + 200 + this.radius;
- let deltaX1 = value + this.radius - x1rod;
- let deltaX2 = x2rod - (value + this.radius);
- let deltaY = this.getYPosFromDisplay(this.dataDoc.positionYDisplay) + this.radius;
- let dir1T = Math.PI - Math.atan(deltaY / deltaX1);
- let dir2T = Math.atan(deltaY / deltaX2);
- let tensionMag2 =
- (this.dataDoc.mass * Math.abs(this.dataDoc.gravity)) /
- ((-Math.cos(dir2T) / Math.cos(dir1T)) * Math.sin(dir1T) +
- Math.sin(dir2T));
- let tensionMag1 =
- (-tensionMag2 * Math.cos(dir2T)) / Math.cos(dir1T);
- dir1T = (dir1T * 180) / Math.PI;
- dir2T = (dir2T * 180) / Math.PI;
- const tensionForce1: IForce = {
- description: "Tension",
- magnitude: tensionMag1,
- directionInDegrees: dir1T,
- component: false,
- };
- const tensionForce2: IForce = {
- description: "Tension",
- magnitude: tensionMag2,
- directionInDegrees: dir2T,
- component: false,
- };
- const grav: IForce = {
- description: "Gravity",
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 270,
- component: false,
- };
- this.dataDoc['updatedForces'] = ([tensionForce1, tensionForce2, grav]);
- }
- }}
- small={true}
- mode={"Freeform"}
- />
- </td>
- )}{" "}
- {(!this.dataDoc.simulationPaused ||
- this.dataDoc.simulationType == "Inclined Plane" ||
- this.dataDoc.simulationType == "Circular Motion" ||
- this.dataDoc.simulationType == "Pulley") && (
- <td style={{ cursor: "default" }}>
- {this.dataDoc.positionYDisplay} m
- </td>
- )}{" "}
- {this.dataDoc.simulationPaused &&
- this.dataDoc.simulationType != "Inclined Plane" &&
- this.dataDoc.simulationType != "Circular Motion" &&
- this.dataDoc.simulationType != "Pulley" && (
- <td
- style={{
- cursor: "default",
- }}
- >
- <InputField
- lowerBound={1}
- dataDoc={this.dataDoc}
- prop={'positionYDisplay'}
- step={1}
- unit={"m"}
- upperBound={this.yMax - 110}
- value={this.dataDoc.positionYDisplay}
- effect={(value) => {
- this.dataDoc.displayChange = ({
- xDisplay: this.dataDoc.positionXDisplay,
- yDisplay: value,
- });
- if (this.dataDoc['simulationType'] == "Suspension") {
- let x1rod = (this.xMax + this.xMin) / 2 - this.radius - this.yMin - 200;
- let x2rod = (this.xMax + this.xMin) / 2 + this.yMin + 200 + this.radius;
- let deltaX1 = this.dataDoc.positionXDisplay + this.radius - x1rod;
- let deltaX2 = x2rod - (this.dataDoc.positionXDisplay + this.radius);
- let deltaY = this.getYPosFromDisplay(value) + this.radius;
- let dir1T = Math.PI - Math.atan(deltaY / deltaX1);
- let dir2T = Math.atan(deltaY / deltaX2);
- let tensionMag2 =
- (this.dataDoc.mass * Math.abs(this.dataDoc.gravity)) /
- ((-Math.cos(dir2T) / Math.cos(dir1T)) * Math.sin(dir1T) +
- Math.sin(dir2T));
- let tensionMag1 =
- (-tensionMag2 * Math.cos(dir2T)) / Math.cos(dir1T);
- dir1T = (dir1T * 180) / Math.PI;
- dir2T = (dir2T * 180) / Math.PI;
- const tensionForce1: IForce = {
- description: "Tension",
- magnitude: tensionMag1,
- directionInDegrees: dir1T,
- component: false,
- };
- const tensionForce2: IForce = {
- description: "Tension",
- magnitude: tensionMag2,
- directionInDegrees: dir2T,
- component: false,
- };
- const grav: IForce = {
- description: "Gravity",
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
- directionInDegrees: 270,
- component: false,
- };
- this.dataDoc['updatedForces'] = ([tensionForce1, tensionForce2, grav]);
- }
- }}
- small={true}
- mode={"Freeform"}
- />
- </td>
- )}{" "}
- </tr>
- <tr>
- <td
- style={{ cursor: "help" }}
- // onClick={() => {
- // window.open(
- // "https://www.khanacademy.org/science/physics/two-dimensional-motion"
- // );
- // }}
- >
- <Box>Velocity</Box>
- </td>
- {(!this.dataDoc.simulationPaused ||
- (this.dataDoc.simulationType != "One Weight" &&
- this.dataDoc.simulationType != "Circular Motion")) && (
- <td style={{ cursor: "default" }}>
- {this.dataDoc.velocityXDisplay} m/s
- </td>
- )}{" "}
- {this.dataDoc.simulationPaused &&
- (this.dataDoc.simulationType == "One Weight" ||
- this.dataDoc.simulationType == "Circular Motion") && (
- <td
- style={{
- cursor: "default",
- }}
- >
- <InputField
- lowerBound={-50}
- dataDoc={this.dataDoc}
- prop={'velocityXDisplay'}
- step={1}
- unit={"m/s"}
- upperBound={50}
- value={this.dataDoc.velocityXDisplay}
- effect={(value) => {
- this.dataDoc.startVelX = (value);
- this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
- }}
- small={true}
- mode={"Freeform"}
- />
- </td>
- )}{" "}
- {(!this.dataDoc.simulationPaused || this.dataDoc.simulationType != "One Weight") && (
- <td style={{ cursor: "default" }}>
- {this.dataDoc.velocityYDisplay} m/s
- </td>
- )}{" "}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "One Weight" && (
- <td
+ <div
+ style={{
+ position: 'fixed',
+ top: this.yMax - 120 + 20 + 'px',
+ left: this.xMin + 90 - 80 + 'px',
+ zIndex: -10000,
+ }}>
+ <svg width={100 + 'px'} height={100 + 'px'}>
+ <defs>
+ <marker id="miniArrow" markerWidth="20" markerHeight="20" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
+ <path d="M0,0 L0,6 L9,3 z" fill={'#000000'} />
+ </marker>
+ </defs>
+ <line x1={20} y1={70} x2={70} y2={70} stroke={'#000000'} strokeWidth="2" markerEnd="url(#miniArrow)" />
+ <line x1={20} y1={70} x2={20} y2={20} stroke={'#000000'} strokeWidth="2" markerEnd="url(#miniArrow)" />
+ </svg>
+ <p
style={{
- cursor: "default",
- }}
- >
- <InputField
- lowerBound={-50}
- dataDoc={this.dataDoc}
- prop={'velocityYDisplay'}
- step={1}
- unit={"m/s"}
- upperBound={50}
- value={this.dataDoc.velocityYDisplay}
- effect={(value) => {
- this.dataDoc.startVelY = (-value);
- this.dataDoc.displayChange = ({
- xDisplay: this.dataDoc.positionXDisplay,
- yDisplay: this.dataDoc.positionYDisplay,
- });
- }}
- small={true}
- mode={"Freeform"}
- />
- </td>
- )}{" "}
- </tr>
- <tr>
- <td
- style={{ cursor: "help" }}
- // onClick={() => {
- // window.open(
- // "https://www.khanacademy.org/science/physics/two-dimensional-motion"
- // );
- // }}
- >
- <Box>Acceleration</Box>
- </td>
- <td style={{ cursor: "default" }}>
- {this.dataDoc.accelerationXDisplay} m/s<sup>2</sup>
- </td>
- <td style={{ cursor: "default" }}>
- {this.dataDoc.accelerationYDisplay} m/s<sup>2</sup>
- </td>
- </tr>
- <tr>
- <td>
- <Box>Momentum</Box>
- </td>
- <td>
- {Math.round(this.dataDoc.velocityXDisplay * this.dataDoc.mass * 10) / 10} kg*m/s
- </td>
- <td>
- {Math.round(this.dataDoc.velocityYDisplay * this.dataDoc.mass * 10) / 10} kg*m/s
- </td>
- </tr>
- </tbody>
- </table>
- )}
- {this.dataDoc.mode == "Freeform" && this.dataDoc.simulationType == "Pulley" && (
- <table>
- <tbody>
- <tr>
- <td>Blue Weight</td>
- <td>X</td>
- <td>Y</td>
- </tr>
- <tr>
- <td>
- <Box>Position</Box>
- </td>
- <td style={{ cursor: "default" }}>{this.dataDoc.positionXDisplay2} m</td>
- <td style={{ cursor: "default" }}>{this.dataDoc.positionYDisplay2} m</td>
- </tr>
- <tr>
- <td>
- <Box>Velocity</Box>
- </td>
- <td style={{ cursor: "default" }}>
- {this.dataDoc.velocityXDisplay2} m/s
- </td>
-
- <td style={{ cursor: "default" }}>
- {this.dataDoc.velocityYDisplay2} m/s
- </td>
- </tr>
- <tr>
- <td>
- <Box>Acceleration</Box>
- </td>
- <td style={{ cursor: "default" }}>
- {this.dataDoc.accelerationXDisplay2} m/s<sup>2</sup>
- </td>
- <td style={{ cursor: "default" }}>
- {this.dataDoc.accelerationYDisplay2} m/s<sup>2</sup>
- </td>
- </tr>
- <tr>
- <td>
- <Box>Momentum</Box>
- </td>
- <td>
- {Math.round(this.dataDoc.velocityXDisplay2 * this.dataDoc.mass * 10) / 10} kg*m/s
- </td>
- <td>
- {Math.round(this.dataDoc.velocityYDisplay2 * this.dataDoc.mass * 10) / 10} kg*m/s
- </td>
- </tr>
- </tbody>
- </table>
- )}
- </div>
- {this.dataDoc.simulationType != "Pendulum" && this.dataDoc.simulationType != "Spring" && (
- <div>
- <p>Kinematic Equations</p>
- <ul>
- <li>
- Position: x<sub>1</sub>=x<sub>0</sub>+v<sub>0</sub>t+
- <sup>1</sup>&frasl;
- <sub>2</sub>at
- <sup>2</sup>
- </li>
- <li>
- Velocity: v<sub>1</sub>=v<sub>0</sub>+at
- </li>
- <li>Acceleration: a = F/m</li>
- </ul>
- </div>
- )}
- {this.dataDoc.simulationType == "Spring" && (
- <div>
- <p>Harmonic Motion Equations: Spring</p>
- <ul>
- <li>
- Spring force: F<sub>s</sub>=kd
- </li>
- <li>
- Spring period: T<sub>s</sub>=2&pi;&#8730;<sup>m</sup>&frasl;
- <sub>k</sub>
- </li>
- <li>Equilibrium displacement for vertical spring: d = mg/k</li>
- <li>
- Elastic potential energy: U<sub>s</sub>=<sup>1</sup>&frasl;
- <sub>2</sub>kd<sup>2</sup>
- </li>
- <ul>
- <li>
- Maximum when system is at maximum displacement, 0 when
- system is at 0 displacement
- </li>
- </ul>
- <li>
- Translational kinetic energy: K=<sup>1</sup>&frasl;
- <sub>2</sub>mv<sup>2</sup>
- </li>
- <ul>
- <li>
- Maximum when system is at maximum/minimum velocity (at 0
- displacement), 0 when velocity is 0 (at maximum
- displacement)
- </li>
- </ul>
- </ul>
- </div>
- )}
- {this.dataDoc.simulationType == "Pendulum" && (
- <div>
- <p>Harmonic Motion Equations: Pendulum</p>
- <ul>
- <li>
- Pendulum period: T<sub>p</sub>=2&pi;&#8730;<sup>l</sup>&frasl;
- <sub>g</sub>
- </li>
- </ul>
+ position: 'fixed',
+ top: this.yMax - 120 + 40 + 'px',
+ left: this.xMin + 90 - 80 + 'px',
+ }}>
+ {this.dataDoc.simulationType == 'Circular Motion' ? 'Z' : 'Y'}
+ </p>
+ <p
+ style={{
+ position: 'fixed',
+ top: this.yMax - 120 + 80 + 'px',
+ left: this.xMin + 90 - 40 + 'px',
+ }}>
+ X
+ </p>
+ </div>
</div>
- )}
- </div>
- </div>
- <div
- style={{
- position: "fixed",
- top: this.yMax - 120 + 20 + "px",
- left: this.xMin + 90 - 80 + "px",
- zIndex: -10000,
- }}
- >
- <svg width={100 + "px"} height={100 + "px"}>
- <defs>
- <marker
- id="miniArrow"
- markerWidth="20"
- markerHeight="20"
- refX="0"
- refY="3"
- orient="auto"
- markerUnits="strokeWidth"
- >
- <path d="M0,0 L0,6 L9,3 z" fill={"#000000"} />
- </marker>
- </defs>
- <line
- x1={20}
- y1={70}
- x2={70}
- y2={70}
- stroke={"#000000"}
- strokeWidth="2"
- markerEnd="url(#miniArrow)"
- />
- <line
- x1={20}
- y1={70}
- x2={20}
- y2={20}
- stroke={"#000000"}
- strokeWidth="2"
- markerEnd="url(#miniArrow)"
- />
- </svg>
- <p
- style={{
- position: "fixed",
- top: this.yMax - 120 + 40 + "px",
- left: this.xMin + 90 - 80 + "px",
- }}
- >
- {this.dataDoc.simulationType == "Circular Motion" ? "Z" : "Y"}
- </p>
- <p
- style={{
- position: "fixed",
- top: this.yMax - 120 + 80 + "px",
- left: this.xMin + 90 - 40 + "px",
- }}
- >
- X
- </p>
- </div>
- </div>
- )
- }
-} \ No newline at end of file
+ );
+ }
+}