aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbrynnchernosky <56202540+brynnchernosky@users.noreply.github.com>2023-05-01 12:51:12 -0400
committerbrynnchernosky <56202540+brynnchernosky@users.noreply.github.com>2023-05-01 12:51:12 -0400
commitf327a27d664f45c10a90a4464cd0fa5edec59b68 (patch)
tree2d5ede56c23493101f2f67a8c64be519dd6c298b /src
parent0cda1a8f8b4e3d79c30291685456c7cb62fd7e8e (diff)
start adding box code
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx745
-rw-r--r--src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx83
2 files changed, 346 insertions, 482 deletions
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
index d0e854263..f27843ab0 100644
--- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
@@ -6,22 +6,41 @@ import { observer } from 'mobx-react';
import "./PhysicsSimulationBox.scss";
import Weight from "./PhysicsSimulationWeight";
import Wall from "./PhysicsSimulationWall"
-import Wedge from "./PhysicsSimulationWedge"
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { CheckBox } from "../search/CheckBox";
-export interface IForce {
- description: string;
- magnitude: number;
- directionInDegrees: number;
-}
-export interface IWallProps {
- length: number;
- xPos: number;
- yPos: number;
- angleInDegrees: number;
-}
-
-interface PhysicsVectorTemplate {
+import PauseIcon from "@mui/icons-material/Pause";
+import PlayArrowIcon from "@mui/icons-material/PlayArrow";
+import ReplayIcon from "@mui/icons-material/Replay";
+import QuestionMarkIcon from "@mui/icons-material/QuestionMark";
+import ArrowLeftIcon from "@mui/icons-material/ArrowLeft";
+import ArrowRightIcon from "@mui/icons-material/ArrowRight";
+import EditIcon from "@mui/icons-material/Edit";
+import EditOffIcon from "@mui/icons-material/EditOff";
+import {
+ Box,
+ Button,
+ Checkbox,
+ Dialog,
+ DialogTitle,
+ DialogContent,
+ DialogContentText,
+ DialogActions,
+ FormControl,
+ FormControlLabel,
+ FormGroup,
+ IconButton,
+ LinearProgress,
+ Stack,
+} from "@mui/material";
+import Typography from "@mui/material/Typography";
+import React, { useEffect, useState } from "react";
+import "./App.scss";
+import { InputField } from "./InputField";
+import questions from "./PhysicsSimulationQuestions.json";
+import tutorials from "./PhysicsSimulationTutorial.json";
+import { IWallProps, Wall } from "./Wall";
+import { IForce, Weight } from "./Weight";
+interface VectorTemplate {
top: number;
left: number;
width: number;
@@ -33,118 +52,191 @@ interface PhysicsVectorTemplate {
weightX: number;
weightY: number;
}
+interface QuestionTemplate {
+ questionSetup: string[];
+ variablesForQuestionSetup: string[];
+ question: string;
+ answerParts: string[];
+ answerSolutionDescriptions: string[];
+ goal: string;
+ hints: { description: string; content: string }[];
+}
+
+interface TutorialTemplate {
+ question: string;
+ steps: {
+ description: string;
+ content: string;
+ forces: {
+ description: string;
+ magnitude: number;
+ directionInDegrees: number;
+ component: boolean;
+ }[];
+ showMagnitude: boolean;
+ }[];
+}
@observer
export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }
- // Constants
- gravityMagnitude = 9.81;
- forceOfGravity: IForce = {
- description: "Gravity",
- magnitude: this.gravityMagnitude,
- directionInDegrees: 270,
- };
- xMin = 0;
- yMin = 0;
- xMax = 300;
- yMax = 300;
- color = `rgba(0,0,0,0.5)`;
- radius = 0.1*this.yMax
- update = true
- menuIsOpen = false
-
constructor(props: any) {
super(props);
}
- // Add one weight to the simulation
- addWeight () {
- this.dataDoc.weight = true;
- this.dataDoc.wedge = false;
- this.dataDoc.pendulum = false;
- this.addWalls();
- };
+ // Constants
+ const xMin = 0;
+ const yMin = 0;
+ const xMax = window.innerWidth * 0.7;
+ const yMax = window.innerHeight * 0.8;
+ const color = `rgba(0,0,0,0.5)`;
+ const radius = 50;
+ const wallPositions: IWallProps[] = [];
- // Set weight defaults
- setToWeightDefault () {
- this.dataDoc.startPosY = this.yMin+this.radius;
- this.dataDoc.startPosX = (this.xMax+this.xMin-this.radius)/2;
- this.dataDoc.updatedForces = [this.forceOfGravity];
- this.dataDoc.startForces = [this.forceOfGravity];
- }
- // Add a wedge with a One Weight to the simulation
- addWedge () {
- this.dataDoc.weight = true;
- this.dataDoc.wedge = true;
- this.dataDoc.pendulum = false;
- this.addWalls();
- };
+ componentDidMount() {
+ this.wallPositions.push({ length: 70, xPos: 0, yPos: 0, angleInDegrees: 0 });
+ this.wallPositions.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 });
+ this.wallPositions.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 });
+ this.wallPositions.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 });
- // Set wedge defaults
- setToWedgeDefault () {
- this.changeWedgeBasedOnNewAngle(26);
- this.updateForcesWithFriction(this.dataDoc.coefficientOfStaticFriction);
- }
+ // Used throughout sims
+ this.xMax = this.layoutDoc._width;
+ this.yMax = this.layoutDoc._height;
+ this.radius = 0.1*this.layoutDoc._height;
+ this.dataDoc.reviewCoefficient = this.dataDoc.reviewCoefficient ?? 0;
+ this.dataDoc.questionVariables = this.dataDoc.questionVariables ?? [];
+ this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0;
+ this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0;
+ this.dataDoc.componentForces = this.dataDoc.componentForces ?? [];
+ this.dataDoc.displayChange = this.dataDoc.displayChange ?? { xDisplay: 0, yDisplay: 0 };
+ this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false;
+ this.dataDoc.gravity = this.dataDoc.gravity ?? -9.81;
+ this.dataDoc.mass = this.dataDoc.mass ?? 1;
+ this.dataDoc.mode = this.dataDoc.mode ?? "Freeform";
+ this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0;
+ this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0;
+ this.dataDoc.resetAll = this.dataDoc.resetAll ?? true;
+ this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false;
+ this.dataDoc.showComponentForces = this.dataDoc.showComponentForces ?? false;
+ this.dataDoc.showForces = this.dataDoc.showForces ?? true;
+ this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? true;
+ this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false;
+ this.dataDoc.simulationPaused = this.dataDoc.simulationPaused ?? true;
+ this.dataDoc.simulationReset = this.dataDoc.simulationReset ?? false;
+ this.dataDoc.simulationSpeed = this.dataDoc.simulationSpeed ?? 2;
+ this.dataDoc.simulationType = this.dataDoc.simulationType ?? "Inclined Plane";
+ this.dataDoc.startForces = this.dataDoc.startForces ?? [];
+ this.dataDoc.startPosX = this.dataDoc.startPosX ?? 0;
+ this.dataDoc.startPosY = this.dataDoc.startPosY ?? 0;
+ this.dataDoc.startVelX = this.dataDoc.startVelX ?? 0;
+ this.dataDoc.startVelY = this.dataDoc.startVelY ?? 0;
+ this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0;
+ this.dataDoc.timer = this.dataDoc.timer ?? 0;
+ this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [];
+ this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0;
+ this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0;
- // Add a simple pendulum to the simulation
- addPendulum = () => {
- this.dataDoc.weight = true;
- this.dataDoc.wedge = false;
- this.dataDoc.pendulum = true;
- this.removeWalls();
- let angle = this.dataDoc.pendulumAngle;
- let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
- let forceOfTension: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: 90 - angle,
- };
- this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension];
- this.dataDoc.startForces = [this.forceOfGravity, forceOfTension];
- };
+ // Used for review mode
+ this.dataDoc.answerInputFields = this.dataDoc.answerInputFields ?? <div></div>;
+ this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? null;
+ this.dataDoc.deleteMode = this.dataDoc.deleteMode ?? false;
+ this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? [];
+ this.dataDoc.hintDialogueOpen = this.dataDoc.hintDialogueOpen ?? false;
+ this.dataDoc.noMovement = this.dataDoc.noMovement ?? false;
+ this.dataDoc.questionNumber = this.dataDoc.questionNumber ?? 0;
+ this.dataDoc.questionPartOne = this.dataDoc.questionPartOne ?? "";
+ this.dataDoc.questionPartTwo = this.dataDoc.questionPartTwo ?? "";
+ this.dataDoc.reviewGravityAngle = this.dataDoc.reviewGravityAngle ?? 0;
+ this.dataDoc.reviewGravityMagnitude = this.dataDoc.reviewGravityMagnitude ?? 0;
+ this.dataDoc.reviewNormalAngle = this.dataDoc.reviewNormalAngle ?? 0;
+ this.dataDoc.reviewNormalMagnitude = this.dataDoc.reviewNormalMagnitude ?? 0;
+ this.dataDoc.reviewStaticAngle = this.dataDoc.reviewStaticAngle ?? 0;
+ this.dataDoc.reviewStaticMagnitude = this.dataDoc.reviewStaticMagnitude ?? 0;
+ this.dataDoc.selectedSolutions = this.dataDoc.selectedSolutions ?? [];
+ this.dataDoc.selectedQuestion = this.dataDoc.selectedQuestion ?? questions.inclinePlane[0];
+ this.dataDoc.sketching = this.dataDoc.sketching ?? false;
+
+ // Used for tutorial mode
+ this.dataDoc.selectedTutorial = this.dataDoc.selectedTutorial ?? tutorials.inclinePlane;
- // Set pendulum defaults
- setToPendulumDefault () {
- let length = this.xMax*0.7;
- let angle = 35;
- let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
- let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
- let xPos = this.xMax / 2 - x - this.radius;
- let yPos = y - this.radius;
- this.dataDoc.startPosX = xPos;
- this.dataDoc.startPosY = yPos;
- let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
- this.dataDoc.pendulumAngle = angle;
- this.dataDoc.pendulumLength = length;
- this.dataDoc.startPendulumAngle = angle;
- this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle;
+ // Used for uniform circular motion
+ this.dataDoc.circularMotionRadius = this.dataDoc.circularMotionRadius ?? 150;
+
+ // Used for spring simulation
+ this.dataDoc.springConstant = this.dataDoc.springConstant ?? 0.5;
+ this.dataDoc.springRestLength = this.dataDoc.springRestLength ?? 200;
+ this.dataDoc.springStartLength = this.dataDoc.springStartLength ?? 200;
+
+ // Used for pendulum simulation
+ this.dataDoc.adjustPendulumAngle = this.dataDoc.adjustPendulumAngle ?? { angle: 0, length: 0 };
+ this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 0;
+ this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300;
+ this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0;
+
+ // Used for wedge simulation
+ this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0;
+ this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0;
+ this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26;
+ this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * 400;
+ this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? 400;
+
+ // Used for pulley simulation
+ this.dataDoc.positionXDisplay2 = this.dataDoc.positionXDisplay2 ?? 0;
+ this.dataDoc.velocityXDisplay2 = this.dataDoc.velocityXDisplay2 ?? 0;
+ this.dataDoc.accelerationXDisplay2 = this.dataDoc.accelerationXDisplay2 ?? 0;
+ this.dataDoc.positionYDisplay2 = this.dataDoc.positionYDisplay2 ?? 0;
+ this.dataDoc.velocityYDisplay2 = this.dataDoc.velocityYDisplay2 ?? 0;
+ this.dataDoc.accelerationYDisplay2 = this.dataDoc.accelerationYDisplay2 ?? 0;
+ this.dataDoc.startPosX2 = this.dataDoc.startPosX2 ?? 0;
+ this.dataDoc.startPosY2 = this.dataDoc.startPosY2 ?? 0;
+ this.dataDoc.displayChange2 = this.dataDoc.displayChange2 ?? { xDisplay: 0, yDisplay: 0 };
+ this.dataDoc.startForces2 = this.dataDoc.startForces2 ?? [];
+ this.dataDoc.updatedForces2 = this.dataDoc.updatedForces2 ?? [];
+ this.dataDoc.mass2 = this.dataDoc.mass2 ?? 1;
+ }
+
+ componentDidUpdate() {
+ this.xMax = this.layoutDoc._width;
+ this.yMax = this.layoutDoc._height;
+ this.radius = 0.1*this.layoutDoc._height;
}
+ // Helper function to go between display and real values
+ getDisplayYPos = (yPos: number) => {
+ return this.yMax - this.dataDoc.yPos - 2 * this.radius + 5;
+ };
+ getYPosFromDisplay = (yDisplay: number) => {
+ return this.yMax - this.dataDoc.yDisplay - 2 * this.radius + 5;
+ };
+
// Update forces when coefficient of static friction changes in freeform mode
- updateForcesWithFriction (
+ updateForcesWithFriction = (
coefficient: number,
- width: number = this.dataDoc.wedgeWidth,
- height: number = this.dataDoc.wedgeHeight
- ) {
- let normalForce = {
+ width: number = this.wedgeWidth,
+ height: number = this.wedgeHeight
+ ) => {
+ const normalForce: IForce = {
description: "Normal Force",
- magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)),
+ magnitude: Math.abs(this.gravity) * Math.cos(Math.atan(height / width)) * this.mass,
directionInDegrees:
180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
+ component: false,
};
let frictionForce: IForce = {
description: "Static Friction Force",
magnitude:
coefficient *
- this.forceOfGravity.magnitude *
- Math.cos(Math.atan(height / width)),
+ Math.abs(this.gravity) *
+ Math.cos(Math.atan(height / width)) *
+ this.mass,
directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
+ component: false,
};
- // reduce magnitude of friction force if necessary such that block cannot slide up plane
- let yForce = -this.forceOfGravity.magnitude;
+ // reduce magnitude or friction force if necessary such that block cannot slide up plane
+ let yForce = -Math.abs(this.gravity) * this.mass;
yForce +=
normalForce.magnitude *
Math.sin((normalForce.directionInDegrees * Math.PI) / 180);
@@ -155,15 +247,65 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi
frictionForce.magnitude =
(-normalForce.magnitude *
Math.sin((normalForce.directionInDegrees * Math.PI) / 180) +
- this.forceOfGravity.magnitude) /
+ Math.abs(this.gravity) * this.mass) /
Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
}
+ const frictionForceComponent: IForce = {
+ description: "Static Friction Force",
+ magnitude:
+ coefficient * Math.abs(this.gravity) * Math.cos(Math.atan(height / width)),
+ directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
+ component: true,
+ };
+ const normalForceComponent: IForce = {
+ description: "Normal Force",
+ magnitude: Math.abs(this.gravity) * Math.cos(Math.atan(height / width)),
+ directionInDegrees:
+ 180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
+ component: true,
+ };
+ const gravityParallel: IForce = {
+ description: "Gravity Parallel Component",
+ magnitude:
+ this.mass *
+ Math.abs(this.gravity) *
+ Math.sin(Math.PI / 2 - Math.atan(height / width)),
+ directionInDegrees:
+ 180 - 90 - (Math.atan(height / width) * 180) / Math.PI + 180,
+ component: true,
+ };
+ const gravityPerpendicular: IForce = {
+ description: "Gravity Perpendicular Component",
+ magnitude:
+ this.mass *
+ Math.abs(this.gravity) *
+ Math.cos(Math.PI / 2 - Math.atan(height / width)),
+ directionInDegrees: 360 - (Math.atan(height / width) * 180) / Math.PI,
+ component: true,
+ };
+ const gravityForce: IForce = {
+ description: "Gravity",
+ magnitude: this.mass * Math.abs(this.gravity),
+ directionInDegrees: 270,
+ component: false,
+ };
if (coefficient != 0) {
- this.dataDoc.startForces = [this.forceOfGravity, normalForce, frictionForce];
- this.dataDoc.updatedForces = [this.forceOfGravity, normalForce, frictionForce];
+ this.dataDoc.startForces = [gravityForce, normalForce, frictionForce];
+ this.dataDoc.updatedForces = [gravityForce, normalForce, frictionForce];
+ this.dataDoc.componentForces = [
+ frictionForceComponent,
+ normalForceComponent,
+ gravityParallel,
+ gravityPerpendicular,
+ ];
} else {
- this.dataDoc.startForces = [this.forceOfGravity, normalForce];
- this.dataDoc.updatedForces = [this.forceOfGravity, normalForce];
+ this.dataDoc.startForces = [gravityForce, normalForce];
+ this.dataDoc.updatedForces = [gravityForce, normalForce];
+ this.dataDoc.componentForces = [
+ normalForceComponent,
+ gravityParallel,
+ gravityPerpendicular,
+ ];
}
};
@@ -172,323 +314,128 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi
let width = 0;
let height = 0;
if (angle < 50) {
- width = this.xMax*0.6;
- height = Math.tan((angle * Math.PI) / 180) * width;
+ width = 400;
+ height = Math.tan((angle * Math.PI) / 180) * 400;
this.dataDoc.wedgeWidth = width;
this.dataDoc.wedgeHeight = height;
} else if (angle < 70) {
- width = this.xMax*0.3;
- height = Math.tan((angle * Math.PI) / 180) * width;
+ width = 200;
+ height = Math.tan((angle * Math.PI) / 180) * 200;
this.dataDoc.wedgeWidth = width;
this.dataDoc.wedgeHeight = height;
} else {
- width = this.xMax*0.15;
- height = Math.tan((angle * Math.PI) / 180) * width;
- this.dataDoc.wedgeWidth = width;
+ width = 100;
+ height = Math.tan((angle * Math.PI) / 180) * 100;
+ this.dataDoc.wedgeWidth = width;
this.dataDoc.wedgeHeight = height;
}
// update weight position based on updated wedge width/height
- let xPos = (this.xMax * 0.2)-this.radius;
- let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius;
+ let yPos = (width - this.radius) * Math.tan((angle * Math.PI) / 180);
+ if (angle < 40) {
+ yPos += Math.sqrt(angle);
+ } else if (angle < 58) {
+ yPos += angle / 2;
+ } else if (angle < 68) {
+ yPos += angle;
+ } else if (angle < 70) {
+ yPos += angle * 1.3;
+ } else if (angle < 75) {
+ yPos += angle * 1.5;
+ } else if (angle < 78) {
+ yPos += angle * 2;
+ } else if (angle < 79) {
+ yPos += angle * 2.25;
+ } else if (angle < 80) {
+ yPos += angle * 2.6;
+ } else {
+ yPos += angle * 3;
+ }
- this.dataDoc.startPosX = xPos;
+ this.dataDoc.startPosX = Math.round((this.xMax * 0.5 - 200) * 10) / 10;
this.dataDoc.startPosY = this.getDisplayYPos(yPos);
- this.updateForcesWithFriction(
- Number(this.dataDoc.coefficientOfStaticFriction),
- width,
- height
- );
- this.dataDoc['updateDisplay'] = !this.dataDoc['updateDisplay']
- };
-
- // Helper function to go between display and real values
- getDisplayYPos = (yPos: number) => {
- return this.yMax - yPos - 2 * 50 + 5;
- };
-
- // In review mode, edit force arrow sketch on mouse movement
- editForce = (element: PhysicsVectorTemplate) => {
- if (!this.dataDoc.sketching) {
- let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element);
- this.dataDoc.forceSketches = sketches;
- this.dataDoc.currentForceSketch = element;
- this.dataDoc.sketching = true;
+ if (this.dataDoc.mode == "Freeform") {
+ this.updateForcesWithFriction(
+ Number(this.dataDoc.coefficientOfStaticFriction),
+ width,
+ height
+ );
}
};
- // In review mode, used to delete force arrow sketch on SHIFT+click
- deleteForce = (element: PhysicsVectorTemplate) => {
- if (!this.dataDoc.sketching) {
- let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element);
- this.dataDoc.forceSketches = sketches;
+ // In review mode, update forces when coefficient of static friction changed
+ updateReviewForcesBasedOnCoefficient = (coefficient: number) => {
+ let theta: number = Number(this.dataDoc.wedgeAngle);
+ let index =
+ this.dataDoc.selectedQuestion.variablesForQuestionSetup.indexOf("theta - max 45");
+ if (index >= 0) {
+ theta = this.dataDoc.questionVariables[index];
}
+ if (isNaN(theta)) {
+ return;
+ }
+ this.dataDoc.reviewGravityMagnitude = (Math.abs(this.dataDoc.gravity));
+ this.dataDoc.reviewGravityAngle = (270);
+ this.dataDoc.reviewNormalMagnitude = (
+ Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180)
+ );
+ this.dataDoc.reviewNormalAngle = (90 - theta);
+ let yForce = -Math.abs(this.dataDoc.gravity);
+ yForce +=
+ Math.abs(this.dataDoc.gravity) *
+ Math.cos((theta * Math.PI) / 180) *
+ Math.sin(((90 - theta) * Math.PI) / 180);
+ yForce +=
+ coefficient *
+ Math.abs(this.dataDoc.gravity) *
+ Math.cos((theta * Math.PI) / 180) *
+ Math.sin(((180 - theta) * Math.PI) / 180);
+ let friction =
+ coefficient * Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180);
+ if (yForce > 0) {
+ friction =
+ (-(Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180)) *
+ Math.sin(((90 - theta) * Math.PI) / 180) +
+ Math.abs(this.dataDoc.gravity)) /
+ Math.sin(((180 - theta) * Math.PI) / 180);
+ }
+ this.dataDoc.reviewStaticMagnitude = (friction);
+ this.dataDoc.reviewStaticAngle = (180 - theta);
};
- // Remove floor and walls from simulation
- removeWalls = () => {
- this.dataDoc.wallPositions = []
- };
-
- // Add floor and walls to simulation
- addWalls = () => {
- let walls = [];
- walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 });
- walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 });
- walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 });
- this.dataDoc.wallPositions = walls
- };
-
-
- componentDidMount() {
- this.xMax = this.layoutDoc._width;
- this.yMax = this.layoutDoc._height;
- this.radius = 0.1*this.layoutDoc._height;
-
- // Add weight
- if (this.dataDoc.simulationType == "Inclined Plane") {
- this.addWedge()
- } else if (this.dataDoc.simulationType == "Pendulum") {
- this.addPendulum()
- } else {
- this.dataDoc.simulationType = "Free Weight"
- this.addWeight()
+ // In review mode, update forces when wedge angle changed
+ updateReviewForcesBasedOnAngle = (angle: number) => {
+ this.dataDoc.reviewGravityMagnitude = (Math.abs(this.dataDoc.gravity));
+ this.dataDoc.reviewGravityAngle = (270);
+ this.dataDoc.reviewNormalMagnitude = (
+ Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180)
+ );
+ this.dataDoc.reviewNormalAngle = (90 - angle);
+ let yForce = -Math.abs(this.dataDoc.gravity);
+ yForce +=
+ Math.abs(this.dataDoc.gravity) *
+ Math.cos((Number(angle) * Math.PI) / 180) *
+ Math.sin(((90 - Number(angle)) * Math.PI) / 180);
+ yForce +=
+ this.dataDoc.reviewCoefficient *
+ Math.abs(this.dataDoc.gravity) *
+ Math.cos((Number(angle) * Math.PI) / 180) *
+ Math.sin(((180 - Number(angle)) * Math.PI) / 180);
+ let friction =
+ this.dataDoc.reviewCoefficient *
+ Math.abs(this.dataDoc.gravity) *
+ Math.cos((Number(angle) * Math.PI) / 180);
+ if (yForce > 0) {
+ friction =
+ (-(Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180)) *
+ Math.sin(((90 - Number(angle)) * Math.PI) / 180) +
+ Math.abs(this.dataDoc.gravity)) /
+ Math.sin(((180 - Number(angle)) * Math.PI) / 180);
}
- this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0;
- this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0;
- this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0;
- this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0;
- this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? [];
- this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false;
- this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? [];
- this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 26;
- this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300;
- this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0;
- this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0;
- this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false;
- this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? false;
- this.dataDoc.showForces = this.dataDoc.showForces ?? false;
- this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false;
- this.dataDoc.startForces = this.dataDoc.startForces ?? [this.forceOfGravity];
- this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0;
- this.dataDoc.startPosX = this.dataDoc.startPosX ?? 50;
- this.dataDoc.startPosY = this.dataDoc.startPosY ?? 50;
- this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0;
- this.dataDoc.updateDisplay = this.dataDoc.updateDisplay ?? false;
- this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [this.forceOfGravity];
- this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0;
- this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0;
- this.dataDoc.wallPositions = this.dataDoc.wallPositions ?? [];
- this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26;
- this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * this.xMax*0.6;
- this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? this.xMax*0.6;
-
- this.dataDoc.adjustPendulumAngle = true;
- this.dataDoc.simulationPaused = true;
- this.dataDoc.simulationReset = false;
+ this.dataDoc.reviewStaticMagnitude = (friction);
+ this.dataDoc.reviewStaticAngle = (180 - angle);
+ };
- // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
- document.addEventListener("keydown", (e) => {
- if (e.shiftKey) {
- this.dataDoc.deleteMode = true;
- }
- });
- document.addEventListener("keyup", (e) => {
- if (e.shiftKey) {
- this.dataDoc.deleteMode = false;
- }
- });
- }
-
- componentDidUpdate() {
- this.xMax = this.layoutDoc._width;
- this.yMax = this.layoutDoc._height;
- this.radius = 0.1*this.layoutDoc._height;
- }
render () {
- return (
- <div>
- <div className="mechanicsSimulationContainer">
- <div className="mechanicsSimulationContentContainer">
- <div className="mechanicsSimulationButtonsAndElements">
- <div className="mechanicsSimulationElements">
- {this.dataDoc.weight && (
- <Weight
- adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
- color={"red"}
- dataDoc={this.dataDoc}
- mass={1}
- radius={this.radius}
- simulationReset={this.dataDoc.simulationReset}
- startPosX={this.dataDoc.startPosX}
- startPosY={this.dataDoc.startPosY}
- timestepSize={0.002}
- updateDisplay={this.dataDoc.updateDisplay}
- walls={this.dataDoc.wallPositions}
- wedge={this.dataDoc.wedge}
- wedgeWidth={this.dataDoc.wedgeWidth}
- wedgeHeight={this.dataDoc.wedgeHeight}
- xMax={this.xMax}
- xMin={this.xMin}
- yMax={this.yMax}
- yMin={this.yMin}
- />
- )}
- {this.dataDoc.wedge && (
- <Wedge
- startWidth={this.dataDoc.wedgeWidth}
- startHeight={this.dataDoc.wedgeHeight}
- startLeft={this.xMax * 0.2}
- xMax={this.xMax}
- yMax={this.yMax}
- />
- )}
- </div>
- <div>
- {(this.dataDoc.wallPositions ?? []).map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
- return (
- <div key={index}>
- <Wall
- length={element.length}
- xPos={element.xPos}
- yPos={element.yPos}
- angleInDegrees={element.angleInDegrees}
- />
- </div>
- );
- })}
- </div>
- </div>
- </div>
- <div style = {{width: this.layoutDoc._width+'px', height: this.layoutDoc._height+'px'}}>
- {this.menuIsOpen && (
- <div className="mechanicsSimulationSettingsMenu">
- <div className="close-button" onClick={() => {this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}>
- <FontAwesomeIcon icon={'times'} color="black" size={'lg'} />
- </div>
- <h4>Simulation Settings</h4>
- <div className="mechanicsSimulationSettingsMenuRow">
- <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Show forces</p></div>
- <div><input type="checkbox" checked={this.dataDoc.showForces} onClick={() => {this.dataDoc.showForces = !this.dataDoc.showForces}}/></div>
- </div>
- <div className="mechanicsSimulationSettingsMenuRow">
- <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Show acceleration</p></div>
- <div><input type="checkbox" checked={this.dataDoc.showAcceleration} onClick={() => {this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/></div>
- </div>
- <div className="mechanicsSimulationSettingsMenuRow">
- <div className="mechanicsSimulationSettingsMenuRowDescription">
- <p>Show velocity</p></div>
- <div><input type="checkbox" checked={this.dataDoc.showVelocity} onClick={() => {this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/></div>
- </div>
- <hr/>
- {this.dataDoc.simulationType == "Free Weight" && <div className="mechanicsSimulationSettingsMenuRow">
- <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Elastic collisions </p></div>
- <div><input type="checkbox" checked={this.dataDoc.elasticCollisions} onClick={() => {this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/></div>
- </div>}
- {this.dataDoc.simulationType == "Pendulum" && <div className="mechanicsSimulationSettingsMenuRow">
- <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Pendulum start angle</p></div>
- <div>
- <input
- type="number"
- value={this.dataDoc.startPendulumAngle}
- max={35}
- min={0}
- step={1}
- onInput={(e) => {
- let angle = e.target.value;
- if (angle > 35) {
- angle = 35
- }
- if (angle < 0) {
- angle = 0
- }
- let length = this.xMax*0.7;
- let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
- let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
- let xPos = this.xMax / 2 - x - this.radius;
- let yPos = y - this.radius;
- this.dataDoc.startPosX = xPos;
- this.dataDoc.startPosY = yPos;
- let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
- this.dataDoc.pendulumAngle = angle;
- this.dataDoc.pendulumLength = length;
- this.dataDoc.startPendulumAngle = angle;
- this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle;
- }}
- />
- </div>
- </div>}
- {this.dataDoc.simulationType == "Inclined Plane" && <div className="mechanicsSimulationSettingsMenuRow">
- <div className="mechanicsSimulationSettingsMenuRowDescription"><p>Inclined plane angle</p></div>
- <div>
- <input
- type="number"
- value={this.dataDoc.wedgeAngle}
- max={70}
- min={0}
- step={1}
- onInput={(e) => {
- let angle = e.target.value ?? 0
- if (angle > 70) {
- angle = 70
- }
- if (angle < 0) {
- angle = 0
- }
- this.dataDoc.wedgeAngle = angle
- this.changeWedgeBasedOnNewAngle(angle)
- }}
- />
- </div>
- </div>}
- </div>
- )}
- </div>
- <div className="mechanicsSimulationEquationContainer">
- <div className="mechanicsSimulationControls">
- <div>
- {this.dataDoc.simulationPaused && (
- <button onClick={() => {
- this.dataDoc.simulationPaused = false}
- } >START</button>
- )}
- {!this.dataDoc.simulationPaused && (
- <button onClick={() => {
- this.dataDoc.simulationPaused = true}
- } >PAUSE</button>
- )}
- {this.dataDoc.simulationPaused && (
- <button onClick={() => {
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset}
- } >RESET</button>
- )}
- {this.dataDoc.simulationPaused && ( <button onClick={() => {
- if (!this.dataDoc.pendulum && !this.dataDoc.wedge) {
- this.addWedge()
- this.setToWedgeDefault()
- this.dataDoc.simulationType = "Inclined Plane"
- this.dataDoc.elasticCollisions = false
- }
- else if (!this.dataDoc.pendulum && this.dataDoc.wedge) {
- this.setToPendulumDefault()
- this.addPendulum()
- this.dataDoc.simulationType = "Pendulum"
- this.dataDoc.elasticCollisions = false
- }
- else {
- this.setToWeightDefault()
- this.addWeight()
- this.dataDoc.simulationType = "Free Weight"
- }
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset
- }} >TYPE</button>)}
- <button onClick={() => {this.menuIsOpen=true; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}>MENU</button>
- </div>
- </div>
- </div>
- </div>
- </div>
- );
- }
} \ No newline at end of file
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx
deleted file mode 100644
index 6134a6bc0..000000000
--- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import React = require('react');
-import "./PhysicsSimulationBox.scss";
-
-export interface IWedgeProps {
- startHeight: number;
- startWidth: number;
- startLeft: number;
- xMax: number;
- yMax: number;
-}
-
-interface IState {
- angleInRadians: number,
- left: number,
- coordinates: string,
-}
-
-export default class Wedge extends React.Component<IWedgeProps, IState> {
-
- constructor(props: any) {
- super(props)
- this.state = {
- angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth),
- left: this.props.startLeft,
- coordinates: "",
- }
- }
-
- color = "#deb887";
-
- updateCoordinates() {
- const coordinatePair1 =
- Math.round(this.state.left) + "," + Math.round(this.props.yMax) + " ";
- const coordinatePair2 =
- Math.round(this.state.left + this.props.startWidth) +
- "," +
- Math.round(this.props.yMax) +
- " ";
- const coordinatePair3 =
- Math.round(this.state.left) +
- "," +
- Math.round(this.props.yMax - this.props.startHeight);
- const coord = coordinatePair1 + coordinatePair2 + coordinatePair3;
- this.setState({coordinates: coord});
- }
-
- componentDidMount() {
- this.updateCoordinates()
- }
-
- componentDidUpdate(prevProps: Readonly<IWedgeProps>, prevState: Readonly<IState>, snapshot?: any): void {
- if (prevProps.startHeight != this.props.startHeight || prevProps.startWidth != this.props.startWidth) {
- this.setState({angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth)});
- this.updateCoordinates();
- }
- }
-
- render() {
- return (
- <div>
- <div style={{ position: "absolute", left: "0", top: "0" }}>
- <svg
- width={this.props.xMax + "px"}
- height={this.props.yMax + "px"}
- >
- <polygon points={this.state.coordinates} style={{ fill: "burlywood" }} />
- </svg>
- </div>
-
- <p
- style={{
- position: "absolute",
- zIndex: 500,
- left: Math.round(this.state.left + this.props.startWidth - 80) + "px",
- top: Math.round(this.props.yMax - 40) + "px",
- }}
- >
- {Math.round(((this.state.angleInRadians * 180) / Math.PI) * 100) / 100}°
- </p>
- </div>
- );
- }
-};