aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts3
-rw-r--r--src/client/util/CurrentUserUtils.ts2
-rw-r--r--src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.scss128
-rw-r--r--src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx1131
-rw-r--r--src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx2840
-rw-r--r--src/fields/Doc.ts2
6 files changed, 1874 insertions, 2232 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 6f8582c2e..4ee3368ab 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -688,8 +688,9 @@ export namespace Docs {
[
DocumentType.SIMULATION,
{
+ data: '',
layout: { view: PhysicsSimulationBox, dataField: defaultDataKey },
- options: { _height: 100 },
+ options: { _height: 100, position: '', velocity: '', acceleration: '', pendulum: '', simulation: '', review: '', show: '', start: '' },
},
],
]);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index fffb9c79b..4a702cef3 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -266,7 +266,7 @@ export class CurrentUserUtils {
{key: "Flashcard", creator: opts => Docs.Create.TextDocument("", opts), opts: { _width: 200, _layout_autoHeight: true, _layout_altContentUI: true}},
{key: "Equation", creator: opts => Docs.Create.EquationDocument(opts), opts: { _width: 300, _height: 35, }},
{key: "Noteboard", creator: opts => Docs.Create.NoteTakingDocument([], opts), opts: { _width: 250, _height: 200, _layout_fitWidth: true}},
- {key: "Simulation", creator: opts => Docs.Create.SimulationDocument(opts), opts: { _width: 300, _height: 300, _freeform_backgroundGrid: true, }},
+ {key: "Simulation", creator: opts => Docs.Create.SimulationDocument(opts), opts: { _width: 300, _height: 300, }},
{key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100, _layout_fitWidth: true }},
{key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, data_useCors: true, }},
{key: "Comparison", creator: Docs.Create.ComparisonDocument, opts: { _width: 300, _height: 300 }},
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.scss
index 7193e3157..c29e36a97 100644
--- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.scss
+++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.scss
@@ -1,76 +1,78 @@
-* {
- box-sizing: border-box;
- font-size: 14px;
-}
+.physicsSimApp {
+ * {
+ box-sizing: border-box;
+ font-size: 14px;
+ }
-.mechanicsSimulationContainer {
- background-color: white;
- height: 100%;
- width: 100%;
- display: flex;
+ .mechanicsSimulationContainer {
+ background-color: white;
+ height: 100%;
+ width: 100%;
+ display: flex;
- .mechanicsSimulationEquationContainer {
- position: fixed;
- left: 60%;
- padding: 1em;
+ .mechanicsSimulationEquationContainer {
+ position: fixed;
+ left: 60%;
+ padding: 1em;
- .mechanicsSimulationControls {
- display: flex;
- justify-content: space-between;
- }
- }
-}
+ .mechanicsSimulationControls {
+ display: flex;
+ justify-content: space-between;
+ }
+ }
+ }
-.coordinateSystem {
- z-index: -100;
-}
+ .coordinateSystem {
+ z-index: -100;
+ }
-th,
-td {
- border-collapse: collapse;
- padding: 1em;
-}
+ th,
+ td {
+ border-collapse: collapse;
+ padding: 1em;
+ }
-table {
- min-width: 300px;
-}
+ table {
+ min-width: 300px;
+ }
-tr:nth-child(even) {
- background-color: #d6eeee;
-}
+ tr:nth-child(even) {
+ background-color: #d6eeee;
+ }
-button {
- z-index: 50;
-}
+ button {
+ z-index: 50;
+ }
-.angleLabel {
- font-weight: bold;
- font-size: 20px;
- user-select: none;
- pointer-events: none;
-}
+ .angleLabel {
+ font-weight: bold;
+ font-size: 20px;
+ user-select: none;
+ pointer-events: none;
+ }
-.mechanicsSimulationSettingsMenu {
- width: 100%;
- height: 100%;
- font-size: 12px;
- background-color: rgb(224, 224, 224);
- border-radius: 2px;
- border-color: black;
- border-style: solid;
- padding: 10px;
- position: fixed;
- z-index: 1000;
-}
+ .mechanicsSimulationSettingsMenu {
+ width: 100%;
+ height: 100%;
+ font-size: 12px;
+ background-color: rgb(224, 224, 224);
+ border-radius: 2px;
+ border-color: black;
+ border-style: solid;
+ padding: 10px;
+ position: fixed;
+ z-index: 1000;
+ }
-.mechanicsSimulationSettingsMenuRow {
- display: flex;
-}
+ .mechanicsSimulationSettingsMenuRow {
+ display: flex;
+ }
-.mechanicsSimulationSettingsMenuRowDescription {
- width: 50%;
-}
+ .mechanicsSimulationSettingsMenuRowDescription {
+ width: 50%;
+ }
-.dropdownMenu {
- z-index: 50;
-} \ No newline at end of file
+ .dropdownMenu {
+ z-index: 50;
+ }
+}
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
index ab93583df..db15c9a5c 100644
--- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx
@@ -1,29 +1,24 @@
-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 { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { CheckBox } from '../../search/CheckBox';
+import ArrowLeftIcon from '@mui/icons-material/ArrowLeft';
+import ArrowRightIcon from '@mui/icons-material/ArrowRight';
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 ReplayIcon from '@mui/icons-material/Replay';
+import { Box, Button, Checkbox, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, FormControl, FormControlLabel, FormGroup, IconButton, LinearProgress, Stack } from '@mui/material';
import Typography from '@mui/material/Typography';
+import { observer } from 'mobx-react';
+import { HeightSym, NumListCast, WidthSym } from '../../../../fields/Doc';
+import { ViewBoxAnnotatableComponent } from '../../DocComponent';
+import { FieldView, FieldViewProps } from './../FieldView';
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';
+import React = require('react');
+import { BoolCast, NumCast, StrCast } from '../../../../fields/Types';
+import { List } from '../../../../fields/List';
interface IWallProps {
length: number;
@@ -70,7 +65,7 @@ interface TutorialTemplate {
directionInDegrees: number;
component: boolean;
}[];
- showMagnitude: boolean;
+ show_Magnitude: boolean;
}[];
}
@@ -99,54 +94,36 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
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.gravity = NumCast(this.dataDoc.gravity, -9.81);
+ this.dataDoc.mass = NumCast(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.show_ComponentForces = this.dataDoc.show_ComponentForces ?? false;
+ this.dataDoc.simulation_Speed = NumCast(this.dataDoc.simulation_Speed, 2);
+ this.dataDoc.simulation_Type = StrCast(this.dataDoc.simulation_Type, 'Inclined Plane');
+ this.dataDoc.start_Forces = this.dataDoc.start_Forces ?? [];
+ this.dataDoc.start_PosX = this.dataDoc.start_PosX ?? Math.round((this.xMax * 0.5 - 200) * 10) / 10;
+ this.dataDoc.start_PosY = this.dataDoc.start_PosY ?? this.getDisplayYPos((400 - 0.08 * this.layoutDoc._height) * Math.tan((26 * Math.PI) / 180) + Math.sqrt(26));
+ this.dataDoc.stepNumber = NumCast(this.dataDoc.stepNumber);
this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [];
- this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0;
- this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0;
// Used for review mode
// this.dataDoc.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.answers = new List<number>();
+ this.dataDoc.show_Icon = 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.review_GravityAngle = 0;
+ this.dataDoc.review_GravityMagnitude = 0;
+ this.dataDoc.review_NormalAngle = 0;
+ this.dataDoc.review_NormalMagnitude = 0;
+ this.dataDoc.review_StaticAngle = 0;
+ this.dataDoc.review_StaticMagnitude = 0;
this.dataDoc.selectedSolutions = [];
this.dataDoc.selectedQuestion = this.dataDoc.selectedQuestion ?? questions.inclinePlane[0];
// this.dataDoc.sketching = this.dataDoc.sketching ?? false;
@@ -158,39 +135,25 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
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;
+ this.dataDoc.springConstant = NumCast(this.dataDoc.springConstant, 0.5);
+ this.dataDoc.springRestLength = NumCast(this.dataDoc.springRestLength, 200);
+ this.dataDoc.springStartLength = NumCast(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;
+ this.dataDoc.pendulum_length = NumCast(this.dataDoc.pendulum_length, 300);
// 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;
+ this.dataDoc.wedgeAngle = NumCast(this.dataDoc.wedgeAngle, 26);
+ this.dataDoc.wedgeHeight = NumCast(this.dataDoc.wedgeHeight, Math.tan((26 * Math.PI) / 180) * this.xMax * 0.5);
+ this.dataDoc.wedgeWidth = NumCast(this.dataDoc.wedgeWidth, this.xMax * 0.5);
// 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.start_Forces2 = this.dataDoc.start_Forces2 ?? [];
this.dataDoc.updatedForces2 = this.dataDoc.updatedForces2 ?? [];
- this.dataDoc.mass2 = this.dataDoc.mass2 ?? 1;
+ this.dataDoc.mass2 = NumCast(this.dataDoc.mass2, 1);
// Setup simulation
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ this.setupSimulation(StrCast(this.dataDoc.simulation_Type), StrCast(this.dataDoc.mode));
// Create walls
let walls = [];
@@ -207,54 +170,54 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
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);
+ this.setupSimulation(StrCast(this.dataDoc.simulation_Type), StrCast(this.dataDoc.mode));
}
}
setupSimulation = (simulationType: string, mode: string) => {
- this.dataDoc.simulationPaused = true;
+ this.dataDoc.simulation_Paused = true;
if (simulationType != 'Circular Motion') {
- this.dataDoc.startVelX = 0;
+ this.dataDoc.start_VelX = 0;
this.dataDoc.setStartVelY = 0;
- this.dataDoc.velocityXDisplay = 0;
- this.dataDoc.velocityYDisplay = 0;
+ this.dataDoc.velocity_XDisplay = 0;
+ this.dataDoc.velocity_YDisplay = 0;
}
if (mode == 'Freeform') {
- this.dataDoc.showForceMagnitudes = true;
+ this.dataDoc.show_ForceMagnitudes = 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.show_ComponentForces = false;
+ this.dataDoc.start_PosY = this.yMin + 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.start_PosX = (this.xMax + this.xMin) / 2 - 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.position_YDisplay = this.getDisplayYPos(this.yMin + 0.08 * this.layoutDoc[HeightSym]());
+ this.dataDoc.position_XDisplay = (this.xMax + this.xMin) / 2 - 0.08 * this.layoutDoc[HeightSym]();
this.dataDoc.updatedForces = [
{
description: 'Gravity',
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ magnitude: Math.abs(NumCast(this.dataDoc.gravity)) * NumCast(this.dataDoc.mass),
directionInDegrees: 270,
component: false,
},
];
- this.dataDoc.startForces = [
+ this.dataDoc.start_Forces = [
{
description: 'Gravity',
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ magnitude: Math.abs(NumCast(this.dataDoc.gravity)) * NumCast(this.dataDoc.mass),
directionInDegrees: 270,
component: false,
},
];
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
} else if (simulationType == 'Inclined Plane') {
this.changeWedgeBasedOnNewAngle(26);
- this.dataDoc.startForces = [
+ this.dataDoc.start_Forces = [
{
description: 'Gravity',
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ magnitude: Math.abs(NumCast(this.dataDoc.gravity)) * NumCast(this.dataDoc.mass),
directionInDegrees: 270,
component: false,
},
];
- this.updateForcesWithFriction(Number(this.dataDoc.coefficientOfStaticFriction));
+ this.updateForcesWithFriction(NumCast(this.dataDoc.coefficientOfStaticFriction));
} else if (simulationType == 'Pendulum') {
this.setupPendulum();
} else if (simulationType == 'Spring') {
@@ -267,11 +230,11 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
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.dataDoc.show_ComponentForces = false;
+ this.dataDoc.show_ForceMagnitudes = true;
+ this.dataDoc.show_Acceleration = false;
+ this.dataDoc.show_Velocity = false;
+ this.dataDoc.show_Forces = true;
this.generateNewQuestion();
if (simulationType == 'One Weight') {
// TODO - one weight review problems
@@ -280,7 +243,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
// TODO - spring review problems
} else if (simulationType == 'Inclined Plane') {
this.dataDoc.updatedForces = [];
- this.dataDoc.startForces = [];
+ this.dataDoc.start_Forces = [];
} else if (simulationType == 'Pendulum') {
this.setupPendulum();
// TODO - pendulum review problems
@@ -295,77 +258,78 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
// TODO - suspension tutorial review problems
}
} else if (mode == 'Tutorial') {
- this.dataDoc.showComponentForces = false;
+ this.dataDoc.show_ComponentForces = 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;
+ this.dataDoc.show_Acceleration = false;
+ if (this.dataDoc.simulation_Type != 'Circular Motion') {
+ this.dataDoc.velocity_XDisplay = 0;
+ this.dataDoc.velocity_YDisplay = 0;
+ this.dataDoc.show_Velocity = false;
} else {
- this.dataDoc.velocityXDisplay = 20;
- this.dataDoc.velocityYDisplay = 0;
- this.dataDoc.showVelocity = true;
+ this.dataDoc.velocity_XDisplay = 20;
+ this.dataDoc.velocity_YDisplay = 0;
+ this.dataDoc.show_Velocity = 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]();
+ if (this.dataDoc.simulation_Type == 'One Weight') {
+ this.dataDoc.show_Forces = true;
+ this.dataDoc.start_PosY = this.yMax - 100;
+ this.dataDoc.start_PosX = (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.dataDoc.start_Forces = this.getForceFromJSON(tutorials.freeWeight.steps[0].forces);
+ this.dataDoc.show_ForceMagnitudes = tutorials.freeWeight.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulation_Type == 'Spring') {
+ this.dataDoc.show_Forces = 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.start_PosY = this.yMin + 200 + 19.62;
+ this.dataDoc.start_PosX = (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;
+ this.dataDoc.start_Forces = this.getForceFromJSON(tutorials.spring.steps[0].forces);
+ this.dataDoc.show_ForceMagnitudes = tutorials.spring.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulation_Type == 'Pendulum') {
+ this.dataDoc.show_Forces = 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.start_PosX = xPos;
+ this.dataDoc.start_PosY = 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.start_Forces = this.getForceFromJSON(tutorials.pendulum.steps[0].forces);
+ this.dataDoc.show_ForceMagnitudes = tutorials.pendulum.steps[0].showMagnitude;
+ this.dataDoc.pendulum_angle = 30;
+ this.dataDoc.pendulum_length = 300;
+ this.dataDoc.pendulum_angle_adjust = 30;
+ this.dataDoc.pendulum_length_adjust = 300;
+ } else if (this.dataDoc.simulation_Type == 'Inclined Plane') {
+ this.dataDoc.show_Forces = 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.dataDoc.start_Forces = this.getForceFromJSON(tutorials.inclinePlane.steps[0].forces);
+ this.dataDoc.show_ForceMagnitudes = tutorials.inclinePlane.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulation_Type == 'Circular Motion') {
+ this.dataDoc.show_Forces = 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.dataDoc.start_Forces = this.getForceFromJSON(tutorials.circular.steps[0].forces);
+ this.dataDoc.show_ForceMagnitudes = tutorials.circular.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulation_Type == 'Pulley') {
+ this.dataDoc.show_Forces = 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.dataDoc.start_Forces = this.getForceFromJSON(tutorials.pulley.steps[0].forces);
+ this.dataDoc.show_ForceMagnitudes = tutorials.pulley.steps[0].showMagnitude;
+ } else if (this.dataDoc.simulation_Type == 'Suspension') {
+ this.dataDoc.show_Forces = 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.start_Forces = this.getForceFromJSON(tutorials.suspension.steps[0].forces);
+ this.dataDoc.show_ForceMagnitudes = tutorials.suspension.steps[0].showMagnitude;
}
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}
};
@@ -378,62 +342,63 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
};
// Update forces when coefficient of static friction changes in freeform mode
- updateForcesWithFriction = (coefficient: number, width: number = this.dataDoc.wedgeWidth, height: number = this.dataDoc.wedgeHeight) => {
+ updateForcesWithFriction = (coefficient: number, width: number = NumCast(this.dataDoc.wedgeWidth), height: number = NumCast(this.dataDoc.wedgeHeight)) => {
const normalForce: IForce = {
description: 'Normal Force',
- magnitude: Math.abs(this.dataDoc.gravity) * Math.cos(Math.atan(height / width)) * this.dataDoc.mass,
+ magnitude: Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos(Math.atan(height / width)) * NumCast(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,
+ magnitude: coefficient * Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos(Math.atan(height / width)) * NumCast(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;
+ let yForce = -Math.abs(NumCast(this.dataDoc.gravity)) * NumCast(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);
+ frictionForce.magnitude =
+ (-normalForce.magnitude * Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + Math.abs(NumCast(this.dataDoc.gravity)) * NumCast(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)),
+ magnitude: coefficient * Math.abs(NumCast(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)),
+ magnitude: Math.abs(NumCast(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)),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(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)),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(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),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(this.dataDoc.gravity)),
directionInDegrees: 270,
component: false,
};
if (coefficient != 0) {
- this.dataDoc.startForces = [gravityForce, normalForce, frictionForce];
+ this.dataDoc.start_Forces = [gravityForce, normalForce, frictionForce];
this.dataDoc.updatedForces = [gravityForce, normalForce, frictionForce];
this.dataDoc.componentForces = [frictionForceComponent, normalForceComponent, gravityParallel, gravityPerpendicular];
} else {
- this.dataDoc.startForces = [gravityForce, normalForce];
+ this.dataDoc.start_Forces = [gravityForce, normalForce];
this.dataDoc.updatedForces = [gravityForce, normalForce];
this.dataDoc.componentForces = [normalForceComponent, gravityParallel, gravityPerpendicular];
}
@@ -468,65 +433,65 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
yPos += 0.08 * this.layoutDoc[HeightSym]() * 0.52;
}
- this.dataDoc.startPosX = this.xMax * 0.25;
- this.dataDoc.startPosY = yPos;
+ this.dataDoc.start_PosX = this.xMax * 0.25;
+ this.dataDoc.start_PosY = 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);
+ this.updateForcesWithFriction(NumCast(this.dataDoc.coefficientOfStaticFriction), this.xMax * 0.5, Math.tan((angle * Math.PI) / 180) * this.xMax * 0.5);
}
};
// In review mode, update forces when coefficient of static friction changed
updateReviewForcesBasedOnCoefficient = (coefficient: number) => {
- let theta: number = Number(this.dataDoc.wedgeAngle);
+ let theta: number = NumCast(this.dataDoc.wedgeAngle);
let index = this.dataDoc.selectedQuestion.variablesForQuestionSetup.indexOf('theta - max 45');
if (index >= 0) {
- theta = this.dataDoc.questionVariables[index];
+ theta = NumListCast(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);
+ this.dataDoc.review_GravityMagnitude = Math.abs(NumCast(this.dataDoc.gravity));
+ this.dataDoc.review_GravityAngle = 270;
+ this.dataDoc.review_NormalMagnitude = Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((theta * Math.PI) / 180);
+ this.dataDoc.review_NormalAngle = 90 - theta;
+ let yForce = -Math.abs(NumCast(this.dataDoc.gravity));
+ yForce += Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((theta * Math.PI) / 180) * Math.sin(((90 - theta) * Math.PI) / 180);
+ yForce += coefficient * Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((theta * Math.PI) / 180) * Math.sin(((180 - theta) * Math.PI) / 180);
+ let friction = coefficient * Math.abs(NumCast(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);
+ friction = (-(Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((theta * Math.PI) / 180)) * Math.sin(((90 - theta) * Math.PI) / 180) + Math.abs(NumCast(this.dataDoc.gravity))) / Math.sin(((180 - theta) * Math.PI) / 180);
}
- this.dataDoc.reviewStaticMagnitude = friction;
- this.dataDoc.reviewStaticAngle = 180 - theta;
+ this.dataDoc.review_StaticMagnitude = friction;
+ this.dataDoc.review_StaticAngle = 180 - theta;
};
// In review mode, update forces when wedge angle changed
updateReviewForcesBasedOnAngle = (angle: number) => {
- this.dataDoc.reviewGravityMagnitude = Math.abs(this.dataDoc.gravity);
- this.dataDoc.reviewGravityAngle = 270;
- this.dataDoc.reviewNormalMagnitude = Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180);
- this.dataDoc.reviewNormalAngle = 90 - angle;
- let yForce = -Math.abs(this.dataDoc.gravity);
- yForce += Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180) * Math.sin(((90 - Number(angle)) * Math.PI) / 180);
- yForce += this.dataDoc.reviewCoefficient * Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180) * Math.sin(((180 - Number(angle)) * Math.PI) / 180);
- let friction = this.dataDoc.reviewCoefficient * Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180);
+ this.dataDoc.review_GravityMagnitude = Math.abs(NumCast(this.dataDoc.gravity));
+ this.dataDoc.review_GravityAngle = 270;
+ this.dataDoc.review_NormalMagnitude = Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((angle * Math.PI) / 180);
+ this.dataDoc.review_NormalAngle = 90 - angle;
+ let yForce = -Math.abs(NumCast(this.dataDoc.gravity));
+ yForce += Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((angle * Math.PI) / 180) * Math.sin(((90 - angle) * Math.PI) / 180);
+ yForce += NumCast(this.dataDoc.review_Coefficient) * Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((angle * Math.PI) / 180) * Math.sin(((180 - angle) * Math.PI) / 180);
+ let friction = NumCast(this.dataDoc.review_Coefficient) * Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((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);
+ friction = (-(Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((angle * Math.PI) / 180)) * Math.sin(((90 - angle) * Math.PI) / 180) + Math.abs(NumCast(this.dataDoc.gravity))) / Math.sin(((180 - angle) * Math.PI) / 180);
}
- this.dataDoc.reviewStaticMagnitude = friction;
- this.dataDoc.reviewStaticAngle = 180 - angle;
+ this.dataDoc.review_StaticMagnitude = friction;
+ this.dataDoc.review_StaticAngle = 180 - angle;
};
// Solve for the correct answers to the generated problem
getAnswersToQuestion = (question: QuestionTemplate, questionVars: number[]) => {
const solutions: number[] = [];
- let theta: number = Number(this.dataDoc.wedgeAngle);
+ let theta: number = NumCast(this.dataDoc.wedgeAngle);
let index = question.variablesForQuestionSetup.indexOf('theta - max 45');
if (index >= 0) {
theta = questionVars[index];
}
- let muS: number = Number(this.dataDoc.coefficientOfStaticFriction);
+ let muS: number = NumCast(this.dataDoc.coefficientOfStaticFriction);
index = question.variablesForQuestionSetup.indexOf('coefficient of static friction');
if (index >= 0) {
muS = questionVars[index];
@@ -534,25 +499,25 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
for (let i = 0; i < question.answerSolutionDescriptions.length; i++) {
const description = question.answerSolutionDescriptions[i];
- if (!isNaN(Number(description))) {
- solutions.push(Number(description));
+ if (!isNaN(NumCast(description))) {
+ solutions.push(NumCast(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));
+ solutions.push(Math.abs(NumCast(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 normalForceMagnitude = Math.abs(NumCast(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 frictionForceMagnitude = (-normalForceMagnitude * Math.sin((normalForceAngle * Math.PI) / 180) + Math.abs(NumCast(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 normalForceMagnitude = Math.abs(NumCast(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 frictionForceMagnitude = (-normalForceMagnitude * Math.sin((normalForceAngle * Math.PI) / 180) + Math.abs(NumCast(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') {
@@ -570,35 +535,35 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
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) {
+ if (Math.abs(NumCast(this.dataDoc.review_GravityMagnitude) - 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) {
+ if (Math.abs(NumCast(this.dataDoc.review_GravityAngle) - 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) {
+ if (Math.abs(NumCast(this.dataDoc.review_NormalMagnitude) - 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) {
+ if (Math.abs(NumCast(this.dataDoc.review_NormalAngle) - 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) {
+ if (Math.abs(NumCast(this.dataDoc.review_StaticMagnitude) - 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) {
+ if (Math.abs(NumCast(this.dataDoc.review_StaticAngle) - 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) {
+ if (Math.abs(NumCast(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) {
+ if (Math.abs(NumCast(this.dataDoc.wedgeAngle) - this.dataDoc.selectedSolutions[i]) > epsilon) {
error = true;
}
}
@@ -606,14 +571,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
}
if (showAlert) {
if (!error) {
- this.dataDoc.simulationPaused = false;
+ this.dataDoc.simulation_Paused = false;
setTimeout(() => {
- this.dataDoc.simulationPaused = true;
+ this.dataDoc.simulation_Paused = true;
}, 3000);
} else {
- this.dataDoc.simulationPaused = false;
+ this.dataDoc.simulation_Paused = false;
setTimeout(() => {
- this.dataDoc.simulationPaused = true;
+ this.dataDoc.simulation_Paused = true;
}, 3000);
}
}
@@ -628,14 +593,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
// 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.review_GravityMagnitude = 0;
+ this.dataDoc.review_GravityAngle = 0;
+ this.dataDoc.review_NormalMagnitude = 0;
+ this.dataDoc.review_NormalAngle = 0;
+ this.dataDoc.review_StaticMagnitude = 0;
+ this.dataDoc.review_StaticAngle = 0;
this.dataDoc.coefficientOfKineticFriction = 0;
- this.dataDoc.simulationPaused = true;
+ this.dataDoc.simulation_Paused = true;
};
// In review mode, reset problem variables and generate a new question
@@ -645,13 +610,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
const vars: number[] = [];
let question: QuestionTemplate = questions.inclinePlane[0];
- if (this.dataDoc.simulationType == 'Inclined Plane') {
- if (this.dataDoc.questionNumber == questions.inclinePlane.length - 1) {
+ if (this.dataDoc.simulation_Type == 'Inclined Plane') {
+ if (this.dataDoc.questionNumber === questions.inclinePlane.length - 1) {
this.dataDoc.questionNumber = 0;
} else {
- this.dataDoc.questionNumber = this.dataDoc.questionNumber + 1;
+ this.dataDoc.questionNumber = NumCast(this.dataDoc.questionNumber) + 1;
}
- question = questions.inclinePlane[this.dataDoc.questionNumber];
+ question = questions.inclinePlane[NumCast(this.dataDoc.questionNumber)];
let coefficient = 0;
let wedgeAngle = 0;
@@ -670,7 +635,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
this.dataDoc.wedgeAngle = wedgeAngle;
this.changeWedgeBasedOnNewAngle(wedgeAngle);
this.dataDoc.coefficientOfStaticFriction = coefficient;
- this.dataDoc.reviewCoefficient = coefficient;
+ this.dataDoc.review_Coefficient = coefficient;
}
let q = '';
for (let i = 0; i < question.questionSetup.length; i++) {
@@ -682,32 +647,32 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
}
}
}
- this.dataDoc.questionVariables = vars;
+ this.dataDoc.questionVariables = new List<number>(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.answers = new List<number>(this.getAnswersToQuestion(question, vars));
+ //this.dataDoc.simulation_Reset = (!this.dataDoc.simulation_Reset);
};
// Default setup for uniform circular motion simulation
setupCircular = (value: number) => {
- this.dataDoc.showComponentForces = false;
- this.dataDoc.startVelY = 0;
- this.dataDoc.startVelX = value;
+ this.dataDoc.show_ComponentForces = false;
+ this.dataDoc.start_VelY = 0;
+ this.dataDoc.start_VelX = 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;
+ let yPos = (this.yMax + this.yMin) / 2 + NumCast(this.dataDoc.circularMotionRadius) - 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.start_PosY = yPos;
+ this.dataDoc.start_PosX = xPos;
const tensionForce: IForce = {
description: 'Centripetal Force',
- magnitude: (this.dataDoc.startVelX ** 2 * this.dataDoc.mass) / this.dataDoc.circularMotionRadius,
+ magnitude: (this.dataDoc.start_VelX ** 2 * NumCast(this.dataDoc.mass)) / NumCast(this.dataDoc.circularMotionRadius),
directionInDegrees: 90,
component: false,
};
this.dataDoc.updatedForces = [tensionForce];
- this.dataDoc.startForces = [tensionForce];
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.start_Forces = [tensionForce];
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
};
// Default setup for pendulum simulation
@@ -718,9 +683,9 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
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);
+ this.dataDoc.start_PosX = xPos;
+ this.dataDoc.start_PosY = yPos;
+ const mag = NumCast(this.dataDoc.mass) * Math.abs(NumCast(this.dataDoc.gravity)) * Math.sin((60 * Math.PI) / 180);
const forceOfTension: IForce = {
description: 'Tension',
magnitude: mag,
@@ -736,13 +701,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
};
const gravityParallel: IForce = {
description: 'Gravity Parallel Component',
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.sin(((90 - angle) * Math.PI) / 180),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(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),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos(((90 - angle) * Math.PI) / 180),
directionInDegrees: -angle,
component: true,
};
@@ -751,55 +716,56 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
this.dataDoc.updatedForces = [
{
description: 'Gravity',
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(this.dataDoc.gravity)),
directionInDegrees: 270,
component: false,
},
forceOfTension,
];
- this.dataDoc.startForces = [
+ this.dataDoc.start_Forces = [
{
description: 'Gravity',
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(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.start_PendulumAngle = 30;
+ this.dataDoc.pendulum_angle = 30;
+ this.dataDoc.pendulum_length = 300;
+ this.dataDoc.pendulum_angle_adjust = 30;
+ this.dataDoc.pendulum_length_adjust = 300;
};
// Default setup for spring simulation
setupSpring = () => {
- this.dataDoc.showComponentForces = false;
+ this.dataDoc.show_ComponentForces = false;
const gravityForce: IForce = {
description: 'Gravity',
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ magnitude: Math.abs(NumCast(this.dataDoc.gravity)) * NumCast(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.start_Forces = [gravityForce];
+ this.dataDoc.start_PosX = this.xMax / 2 - 0.08 * this.layoutDoc[HeightSym]();
+ this.dataDoc.start_PosY = 200;
this.dataDoc.springConstant = 0.5;
this.dataDoc.springRestLength = 200;
this.dataDoc.springStartLength = 200;
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
};
// 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));
+ this.dataDoc.start_PosY = yPos;
+ this.dataDoc.start_PosX = xPos;
+ this.dataDoc.position_YDisplay = this.getDisplayYPos(yPos);
+ this.dataDoc.position_XDisplay = xPos;
+ let tensionMag = (NumCast(this.dataDoc.mass) * Math.abs(NumCast(this.dataDoc.gravity))) / (2 * Math.sin(Math.PI / 4));
const tensionForce1: IForce = {
description: 'Tension',
magnitude: tensionMag,
@@ -814,59 +780,59 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
};
const grav: IForce = {
description: 'Gravity',
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(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.start_Forces = [tensionForce1, tensionForce2, grav];
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
};
// 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);
+ this.dataDoc.show_ComponentForces = false;
+ this.dataDoc.start_PosY = (this.yMax + this.yMin) / 2;
+ this.dataDoc.start_PosX = (this.xMin + this.xMax) / 2 - 2 * (0.08 * this.layoutDoc[HeightSym]()) - 5;
+ this.dataDoc.position_YDisplay = this.getDisplayYPos((this.yMax + this.yMin) / 2);
+ this.dataDoc.position_XDisplay = (this.xMin + this.xMax) / 2 - 2 * (0.08 * this.layoutDoc[HeightSym]()) - 5;
+ let a = (-1 * ((NumCast(this.dataDoc.mass) - NumCast(this.dataDoc.mass2)) * Math.abs(NumCast(this.dataDoc.gravity)))) / (NumCast(this.dataDoc.mass) + NumCast(this.dataDoc.mass2));
const gravityForce1: IForce = {
description: 'Gravity',
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(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),
+ magnitude: NumCast(this.dataDoc.mass) * a + NumCast(this.dataDoc.mass) * Math.abs(NumCast(this.dataDoc.gravity)),
directionInDegrees: 90,
component: false,
};
a *= -1;
const gravityForce2: IForce = {
description: 'Gravity',
- magnitude: this.dataDoc.mass2 * Math.abs(this.dataDoc.gravity),
+ magnitude: NumCast(this.dataDoc.mass2) * Math.abs(NumCast(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),
+ magnitude: NumCast(this.dataDoc.mass2) * a + NumCast(this.dataDoc.mass2) * Math.abs(NumCast(this.dataDoc.gravity)),
directionInDegrees: 90,
component: false,
};
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.start_Forces = [gravityForce1, tensionForce1];
+ this.dataDoc.start_PosY2 = (this.yMax + this.yMin) / 2;
+ this.dataDoc.start_PosX2 = (this.xMin + this.xMax) / 2 + 5;
+ this.dataDoc.position_YDisplay2 = this.getDisplayYPos((this.yMax + this.yMin) / 2);
+ this.dataDoc.position_XDisplay2 = (this.xMin + this.xMax) / 2 + 5;
this.dataDoc.updatedForces2 = [gravityForce2, tensionForce2];
- this.dataDoc.startForces2 = [gravityForce2, tensionForce2];
+ this.dataDoc.start_Forces2 = [gravityForce2, tensionForce2];
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
};
// Helper function used for tutorial and review mode
@@ -895,23 +861,23 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
updateReviewModeValues = () => {
const forceOfGravityReview: IForce = {
description: 'Gravity',
- magnitude: this.dataDoc.reviewGravityMagnitude,
- directionInDegrees: this.dataDoc.reviewGravityAngle,
+ magnitude: NumCast(this.dataDoc.review_GravityMagnitude),
+ directionInDegrees: NumCast(this.dataDoc.review_GravityAngle),
component: false,
};
const normalForceReview: IForce = {
description: 'Normal Force',
- magnitude: this.dataDoc.reviewNormalMagnitude,
- directionInDegrees: this.dataDoc.reviewNormalAngle,
+ magnitude: NumCast(this.dataDoc.review_NormalMagnitude),
+ directionInDegrees: NumCast(this.dataDoc.review_NormalAngle),
component: false,
};
const staticFrictionForceReview: IForce = {
description: 'Static Friction Force',
- magnitude: this.dataDoc.reviewStaticMagnitude,
- directionInDegrees: this.dataDoc.reviewStaticAngle,
+ magnitude: NumCast(this.dataDoc.review_StaticMagnitude),
+ directionInDegrees: NumCast(this.dataDoc.review_StaticAngle),
component: false,
};
- this.dataDoc.startForces = [forceOfGravityReview, normalForceReview, staticFrictionForceReview];
+ this.dataDoc.start_Forces = [forceOfGravityReview, normalForceReview, staticFrictionForceReview];
this.dataDoc.updatedForces = [forceOfGravityReview, normalForceReview, staticFrictionForceReview];
};
@@ -922,7 +888,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<div className="mechanicsSimulationContentContainer">
<div className="mechanicsSimulationButtonsAndElements">
<div className="mechanicsSimulationButtons">
- {!this.dataDoc.simulationPaused && (
+ {!this.dataDoc.simulation_Paused && (
<div
style={{
position: 'fixed',
@@ -939,92 +905,96 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
dataDoc={this.dataDoc}
layoutDoc={this.layoutDoc}
wallPositions={this.wallPositions}
- adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
- gravity={this.dataDoc.gravity}
- circularMotionRadius={this.dataDoc.circularMotionRadius}
+ adjustPendulumAngle={NumCast(this.dataDoc.pendulum_angle_adjust)}
+ adjustPendulumLength={NumCast(this.dataDoc.pendulum_length_adjust)}
+ gravity={NumCast(this.dataDoc.gravity)}
+ circularMotionRadius={NumCast(this.dataDoc.circularMotionRadius)}
componentForces={this.dataDoc.componentForces}
- showComponentForces={this.dataDoc.showComponentForces}
+ showComponentForces={BoolCast(this.dataDoc.show_ComponentForces)}
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}
+ coefficientOfKineticFriction={NumCast(this.dataDoc.coefficientOfKineticFriction)}
+ displayXVelocity={NumCast(this.dataDoc.velocity_XDisplay)}
+ displayYVelocity={NumCast(this.dataDoc.velocity_YDisplay)}
+ elasticCollisions={BoolCast(this.dataDoc.elasticCollisions)}
+ mass={NumCast(this.dataDoc.mass)}
+ mode={StrCast(this.dataDoc.mode)}
+ noMovement={BoolCast(this.dataDoc.noMovement)}
+ paused={BoolCast(this.dataDoc.simulation_Paused)}
+ pendulumAngle={NumCast(this.dataDoc.pendulum_angle)}
+ pendulumLength={NumCast(this.dataDoc.pendulum_length)}
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}
+ reset={BoolCast(this.dataDoc.simulation_Reset)}
+ simulationSpeed={NumCast(this.dataDoc.simulation_Speed)}
+ startPendulumAngle={NumCast(this.dataDoc.start_PendulumAngle)}
+ showAcceleration={BoolCast(this.dataDoc.show_Acceleration)}
+ showForceMagnitudes={BoolCast(this.dataDoc.show_ForceMagnitudes)}
+ showForces={BoolCast(this.dataDoc.show_Forces)}
+ showVelocity={BoolCast(this.dataDoc.show_Velocity)}
+ simulationType={StrCast(this.dataDoc.simulation_Type)}
+ springConstant={NumCast(this.dataDoc.springConstant)}
+ springStartLength={NumCast(this.dataDoc.springStartLength)}
+ springRestLength={NumCast(this.dataDoc.springRestLength)}
+ startForces={this.dataDoc.start_Forces}
+ startPosX={NumCast(this.dataDoc.start_PosX)}
+ startPosY={NumCast(this.dataDoc.start_PosY)}
+ startVelX={NumCast(this.dataDoc.start_VelX)}
+ startVelY={NumCast(this.dataDoc.start_VelY)}
timestepSize={0.05}
- updateDisplay={this.dataDoc.displayChange}
+ updateXDisplay={NumCast(this.dataDoc.display_xChange)}
+ updateYDisplay={NumCast(this.dataDoc.display_yChange)}
updatedForces={this.dataDoc.updatedForces}
- wedgeHeight={this.dataDoc.wedgeHeight}
- wedgeWidth={this.dataDoc.wedgeWidth}
+ wedgeHeight={NumCast(this.dataDoc.wedgeHeight)}
+ wedgeWidth={NumCast(this.dataDoc.wedgeWidth)}
xMax={this.xMax}
xMin={this.xMin}
yMax={this.yMax}
yMin={this.yMin}
/>
- {this.dataDoc.simulationType == 'Pulley' && (
+ {this.dataDoc.simulation_Type == 'Pulley' && (
<Weight
dataDoc={this.dataDoc}
layoutDoc={this.layoutDoc}
wallPositions={this.wallPositions}
- adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
- circularMotionRadius={this.dataDoc.circularMotionRadius}
- gravity={this.dataDoc.gravity}
+ adjustPendulumAngle={NumCast(this.dataDoc.pendulum_angle_adjust)}
+ adjustPendulumLength={NumCast(this.dataDoc.pendulum_length_adjust)}
+ circularMotionRadius={NumCast(this.dataDoc.circularMotionRadius)}
+ gravity={NumCast(this.dataDoc.gravity)}
componentForces={this.dataDoc.componentForces}
- showComponentForces={this.dataDoc.showComponentForces}
+ showComponentForces={BoolCast(this.dataDoc.show_ComponentForces)}
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}
+ coefficientOfKineticFriction={NumCast(this.dataDoc.coefficientOfKineticFriction)}
+ displayXVelocity={NumCast(this.dataDoc.velocity_XDisplay)}
+ displayYVelocity={NumCast(this.dataDoc.velocity_YDisplay)}
+ elasticCollisions={BoolCast(this.dataDoc.elasticCollisions)}
+ mass={NumCast(this.dataDoc.mass2)}
+ mode={StrCast(this.dataDoc.mode)}
+ noMovement={BoolCast(this.dataDoc.noMovement)}
+ paused={BoolCast(this.dataDoc.simulation_Paused)}
+ pendulumAngle={NumCast(this.dataDoc.pendulum_angle)}
+ pendulumLength={NumCast(this.dataDoc.pendulum_length)}
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}
+ reset={BoolCast(this.dataDoc.simulation_Reset)}
+ simulationSpeed={NumCast(this.dataDoc.simulation_Speed)}
+ startPendulumAngle={NumCast(this.dataDoc.start_PendulumAngle)}
+ showAcceleration={BoolCast(this.dataDoc.show_Acceleration)}
+ showForceMagnitudes={BoolCast(this.dataDoc.show_ForceMagnitudes)}
+ showForces={BoolCast(this.dataDoc.show_Forces)}
+ showVelocity={BoolCast(this.dataDoc.show_Velocity)}
+ simulationType={this.dataDoc.simulation_Type}
+ springConstant={NumCast(this.dataDoc.springConstant)}
+ springStartLength={NumCast(this.dataDoc.springStartLength)}
+ springRestLength={NumCast(this.dataDoc.springRestLength)}
+ startForces={this.dataDoc.start_Forces2}
+ startPosX={NumCast(this.dataDoc.start_PosX2)}
+ startPosY={NumCast(this.dataDoc.start_PosY2)}
+ startVelX={NumCast(this.dataDoc.start_VelX)}
+ startVelY={NumCast(this.dataDoc.start_VelY)}
timestepSize={0.05}
- updateDisplay={this.dataDoc.displayChange2}
+ updateXDisplay={NumCast(this.dataDoc.display_xChange2)}
+ updateYDisplay={NumCast(this.dataDoc.display_yChange2)}
updatedForces={this.dataDoc.updatedForces2}
- wedgeHeight={this.dataDoc.wedgeHeight}
- wedgeWidth={this.dataDoc.wedgeWidth}
+ wedgeHeight={NumCast(this.dataDoc.wedgeHeight)}
+ wedgeWidth={NumCast(this.dataDoc.wedgeWidth)}
xMax={this.xMax}
xMin={this.xMin}
yMax={this.yMax}
@@ -1033,7 +1003,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
)}
</div>
<div>
- {(this.dataDoc.simulationType == 'One Weight' || this.dataDoc.simulationType == 'Inclined Plane') &&
+ {(this.dataDoc.simulation_Type == 'One Weight' || this.dataDoc.simulation_Type == '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} />;
@@ -1044,26 +1014,26 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<div className="mechanicsSimulationEquationContainer">
<div className="mechanicsSimulationControls">
<Stack direction="row" spacing={1}>
- {this.dataDoc.simulationPaused && this.dataDoc.mode != 'Tutorial' && (
+ {this.dataDoc.simulation_Paused && this.dataDoc.mode != 'Tutorial' && (
<IconButton
onClick={() => {
- this.dataDoc.simulationPaused = false;
+ this.dataDoc.simulation_Paused = false;
}}>
<PlayArrowIcon />
</IconButton>
)}
- {!this.dataDoc.simulationPaused && this.dataDoc.mode != 'Tutorial' && (
+ {!this.dataDoc.simulation_Paused && this.dataDoc.mode != 'Tutorial' && (
<IconButton
onClick={() => {
- this.dataDoc.simulationPaused = true;
+ this.dataDoc.simulation_Paused = true;
}}>
<PauseIcon />
</IconButton>
)}
- {this.dataDoc.simulationPaused && this.dataDoc.mode != 'Tutorial' && (
+ {this.dataDoc.simulation_Paused && this.dataDoc.mode != 'Tutorial' && (
<IconButton
onClick={() => {
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}}>
<ReplayIcon />
</IconButton>
@@ -1071,10 +1041,10 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
</Stack>
<div className="dropdownMenu">
<select
- value={this.dataDoc.simulationType}
+ value={StrCast(this.dataDoc.simulation_Type)}
onChange={event => {
- this.dataDoc.simulationType = event.target.value;
- this.setupSimulation(event.target.value, this.dataDoc.mode);
+ this.dataDoc.simulation_Type = event.target.value;
+ this.setupSimulation(event.target.value, StrCast(this.dataDoc.mode));
}}
style={{ height: '2em', width: '100%', fontSize: '16px' }}>
<option value="One Weight">Projectile</option>
@@ -1088,10 +1058,10 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
</div>
<div className="dropdownMenu">
<select
- value={this.dataDoc.mode}
+ value={StrCast(this.dataDoc.mode)}
onChange={event => {
this.dataDoc.mode = event.target.value;
- this.setupSimulation(this.dataDoc.simulationType, event.target.value);
+ this.setupSimulation(StrCast(this.dataDoc.simulation_Type), event.target.value);
}}
style={{ height: '2em', width: '100%', fontSize: '16px' }}>
<option value="Tutorial">Tutorial Mode</option>
@@ -1100,13 +1070,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
</select>
</div>
</div>
- {this.dataDoc.mode == 'Review' && this.dataDoc.simulationType != 'Inclined Plane' && (
+ {this.dataDoc.mode == 'Review' && this.dataDoc.simulation_Type != 'Inclined Plane' && (
<div className="wordProblemBox">
- <p>{this.dataDoc.simulationType} review problems in progress!</p>
+ <p>{this.dataDoc.simulation_Type} review problems in progress!</p>
<hr />
</div>
)}
- {this.dataDoc.mode == 'Review' && this.dataDoc.simulationType == 'Inclined Plane' && (
+ {this.dataDoc.mode == 'Review' && this.dataDoc.simulation_Type == 'Inclined Plane' && (
<div>
{!this.dataDoc.hintDialogueOpen && (
<IconButton
@@ -1121,26 +1091,25 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<QuestionMarkIcon />
</IconButton>
)}
- <Dialog maxWidth={'sm'} fullWidth={true} open={this.dataDoc.hintDialogueOpen} onClose={() => (this.dataDoc.hintDialogueOpen = false)}>
+ <Dialog maxWidth={'sm'} fullWidth={true} open={BoolCast(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>
- );
- })}
+ {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
@@ -1153,8 +1122,8 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
</Dialog>
<div className="wordProblemBox">
<div className="question">
- <p>{this.dataDoc.questionPartOne}</p>
- <p>{this.dataDoc.questionPartTwo}</p>
+ <p>{StrCast(this.dataDoc.questionPartOne)}</p>
+ <p>{StrCast(this.dataDoc.questionPartTwo)}</p>
</div>
<div className="answers">
{this.dataDoc.selectedQuestion.answerParts.includes('force of gravity') && (
@@ -1162,13 +1131,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
label={<p>Gravity magnitude</p>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'reviewGravityMagnitude'}
+ prop="review_GravityMagnitude"
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')]}
+ value={NumCast(this.dataDoc.review_GravityMagnitude)}
+ showIcon={BoolCast(this.dataDoc.show_Icon)}
+ correctValue={NumListCast(this.dataDoc.answers)[this.dataDoc.selectedQuestion.answerParts.indexOf('force of gravity')]}
labelWidth={'7em'}
/>
)}
@@ -1177,14 +1146,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
label={<p>Gravity angle</p>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'reviewGravityAngle'}
+ prop="review_GravityAngle"
step={1}
unit={'°'}
upperBound={360}
- value={this.dataDoc.reviewGravityAngle}
+ value={NumCast(this.dataDoc.review_GravityAngle)}
radianEquivalent={true}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('angle of gravity')]}
+ showIcon={BoolCast(this.dataDoc.show_Icon)}
+ correctValue={NumListCast(this.dataDoc.answers)[this.dataDoc.selectedQuestion.answerParts.indexOf('angle of gravity')]}
labelWidth={'7em'}
/>
)}
@@ -1193,13 +1162,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
label={<p>Normal force magnitude</p>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'reviewNormalMagnitude'}
+ prop="review_NormalMagnitude"
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')]}
+ value={NumCast(this.dataDoc.review_NormalMagnitude)}
+ showIcon={BoolCast(this.dataDoc.show_Icon)}
+ correctValue={NumListCast(this.dataDoc.answers)[this.dataDoc.selectedQuestion.answerParts.indexOf('normal force')]}
labelWidth={'7em'}
/>
)}
@@ -1208,14 +1177,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
label={<p>Normal force angle</p>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'reviewNormalAngle'}
+ prop="review_NormalAngle"
step={1}
unit={'°'}
upperBound={360}
- value={this.dataDoc.reviewNormalAngle}
+ value={NumCast(this.dataDoc.review_NormalAngle)}
radianEquivalent={true}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('angle of normal force')]}
+ showIcon={BoolCast(this.dataDoc.show_Icon)}
+ correctValue={NumListCast(this.dataDoc.answers)[this.dataDoc.selectedQuestion.answerParts.indexOf('angle of normal force')]}
labelWidth={'7em'}
/>
)}
@@ -1224,13 +1193,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
label={<p>Static friction magnitude</p>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'reviewStaticMagnitude'}
+ prop="review_StaticMagnitude"
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')]}
+ value={NumCast(this.dataDoc.review_StaticMagnitude)}
+ showIcon={BoolCast(this.dataDoc.show_Icon)}
+ correctValue={NumListCast(this.dataDoc.answers)[this.dataDoc.selectedQuestion.answerParts.indexOf('force of static friction')]}
labelWidth={'7em'}
/>
)}
@@ -1239,14 +1208,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
label={<p>Static friction angle</p>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'reviewStaticAngle'}
+ prop="review_StaticAngle"
step={1}
unit={'°'}
upperBound={360}
- value={this.dataDoc.reviewStaticAngle}
+ value={NumCast(this.dataDoc.review_StaticAngle)}
radianEquivalent={true}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('angle of static friction')]}
+ showIcon={BoolCast(this.dataDoc.show_Icon)}
+ correctValue={NumListCast(this.dataDoc.answers)[this.dataDoc.selectedQuestion.answerParts.indexOf('angle of static friction')]}
labelWidth={'7em'}
/>
)}
@@ -1259,14 +1228,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'coefficientOfStaticFriction'}
+ prop="coefficientOfStaticFriction"
step={0.1}
unit={''}
upperBound={1}
- value={this.dataDoc.coefficientOfStaticFriction}
+ value={NumCast(this.dataDoc.coefficientOfStaticFriction)}
effect={this.updateReviewForcesBasedOnCoefficient}
- showIcon={this.dataDoc.showIcon}
- correctValue={this.dataDoc.answers[this.dataDoc.selectedQuestion.answerParts.indexOf('coefficient of static friction')]}
+ showIcon={BoolCast(this.dataDoc.show_Icon)}
+ correctValue={NumListCast(this.dataDoc.answers)[this.dataDoc.selectedQuestion.answerParts.indexOf('coefficient of static friction')]}
/>
)}
{this.dataDoc.selectedQuestion.answerParts.includes('wedge angle') && (
@@ -1274,18 +1243,18 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
label={<Box>&theta;</Box>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'wedgeAngle'}
+ prop="wedgeAngle"
step={1}
unit={'°'}
upperBound={49}
- value={this.dataDoc.wedgeAngle ?? 26}
+ value={NumCast(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')]}
+ showIcon={BoolCast(this.dataDoc.show_Icon)}
+ correctValue={NumListCast(this.dataDoc.answers)[this.dataDoc.selectedQuestion.answerParts.indexOf('wedge angle')]}
/>
)}
</div>
@@ -1306,40 +1275,40 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
}}>
<IconButton
onClick={() => {
- let step = this.dataDoc.stepNumber - 1;
+ let step = NumCast(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.start_Forces = 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;
+ this.dataDoc.show_ForceMagnitudes = this.dataDoc.selectedTutorial.steps[step].show_Magnitude;
}}
disabled={this.dataDoc.stepNumber == 0}>
<ArrowLeftIcon />
</IconButton>
<div>
<h3>
- Step {this.dataDoc.stepNumber + 1}: {this.dataDoc.selectedTutorial.steps[this.dataDoc.stepNumber].description}
+ Step {NumCast(this.dataDoc.stepNumber) + 1}: {this.dataDoc.selectedTutorial.steps[this.dataDoc.stepNumber].description}
</h3>
- <p>{this.dataDoc.selectedTutorial.steps[this.dataDoc.stepNumber].content}</p>
+ <p>{this.dataDoc.selectedTutorial.steps[NumCast(this.dataDoc.stepNumber)].content}</p>
</div>
<IconButton
onClick={() => {
- let step = this.dataDoc.stepNumber + 1;
+ let step = NumCast(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.start_Forces = 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;
+ this.dataDoc.show_ForceMagnitudes = this.dataDoc.selectedTutorial.steps[step].show_Magnitude;
}}
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' && (
+ {(this.dataDoc.simulation_Type == 'One Weight' || this.dataDoc.simulation_Type == 'Inclined Plane' || this.dataDoc.simulation_Type == 'Pendulum') && <p>Resources</p>}
+ {this.dataDoc.simulation_Type == 'One Weight' && (
<ul>
<li>
<a
@@ -1367,7 +1336,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
</li>
</ul>
)}
- {this.dataDoc.simulationType == 'Inclined Plane' && (
+ {this.dataDoc.simulation_Type == 'Inclined Plane' && (
<ul>
<li>
<a
@@ -1395,7 +1364,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
</li>
</ul>
)}
- {this.dataDoc.simulationType == 'Pendulum' && (
+ {this.dataDoc.simulation_Type == 'Pendulum' && (
<ul>
<li>
<a
@@ -1414,7 +1383,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
</div>
</div>
)}
- {this.dataDoc.mode == 'Review' && this.dataDoc.simulationType == 'Inclined Plane' && (
+ {this.dataDoc.mode == 'Review' && this.dataDoc.simulation_Type == 'Inclined Plane' && (
<div
style={{
display: 'flex',
@@ -1434,9 +1403,9 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<div style={{ display: 'flex', flexDirection: 'column' }}>
<Button
onClick={() => {
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
this.checkAnswers();
- this.dataDoc.showIcon = true;
+ this.dataDoc.show_Icon = true;
}}
variant="outlined">
<p>Submit</p>
@@ -1444,7 +1413,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<Button
onClick={() => {
this.generateNewQuestion();
- this.dataDoc.showIcon = false;
+ this.dataDoc.show_Icon = false;
}}
variant="outlined">
<p>New question</p>
@@ -1456,123 +1425,127 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<div className="vars">
<FormControl component="fieldset">
<FormGroup>
- {this.dataDoc.simulationType == 'One Weight' && (
+ {this.dataDoc.simulation_Type == 'One Weight' && (
<FormControlLabel
- control={<Checkbox checked={this.dataDoc.elasticCollisions} onChange={() => (this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions)} />}
+ control={<Checkbox checked={BoolCast(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={BoolCast(this.dataDoc.show_Forces)} onChange={() => (this.dataDoc.show_Forces = !this.dataDoc.show_Forces)} />} label="Show force vectors" labelPlacement="start" />
+ {(this.dataDoc.simulation_Type == 'Inclined Plane' || this.dataDoc.simulation_Type == 'Pendulum') && (
<FormControlLabel
- control={<Checkbox checked={this.dataDoc.showForces} onChange={() => (this.dataDoc.showComponentForces = !this.dataDoc.showComponentForces)} />}
+ control={<Checkbox checked={BoolCast(this.dataDoc.show_Forces)} onChange={() => (this.dataDoc.show_ComponentForces = !this.dataDoc.show_ComponentForces)} />}
label="Show component force vectors"
labelPlacement="start"
/>
)}
<FormControlLabel
- control={<Checkbox checked={this.dataDoc.showAcceleration} onChange={() => (this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration)} />}
+ control={<Checkbox checked={BoolCast(this.dataDoc.show_Acceleration)} onChange={() => (this.dataDoc.show_Acceleration = !this.dataDoc.show_Acceleration)} />}
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' && (
+ <FormControlLabel
+ control={<Checkbox checked={BoolCast(this.dataDoc.show_Velocity)} onChange={() => (this.dataDoc.show_Velocity = !this.dataDoc.show_Velocity)} />}
+ label="Show velocity vector"
+ labelPlacement="start"
+ />
+ <InputField label={<Box>Speed</Box>} lowerBound={1} dataDoc={this.dataDoc} prop="simulation_Speed" step={1} unit={'x'} upperBound={10} value={this.dataDoc.simulation_Speed ?? 2} labelWidth={'5em'} />
+ {this.dataDoc.simulation_Paused && this.dataDoc.simulation_Type != 'Circular Motion' && (
<InputField
label={<Box>Gravity</Box>}
lowerBound={-30}
dataDoc={this.dataDoc}
- prop={'gravity'}
+ prop="gravity"
step={0.01}
unit={'m/s2'}
upperBound={0}
- value={this.dataDoc.gravity ?? -9.81}
+ value={NumCast(this.dataDoc.gravity, -9.81)}
effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ this.setupSimulation(StrCast(this.dataDoc.simulation_Type), StrCast(this.dataDoc.mode));
}}
labelWidth={'5em'}
/>
)}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType != 'Pulley' && (
+ {this.dataDoc.simulation_Paused && this.dataDoc.simulation_Type != 'Pulley' && (
<InputField
label={<Box>Mass</Box>}
lowerBound={1}
dataDoc={this.dataDoc}
- prop={'mass'}
+ prop="mass"
step={0.1}
unit={'kg'}
upperBound={5}
- value={this.dataDoc.mass ?? 1}
+ value={NumCast(this.dataDoc.mass) ?? 1}
effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ this.setupSimulation(StrCast(this.dataDoc.simulation_Type), StrCast(this.dataDoc.mode));
}}
labelWidth={'5em'}
/>
)}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType == 'Pulley' && (
+ {this.dataDoc.simulation_Paused && this.dataDoc.simulation_Type == 'Pulley' && (
<InputField
label={<Box>Red mass</Box>}
lowerBound={1}
dataDoc={this.dataDoc}
- prop={'mass'}
+ prop="mass"
step={0.1}
unit={'kg'}
upperBound={5}
- value={this.dataDoc.mass ?? 1}
+ value={NumCast(this.dataDoc.mass) ?? 1}
effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ this.setupSimulation(StrCast(this.dataDoc.simulation_Type), StrCast(this.dataDoc.mode));
}}
labelWidth={'5em'}
/>
)}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType == 'Pulley' && (
+ {this.dataDoc.simulation_Paused && this.dataDoc.simulation_Type == 'Pulley' && (
<InputField
label={<Box>Blue mass</Box>}
lowerBound={1}
dataDoc={this.dataDoc}
- prop={'mass2'}
+ prop="mass2"
step={0.1}
unit={'kg'}
upperBound={5}
- value={this.dataDoc.mass2 ?? 1}
+ value={NumCast(this.dataDoc.mass2) ?? 1}
effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ this.setupSimulation(StrCast(this.dataDoc.simulation_Type), StrCast(this.dataDoc.mode));
}}
labelWidth={'5em'}
/>
)}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType == 'Circular Motion' && (
+ {this.dataDoc.simulation_Paused && this.dataDoc.simulation_Type == 'Circular Motion' && (
<InputField
label={<Box>Rod length</Box>}
lowerBound={100}
dataDoc={this.dataDoc}
- prop={'circularMotionRadius'}
+ prop="circularMotionRadius"
step={5}
unit={'m'}
upperBound={250}
- value={this.dataDoc.circularMotionRadius ?? 100}
+ value={NumCast(this.dataDoc.circularMotionRadius) ?? 100}
effect={(val: number) => {
- this.setupSimulation(this.dataDoc.simulationType, this.dataDoc.mode);
+ this.setupSimulation(StrCast(this.dataDoc.simulation_Type), StrCast(this.dataDoc.mode));
}}
labelWidth={'5em'}
/>
)}
</FormGroup>
</FormControl>
- {this.dataDoc.simulationType == 'Spring' && this.dataDoc.simulationPaused && (
+ {this.dataDoc.simulation_Type == 'Spring' && this.dataDoc.simulation_Paused && (
<div>
<InputField
label={<Typography color="inherit">Spring stiffness</Typography>}
lowerBound={0.1}
dataDoc={this.dataDoc}
- prop={'springConstant'}
+ prop="springConstant"
step={1}
unit={'N/m'}
upperBound={500}
- value={this.dataDoc.springConstant ?? 0.5}
+ value={NumCast(this.dataDoc.springConstant) ?? 0.5}
effect={(val: number) => {
- this.dataDoc.simulationReset(!this.dataDoc.simulationReset);
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}}
radianEquivalent={false}
mode={'Freeform'}
@@ -1582,13 +1555,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
label={<Typography color="inherit">Rest length</Typography>}
lowerBound={10}
dataDoc={this.dataDoc}
- prop={'springRestLength'}
+ prop="springRestLength"
step={100}
unit={''}
upperBound={500}
- value={this.dataDoc.springRestLength ?? 200}
+ value={NumCast(this.dataDoc.springRestLength) ?? 200}
effect={(val: number) => {
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}}
radianEquivalent={false}
mode={'Freeform'}
@@ -1596,17 +1569,17 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
/>
<InputField
label={<Typography color="inherit">Starting displacement</Typography>}
- lowerBound={-(this.dataDoc.springRestLength - 10)}
+ lowerBound={-(NumCast(this.dataDoc.springRestLength) - 10)}
dataDoc={this.dataDoc}
- prop={''}
+ prop=""
step={10}
unit={''}
- upperBound={this.dataDoc.springRestLength}
- value={this.dataDoc.springStartLength - this.dataDoc.springRestLength ?? 0}
+ upperBound={NumCast(this.dataDoc.springRestLength)}
+ value={NumCast(this.dataDoc.springStartLength) - NumCast(this.dataDoc.springRestLength)}
effect={(val: number) => {
- this.dataDoc.startPosY = this.dataDoc.springRestLength + val;
- this.dataDoc.springStartLength = this.dataDoc.springRestLength + val;
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.start_PosY = NumCast(this.dataDoc.springRestLength) + val;
+ this.dataDoc.springStartLength = NumCast(this.dataDoc.springRestLength) + val;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}}
radianEquivalent={false}
mode={'Freeform'}
@@ -1614,20 +1587,20 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
/>
</div>
)}
- {this.dataDoc.simulationType == 'Inclined Plane' && this.dataDoc.simulationPaused && (
+ {this.dataDoc.simulation_Type == 'Inclined Plane' && this.dataDoc.simulation_Paused && (
<div>
<InputField
label={<Box>&theta;</Box>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'wedgeAngle'}
+ prop="wedgeAngle"
step={1}
unit={'°'}
upperBound={49}
- value={this.dataDoc.wedgeAngle ?? 26}
+ value={NumCast(this.dataDoc.wedgeAngle, 26)}
effect={(val: number) => {
this.changeWedgeBasedOnNewAngle(val);
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}}
radianEquivalent={true}
mode={'Freeform'}
@@ -1641,17 +1614,17 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'coefficientOfStaticFriction'}
+ prop="coefficientOfStaticFriction"
step={0.1}
unit={''}
upperBound={1}
- value={this.dataDoc.coefficientOfStaticFriction ?? 0}
+ value={NumCast(this.dataDoc.coefficientOfStaticFriction) ?? 0}
effect={(val: number) => {
this.updateForcesWithFriction(val);
- if (val < Number(this.dataDoc.coefficientOfKineticFriction)) {
+ if (val < NumCast(this.dataDoc.coefficientOfKineticFriction)) {
this.dataDoc.soefficientOfKineticFriction = val;
}
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}}
mode={'Freeform'}
labelWidth={'2em'}
@@ -1664,48 +1637,48 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'coefficientOfKineticFriction'}
+ prop="coefficientOfKineticFriction"
step={0.1}
unit={''}
- upperBound={Number(this.dataDoc.coefficientOfStaticFriction)}
- value={this.dataDoc.coefficientOfKineticFriction ?? 0}
+ upperBound={NumCast(this.dataDoc.coefficientOfStaticFriction)}
+ value={NumCast(this.dataDoc.coefficientOfKineticFriction) ?? 0}
effect={(val: number) => {
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}}
mode={'Freeform'}
labelWidth={'2em'}
/>
</div>
)}
- {this.dataDoc.simulationType == 'Inclined Plane' && !this.dataDoc.simulationPaused && (
+ {this.dataDoc.simulation_Type == 'Inclined Plane' && !this.dataDoc.simulation_Paused && (
<Typography>
- &theta;: {Math.round(Number(this.dataDoc.wedgeAngle) * 100) / 100}° ≈ {Math.round(((Number(this.dataDoc.wedgeAngle) * Math.PI) / 180) * 100) / 100} rad
+ &theta;: {Math.round(NumCast(this.dataDoc.wedgeAngle) * 100) / 100}° ≈ {Math.round(((NumCast(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 && (
+ {this.dataDoc.simulation_Type == 'Pendulum' && !this.dataDoc.simulation_Paused && (
<Typography>
- &theta;: {Math.round(this.dataDoc.pendulumAngle * 100) / 100}° ≈ {Math.round(((this.dataDoc.pendulumAngle * Math.PI) / 180) * 100) / 100} rad
+ &theta;: {Math.round(NumCast(this.dataDoc.pendulum_angle) * 100) / 100}° ≈ {Math.round(((NumCast(this.dataDoc.pendulum_angle) * Math.PI) / 180) * 100) / 100} rad
</Typography>
)}
- {this.dataDoc.simulationType == 'Pendulum' && this.dataDoc.simulationPaused && (
+ {this.dataDoc.simulation_Type == 'Pendulum' && this.dataDoc.simulation_Paused && (
<div>
<InputField
label={<Box>Angle</Box>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'pendulumAngle'}
+ prop="pendulum_angle"
step={1}
unit={'°'}
upperBound={59}
- value={this.dataDoc.pendulumAngle ?? 30}
+ value={NumCast(this.dataDoc.pendulum_angle, 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);
+ this.dataDoc.start_PendulumAngle = value;
+ if (this.dataDoc.simulation_Type == 'Pendulum') {
+ const mag = NumCast(this.dataDoc.mass) * Math.abs(NumCast(this.dataDoc.gravity)) * Math.cos((value * Math.PI) / 180);
const forceOfTension: IForce = {
description: 'Tension',
@@ -1722,29 +1695,29 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
};
const gravityParallel: IForce = {
description: 'Gravity Parallel Component',
- magnitude: Math.abs(this.dataDoc.gravity) * Math.cos((value * Math.PI) / 180),
+ magnitude: Math.abs(NumCast(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),
+ magnitude: Math.abs(NumCast(this.dataDoc.gravity)) * Math.sin((value * Math.PI) / 180),
directionInDegrees: -value,
component: true,
};
- const length = this.dataDoc.pendulumLength;
+ const length = NumCast(this.dataDoc.pendulum_length);
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 xPos = this.xMax / 2 - x - NumCast(this.dataDoc.radius);
+ const yPos = y - NumCast(this.dataDoc.radius) - 5;
+ this.dataDoc.start_PosX = xPos;
+ this.dataDoc.start_PosY = yPos;
- this.dataDoc.startForces = [
+ this.dataDoc.start_Forces = [
{
description: 'Gravity',
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ magnitude: Math.abs(NumCast(this.dataDoc.gravity)) * NumCast(this.dataDoc.mass),
directionInDegrees: 270,
component: false,
},
@@ -1753,18 +1726,15 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
this.dataDoc.updatedForces = [
{
description: 'Gravity',
- magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
+ magnitude: Math.abs(NumCast(this.dataDoc.gravity)) * NumCast(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;
+ this.dataDoc.pendulum_angle_adjust = value;
+ (this.dataDoc.pendulum_length_adjust = this.dataDoc.pendulum_length), (this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset);
}
}}
radianEquivalent={true}
@@ -1775,18 +1745,16 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
label={<Box>Rod length</Box>}
lowerBound={0}
dataDoc={this.dataDoc}
- prop={'pendulumLength'}
+ prop="pendulum_length"
step={1}
unit={'m'}
upperBound={400}
- value={Math.round(this.dataDoc.pendulumLength)}
+ value={Math.round(NumCast(this.dataDoc.pendulum_length))}
effect={value => {
- if (this.dataDoc.simulationType == 'Pendulum') {
- this.dataDoc.adjustPendulumAngle = {
- angle: this.dataDoc.pendulumAngle,
- length: value,
- };
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ if (this.dataDoc.simulation_Type == 'Pendulum') {
+ this.dataDoc.pendulum_angle_adjust = NumCast(this.dataDoc.pendulum_angle);
+ this.dataDoc.pendulum_length_adjust = value;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}
}}
radianEquivalent={false}
@@ -1802,7 +1770,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<table>
<tbody>
<tr>
- <td>{this.dataDoc.simulationType == 'Pulley' ? 'Red Weight' : ''}</td>
+ <td>{this.dataDoc.simulation_Type == 'Pulley' ? 'Red Weight' : ''}</td>
<td>X</td>
<td>Y</td>
</tr>
@@ -1817,36 +1785,34 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
>
<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.simulation_Paused || this.dataDoc.simulation_Type == 'Inclined Plane' || this.dataDoc.simulation_Type == 'Circular Motion' || this.dataDoc.simulation_Type == 'Pulley') && (
+ <td style={{ cursor: 'default' }}>{this.dataDoc.position_XDisplay} m</td>
)}{' '}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType != 'Inclined Plane' && this.dataDoc.simulationType != 'Circular Motion' && this.dataDoc.simulationType != 'Pulley' && (
+ {this.dataDoc.simulation_Paused && this.dataDoc.simulation_Type != 'Inclined Plane' && this.dataDoc.simulation_Type != 'Circular Motion' && this.dataDoc.simulation_Type != 'Pulley' && (
<td
style={{
cursor: 'default',
}}>
<InputField
- lowerBound={this.dataDoc.simulationType == 'Projectile' ? 1 : (this.xMax + this.xMin) / 4 - this.radius - 15}
+ lowerBound={this.dataDoc.simulation_Type == 'Projectile' ? 1 : (this.xMax + this.xMin) / 4 - this.radius - 15}
dataDoc={this.dataDoc}
- prop={'positionXDisplay'}
+ prop="position_XDisplay"
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}
+ upperBound={this.dataDoc.simulation_Type == 'Projectile' ? this.xMax - 110 : (3 * (this.xMax + this.xMin)) / 4 - this.radius / 2 - 15}
+ value={NumCast(this.dataDoc.position_XDisplay)}
effect={value => {
- this.dataDoc.displayChange = {
- xDisplay: value,
- yDisplay: this.dataDoc.positionYDisplay,
- };
- if (this.dataDoc['simulationType'] == 'Suspension') {
+ this.dataDoc.display_xChange = value;
+ this.dataDoc.display_yChange = this.dataDoc.position_YDisplay;
+ if (this.dataDoc.simulation_Type == '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 deltaY = this.getYPosFromDisplay(NumCast(this.dataDoc.position_YDisplay)) + 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 tensionMag2 = (NumCast(this.dataDoc.mass) * Math.abs(NumCast(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;
@@ -1864,11 +1830,11 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
};
const grav: IForce = {
description: 'Gravity',
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(this.dataDoc.gravity)),
directionInDegrees: 270,
component: false,
};
- this.dataDoc['updatedForces'] = [tensionForce1, tensionForce2, grav];
+ this.dataDoc.updatedForces = [tensionForce1, tensionForce2, grav];
}
}}
small={true}
@@ -1876,10 +1842,10 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
/>
</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.simulation_Paused || this.dataDoc.simulation_Type == 'Inclined Plane' || this.dataDoc.simulation_Type == 'Circular Motion' || this.dataDoc.simulation_Type == 'Pulley') && (
+ <td style={{ cursor: 'default' }}>{`${NumCast(this.dataDoc.position_YDisplay)} m`}</td>
)}{' '}
- {this.dataDoc.simulationPaused && this.dataDoc.simulationType != 'Inclined Plane' && this.dataDoc.simulationType != 'Circular Motion' && this.dataDoc.simulationType != 'Pulley' && (
+ {this.dataDoc.simulation_Paused && this.dataDoc.simulation_Type != 'Inclined Plane' && this.dataDoc.simulation_Type != 'Circular Motion' && this.dataDoc.simulation_Type != 'Pulley' && (
<td
style={{
cursor: 'default',
@@ -1887,25 +1853,23 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<InputField
lowerBound={1}
dataDoc={this.dataDoc}
- prop={'positionYDisplay'}
+ prop="position_YDisplay"
step={1}
unit={'m'}
upperBound={this.yMax - 110}
- value={this.dataDoc.positionYDisplay}
+ value={NumCast(this.dataDoc.position_YDisplay)}
effect={value => {
- this.dataDoc.displayChange = {
- xDisplay: this.dataDoc.positionXDisplay,
- yDisplay: value,
- };
- if (this.dataDoc['simulationType'] == 'Suspension') {
+ this.dataDoc.display_xChange = NumCast(this.dataDoc.position_XDisplay);
+ this.dataDoc.display_yChange = value;
+ if (this.dataDoc.simulation_Type == '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 deltaX1 = NumCast(this.dataDoc.position_XDisplay) + this.radius - x1rod;
+ let deltaX2 = x2rod - (NumCast(this.dataDoc.position_XDisplay) + 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 tensionMag2 = (NumCast(this.dataDoc.mass) * Math.abs(NumCast(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;
@@ -1923,11 +1887,11 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
};
const grav: IForce = {
description: 'Gravity',
- magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
+ magnitude: NumCast(this.dataDoc.mass) * Math.abs(NumCast(this.dataDoc.gravity)),
directionInDegrees: 270,
component: false,
};
- this.dataDoc['updatedForces'] = [tensionForce1, tensionForce2, grav];
+ this.dataDoc.updatedForces = [tensionForce1, tensionForce2, grav];
}
}}
small={true}
@@ -1947,10 +1911,10 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
>
<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.simulation_Paused || (this.dataDoc.simulation_Type != 'One Weight' && this.dataDoc.simulation_Type != 'Circular Motion')) && (
+ <td style={{ cursor: 'default' }}>{`${NumCast(this.dataDoc.velocity_XDisplay)} m/s`}</td>
)}{' '}
- {this.dataDoc.simulationPaused && (this.dataDoc.simulationType == 'One Weight' || this.dataDoc.simulationType == 'Circular Motion') && (
+ {this.dataDoc.simulation_Paused && (this.dataDoc.simulation_Type == 'One Weight' || this.dataDoc.simulation_Type == 'Circular Motion') && (
<td
style={{
cursor: 'default',
@@ -1958,22 +1922,22 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<InputField
lowerBound={-50}
dataDoc={this.dataDoc}
- prop={'velocityXDisplay'}
+ prop="velocity_XDisplay"
step={1}
unit={'m/s'}
upperBound={50}
- value={this.dataDoc.velocityXDisplay}
+ value={this.dataDoc.velocity_XDisplay}
effect={value => {
- this.dataDoc.startVelX = value;
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ this.dataDoc.start_VelX = value;
+ this.dataDoc.simulation_Reset = !this.dataDoc.simulation_Reset;
}}
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' && (
+ {(!this.dataDoc.simulation_Paused || this.dataDoc.simulation_Type != 'One Weight') && <td style={{ cursor: 'default' }}>{this.dataDoc.velocity_YDisplay} m/s</td>}{' '}
+ {this.dataDoc.simulation_Paused && this.dataDoc.simulation_Type == 'One Weight' && (
<td
style={{
cursor: 'default',
@@ -1981,17 +1945,15 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<InputField
lowerBound={-50}
dataDoc={this.dataDoc}
- prop={'velocityYDisplay'}
+ prop="velocity_YDisplay"
step={1}
unit={'m/s'}
upperBound={50}
- value={this.dataDoc.velocityYDisplay}
+ value={this.dataDoc.velocity_YDisplay}
effect={value => {
- this.dataDoc.startVelY = -value;
- this.dataDoc.displayChange = {
- xDisplay: this.dataDoc.positionXDisplay,
- yDisplay: this.dataDoc.positionYDisplay,
- };
+ this.dataDoc.start_VelY = -value;
+ this.dataDoc.display_xChange = this.dataDoc.position_XDisplay;
+ this.dataDoc.display_yChange = this.dataDoc.position_YDisplay;
}}
small={true}
mode={'Freeform'}
@@ -2011,23 +1973,23 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<Box>Acceleration</Box>
</td>
<td style={{ cursor: 'default' }}>
- {this.dataDoc.accelerationXDisplay} m/s<sup>2</sup>
+ {this.dataDoc.acceleration_XDisplay} m/s<sup>2</sup>
</td>
<td style={{ cursor: 'default' }}>
- {this.dataDoc.accelerationYDisplay} m/s<sup>2</sup>
+ {this.dataDoc.acceleration_YDisplay} 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>
+ <td>{Math.round(this.dataDoc.velocity_XDisplay * this.dataDoc.mass * 10) / 10} kg*m/s</td>
+ <td>{Math.round(this.dataDoc.velocity_YDisplay * this.dataDoc.mass * 10) / 10} kg*m/s</td>
</tr>
</tbody>
</table>
)}
- {this.dataDoc.mode == 'Freeform' && this.dataDoc.simulationType == 'Pulley' && (
+ {this.dataDoc.mode == 'Freeform' && this.dataDoc.simulation_Type == 'Pulley' && (
<table>
<tbody>
<tr>
@@ -2039,40 +2001,39 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
<td>
<Box>Position</Box>
</td>
- <td style={{ cursor: 'default' }}>{this.dataDoc.positionXDisplay2} m</td>
- <td style={{ cursor: 'default' }}>{this.dataDoc.positionYDisplay2} m</td>
+ <td style={{ cursor: 'default' }}>{`${this.dataDoc.position_XDisplay2} m`}</td>
+ <td style={{ cursor: 'default' }}>{`${this.dataDoc.position_YDisplay2} 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>
+ <td style={{ cursor: 'default' }}>{`${this.dataDoc.position_XDisplay2} m/s`}</td>
+ <td style={{ cursor: 'default' }}>{`${this.dataDoc.position_YDisplay2} m/s`}</td>
</tr>
<tr>
<td>
<Box>Acceleration</Box>
</td>
<td style={{ cursor: 'default' }}>
- {this.dataDoc.accelerationXDisplay2} m/s<sup>2</sup>
+ {this.dataDoc.acceleration_XDisplay2} m/s<sup>2</sup>
</td>
<td style={{ cursor: 'default' }}>
- {this.dataDoc.accelerationYDisplay2} m/s<sup>2</sup>
+ {this.dataDoc.acceleration_YDisplay2} 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>
+ <td>{Math.round(NumCast(this.dataDoc.velocity_XDisplay2) * NumCast(this.dataDoc.mass) * 10) / 10} kg*m/s</td>
+ <td>{Math.round(NumCast(this.dataDoc.velocity_YDisplay2) * NumCast(this.dataDoc.mass) * 10) / 10} kg*m/s</td>
</tr>
</tbody>
</table>
)}
</div>
- {this.dataDoc.simulationType != 'Pendulum' && this.dataDoc.simulationType != 'Spring' && (
+ {this.dataDoc.simulation_Type != 'Pendulum' && this.dataDoc.simulation_Type != 'Spring' && (
<div>
<p>Kinematic Equations</p>
<ul>
@@ -2089,7 +2050,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
</ul>
</div>
)}
- {this.dataDoc.simulationType == 'Spring' && (
+ {this.dataDoc.simulation_Type == 'Spring' && (
<div>
<p>Harmonic Motion Equations: Spring</p>
<ul>
@@ -2118,7 +2079,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
</ul>
</div>
)}
- {this.dataDoc.simulationType == 'Pendulum' && (
+ {this.dataDoc.simulation_Type == 'Pendulum' && (
<div>
<p>Harmonic Motion Equations: Pendulum</p>
<ul>
@@ -2153,7 +2114,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP
top: this.yMax - 120 + 40 + 'px',
left: this.xMin + 90 - 80 + 'px',
}}>
- {this.dataDoc.simulationType == 'Circular Motion' ? 'Z' : 'Y'}
+ {this.dataDoc.simulation_Type == 'Circular Motion' ? 'Z' : 'Y'}
</p>
<p
style={{
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx
index 88af37791..a2883e825 100644
--- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx
@@ -1,1674 +1,1352 @@
-import { Doc } from '../../../../fields/Doc';
+import { Doc, HeightSym, WidthSym } from '../../../../fields/Doc';
import React = require('react');
-import "./PhysicsSimulationBox.scss";
+import './PhysicsSimulationBox.scss';
+import { NumCast } from '../../../../fields/Types';
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;
}
export interface IWeightProps {
- dataDoc: Doc;
- layoutDoc: Doc;
- adjustPendulumAngle: { angle: number; length: number };
- circularMotionRadius: number;
- coefficientOfKineticFriction: number;
- color: string;
- componentForces: IForce[];
- displayXVelocity: number;
- displayYVelocity: number;
- elasticCollisions: boolean;
- gravity: number;
- mass: number;
- mode: string;
- noMovement: boolean;
- paused: boolean;
- pendulumAngle: number;
- pendulumLength: number;
- radius: number;
- reset: boolean;
- showAcceleration: boolean;
- showComponentForces: boolean;
- showForceMagnitudes: boolean;
- showForces: boolean;
- showVelocity: boolean;
- simulationSpeed: number;
- simulationType: string;
- springConstant: number;
- springRestLength: number;
- springStartLength: number;
- startForces: IForce[];
- startPendulumAngle: number;
- startPosX: number;
- startPosY: number;
- startVelX: number;
- startVelY: number;
- timestepSize: number;
- updateDisplay: { xDisplay: number; yDisplay: number };
- updatedForces: IForce[];
- wallPositions: IWallProps[];
- wedgeHeight: number;
- wedgeWidth: number;
- xMax: number;
- xMin: number;
- yMax: number;
- yMin: number;
+ dataDoc: Doc;
+ layoutDoc: Doc;
+ adjustPendulumAngle: number;
+ adjustPendulumLength: number;
+ circularMotionRadius: number;
+ coefficientOfKineticFriction: number;
+ color: string;
+ componentForces: IForce[];
+ displayXVelocity: number;
+ displayYVelocity: number;
+ elasticCollisions: boolean;
+ gravity: number;
+ mass: number;
+ mode: string;
+ noMovement: boolean;
+ paused: boolean;
+ pendulumAngle: number;
+ pendulumLength: number;
+ radius: number;
+ reset: boolean;
+ showAcceleration: boolean;
+ showComponentForces: boolean;
+ showForceMagnitudes: boolean;
+ showForces: boolean;
+ showVelocity: boolean;
+ simulationSpeed: number;
+ simulationType: string;
+ springConstant: number;
+ springRestLength: number;
+ springStartLength: number;
+ startForces: IForce[];
+ startPendulumAngle: number;
+ startPosX: number;
+ startPosY: number;
+ startVelX: number;
+ startVelY: number;
+ timestepSize: number;
+ updateXDisplay: number;
+ updateYDisplay: number;
+ updatedForces: IForce[];
+ wallPositions: IWallProps[];
+ wedgeHeight: number;
+ wedgeWidth: number;
+ xMax: number;
+ xMin: number;
+ yMax: number;
+ yMin: number;
}
interface IState {
- angleLabel: number,
- clickPositionX: number,
- clickPositionY: number,
- coordinates: string,
- dragging: boolean,
- kineticFriction: boolean,
- maxPosYConservation: number,
- timer: number,
- updatedStartPosX: any,
- updatedStartPosY: any,
- walls: IWallProps[],
- xPosition: any,
- xVelocity: number,
- yPosition: any,
- yVelocity: number,
- xAccel: number,
- yAccel: number,
+ angleLabel: number;
+ clickPositionX: number;
+ clickPositionY: number;
+ coordinates: string;
+ dragging: boolean;
+ kineticFriction: boolean;
+ maxPosYConservation: number;
+ timer: number;
+ updatedStartPosX: any;
+ updatedStartPosY: any;
+ walls: IWallProps[];
+ xPosition: any;
+ xVelocity: number;
+ yPosition: any;
+ yVelocity: number;
+ xAccel: number;
+ yAccel: number;
}
export default class Weight extends React.Component<IWeightProps, IState> {
-
- constructor(props: any) {
- super(props)
- this.state = {
- angleLabel: 0,
- clickPositionX: 0,
- clickPositionY: 0,
- coordinates: "",
- dragging: false,
- kineticFriction: false,
- maxPosYConservation: 0,
- timer: 0,
- updatedStartPosX: this.props.startPosX ?? 0,
- updatedStartPosY: this.props.startPosY ?? 0,
- walls: [],
- xPosition: this.props.startPosX ?? 0,
- xVelocity: this.props.startVelX ? this.props.startVelX: 0,
- yPosition: this.props.startPosY ?? 0,
- yVelocity: this.props.startVelY ? this.props.startVelY: 0,
- xAccel: 0,
- yAccel: 0,
+ constructor(props: any) {
+ super(props);
+ this.state = {
+ angleLabel: 0,
+ clickPositionX: 0,
+ clickPositionY: 0,
+ coordinates: '',
+ dragging: false,
+ kineticFriction: false,
+ maxPosYConservation: 0,
+ timer: 0,
+ updatedStartPosX: this.props.startPosX ?? 0,
+ updatedStartPosY: this.props.startPosY ?? 0,
+ walls: [],
+ xPosition: this.props.startPosX ?? 0,
+ xVelocity: this.props.startVelX ? this.props.startVelX : 0,
+ yPosition: this.props.startPosY ?? 0,
+ yVelocity: this.props.startVelY ? this.props.startVelY : 0,
+ xAccel: 0,
+ yAccel: 0,
+ };
}
- }
-
- componentDidMount() {
- // Timer for animating the simulation
- setInterval(() => {
- this.setState({timer: this.state.timer + 1});
- }, 50);
- }
-
- // Constants
- draggable =
- this.props.dataDoc['simulationType'] != "Inclined Plane" &&
- this.props.dataDoc['simulationType'] != "Pendulum" &&
- this.props.dataDoc['mode'] == "Freeform";
- epsilon = 0.0001;
- labelBackgroundColor = `rgba(255,255,255,0.5)`;
-
- // Variables
- weightStyle = {
- alignItems: "center",
- backgroundColor: this.props.color,
- borderColor: "black",
- borderRadius: 50 + "%",
- borderStyle: "solid",
- display: "flex",
- height: 2 * this.props.radius + "px",
- justifyContent: "center",
- left: this.props.startPosX + "px",
- position: "absolute" as "absolute",
- top: this.props.startPosY + "px",
- touchAction: "none",
- width: 2 * this.props.radius + "px",
- zIndex: 5,
- };
-
- // Helper function to go between display and real values
- getDisplayYPos = (yPos: number) => {
- return this.props.yMax - yPos - 2 * this.props.radius + 5;
- };
- getYPosFromDisplay = (yDisplay: number) => {
- return this.props.yMax - yDisplay - 2 * this.props.radius + 5;
- };
- // Set display values based on real values
- setYPosDisplay = (yPos: number) => {
- const displayPos = this.getDisplayYPos(yPos);
- if (this.props.color == 'red') {
- this.props.dataDoc['positionYDisplay'] = Math.round(displayPos * 100) / 100
- } else {
- this.props.dataDoc['positionYDisplay2'] = Math.round(displayPos * 100) / 100
+ componentDidMount() {
+ // Timer for animating the simulation
+ setInterval(() => {
+ this.setState({ timer: this.state.timer + 1 });
+ }, 50);
}
- };
- setXPosDisplay = (xPos: number) => {
- if (this.props.color == 'red') {
- this.props.dataDoc['positionXDisplay'] = Math.round(xPos * 100) / 100;
- } else {
- this.props.dataDoc['positionXDisplay2'] = Math.round(xPos * 100) / 100;}
- };
- setYVelDisplay = (yVel: number) => {
- if (this.props.color == 'red') {
- this.props.dataDoc['velocityYDisplay'] = (-1 * Math.round(yVel * 100)) / 100;
- } else {
- this.props.dataDoc['velocityYDisplay2'] = (-1 * Math.round(yVel * 100)) / 100;}
- };
- setXVelDisplay = (xVel: number) => {
- if (this.props.color == 'red') {
- this.props.dataDoc['velocityXDisplay'] = Math.round(xVel * 100) / 100;
- } else {
- this.props.dataDoc['velocityXDisplay2'] = Math.round(xVel * 100) / 100;}
- };
- // Update display values when simulation updates
- setDisplayValues = (
- xPos: number = this.state.xPosition,
- yPos: number = this.state.yPosition,
- xVel: number = this.state.xVelocity,
- yVel: number = this.state.yVelocity
- ) => {
- this.setYPosDisplay(yPos);
- this.setXPosDisplay(xPos);
- this.setYVelDisplay(yVel);
- this.setXVelDisplay(xVel);
- if (this.props.color == 'red') {
- this.props.dataDoc['accelerationYDisplay'] =
- (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100
- ;
- this.props.dataDoc['accelerationXDisplay'] =
- Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100
- ;
- } else {
- this.props.dataDoc['accelerationYDisplay2'] =
- (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100
- ;
- this.props.dataDoc['accelerationXDisplay2'] =
- Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100
- ;}
+ // Constants
+ draggable = this.props.dataDoc.simulation_Type != 'Inclined Plane' && this.props.dataDoc.simulation_Type != 'Pendulum' && this.props.dataDoc.mode == 'Freeform';
+ epsilon = 0.0001;
+ labelBackgroundColor = `rgba(255,255,255,0.5)`;
- this.setState({xAccel : (Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100)})
- this.setState({yAccel :
- (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100
- });
- };
+ // Variables
+ weightStyle = {
+ alignItems: 'center',
+ backgroundColor: this.props.color,
+ borderColor: 'black',
+ borderRadius: 50 + '%',
+ borderStyle: 'solid',
+ display: 'flex',
+ height: 2 * this.props.radius + 'px',
+ justifyContent: 'center',
+ left: this.props.startPosX + 'px',
+ position: 'absolute' as 'absolute',
+ top: this.props.startPosY + 'px',
+ touchAction: 'none',
+ width: 2 * this.props.radius + 'px',
+ zIndex: 5,
+ };
- componentDidUpdate(prevProps: Readonly<IWeightProps>, prevState: Readonly<IState>, snapshot?: any): void {
- // Change pendulum angle from input field
- if (prevProps.adjustPendulumAngle != this.props.adjustPendulumAngle) {
- let length = this.props.adjustPendulumAngle.length;
- const x =
- length * Math.cos(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180);
- const y =
- length * Math.sin(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180);
- const xPos = this.props.xMax / 2 - x - this.props.radius;
- const yPos = y - this.props.radius - 5;
- this.setState({xPosition: xPos})
- this.setState({yPosition: yPos})
- this.setState({updatedStartPosX: xPos})
- this.setState({updatedStartPosY: yPos})
- this.props.dataDoc['pendulumAngle'] = this.props.adjustPendulumAngle.angle
- this.props.dataDoc['pendulumLength'] = this.props.adjustPendulumAngle.length
- }
+ // Helper function to go between display and real values
+ getDisplayYPos = (yPos: number) => {
+ return this.props.yMax - yPos - 2 * this.props.radius + 5;
+ };
+ getYPosFromDisplay = (yDisplay: number) => {
+ return this.props.yMax - yDisplay - 2 * this.props.radius + 5;
+ };
- // When display values updated by user, update real values
- if (prevProps.updateDisplay != this.props.updateDisplay) {
- if (this.props.updateDisplay.xDisplay != this.state.xPosition) {
- let x = this.props.updateDisplay.xDisplay;
- x = Math.max(0, x);
- x = Math.min(x, this.props.xMax - 2 * this.props.radius);
- this.setState({updatedStartPosX: x})
- this.setState({xPosition: x})
+ // Set display values based on real values
+ setYPosDisplay = (yPos: number) => {
+ const displayPos = this.getDisplayYPos(yPos);
if (this.props.color == 'red') {
- this.props.dataDoc['positionXDisplay'] = x
+ this.props.dataDoc.position_YDisplay = Math.round(displayPos * 100) / 100;
} else {
- this.props.dataDoc['positionXDisplay2'] = x
+ this.props.dataDoc.position_YDisplay2 = Math.round(displayPos * 100) / 100;
}
- }
-
- if (this.props.updateDisplay.yDisplay != this.getDisplayYPos(this.state.yPosition)) {
- let y = this.props.updateDisplay.yDisplay;
- y = Math.max(0, y);
- y = Math.min(y, this.props.yMax - 2 * this.props.radius);
- let coordinatePosition = this.getYPosFromDisplay(y);
- this.setState({updatedStartPosY: coordinatePosition})
- this.setState({yPosition: coordinatePosition})
+ };
+ setXPosDisplay = (xPos: number) => {
if (this.props.color == 'red') {
- this.props.dataDoc['positionYDisplay'] = y
+ this.props.dataDoc.position_XDisplay = Math.round(xPos * 100) / 100;
} else {
- this.props.dataDoc['positionYDisplay2'] = y
+ this.props.dataDoc.position_XDisplay2 = Math.round(xPos * 100) / 100;
}
- }
-
- if (this.props.displayXVelocity != this.state.xVelocity) {
- let x = this.props.displayXVelocity;
- this.setState({xVelocity: x})
+ };
+ setYVelDisplay = (yVel: number) => {
if (this.props.color == 'red') {
- this.props.dataDoc['velocityXDisplay'] = x
+ this.props.dataDoc.velocity_YDisplay = (-1 * Math.round(yVel * 100)) / 100;
} else {
- this.props.dataDoc['velocityXDisplay2'] = x
+ this.props.dataDoc.velocity_YDisplay2 = (-1 * Math.round(yVel * 100)) / 100;
}
- }
-
- if (this.props.displayYVelocity != -this.state.yVelocity) {
- let y = this.props.displayYVelocity;
- this.setState({yVelocity: -y})
+ };
+ setXVelDisplay = (xVel: number) => {
if (this.props.color == 'red') {
- this.props.dataDoc['velocityYDisplay'] = y
+ this.props.dataDoc.velocity_XDisplay = Math.round(xVel * 100) / 100;
} else {
- this.props.dataDoc['velocityYDisplay2'] = y
+ this.props.dataDoc.velocity_XDisplay2 = Math.round(xVel * 100) / 100;
}
- }
- }
-
- // Prevent bug when switching between sims
- if (prevProps.startForces != this.props.startForces) {
- this.setState({xVelocity: this.props.startVelX})
- this.setState({yVelocity: this.props.startVelY})
- this.setDisplayValues();
- }
+ };
- // Make sure weight doesn't go above max height
- if ((prevState.updatedStartPosY != this.state.updatedStartPosY || prevProps.startVelY != this.props.startVelY) && !isNaN(this.state.updatedStartPosY) && !isNaN(this.props.startVelY)){
- if (this.props.dataDoc['simulationType'] == "One Weight") {
- let maxYPos = this.state.updatedStartPosY;
- if (this.props.startVelY != 0) {
- maxYPos -= (this.props.startVelY * this.props.startVelY) / (2 * Math.abs(this.props.gravity));
+ // Update display values when simulation updates
+ setDisplayValues = (xPos: number = this.state.xPosition, yPos: number = this.state.yPosition, xVel: number = this.state.xVelocity, yVel: number = this.state.yVelocity) => {
+ this.setYPosDisplay(yPos);
+ this.setXPosDisplay(xPos);
+ this.setYVelDisplay(yVel);
+ this.setXVelDisplay(xVel);
+ if (this.props.color == 'red') {
+ this.props.dataDoc.acceleration_YDisplay = (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100;
+ this.props.dataDoc.acceleration_XDisplay = Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100;
+ } else {
+ this.props.dataDoc.acceleration_YDisplay2 = (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100;
+ this.props.dataDoc.acceleration_XDisplay2 = Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100;
}
- if (maxYPos < 0) {
- maxYPos = 0;
+
+ this.setState({ xAccel: Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100 });
+ this.setState({ yAccel: (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100 });
+ };
+
+ componentDidUpdate(prevProps: Readonly<IWeightProps>, prevState: Readonly<IState>, snapshot?: any): void {
+ // Change pendulum angle from input field
+ if (prevProps.adjustPendulumAngle != this.props.adjustPendulumAngle || prevProps.adjustPendulumLength !== this.props.adjustPendulumLength) {
+ let length = this.props.adjustPendulumLength;
+ const x = length * Math.cos(((90 - this.props.adjustPendulumAngle) * Math.PI) / 180);
+ const y = length * Math.sin(((90 - this.props.adjustPendulumAngle) * Math.PI) / 180);
+ const xPos = this.props.xMax / 2 - x - this.props.radius;
+ const yPos = y - this.props.radius - 5;
+ this.setState({ xPosition: xPos });
+ this.setState({ yPosition: yPos });
+ this.setState({ updatedStartPosX: xPos });
+ this.setState({ updatedStartPosY: yPos });
+ this.props.dataDoc.pendulum_angle = this.props.adjustPendulumAngle;
+ this.props.dataDoc.pendulum_length = this.props.adjustPendulumLength;
}
- this.setState({maxPosYConservation: maxYPos})
- }
- }
- // Check for collisions and update
- if (!this.props.paused) {
- if (prevState.timer != this.state.timer) {
- if (!this.props.noMovement) {
- let collisions = false;
- if (
- this.props.dataDoc['simulationType'] == "One Weight" ||
- this.props.dataDoc['simulationType'] == "Inclined Plane"
- ) {
- const collisionsWithGround = this.checkForCollisionsWithGround();
- const collisionsWithWalls = this.checkForCollisionsWithWall();
- collisions = collisionsWithGround || collisionsWithWalls;
- }
- if (this.props.dataDoc['simulationType'] == "Pulley") {
- if (this.state.yPosition <= this.props.yMin + 100 || this.state.yPosition >= this.props.yMax - 100) {
- collisions = true;
+ // When display values updated by user, update real value
+ if (prevProps.updateYDisplay != this.props.updateYDisplay || prevProps.updateXDisplay !== this.props.updateXDisplay) {
+ if (this.props.updateXDisplay != this.state.xPosition) {
+ let x = this.props.updateXDisplay;
+ x = Math.max(0, x);
+ x = Math.min(x, this.props.xMax - 2 * this.props.radius);
+ this.setState({ updatedStartPosX: x });
+ this.setState({ xPosition: x });
+ if (this.props.color == 'red') {
+ this.props.dataDoc.position_XDisplay = x;
+ } else {
+ this.props.dataDoc.position_XDisplay2 = x;
+ }
+ }
+
+ if (this.props.updateYDisplay != this.getDisplayYPos(this.state.yPosition)) {
+ let y = this.props.updateYDisplay;
+ y = Math.max(0, y);
+ y = Math.min(y, this.props.yMax - 2 * this.props.radius);
+ let coordinatePosition = this.getYPosFromDisplay(y);
+ this.setState({ updatedStartPosY: coordinatePosition });
+ this.setState({ yPosition: coordinatePosition });
+ if (this.props.color == 'red') {
+ this.props.dataDoc.position_YDisplay = y;
+ } else {
+ this.props.dataDoc.position_YDisplay2 = y;
+ }
+ }
+
+ if (this.props.displayXVelocity != this.state.xVelocity) {
+ let x = this.props.displayXVelocity;
+ this.setState({ xVelocity: x });
+ if (this.props.color == 'red') {
+ this.props.dataDoc.velocity_XDisplay = x;
+ } else {
+ this.props.dataDoc.velocity_XDisplay2 = x;
+ }
+ }
+
+ if (this.props.displayYVelocity != -this.state.yVelocity) {
+ let y = this.props.displayYVelocity;
+ this.setState({ yVelocity: -y });
+ if (this.props.color == 'red') {
+ this.props.dataDoc.velocity_YDisplay = y;
+ } else {
+ this.props.dataDoc.velocity_YDisplay2 = y;
+ }
}
- }
- if (!collisions) {
- this.update();
- }
- this.setDisplayValues();
}
- }
- }
- // Reset everything on reset button click
- if (prevProps.reset != this.props.reset) {
- this.resetEverything();
- }
-
- // Convert from static to kinetic friction if/when weight slips on inclined plane
- if (prevState.xVelocity != this.state.xVelocity) {
- if (
- this.props.dataDoc['simulationType'] == "Inclined Plane" &&
- Math.abs(this.state.xVelocity) > 0.1 &&
- this.props.dataDoc['mode'] != "Review" &&
- !this.state.kineticFriction
- ) {
- this.setState({kineticFriction: true})
- const normalForce: IForce = {
- description: "Normal Force",
- magnitude:
- this.props.mass *
- Math.abs(this.props.gravity) *
- Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
- directionInDegrees:
- 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
- component: false,
- };
- let frictionForce: IForce = {
- description: "Kinetic Friction Force",
- magnitude:
- this.props.mass *
- this.props.coefficientOfKineticFriction *
- Math.abs(this.props.gravity) *
- Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
- directionInDegrees:
- 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
- component: false,
- };
- // reduce magnitude of friction force if necessary such that block cannot slide up plane
- let yForce = -Math.abs(this.props.gravity);
- 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.props.gravity)) /
- Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
+ // Prevent bug when switching between sims
+ if (prevProps.startForces != this.props.startForces) {
+ this.setState({ xVelocity: this.props.startVelX });
+ this.setState({ yVelocity: this.props.startVelY });
+ this.setDisplayValues();
}
- const frictionForceComponent: IForce = {
- description: "Kinetic Friction Force",
+ // Make sure weight doesn't go above max height
+ if ((prevState.updatedStartPosY != this.state.updatedStartPosY || prevProps.startVelY != this.props.startVelY) && !isNaN(this.state.updatedStartPosY) && !isNaN(this.props.startVelY)) {
+ if (this.props.dataDoc.simulation_Type == 'One Weight') {
+ let maxYPos = this.state.updatedStartPosY;
+ if (this.props.startVelY != 0) {
+ maxYPos -= (this.props.startVelY * this.props.startVelY) / (2 * Math.abs(this.props.gravity));
+ }
+ if (maxYPos < 0) {
+ maxYPos = 0;
+ }
+ this.setState({ maxPosYConservation: maxYPos });
+ }
+ }
- magnitude:
- this.props.mass *
- this.props.coefficientOfKineticFriction *
- Math.abs(this.props.gravity) *
- Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
- directionInDegrees:
- 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
- component: true,
- };
- const normalForceComponent: IForce = {
- description: "Normal Force",
- magnitude:
- this.props.mass *
- Math.abs(this.props.gravity) *
- Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
- directionInDegrees:
- 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
- component: true,
- };
- const gravityParallel: IForce = {
- description: "Gravity Parallel Component",
- magnitude:
- this.props.mass *
- Math.abs(this.props.gravity) *
- Math.sin(Math.PI / 2 - Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
- directionInDegrees:
- 180 -
- 90 -
- (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI +
- 180,
- component: true,
- };
- const gravityPerpendicular: IForce = {
- description: "Gravity Perpendicular Component",
- magnitude:
- this.props.mass *
- Math.abs(this.props.gravity) *
- Math.cos(Math.PI / 2 - Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
- directionInDegrees:
- 360 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
- component: true,
- };
- const gravityForce: IForce = {
- description: "Gravity",
- magnitude: this.props.mass * Math.abs(this.props.gravity),
- directionInDegrees: 270,
- component: false,
- };
- if (this.props.coefficientOfKineticFriction != 0) {
- this.props.dataDoc['updatedForces'] = ([gravityForce, normalForce, frictionForce]);
- this.props.dataDoc['componentForces'] = ([
- frictionForceComponent,
- normalForceComponent,
- gravityParallel,
- gravityPerpendicular,
- ]);
- } else {
- this.props.dataDoc['updatedForces'] = ([gravityForce, normalForce]);
- this.props.dataDoc['componentForces'] = ([
- normalForceComponent,
- gravityParallel,
- gravityPerpendicular,
- ]);
+ // Check for collisions and update
+ if (!this.props.paused) {
+ if (prevState.timer != this.state.timer) {
+ if (!this.props.noMovement) {
+ let collisions = false;
+ if (this.props.dataDoc.simulation_Type == 'One Weight' || this.props.dataDoc.simulation_Type == 'Inclined Plane') {
+ const collisionsWithGround = this.checkForCollisionsWithGround();
+ const collisionsWithWalls = this.checkForCollisionsWithWall();
+ collisions = collisionsWithGround || collisionsWithWalls;
+ }
+ if (this.props.dataDoc.simulation_Type == 'Pulley') {
+ if (this.state.yPosition <= this.props.yMin + 100 || this.state.yPosition >= this.props.yMax - 100) {
+ collisions = true;
+ }
+ }
+ if (!collisions) {
+ this.update();
+ }
+ this.setDisplayValues();
+ }
+ }
}
- }
- }
- // Add/remove walls when simulation type changes
- if (prevProps.simulationType != this.props.simulationType) {
- let w: IWallProps[] = [];
- if (this.props.dataDoc['simulationType'] == "One Weight" || this.props.dataDoc['simulationType'] == "Inclined Plane") {
- w = this.props.wallPositions
- }
- this.setState({walls: w})
- }
+ // Reset everything on reset button click
+ if (prevProps.reset != this.props.reset) {
+ this.resetEverything();
+ }
- // Update x position when start pos x changes
- if (prevProps.startPosX != this.props.startPosX) {
- if (this.props.paused && !isNaN(this.props.startPosX)) {
- this.setState({xPosition: this.props.startPosX})
- this.setState({updatedStartPosX: this.props.startPosX})
- this.setXPosDisplay(this.props.startPosX)
- }
- }
+ // Convert from static to kinetic friction if/when weight slips on inclined plane
+ if (prevState.xVelocity != this.state.xVelocity) {
+ if (this.props.dataDoc.simulation_Type == 'Inclined Plane' && Math.abs(this.state.xVelocity) > 0.1 && this.props.dataDoc.mode != 'Review' && !this.state.kineticFriction) {
+ this.setState({ kineticFriction: true });
+ const normalForce: IForce = {
+ description: 'Normal Force',
+ magnitude: this.props.mass * Math.abs(this.props.gravity) * Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ directionInDegrees: 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
+ component: false,
+ };
+ let frictionForce: IForce = {
+ description: 'Kinetic Friction Force',
+ magnitude: this.props.mass * this.props.coefficientOfKineticFriction * Math.abs(this.props.gravity) * Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ directionInDegrees: 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
+ component: false,
+ };
+ // reduce magnitude of friction force if necessary such that block cannot slide up plane
+ let yForce = -Math.abs(this.props.gravity);
+ 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.props.gravity)) / Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
+ }
- // Update y position when start pos y changes TODO debug
- if (prevProps.startPosY != this.props.startPosY) {
- if (this.props.paused && !isNaN(this.props.startPosY)) {
- this.setState({yPosition: this.props.startPosY})
- this.setState({updatedStartPosY: this.props.startPosY ?? 0})
- this.setYPosDisplay(this.props.startPosY ?? 0)
- }
- }
+ const frictionForceComponent: IForce = {
+ description: 'Kinetic Friction Force',
- // Update wedge coordinates
- if (prevProps.wedgeWidth != this.props.wedgeWidth || prevProps.wedgeHeight != this.props.wedgeHeight) {
- const left = this.props.xMax * 0.25;
- const coordinatePair1 = Math.round(left) + "," + this.props.yMax + " ";
- const coordinatePair2 = Math.round(left + this.props.wedgeWidth) + "," + this.props.yMax + " ";
- const coordinatePair3 = Math.round(left) + "," + (this.props.yMax - this.props.wedgeHeight);
- const coord = coordinatePair1 + coordinatePair2 + coordinatePair3;
- this.setState({coordinates: coord})
- }
+ magnitude: this.props.mass * this.props.coefficientOfKineticFriction * Math.abs(this.props.gravity) * Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ directionInDegrees: 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
+ component: true,
+ };
+ const normalForceComponent: IForce = {
+ description: 'Normal Force',
+ magnitude: this.props.mass * Math.abs(this.props.gravity) * Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ directionInDegrees: 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
+ component: true,
+ };
+ const gravityParallel: IForce = {
+ description: 'Gravity Parallel Component',
+ magnitude: this.props.mass * Math.abs(this.props.gravity) * Math.sin(Math.PI / 2 - Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ directionInDegrees: 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI + 180,
+ component: true,
+ };
+ const gravityPerpendicular: IForce = {
+ description: 'Gravity Perpendicular Component',
+ magnitude: this.props.mass * Math.abs(this.props.gravity) * Math.cos(Math.PI / 2 - Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ directionInDegrees: 360 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
+ component: true,
+ };
+ const gravityForce: IForce = {
+ description: 'Gravity',
+ magnitude: this.props.mass * Math.abs(this.props.gravity),
+ directionInDegrees: 270,
+ component: false,
+ };
+ if (this.props.coefficientOfKineticFriction != 0) {
+ this.props.dataDoc.updatedForces = [gravityForce, normalForce, frictionForce];
+ this.props.dataDoc.componentForces = [frictionForceComponent, normalForceComponent, gravityParallel, gravityPerpendicular];
+ } else {
+ this.props.dataDoc.updatedForces = [gravityForce, normalForce];
+ this.props.dataDoc.componentForces = [normalForceComponent, gravityParallel, gravityPerpendicular];
+ }
+ }
+ }
- if (this.state.xPosition != prevState.xPosition || this.state.yPosition != prevState.yPosition) {
- this.weightStyle = {
- alignItems: "center",
- backgroundColor: this.props.color,
- borderColor: "black",
- borderRadius: 50 + "%",
- borderStyle: "solid",
- display: "flex",
- height: 2 * this.props.radius + "px",
- justifyContent: "center",
- left: this.state.xPosition + "px",
- position: "absolute" as "absolute",
- top: this.state.yPosition + "px",
- touchAction: "none",
- width: 2 * this.props.radius + "px",
- zIndex: 5,
- };
- }
- }
+ // Add/remove walls when simulation type changes
+ if (prevProps.simulationType != this.props.simulationType) {
+ let w: IWallProps[] = [];
+ if (this.props.dataDoc.simulation_Type == 'One Weight' || this.props.dataDoc.simulation_Type == 'Inclined Plane') {
+ w = this.props.wallPositions;
+ }
+ this.setState({ walls: w });
+ }
- // Reset simulation on reset button click
- resetEverything = () => {
- this.setState({kineticFriction: false})
- this.setState({xPosition: this.state.updatedStartPosX})
- this.setState({yPosition: this.state.updatedStartPosY})
- this.setState({xVelocity: this.props.startVelX ?? 0})
- this.setState({yVelocity: this.props.startVelY ?? 0})
- this.props.dataDoc['pendulumAngle'] = this.props.dataDoc['startPendulumAngle']
- this.props.dataDoc['updatedForces'] = (this.props.dataDoc['startForces'])
- this.props.dataDoc['updatedForces2'] = (this.props.dataDoc['startForces2'])
- if (this.props.color == 'red') {
- this.props.dataDoc['positionXDisplay'] = this.state.updatedStartPosX
- this.props.dataDoc['positionYDisplay'] = this.state.updatedStartPosY
- this.props.dataDoc['velocityXDisplay'] = this.props.startVelX ?? 0
- this.props.dataDoc['velocityYDisplay'] = this.props.startVelY ?? 0
- this.props.dataDoc['accelerationXDisplay'] = 0
- this.props.dataDoc['accelerationYDisplay'] = 0
- } else {
- this.props.dataDoc['positionXDisplay2'] = this.state.updatedStartPosX
- this.props.dataDoc['positionYDisplay2'] = this.state.updatedStartPosY
- this.props.dataDoc['velocityXDisplay2'] = this.props.startVelX ?? 0
- this.props.dataDoc['velocityYDisplay2'] = this.props.startVelY ?? 0
- this.props.dataDoc['accelerationXDisplay2'] = 0
- this.props.dataDoc['accelerationYDisplay2'] = 0
- }
- this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle'] ?? 0 * 100) / 100})
- };
+ // Update x position when start pos x changes
+ if (prevProps.startPosX != this.props.startPosX) {
+ if (this.props.paused && !isNaN(this.props.startPosX)) {
+ this.setState({ xPosition: this.props.startPosX });
+ this.setState({ updatedStartPosX: this.props.startPosX });
+ this.setXPosDisplay(this.props.startPosX);
+ }
+ }
- // Compute x acceleration from forces, F=ma
- getNewAccelerationX = (forceList: IForce[]) => {
- let newXAcc = 0;
- if (forceList) {
- forceList.forEach((force) => {
- newXAcc +=
- (force.magnitude *
- Math.cos((force.directionInDegrees * Math.PI) / 180)) /
- this.props.mass;
- });
- }
- return newXAcc;
- };
+ // Update y position when start pos y changes TODO debug
+ if (prevProps.startPosY != this.props.startPosY) {
+ if (this.props.paused && !isNaN(this.props.startPosY)) {
+ this.setState({ yPosition: this.props.startPosY });
+ this.setState({ updatedStartPosY: this.props.startPosY ?? 0 });
+ this.setYPosDisplay(this.props.startPosY ?? 0);
+ }
+ }
+ // Update wedge coordinates
+ if (this.state.coordinates === '' || prevProps.wedgeWidth != this.props.wedgeWidth || prevProps.wedgeHeight != this.props.wedgeHeight) {
+ const left = this.props.xMax * 0.25;
+ const coordinatePair1 = Math.round(left) + ',' + this.props.yMax + ' ';
+ const coordinatePair2 = Math.round(left + this.props.wedgeWidth) + ',' + this.props.yMax + ' ';
+ const coordinatePair3 = Math.round(left) + ',' + (this.props.yMax - this.props.wedgeHeight);
+ const coord = coordinatePair1 + coordinatePair2 + coordinatePair3;
+ this.setState({ coordinates: coord });
+ }
- // Compute y acceleration from forces, F=ma
- getNewAccelerationY = (forceList: IForce[]) => {
- let newYAcc = 0;
- if (forceList) {
- forceList.forEach((force) => {
- newYAcc +=
- (-1 *
- (force.magnitude *
- Math.sin((force.directionInDegrees * Math.PI) / 180))) /
- this.props.mass;
- });
+ if (this.state.xPosition != prevState.xPosition || this.state.yPosition != prevState.yPosition) {
+ this.weightStyle = {
+ alignItems: 'center',
+ backgroundColor: this.props.color,
+ borderColor: 'black',
+ borderRadius: 50 + '%',
+ borderStyle: 'solid',
+ display: 'flex',
+ height: 2 * this.props.radius + 'px',
+ justifyContent: 'center',
+ left: this.state.xPosition + 'px',
+ position: 'absolute' as 'absolute',
+ top: this.state.yPosition + 'px',
+ touchAction: 'none',
+ width: 2 * this.props.radius + 'px',
+ zIndex: 5,
+ };
+ }
}
- return newYAcc;
- };
- // Compute uniform circular motion forces given x, y positions
- getNewCircularMotionForces = (xPos: number, yPos: number) => {
- let deltaX = (this.props.xMin + this.props.xMax) / 2 - (xPos + this.props.radius);
- let deltaY = yPos + this.props.radius - (this.props.yMin + this.props.yMax) / 2;
- let dir = (Math.atan2(deltaY, deltaX) * 180) / Math.PI;
- const tensionForce: IForce = {
- description: "Centripetal Force",
- magnitude: (this.props.startVelX ** 2 * this.props.mass) / this.props.circularMotionRadius,
- directionInDegrees: dir,
- component: false,
+ // Reset simulation on reset button click
+ resetEverything = () => {
+ this.setState({ kineticFriction: false });
+ this.setState({ xPosition: this.state.updatedStartPosX });
+ this.setState({ yPosition: this.state.updatedStartPosY });
+ this.setState({ xVelocity: this.props.startVelX ?? 0 });
+ this.setState({ yVelocity: this.props.startVelY ?? 0 });
+ this.props.dataDoc.pendulum_angle = this.props.dataDoc.start_PendulumAngle;
+ this.props.dataDoc.updatedForces = this.props.dataDoc.start_Forces;
+ this.props.dataDoc.updatedForces2 = this.props.dataDoc.start_Forces2;
+ if (this.props.color == 'red') {
+ this.props.dataDoc.position_XDisplay = this.state.updatedStartPosX;
+ this.props.dataDoc.position_YDisplay = this.state.updatedStartPosY;
+ this.props.dataDoc.velocity_XDisplay = this.props.startVelX ?? 0;
+ this.props.dataDoc.velocity_YDisplay = this.props.startVelY ?? 0;
+ this.props.dataDoc.acceleration_XDisplay = 0;
+ this.props.dataDoc.acceleration_YDisplay = 0;
+ } else {
+ this.props.dataDoc.position_XDisplay2 = this.state.updatedStartPosX;
+ this.props.dataDoc.position_YDisplay2 = this.state.updatedStartPosY;
+ this.props.dataDoc.velocity_XDisplay2 = this.props.startVelX ?? 0;
+ this.props.dataDoc.velocity_YDisplay2 = this.props.startVelY ?? 0;
+ this.props.dataDoc.acceleration_XDisplay2 = 0;
+ this.props.dataDoc.acceleration_YDisplay2 = 0;
+ }
+ this.setState({ angleLabel: Math.round(NumCast(this.props.dataDoc.pendulum_angle) ?? 0 * 100) / 100 });
};
- return [tensionForce];
- };
- // Compute spring forces given y position
- getNewSpringForces = (yPos: number) => {
- let springForce: IForce = {
- description: "Spring Force",
- magnitude: 0,
- directionInDegrees: 90,
- component: false,
+ // Compute x acceleration from forces, F=ma
+ getNewAccelerationX = (forceList: IForce[]) => {
+ let newXAcc = 0;
+ if (forceList) {
+ forceList.forEach(force => {
+ newXAcc += (force.magnitude * Math.cos((force.directionInDegrees * Math.PI) / 180)) / this.props.mass;
+ });
+ }
+ return newXAcc;
};
- if (yPos - this.props.springRestLength > 0) {
- springForce = {
- description: "Spring Force",
- magnitude: this.props.springConstant * (yPos - this.props.springRestLength),
- directionInDegrees: 90,
- component: false,
- };
- } else if (yPos - this.props.springRestLength < 0) {
- springForce = {
- description: "Spring Force",
- magnitude: this.props.springConstant * (this.props.springRestLength - yPos),
- directionInDegrees: 270,
- component: false,
- };
- }
- return [
- {
- description: "Gravity",
- magnitude: Math.abs(this.props.gravity) * this.props.mass,
- directionInDegrees: 270,
- component: false,
- },
- springForce,
- ];
- };
-
- // Compute pendulum forces given position, velocity
- getNewPendulumForces = (
- xPos: number,
- yPos: number,
- xVel: number,
- yVel: number
- ) => {
- const x = this.props.xMax / 2 - xPos - this.props.radius;
- const y = yPos + this.props.radius + 5;
- let angle = (Math.atan(y / x) * 180) / Math.PI;
- if (angle < 0) {
- angle += 180;
- }
- let oppositeAngle = 90 - angle;
- if (oppositeAngle < 0) {
- oppositeAngle = 90 - (180 - angle);
- }
-
- const pendulumLength = Math.sqrt(x * x + y * y);
- this.props.dataDoc['pendulumAngle'] = oppositeAngle;
- const mag =
- this.props.mass * Math.abs(this.props.gravity) * Math.cos((oppositeAngle * Math.PI) / 180) +
- (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength;
-
- const forceOfTension: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: angle,
- component: false,
+ // Compute y acceleration from forces, F=ma
+ getNewAccelerationY = (forceList: IForce[]) => {
+ let newYAcc = 0;
+ if (forceList) {
+ forceList.forEach(force => {
+ newYAcc += (-1 * (force.magnitude * Math.sin((force.directionInDegrees * Math.PI) / 180))) / this.props.mass;
+ });
+ }
+ return newYAcc;
};
- return [
- {
- description: "Gravity",
- magnitude: Math.abs(this.props.gravity) * this.props.mass,
- directionInDegrees: 270,
- component: false,
- },
- forceOfTension,
- ];
- };
+ // Compute uniform circular motion forces given x, y positions
+ getNewCircularMotionForces = (xPos: number, yPos: number) => {
+ let deltaX = (this.props.xMin + this.props.xMax) / 2 - (xPos + this.props.radius);
+ let deltaY = yPos + this.props.radius - (this.props.yMin + this.props.yMax) / 2;
+ let dir = (Math.atan2(deltaY, deltaX) * 180) / Math.PI;
+ const tensionForce: IForce = {
+ description: 'Centripetal Force',
+ magnitude: (this.props.startVelX ** 2 * this.props.mass) / this.props.circularMotionRadius,
+ directionInDegrees: dir,
+ component: false,
+ };
+ return [tensionForce];
+ };
- // Check for collisions in x direction
- checkForCollisionsWithWall = () => {
- let collision = false;
- const minX = this.state.xPosition;
- const maxX = this.state.xPosition + 2 * this.props.radius;
- if (this.state.xVelocity != 0) {
- this.state.walls.forEach((wall) => {
- if (wall.angleInDegrees == 90) {
- const wallX = (wall.xPos / 100) * this.props.layoutDoc._width;
- if (wall.xPos < 0.35) {
- if (minX <= wallX) {
- this.setState({xPosition: wallX+0.01});
- if (this.props.elasticCollisions) {
- this.setState({xVelocity: -this.state.xVelocity});
- } else {
- this.setState({xVelocity: 0});
- }
- collision = true;
- }
- } else {
- if (maxX >= wallX) {
- this.setState({xPosition: wallX- 2 * this.props.radius-0.01});
- if (this.props.elasticCollisions) {
- this.setState({xVelocity: -this.state.xVelocity});
- } else {
- this.setState({xVelocity: 0});
- }
- collision = true;
- }
- }
+ // Compute spring forces given y position
+ getNewSpringForces = (yPos: number) => {
+ let springForce: IForce = {
+ description: 'Spring Force',
+ magnitude: 0,
+ directionInDegrees: 90,
+ component: false,
+ };
+ if (yPos - this.props.springRestLength > 0) {
+ springForce = {
+ description: 'Spring Force',
+ magnitude: this.props.springConstant * (yPos - this.props.springRestLength),
+ directionInDegrees: 90,
+ component: false,
+ };
+ } else if (yPos - this.props.springRestLength < 0) {
+ springForce = {
+ description: 'Spring Force',
+ magnitude: this.props.springConstant * (this.props.springRestLength - yPos),
+ directionInDegrees: 270,
+ component: false,
+ };
}
- });
- }
- return collision;
- };
+ return [
+ {
+ description: 'Gravity',
+ magnitude: Math.abs(this.props.gravity) * this.props.mass,
+ directionInDegrees: 270,
+ component: false,
+ },
+ springForce,
+ ];
+ };
- // Check for collisions in y direction
- checkForCollisionsWithGround = () => {
- let collision = false;
- const minY = this.state.yPosition;
- const maxY = this.state.yPosition + 2 * this.props.radius;
- if (this.state.yVelocity > 0) {
- this.state.walls.forEach((wall) => {
- if (wall.angleInDegrees == 0 && wall.yPos > 0.4) {
- const groundY = (wall.yPos / 100) * this.props.layoutDoc._height;
- if (maxY > groundY) {
- this.setState({yPosition: groundY- 2 * this.props.radius-0.01});
- if (this.props.elasticCollisions) {
- this.setState({yVelocity: -this.state.yVelocity});
- } else {
- this.setState({yVelocity: 0});
- if (this.props.dataDoc['simulationType'] != "Two Weights") {
- const forceOfGravity: IForce = {
- description: "Gravity",
- magnitude: Math.abs(this.props.gravity) * this.props.mass,
- directionInDegrees: 270,
- component: false,
- };
- const normalForce: IForce = {
- description: "Normal force",
- magnitude: Math.abs(this.props.gravity) * this.props.mass,
- directionInDegrees: wall.angleInDegrees + 90,
- component: false,
- };
- this.props.dataDoc['updatedForces'] = ([forceOfGravity, normalForce]);
- if (this.props.dataDoc['simulationType'] == "Inclined Plane") {
- const forceOfGravityC: IForce = {
- description: "Gravity",
- magnitude: Math.abs(this.props.gravity) * this.props.mass,
- directionInDegrees: 270,
- component: true,
- };
- const normalForceC: IForce = {
- description: "Normal force",
- magnitude: Math.abs(this.props.gravity) * this.props.mass,
- directionInDegrees: wall.angleInDegrees + 90,
- component: true,
- };
- this.props.dataDoc['componentForces'] = ([forceOfGravityC, normalForceC]);
- }
- }
- }
- collision = true;
- }
+ // Compute pendulum forces given position, velocity
+ getNewPendulumForces = (xPos: number, yPos: number, xVel: number, yVel: number) => {
+ const x = this.props.xMax / 2 - xPos - this.props.radius;
+ const y = yPos + this.props.radius + 5;
+ let angle = (Math.atan(y / x) * 180) / Math.PI;
+ if (angle < 0) {
+ angle += 180;
}
- });
- }
- if (this.state.yVelocity < 0) {
- this.state.walls.forEach((wall) => {
- if (wall.angleInDegrees == 0 && wall.yPos < 0.4) {
- const groundY = (wall.yPos / 100) * this.props.layoutDoc._height;
- if (minY < groundY) {
- this.setState({yPosition: groundY + 0.01});
- if (this.props.elasticCollisions) {
- this.setState({yVelocity: -this.state.yVelocity});
- } else {
- this.setState({yVelocity: 0});
- }
- collision = true;
- }
+ let oppositeAngle = 90 - angle;
+ if (oppositeAngle < 0) {
+ oppositeAngle = 90 - (180 - angle);
}
- });
- }
- return collision;
- };
- // Called at each RK4 step
- evaluate = (
- currentXPos: number,
- currentYPos: number,
- currentXVel: number,
- currentYVel: number,
- deltaXPos: number,
- deltaYPos: number,
- deltaXVel: number,
- deltaYVel: number,
- dt: number
- ) => {
- const newXPos = currentXPos + deltaXPos * dt;
- const newYPos = currentYPos + deltaYPos * dt;
- const newXVel = currentXVel + deltaXVel * dt;
- const newYVel = currentYVel + deltaYVel * dt;
- const newDeltaXPos = newXVel;
- const newDeltaYPos = newYVel;
- let forces = this.props.updatedForces;
- if (this.props.dataDoc['simulationType'] == "Pendulum") {
- forces = this.getNewPendulumForces(newXPos, newYPos, newXVel, newYVel);
- } else if (this.props.dataDoc['simulationType'] == "Spring") {
- forces = this.getNewSpringForces(newYPos);
- } else if (this.props.dataDoc['simulationType'] == "Circular Motion") {
- forces = this.getNewCircularMotionForces(newXPos, newYPos);
- }
- const newDeltaXVel = this.getNewAccelerationX(forces);
- const newDeltaYVel = this.getNewAccelerationY(forces);
- return {
- xPos: newXPos,
- yPos: newYPos,
- xVel: newXVel,
- yVel: newYVel,
- deltaXPos: newDeltaXPos,
- deltaYPos: newDeltaYPos,
- deltaXVel: newDeltaXVel,
- deltaYVel: newDeltaYVel,
+ const pendulumLength = Math.sqrt(x * x + y * y);
+ this.props.dataDoc.pendulum_angle = oppositeAngle;
+
+ const mag = this.props.mass * Math.abs(this.props.gravity) * Math.cos((oppositeAngle * Math.PI) / 180) + (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength;
+
+ const forceOfTension: IForce = {
+ description: 'Tension',
+ magnitude: mag,
+ directionInDegrees: angle,
+ component: false,
+ };
+
+ return [
+ {
+ description: 'Gravity',
+ magnitude: Math.abs(this.props.gravity) * this.props.mass,
+ directionInDegrees: 270,
+ component: false,
+ },
+ forceOfTension,
+ ];
};
- };
- // Update position, velocity using RK4 method
- update = () => {
- let startXVel = this.state.xVelocity;
- let startYVel = this.state.yVelocity;
- let xPos = this.state.xPosition;
- let yPos = this.state.yPosition;
- let xVel = this.state.xVelocity;
- let yVel = this.state.yVelocity;
- let forces: IForce[] = this.props.dataDoc['updatedForces'];
- if (this.props.dataDoc['simulationType'] == "Pendulum") {
- forces = this.getNewPendulumForces(xPos, yPos, xVel, yVel);
- } else if (this.props.dataDoc['simulationType'] == "Spring") {
- forces = this.getNewSpringForces(yPos);
- } else if (this.props.dataDoc['simulationType'] == "Circular Motion") {
- forces = this.getNewCircularMotionForces(xPos, yPos);
- }
- const xAcc = this.getNewAccelerationX(forces);
- const yAcc = this.getNewAccelerationY(forces);
- for (let i = 0; i < this.props.simulationSpeed; i++) {
- const k1 = this.evaluate(xPos, yPos, xVel, yVel, xVel, yVel, xAcc, yAcc, 0);
- const k2 = this.evaluate(
- xPos,
- yPos,
- xVel,
- yVel,
- k1.deltaXPos,
- k1.deltaYPos,
- k1.deltaXVel,
- k1.deltaYVel,
- this.props.timestepSize * 0.5
- );
- const k3 = this.evaluate(
- xPos,
- yPos,
- xVel,
- yVel,
- k2.deltaXPos,
- k2.deltaYPos,
- k2.deltaXVel,
- k2.deltaYVel,
- this.props.timestepSize * 0.5
- );
- const k4 = this.evaluate(
- xPos,
- yPos,
- xVel,
- yVel,
- k3.deltaXPos,
- k3.deltaYPos,
- k3.deltaXVel,
- k3.deltaYVel,
- this.props.timestepSize
- );
+ // Check for collisions in x direction
+ checkForCollisionsWithWall = () => {
+ let collision = false;
+ const minX = this.state.xPosition;
+ const maxX = this.state.xPosition + 2 * this.props.radius;
+ if (this.state.xVelocity != 0) {
+ this.state.walls.forEach(wall => {
+ if (wall.angleInDegrees == 90) {
+ const wallX = (wall.xPos / 100) * this.props.layoutDoc[WidthSym]();
+ if (wall.xPos < 0.35) {
+ if (minX <= wallX) {
+ this.setState({ xPosition: wallX + 0.01 });
+ if (this.props.elasticCollisions) {
+ this.setState({ xVelocity: -this.state.xVelocity });
+ } else {
+ this.setState({ xVelocity: 0 });
+ }
+ collision = true;
+ }
+ } else {
+ if (maxX >= wallX) {
+ this.setState({ xPosition: wallX - 2 * this.props.radius - 0.01 });
+ if (this.props.elasticCollisions) {
+ this.setState({ xVelocity: -this.state.xVelocity });
+ } else {
+ this.setState({ xVelocity: 0 });
+ }
+ collision = true;
+ }
+ }
+ }
+ });
+ }
+ return collision;
+ };
- xVel +=
- ((this.props.timestepSize * 1.0) / 6.0) *
- (k1.deltaXVel + 2 * (k2.deltaXVel + k3.deltaXVel) + k4.deltaXVel);
- yVel +=
- ((this.props.timestepSize * 1.0) / 6.0) *
- (k1.deltaYVel + 2 * (k2.deltaYVel + k3.deltaYVel) + k4.deltaYVel);
- xPos +=
- ((this.props.timestepSize * 1.0) / 6.0) *
- (k1.deltaXPos + 2 * (k2.deltaXPos + k3.deltaXPos) + k4.deltaXPos);
- yPos +=
- ((this.props.timestepSize * 1.0) / 6.0) *
- (k1.deltaYPos + 2 * (k2.deltaYPos + k3.deltaYPos) + k4.deltaYPos);
- }
- // make sure harmonic motion maintained and errors don't propagate
- if (this.props.dataDoc['simulationType'] == "Spring") {
- if (startYVel < 0 && yVel > 0 && yPos < this.props.springRestLength) {
- let equilibriumPos =
- this.props.springRestLength + (this.props.mass * Math.abs(this.props.gravity)) / this.props.springConstant;
- let amplitude = Math.abs(equilibriumPos - this.props.springStartLength);
- yPos = equilibriumPos - amplitude;
- } else if (startYVel > 0 && yVel < 0 && yPos > this.props.springRestLength) {
- let equilibriumPos =
- this.props.springRestLength + (this.props.mass * Math.abs(this.props.gravity)) / this.props.springConstant;
- let amplitude = Math.abs(equilibriumPos - this.props.springStartLength);
- yPos = equilibriumPos + amplitude;
- }
- }
- if (this.props.dataDoc['simulationType'] == "Pendulum") {
- let startX = this.state.updatedStartPosX;
- if (startXVel <= 0 && xVel > 0) {
- xPos = this.state.updatedStartPosX;
- if (this.state.updatedStartPosX > this.props.xMax / 2) {
- xPos = this.props.xMax / 2 + (this.props.xMax / 2 - startX) - 2 * this.props.radius;
+ // Check for collisions in y direction
+ checkForCollisionsWithGround = () => {
+ let collision = false;
+ const minY = this.state.yPosition;
+ const maxY = this.state.yPosition + 2 * this.props.radius;
+ if (this.state.yVelocity > 0) {
+ this.state.walls.forEach(wall => {
+ if (wall.angleInDegrees == 0 && wall.yPos > 0.4) {
+ const groundY = (wall.yPos / 100) * this.props.layoutDoc[HeightSym]();
+ if (maxY > groundY) {
+ this.setState({ yPosition: groundY - 2 * this.props.radius - 0.01 });
+ if (this.props.elasticCollisions) {
+ this.setState({ yVelocity: -this.state.yVelocity });
+ } else {
+ this.setState({ yVelocity: 0 });
+ if (this.props.dataDoc.simulation_Type != 'Two Weights') {
+ const forceOfGravity: IForce = {
+ description: 'Gravity',
+ magnitude: Math.abs(this.props.gravity) * this.props.mass,
+ directionInDegrees: 270,
+ component: false,
+ };
+ const normalForce: IForce = {
+ description: 'Normal force',
+ magnitude: Math.abs(this.props.gravity) * this.props.mass,
+ directionInDegrees: wall.angleInDegrees + 90,
+ component: false,
+ };
+ this.props.dataDoc.updatedForces = [forceOfGravity, normalForce];
+ if (this.props.dataDoc.simulation_Type == 'Inclined Plane') {
+ const forceOfGravityC: IForce = {
+ description: 'Gravity',
+ magnitude: Math.abs(this.props.gravity) * this.props.mass,
+ directionInDegrees: 270,
+ component: true,
+ };
+ const normalForceC: IForce = {
+ description: 'Normal force',
+ magnitude: Math.abs(this.props.gravity) * this.props.mass,
+ directionInDegrees: wall.angleInDegrees + 90,
+ component: true,
+ };
+ this.props.dataDoc.componentForces = [forceOfGravityC, normalForceC];
+ }
+ }
+ }
+ collision = true;
+ }
+ }
+ });
}
- yPos = this.props.startPosY;
- } else if (startXVel >= 0 && xVel < 0) {
- xPos = this.state.updatedStartPosX;
- if (this.state.updatedStartPosX < this.props.xMax / 2) {
- xPos = this.props.xMax / 2 + (this.props.xMax / 2 - startX) - 2 * this.props.radius;
+ if (this.state.yVelocity < 0) {
+ this.state.walls.forEach(wall => {
+ if (wall.angleInDegrees == 0 && wall.yPos < 0.4) {
+ const groundY = (wall.yPos / 100) * this.props.layoutDoc[HeightSym]();
+ if (minY < groundY) {
+ this.setState({ yPosition: groundY + 0.01 });
+ if (this.props.elasticCollisions) {
+ this.setState({ yVelocity: -this.state.yVelocity });
+ } else {
+ this.setState({ yVelocity: 0 });
+ }
+ collision = true;
+ }
+ }
+ });
}
- yPos = this.props.startPosY;
- }
- }
- if (this.props.dataDoc['simulationType'] == "One Weight") {
- if (yPos < this.state.maxPosYConservation) {
- yPos = this.state.maxPosYConservation;
- }
- }
- this.setState({xVelocity: xVel});
- this.setState({yVelocity: yVel});
- this.setState({xPosition: xPos});
- this.setState({yPosition: yPos});
- let forcesn = this.props.dataDoc['updatedForces']
- if (this.props.dataDoc['simulationType'] == "Pendulum") {
- forcesn = this.getNewPendulumForces(xPos, yPos, xVel, yVel);
- } else if (this.props.dataDoc['simulationType'] == "Spring") {
- forcesn = this.getNewSpringForces(yPos);
- } else if (this.props.dataDoc['simulationType'] == "Circular Motion") {
- forcesn = this.getNewCircularMotionForces(xPos, yPos);
- }
- this.props.dataDoc['updatedForces'] = (forcesn);
-
- // set component forces if they change
- if (this.props.dataDoc['simulationType'] == "Pendulum") {
- let x = this.props.xMax / 2 - xPos - this.props.radius;
- let y = yPos + this.props.radius + 5;
- let angle = (Math.atan(y / x) * 180) / Math.PI;
- if (angle < 0) {
- angle += 180;
- }
- let oppositeAngle = 90 - angle;
- if (oppositeAngle < 0) {
- oppositeAngle = 90 - (180 - angle);
- }
-
- const pendulumLength = Math.sqrt(x * x + y * y);
+ return collision;
+ };
- const mag =
- this.props.mass * Math.abs(this.props.gravity) * Math.cos((oppositeAngle * Math.PI) / 180) +
- (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength;
+ // Called at each RK4 step
+ evaluate = (currentXPos: number, currentYPos: number, currentXVel: number, currentYVel: number, deltaXPos: number, deltaYPos: number, deltaXVel: number, deltaYVel: number, dt: number) => {
+ const newXPos = currentXPos + deltaXPos * dt;
+ const newYPos = currentYPos + deltaYPos * dt;
+ const newXVel = currentXVel + deltaXVel * dt;
+ const newYVel = currentYVel + deltaYVel * dt;
+ const newDeltaXPos = newXVel;
+ const newDeltaYPos = newYVel;
+ let forces = this.props.updatedForces;
+ if (this.props.dataDoc.simulation_Type == 'Pendulum') {
+ forces = this.getNewPendulumForces(newXPos, newYPos, newXVel, newYVel);
+ } else if (this.props.dataDoc.simulation_Type == 'Spring') {
+ forces = this.getNewSpringForces(newYPos);
+ } else if (this.props.dataDoc.simulation_Type == 'Circular Motion') {
+ forces = this.getNewCircularMotionForces(newXPos, newYPos);
+ }
+ const newDeltaXVel = this.getNewAccelerationX(forces);
+ const newDeltaYVel = this.getNewAccelerationY(forces);
+ return {
+ xPos: newXPos,
+ yPos: newYPos,
+ xVel: newXVel,
+ yVel: newYVel,
+ deltaXPos: newDeltaXPos,
+ deltaYPos: newDeltaYPos,
+ deltaXVel: newDeltaXVel,
+ deltaYVel: newDeltaYVel,
+ };
+ };
- const tensionComponent: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: angle,
- component: true,
- };
- const gravityParallel: IForce = {
- description: "Gravity Parallel Component",
- magnitude: Math.abs(this.props.gravity) * Math.cos(((90 - angle) * Math.PI) / 180),
- directionInDegrees: 270 - (90 - angle),
- component: true,
- };
- const gravityPerpendicular: IForce = {
- description: "Gravity Perpendicular Component",
- magnitude: Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180),
- directionInDegrees: -(90 - angle),
- component: true,
- };
- if (Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180) < 0) {
- gravityPerpendicular.magnitude = Math.abs(
- Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180)
- );
- gravityPerpendicular.directionInDegrees = 180 - (90 - angle);
- }
- this.props.dataDoc['componentForces'] = ([
- tensionComponent,
- gravityParallel,
- gravityPerpendicular,
- ]);
- }
- };
+ // Update position, velocity using RK4 method
+ update = () => {
+ let startXVel = this.state.xVelocity;
+ let startYVel = this.state.yVelocity;
+ let xPos = this.state.xPosition;
+ let yPos = this.state.yPosition;
+ let xVel = this.state.xVelocity;
+ let yVel = this.state.yVelocity;
+ let forces: IForce[] = this.props.dataDoc.updatedForces;
+ if (this.props.dataDoc.simulation_Type == 'Pendulum') {
+ forces = this.getNewPendulumForces(xPos, yPos, xVel, yVel);
+ } else if (this.props.dataDoc.simulation_Type == 'Spring') {
+ forces = this.getNewSpringForces(yPos);
+ } else if (this.props.dataDoc.simulation_Type == 'Circular Motion') {
+ forces = this.getNewCircularMotionForces(xPos, yPos);
+ }
+ const xAcc = this.getNewAccelerationX(forces);
+ const yAcc = this.getNewAccelerationY(forces);
+ for (let i = 0; i < this.props.simulationSpeed; i++) {
+ const k1 = this.evaluate(xPos, yPos, xVel, yVel, xVel, yVel, xAcc, yAcc, 0);
+ const k2 = this.evaluate(xPos, yPos, xVel, yVel, k1.deltaXPos, k1.deltaYPos, k1.deltaXVel, k1.deltaYVel, this.props.timestepSize * 0.5);
+ const k3 = this.evaluate(xPos, yPos, xVel, yVel, k2.deltaXPos, k2.deltaYPos, k2.deltaXVel, k2.deltaYVel, this.props.timestepSize * 0.5);
+ const k4 = this.evaluate(xPos, yPos, xVel, yVel, k3.deltaXPos, k3.deltaYPos, k3.deltaXVel, k3.deltaYVel, this.props.timestepSize);
- // Render weight, spring, rod(s), vectors
- render () {
- return (
- <div>
- <div
- className="weightContainer"
- onPointerDown={(e) => {
- if (this.draggable) {
- this.props.dataDoc['paused'] = true;
- this.setState({dragging: true});
- this.setState({clickPositionX: e.clientX});
- this.setState({clickPositionY: e.clientY});
- }
- }}
- onPointerMove={(e) => {
- if (this.state.dragging) {
- let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
- if (newY > this.props.yMax - 2 * this.props.radius - 10) {
- newY = this.props.yMax - 2 * this.props.radius - 10;
- } else if (newY < 10) {
- newY = 10;
+ xVel += ((this.props.timestepSize * 1.0) / 6.0) * (k1.deltaXVel + 2 * (k2.deltaXVel + k3.deltaXVel) + k4.deltaXVel);
+ yVel += ((this.props.timestepSize * 1.0) / 6.0) * (k1.deltaYVel + 2 * (k2.deltaYVel + k3.deltaYVel) + k4.deltaYVel);
+ xPos += ((this.props.timestepSize * 1.0) / 6.0) * (k1.deltaXPos + 2 * (k2.deltaXPos + k3.deltaXPos) + k4.deltaXPos);
+ yPos += ((this.props.timestepSize * 1.0) / 6.0) * (k1.deltaYPos + 2 * (k2.deltaYPos + k3.deltaYPos) + k4.deltaYPos);
+ }
+ // make sure harmonic motion maintained and errors don't propagate
+ if (this.props.dataDoc.simulation_Type == 'Spring') {
+ if (startYVel < 0 && yVel > 0 && yPos < this.props.springRestLength) {
+ let equilibriumPos = this.props.springRestLength + (this.props.mass * Math.abs(this.props.gravity)) / this.props.springConstant;
+ let amplitude = Math.abs(equilibriumPos - this.props.springStartLength);
+ yPos = equilibriumPos - amplitude;
+ } else if (startYVel > 0 && yVel < 0 && yPos > this.props.springRestLength) {
+ let equilibriumPos = this.props.springRestLength + (this.props.mass * Math.abs(this.props.gravity)) / this.props.springConstant;
+ let amplitude = Math.abs(equilibriumPos - this.props.springStartLength);
+ yPos = equilibriumPos + amplitude;
}
-
- let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
- if (newX > this.props.xMax - 2 * this.props.radius - 10) {
- newX = this.props.xMax - 2 * this.props.radius - 10;
- } else if (newX < 10) {
- newX = 10;
+ }
+ if (this.props.dataDoc.simulation_Type == 'Pendulum') {
+ let startX = this.state.updatedStartPosX;
+ if (startXVel <= 0 && xVel > 0) {
+ xPos = this.state.updatedStartPosX;
+ if (this.state.updatedStartPosX > this.props.xMax / 2) {
+ xPos = this.props.xMax / 2 + (this.props.xMax / 2 - startX) - 2 * this.props.radius;
+ }
+ yPos = this.props.startPosY;
+ } else if (startXVel >= 0 && xVel < 0) {
+ xPos = this.state.updatedStartPosX;
+ if (this.state.updatedStartPosX < this.props.xMax / 2) {
+ xPos = this.props.xMax / 2 + (this.props.xMax / 2 - startX) - 2 * this.props.radius;
+ }
+ yPos = this.props.startPosY;
}
- if (this.props.dataDoc['simulationType'] == "Suspension") {
- if (newX < (this.props.xMax + this.props.xMin) / 4 - this.props.radius - 15) {
- newX = (this.props.xMax + this.props.xMin) / 4 - this.props.radius - 15;
- } else if (newX > (3 * (this.props.xMax + this.props.xMin)) / 4 - this.props.radius / 2 - 15) {
- newX = (3 * (this.props.xMax + this.props.xMin)) / 4 - this.props.radius / 2 - 15;
- }
+ }
+ if (this.props.dataDoc.simulation_Type == 'One Weight') {
+ if (yPos < this.state.maxPosYConservation) {
+ yPos = this.state.maxPosYConservation;
}
+ }
+ this.setState({ xVelocity: xVel });
+ this.setState({ yVelocity: yVel });
+ this.setState({ xPosition: xPos });
+ this.setState({ yPosition: yPos });
+ let forcesn = this.props.dataDoc.updatedForces;
+ if (this.props.dataDoc.simulation_Type == 'Pendulum') {
+ forcesn = this.getNewPendulumForces(xPos, yPos, xVel, yVel);
+ } else if (this.props.dataDoc.simulation_Type == 'Spring') {
+ forcesn = this.getNewSpringForces(yPos);
+ } else if (this.props.dataDoc.simulation_Type == 'Circular Motion') {
+ forcesn = this.getNewCircularMotionForces(xPos, yPos);
+ }
+ this.props.dataDoc.updatedForces = forcesn;
- this.setState({yPosition: newY});
- this.props.dataDoc['positionYDisplay'] =
- Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100
- if (this.props.dataDoc['simulationType'] != "Pulley") {
- this.setState({xPosition: newX});
- this.props.dataDoc['positionXDisplay'] = newX
- }
- if (this.props.dataDoc['simulationType'] != "Suspension") {
- if (this.props.dataDoc['simulationType'] != "Pulley") {
- this.setState({updatedStartPosX: newX});
- }
- this.setState({updatedStartPosY: newY});
- }
- this.setState({clickPositionX: e.clientX});
- this.setState({clickPositionY: e.clientY});
- this.setDisplayValues();
- }
- }}
- onPointerUp={(e) => {
- if (this.state.dragging) {
- if (
- this.props.dataDoc['simulationType'] != "Pendulum" &&
- this.props.dataDoc['simulationType'] != "Suspension"
- ) {
- this.resetEverything();
+ // set component forces if they change
+ if (this.props.dataDoc.simulation_Type == 'Pendulum') {
+ let x = this.props.xMax / 2 - xPos - this.props.radius;
+ let y = yPos + this.props.radius + 5;
+ let angle = (Math.atan(y / x) * 180) / Math.PI;
+ if (angle < 0) {
+ angle += 180;
}
- this.setState({dragging: false});
- let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
- if (newY > this.props.yMax - 2 * this.props.radius - 10) {
- newY = this.props.yMax - 2 * this.props.radius - 10;
- } else if (newY < 10) {
- newY = 10;
+ let oppositeAngle = 90 - angle;
+ if (oppositeAngle < 0) {
+ oppositeAngle = 90 - (180 - angle);
}
- let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
- if (newX > this.props.xMax - 2 * this.props.radius - 10) {
- newX = this.props.xMax - 2 * this.props.radius - 10;
- } else if (newX < 10) {
- newX = 10;
- }
- if (this.props.dataDoc['simulationType'] == "Spring") {
- this.props.dataDoc.springStartLength = newY
- }
- if (this.props.dataDoc['simulationType'] == "Suspension") {
- let x1rod = (this.props.xMax + this.props.xMin) / 2 - this.props.radius - this.props.yMin - 200;
- let x2rod = (this.props.xMax + this.props.xMin) / 2 + this.props.yMin + 200 + this.props.radius;
- let deltaX1 = this.state.xPosition + this.props.radius - x1rod;
- let deltaX2 = x2rod - (this.state.xPosition + this.props.radius);
- let deltaY = this.state.yPosition + this.props.radius;
- let dir1T = Math.PI - Math.atan(deltaY / deltaX1);
- let dir2T = Math.atan(deltaY / deltaX2);
- let tensionMag2 =
- (this.props.mass * Math.abs(this.props.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.props.mass * Math.abs(this.props.gravity),
- directionInDegrees: 270,
- component: false,
- };
- this.props.dataDoc['updatedForces'] = ([tensionForce1, tensionForce2, grav]);
+ const pendulumLength = Math.sqrt(x * x + y * y);
+
+ const mag = this.props.mass * Math.abs(this.props.gravity) * Math.cos((oppositeAngle * Math.PI) / 180) + (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength;
+
+ const tensionComponent: IForce = {
+ description: 'Tension',
+ magnitude: mag,
+ directionInDegrees: angle,
+ component: true,
+ };
+ const gravityParallel: IForce = {
+ description: 'Gravity Parallel Component',
+ magnitude: Math.abs(this.props.gravity) * Math.cos(((90 - angle) * Math.PI) / 180),
+ directionInDegrees: 270 - (90 - angle),
+ component: true,
+ };
+ const gravityPerpendicular: IForce = {
+ description: 'Gravity Perpendicular Component',
+ magnitude: Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180),
+ directionInDegrees: -(90 - angle),
+ component: true,
+ };
+ if (Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180) < 0) {
+ gravityPerpendicular.magnitude = Math.abs(Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180));
+ gravityPerpendicular.directionInDegrees = 180 - (90 - angle);
}
- }
- }}
- >
- <div className="weight" style={this.weightStyle}>
- <p className="weightLabel">{this.props.mass} kg</p>
- </div>
- </div>
- {this.props.dataDoc['simulationType'] == "Spring" && (
- <div
- className="spring"
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: 0,
- top: 0,
- }}
- >
- <svg width={this.props.xMax + "px"} height={this.props.layoutDoc._height + "px"}>
- {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map((val) => {
- const count = 10;
- let xPos1;
- let yPos1;
- let xPos2;
- let yPos2;
- if (val % 2 == 0) {
- xPos1 = this.state.xPosition + this.props.radius - 20;
- xPos2 = this.state.xPosition + this.props.radius + 20;
- } else {
- xPos1 = this.state.xPosition + this.props.radius + 20;
- xPos2 = this.state.xPosition + this.props.radius - 20;
- }
- yPos1 = (val * this.state.yPosition) / count;
- yPos2 = ((val + 1) * this.state.yPosition) / count;
- return (
- <line
- key={val}
- x1={xPos1}
- y1={yPos1}
- x2={xPos2}
- y2={yPos2}
- stroke={"#808080"}
- strokeWidth="10"
- />
- );
- })}
- </svg>
- </div>
- )}
-
- {this.props.dataDoc['simulationType'] == "Pulley" && (
- <div
- className="rod"
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: 0,
- top: 0,
- }}
- >
- <svg width={this.props.xMax + "px"} height={this.props.layoutDoc._height + "px"}>
- <line
- x1={this.state.xPosition + this.props.radius}
- y1={this.state.yPosition + this.props.radius}
- x2={this.state.xPosition + this.props.radius}
- y2={this.props.yMin}
- stroke={"#deb887"}
- strokeWidth="10"
- />
- </svg>
- </div>
- )}
- {this.props.dataDoc['simulationType'] == "Pulley" && (
- <div
- className="wheel"
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: 0,
- top: 0,
- }}
- >
- <svg width={this.props.xMax + "px"} height={this.props.layoutDoc._height + "px"}>
- <circle
- cx={(this.props.xMax + this.props.xMin) / 2}
- cy={this.props.radius}
- r={this.props.radius * 1.5}
- fill={"#808080"}
- />
- </svg>
- </div>
- )}
- {this.props.dataDoc['simulationType'] == "Suspension" && (
- <div
- className="rod"
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: 0,
- top: 0,
- }}
- >
- <svg width={this.props.xMax + "px"} height={this.props.layoutDoc._height + "px"}>
- <line
- x1={this.state.xPosition + this.props.radius}
- y1={this.state.yPosition + this.props.radius}
- x2={(this.props.xMax + this.props.xMin) / 2 - this.props.radius - this.props.yMin - 200}
- y2={this.props.yMin}
- stroke={"#deb887"}
- strokeWidth="10"
- />
- </svg>
- <p
- style={{
- position: "absolute",
- left: (this.props.xMax + this.props.xMin) / 2 - this.props.radius - this.props.yMin - 200 + 80 + "px",
- top: 10 + "px",
- backgroundColor: this.labelBackgroundColor,
- }}
- >
- {Math.round(
- ((Math.atan(
- (this.state.yPosition + this.props.radius) /
- (this.state.xPosition +
- this.props.radius -
- ((this.props.xMax + this.props.xMin) / 2 - this.props.radius - this.props.yMin - 200))
- ) *
- 180) /
- Math.PI) *
- 100
- ) / 100}
- °
- </p>
- <svg width={this.props.layoutDoc._width + "px"} height={this.props.layoutDoc._height + "px"}>
- <line
- x1={this.state.xPosition + this.props.radius}
- y1={this.state.yPosition + this.props.radius}
- x2={(this.props.xMax + this.props.xMin) / 2 + this.props.yMin + 200 + this.props.radius}
- y2={this.props.yMin}
- stroke={"#deb887"}
- strokeWidth="10"
- />
- </svg>
+ this.props.dataDoc.componentForces = [tensionComponent, gravityParallel, gravityPerpendicular];
+ }
+ };
- <p
- style={{
- position: "absolute",
- left: (this.props.xMax + this.props.xMin) / 2 + this.props.yMin + 200 + this.props.radius - 80 + "px",
- top: 10 + "px",
- backgroundColor: this.labelBackgroundColor,
- }}
- >
- {Math.round(
- ((Math.atan(
- (this.state.yPosition + this.props.radius) /
- ((this.props.xMax + this.props.xMin) / 2 +
- this.props.yMin +
- 200 +
- this.props.radius -
- (this.state.xPosition + this.props.radius))
- ) *
- 180) /
- Math.PI) *
- 100
- ) / 100}
- °
- </p>
- </div>
- )}
- {this.props.dataDoc['simulationType'] == "Circular Motion" && (
- <div
- className="rod"
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: 0,
- top: 0,
- }}
- >
- <svg width={this.props.xMax + "px"} height={this.props.layoutDoc._height + "px"}>
- <line
- x1={this.state.xPosition + this.props.radius}
- y1={this.state.yPosition + this.props.radius}
- x2={(this.props.xMin + this.props.xMax) / 2}
- y2={(this.props.yMin + this.props.yMax) / 2}
- stroke={"#deb887"}
- strokeWidth="10"
- />
- </svg>
- </div>
- )}
- {this.props.dataDoc['simulationType'] == "Pendulum" && (
- <div
- className="rod"
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: 0,
- top: 0,
- }}
- >
- <svg width={this.props.xMax + "px"} height={this.props.layoutDoc._height + "px"}>
- <line
- x1={this.state.xPosition + this.props.radius}
- y1={this.state.yPosition + this.props.radius}
- x2={this.props.xMax / 2}
- y2={-5}
- stroke={"#deb887"}
- strokeWidth="10"
- />
- </svg>
- {!this.state.dragging && (
+ // Render weight, spring, rod(s), vectors
+ render() {
+ return (
<div>
- <p
- style={{
- position: "absolute",
- zIndex: 5,
- left: this.state.xPosition + "px",
- top: this.state.yPosition - 70 + "px",
- backgroundColor: this.labelBackgroundColor,
- }}
- >
- {Math.round(this.props.pendulumLength)} m
- </p>
- <p
- style={{
- position: "absolute",
- left: this.props.xMax / 2 + "px",
- top: 30 + "px",
- backgroundColor: this.labelBackgroundColor,
- }}
- >
- {Math.round(this.props.pendulumAngle * 100) / 100}°
- </p>
- </div>
- )}
- </div>
- )}
- {this.props.dataDoc['simulationType'] == "Inclined Plane" && (
- <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",
- left: Math.round(this.props.xMax * 0.5 - 200 + this.props.wedgeWidth - 80) + "px",
- top: Math.round(this.props.yMax - 40) + "px",
- }}
- >
- {Math.round(
- ((Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI) * 100
- ) / 100}
- °
- </p>
- </div>
- )}
- {!this.state.dragging && this.props.showAcceleration && (
- <div>
- <div
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: 0,
- top: 0,
- }}
- >
- <svg width={this.props.xMax + "px"} height={this.props.layoutDoc._height + "px"}>
- <defs>
- <marker
- id="accArrow"
- markerWidth="10"
- markerHeight="10"
- refX="0"
- refY="3"
- orient="auto"
- markerUnits="strokeWidth"
- >
- <path d="M0,0 L0,6 L9,3 z" fill="green" />
- </marker>
- </defs>
- <line
- x1={this.state.xPosition + this.props.radius}
- y1={this.state.yPosition + this.props.radius}
- x2={this.state.xPosition + this.props.radius + this.getNewAccelerationX(this.props.updatedForces) * 15}
- y2={this.state.yPosition + this.props.radius + this.getNewAccelerationY(this.props.updatedForces) * 15}
- stroke={"green"}
- strokeWidth="5"
- markerEnd="url(#accArrow)"
- />
- </svg>
- <div
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: this.state.xPosition + this.props.radius + this.state.xAccel * 15 + 25 + "px",
- top: this.state.yPosition + this.props.radius + this.state.yAccel * 15 + 70 + "px",
- lineHeight: 1,
- }}
- >
- <p>
- {Math.round(
- 100 * Math.sqrt(this.state.xAccel * this.state.xAccel + this.state.yAccel * this.state.yAccel)
- ) / 100}{" "}
- m/s
- <sup>2</sup>
- </p>
- </div>
- </div>
- </div>
- )}
- {!this.state.dragging && this.props.showVelocity && (
- <div>
- <div
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: 0,
- top: 0,
- }}
- >
- <svg width={this.props.xMax + "px"} height={this.props.layoutDoc._height + "px"}>
- <defs>
- <marker
- id="velArrow"
- markerWidth="10"
- markerHeight="10"
- refX="0"
- refY="3"
- orient="auto"
- markerUnits="strokeWidth"
- >
- <path d="M0,0 L0,6 L9,3 z" fill="blue" />
- </marker>
- </defs>
- <line
- x1={this.state.xPosition + this.props.radius}
- y1={this.state.yPosition + this.props.radius}
- x2={this.state.xPosition + this.props.radius + this.state.xVelocity * 7}
- y2={this.state.yPosition + this.props.radius + this.state.yVelocity * 7}
- stroke={"blue"}
- strokeWidth="5"
- markerEnd="url(#velArrow)"
- />
- </svg>
- <div
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: this.state.xPosition + this.props.radius + this.state.xVelocity * 7 + 25 + "px",
- top: this.state.yPosition + this.props.radius + this.state.yVelocity * 7 + "px",
- lineHeight: 1,
- }}
- >
- <p>
- {Math.round(
- 100 *
- Math.sqrt(
- this.props.displayXVelocity * this.props.displayXVelocity +
- this.props.displayYVelocity * this.props.displayYVelocity
- )
- ) / 100}{" "}
- m/s
- </p>
- </div>
- </div>
- </div>
- )}
- {!this.state.dragging &&
- this.props.showComponentForces &&
- this.props.componentForces.map((force, index) => {
- if (force.magnitude < this.epsilon) {
- return;
- }
- let arrowStartY: number = this.state.yPosition + this.props.radius;
- const arrowStartX: number = this.state.xPosition + this.props.radius;
- let arrowEndY: number =
- arrowStartY -
- Math.abs(force.magnitude) *
- 20 *
- Math.sin((force.directionInDegrees * Math.PI) / 180);
- const arrowEndX: number =
- arrowStartX +
- Math.abs(force.magnitude) *
- 20 *
- Math.cos((force.directionInDegrees * Math.PI) / 180);
+ <div
+ className="weightContainer"
+ onPointerDown={e => {
+ if (this.draggable) {
+ this.props.dataDoc.paused = true;
+ this.setState({ dragging: true });
+ this.setState({ clickPositionX: e.clientX });
+ this.setState({ clickPositionY: e.clientY });
+ }
+ }}
+ onPointerMove={e => {
+ if (this.state.dragging) {
+ let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
+ if (newY > this.props.yMax - 2 * this.props.radius - 10) {
+ newY = this.props.yMax - 2 * this.props.radius - 10;
+ } else if (newY < 10) {
+ newY = 10;
+ }
- let color = "#0d0d0d";
+ let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
+ if (newX > this.props.xMax - 2 * this.props.radius - 10) {
+ newX = this.props.xMax - 2 * this.props.radius - 10;
+ } else if (newX < 10) {
+ newX = 10;
+ }
+ if (this.props.dataDoc.simulation_Type == 'Suspension') {
+ if (newX < (this.props.xMax + this.props.xMin) / 4 - this.props.radius - 15) {
+ newX = (this.props.xMax + this.props.xMin) / 4 - this.props.radius - 15;
+ } else if (newX > (3 * (this.props.xMax + this.props.xMin)) / 4 - this.props.radius / 2 - 15) {
+ newX = (3 * (this.props.xMax + this.props.xMin)) / 4 - this.props.radius / 2 - 15;
+ }
+ }
- let labelTop = arrowEndY;
- let labelLeft = arrowEndX;
- if (force.directionInDegrees > 90 && force.directionInDegrees < 270) {
- labelLeft -= 120;
- } else {
- labelLeft += 30;
- }
- if (force.directionInDegrees >= 0 && force.directionInDegrees < 180) {
- labelTop += 40;
- } else {
- labelTop -= 40;
- }
- labelTop = Math.min(labelTop, this.props.yMax + 50);
- labelTop = Math.max(labelTop, this.props.yMin);
- labelLeft = Math.min(labelLeft, this.props.xMax - 60);
- labelLeft = Math.max(labelLeft, this.props.xMin);
+ this.setState({ yPosition: newY });
+ this.props.dataDoc.position_YDisplay = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100;
+ if (this.props.dataDoc.simulation_Type != 'Pulley') {
+ this.setState({ xPosition: newX });
+ this.props.dataDoc.position_XDisplay = newX;
+ }
+ if (this.props.dataDoc.simulation_Type != 'Suspension') {
+ if (this.props.dataDoc.simulation_Type != 'Pulley') {
+ this.setState({ updatedStartPosX: newX });
+ }
+ this.setState({ updatedStartPosY: newY });
+ }
+ this.setState({ clickPositionX: e.clientX });
+ this.setState({ clickPositionY: e.clientY });
+ this.setDisplayValues();
+ }
+ }}
+ onPointerUp={e => {
+ if (this.state.dragging) {
+ if (this.props.dataDoc.simulation_Type != 'Pendulum' && this.props.dataDoc.simulation_Type != 'Suspension') {
+ this.resetEverything();
+ }
+ this.setState({ dragging: false });
+ let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
+ if (newY > this.props.yMax - 2 * this.props.radius - 10) {
+ newY = this.props.yMax - 2 * this.props.radius - 10;
+ } else if (newY < 10) {
+ newY = 10;
+ }
- return (
- <div key={index}>
- <div
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: this.props.xMin,
- top: this.props.yMin,
- }}
- >
- <svg
- width={this.props.xMax - this.props.xMin + "px"}
- height={this.props.layoutDoc._height + "px"}
- >
- <defs>
- <marker
- id="forceArrow"
- markerWidth="10"
- markerHeight="10"
- refX="0"
- refY="3"
- orient="auto"
- markerUnits="strokeWidth"
- >
- <path d="M0,0 L0,6 L9,3 z" fill={color} />
- </marker>
- </defs>
- {force.component == true && (
- <line
- x1={arrowStartX}
- y1={arrowStartY}
- x2={arrowEndX}
- y2={arrowEndY}
- stroke={color}
- strokeWidth="5"
- strokeDasharray="10,10"
- markerEnd="url(#forceArrow)"
- />
- )}
- {force.component == false && (
- <line
- x1={arrowStartX}
- y1={arrowStartY}
- x2={arrowEndX}
- y2={arrowEndY}
- stroke={color}
- strokeWidth="5"
- markerEnd="url(#forceArrow)"
- />
- )}
- </svg>
- </div>
- <div
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: labelLeft + "px",
- top: labelTop + "px",
- lineHeight: 1,
- backgroundColor: this.labelBackgroundColor,
- }}
- >
- {force.description && <p>{force.description}</p>}
- {!force.description && <p>Force</p>}
- {this.props.showForceMagnitudes && (
- <p>{Math.round(100 * force.magnitude) / 100} N</p>
+ let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
+ if (newX > this.props.xMax - 2 * this.props.radius - 10) {
+ newX = this.props.xMax - 2 * this.props.radius - 10;
+ } else if (newX < 10) {
+ newX = 10;
+ }
+ if (this.props.dataDoc.simulation_Type == 'Spring') {
+ this.props.dataDoc.springStartLength = newY;
+ }
+ if (this.props.dataDoc.simulation_Type == 'Suspension') {
+ let x1rod = (this.props.xMax + this.props.xMin) / 2 - this.props.radius - this.props.yMin - 200;
+ let x2rod = (this.props.xMax + this.props.xMin) / 2 + this.props.yMin + 200 + this.props.radius;
+ let deltaX1 = this.state.xPosition + this.props.radius - x1rod;
+ let deltaX2 = x2rod - (this.state.xPosition + this.props.radius);
+ let deltaY = this.state.yPosition + this.props.radius;
+ let dir1T = Math.PI - Math.atan(deltaY / deltaX1);
+ let dir2T = Math.atan(deltaY / deltaX2);
+ let tensionMag2 = (this.props.mass * Math.abs(this.props.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.props.mass * Math.abs(this.props.gravity),
+ directionInDegrees: 270,
+ component: false,
+ };
+ this.props.dataDoc.updatedForces = [tensionForce1, tensionForce2, grav];
+ }
+ }
+ }}>
+ <div className="weight" style={this.weightStyle}>
+ <p className="weightLabel">{this.props.mass} kg</p>
+ </div>
+ </div>
+ {this.props.dataDoc.simulation_Type == 'Spring' && (
+ <div
+ className="spring"
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ }}>
+ <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(val => {
+ const count = 10;
+ let xPos1;
+ let yPos1;
+ let xPos2;
+ let yPos2;
+ if (val % 2 == 0) {
+ xPos1 = this.state.xPosition + this.props.radius - 20;
+ xPos2 = this.state.xPosition + this.props.radius + 20;
+ } else {
+ xPos1 = this.state.xPosition + this.props.radius + 20;
+ xPos2 = this.state.xPosition + this.props.radius - 20;
+ }
+ yPos1 = (val * this.state.yPosition) / count;
+ yPos2 = ((val + 1) * this.state.yPosition) / count;
+ return <line key={val} x1={xPos1} y1={yPos1} x2={xPos2} y2={yPos2} stroke={'#808080'} strokeWidth="10" />;
+ })}
+ </svg>
+ </div>
)}
- </div>
- </div>
- );
- })}
- {!this.state.dragging &&
- this.props.showForces && this.props.updatedForces &&
- this.props.updatedForces.map((force, index) => {
- if (force.magnitude < this.epsilon) {
- return;
- }
- let arrowStartY: number = this.state.yPosition + this.props.radius;
- const arrowStartX: number = this.state.xPosition + this.props.radius;
- let arrowEndY: number =
- arrowStartY -
- Math.abs(force.magnitude) *
- 20 *
- Math.sin((force.directionInDegrees * Math.PI) / 180);
- const arrowEndX: number =
- arrowStartX +
- Math.abs(force.magnitude) *
- 20 *
- Math.cos((force.directionInDegrees * Math.PI) / 180);
- let color = "#0d0d0d";
+ {this.props.dataDoc.simulation_Type == 'Pulley' && (
+ <div
+ className="rod"
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ }}>
+ <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <line x1={this.state.xPosition + this.props.radius} y1={this.state.yPosition + this.props.radius} x2={this.state.xPosition + this.props.radius} y2={this.props.yMin} stroke={'#deb887'} strokeWidth="10" />
+ </svg>
+ </div>
+ )}
+ {this.props.dataDoc.simulation_Type == 'Pulley' && (
+ <div
+ className="wheel"
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ }}>
+ <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <circle cx={(this.props.xMax + this.props.xMin) / 2} cy={this.props.radius} r={this.props.radius * 1.5} fill={'#808080'} />
+ </svg>
+ </div>
+ )}
+ {this.props.dataDoc.simulation_Type == 'Suspension' && (
+ <div
+ className="rod"
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ }}>
+ <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <line
+ x1={this.state.xPosition + this.props.radius}
+ y1={this.state.yPosition + this.props.radius}
+ x2={(this.props.xMax + this.props.xMin) / 2 - this.props.radius - this.props.yMin - 200}
+ y2={this.props.yMin}
+ stroke={'#deb887'}
+ strokeWidth="10"
+ />
+ </svg>
+ <p
+ style={{
+ position: 'absolute',
+ left: (this.props.xMax + this.props.xMin) / 2 - this.props.radius - this.props.yMin - 200 + 80 + 'px',
+ top: 10 + 'px',
+ backgroundColor: this.labelBackgroundColor,
+ }}>
+ {Math.round(
+ ((Math.atan((this.state.yPosition + this.props.radius) / (this.state.xPosition + this.props.radius - ((this.props.xMax + this.props.xMin) / 2 - this.props.radius - this.props.yMin - 200))) * 180) / Math.PI) * 100
+ ) / 100}
+ °
+ </p>
+ <div
+ className="rod"
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ }}>
+ <svg width={this.props.layoutDoc._width + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <line
+ x1={this.state.xPosition + this.props.radius}
+ y1={this.state.yPosition + this.props.radius}
+ x2={(this.props.xMax + this.props.xMin) / 2 + this.props.yMin + 200 + this.props.radius}
+ y2={this.props.yMin}
+ stroke={'#deb887'}
+ strokeWidth="10"
+ />
+ </svg>
+ </div>
- let labelTop = arrowEndY;
- let labelLeft = arrowEndX;
- if (force.directionInDegrees > 90 && force.directionInDegrees < 270) {
- labelLeft -= 120;
- } else {
- labelLeft += 30;
- }
- if (force.directionInDegrees >= 0 && force.directionInDegrees < 180) {
- labelTop += 40;
- } else {
- labelTop -= 40;
- }
- labelTop = Math.min(labelTop, this.props.yMax + 50);
- labelTop = Math.max(labelTop, this.props.yMin);
- labelLeft = Math.min(labelLeft, this.props.xMax - 60);
- labelLeft = Math.max(labelLeft, this.props.xMin);
+ <p
+ style={{
+ position: 'absolute',
+ left: (this.props.xMax + this.props.xMin) / 2 + this.props.yMin + 200 + this.props.radius - 80 + 'px',
+ top: 10 + 'px',
+ backgroundColor: this.labelBackgroundColor,
+ }}>
+ {Math.round(
+ ((Math.atan((this.state.yPosition + this.props.radius) / ((this.props.xMax + this.props.xMin) / 2 + this.props.yMin + 200 + this.props.radius - (this.state.xPosition + this.props.radius))) * 180) / Math.PI) * 100
+ ) / 100}
+ °
+ </p>
+ </div>
+ )}
+ {this.props.dataDoc.simulation_Type == 'Circular Motion' && (
+ <div
+ className="rod"
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ }}>
+ <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <line
+ x1={this.state.xPosition + this.props.radius}
+ y1={this.state.yPosition + this.props.radius}
+ x2={(this.props.xMin + this.props.xMax) / 2}
+ y2={(this.props.yMin + this.props.yMax) / 2}
+ stroke={'#deb887'}
+ strokeWidth="10"
+ />
+ </svg>
+ </div>
+ )}
+ {this.props.dataDoc.simulation_Type == 'Pendulum' && (
+ <div
+ className="rod"
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ }}>
+ <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <line x1={this.state.xPosition + this.props.radius} y1={this.state.yPosition + this.props.radius} x2={this.props.xMax / 2} y2={-5} stroke={'#deb887'} strokeWidth="10" />
+ </svg>
+ {!this.state.dragging && (
+ <div>
+ <p
+ style={{
+ position: 'absolute',
+ zIndex: 5,
+ left: this.state.xPosition + 'px',
+ top: this.state.yPosition - 70 + 'px',
+ backgroundColor: this.labelBackgroundColor,
+ }}>
+ {Math.round(this.props.pendulumLength)} m
+ </p>
+ <p
+ style={{
+ position: 'absolute',
+ left: this.props.xMax / 2 + 'px',
+ top: 30 + 'px',
+ backgroundColor: this.labelBackgroundColor,
+ }}>
+ {Math.round(this.props.pendulum_angle * 100) / 100}°
+ </p>
+ </div>
+ )}
+ </div>
+ )}
+ {this.props.dataDoc.simulation_Type == 'Inclined Plane' && (
+ <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>
- return (
- <div key={index}>
- <div
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: this.props.xMin,
- top: this.props.yMin,
- }}
- >
- <svg
- width={this.props.xMax - this.props.xMin + "px"}
- height={this.props.layoutDoc._height + "px"}
- >
- <defs>
- <marker
- id="forceArrow"
- markerWidth="10"
- markerHeight="10"
- refX="0"
- refY="3"
- orient="auto"
- markerUnits="strokeWidth"
- >
- <path d="M0,0 L0,6 L9,3 z" fill={color} />
- </marker>
- </defs>
- {force.component == true && (
- <line
- x1={arrowStartX}
- y1={arrowStartY}
- x2={arrowEndX}
- y2={arrowEndY}
- stroke={color}
- strokeWidth="5"
- strokeDasharray="10,10"
- markerEnd="url(#forceArrow)"
- />
- )}
- {force.component == false && (
- <line
- x1={arrowStartX}
- y1={arrowStartY}
- x2={arrowEndX}
- y2={arrowEndY}
- stroke={color}
- strokeWidth="5"
- markerEnd="url(#forceArrow)"
- />
- )}
- </svg>
- </div>
- <div
- style={{
- pointerEvents: "none",
- position: "absolute",
- left: labelLeft + "px",
- top: labelTop + "px",
- lineHeight: 1,
- backgroundColor: this.labelBackgroundColor,
- }}
- >
- {force.description && <p>{force.description}</p>}
- {!force.description && <p>Force</p>}
- {this.props.showForceMagnitudes && (
- <p>{Math.round(100 * force.magnitude) / 100} N</p>
+ <p
+ style={{
+ position: 'absolute',
+ left: Math.round(this.props.xMax * 0.5 - 200 + this.props.wedgeWidth - 80) + 'px',
+ top: Math.round(this.props.yMax - 40) + 'px',
+ }}>
+ {Math.round(((Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI) * 100) / 100}°
+ </p>
+ </div>
)}
- </div>
+ {!this.state.dragging && this.props.showAcceleration && (
+ <div>
+ <div
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ }}>
+ <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <defs>
+ <marker id="accArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
+ <path d="M0,0 L0,6 L9,3 z" fill="green" />
+ </marker>
+ </defs>
+ <line
+ x1={this.state.xPosition + this.props.radius}
+ y1={this.state.yPosition + this.props.radius}
+ x2={this.state.xPosition + this.props.radius + this.getNewAccelerationX(this.props.updatedForces) * 15}
+ y2={this.state.yPosition + this.props.radius + this.getNewAccelerationY(this.props.updatedForces) * 15}
+ stroke={'green'}
+ strokeWidth="5"
+ markerEnd="url(#accArrow)"
+ />
+ </svg>
+ <div
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: this.state.xPosition + this.props.radius + this.state.xAccel * 15 + 25 + 'px',
+ top: this.state.yPosition + this.props.radius + this.state.yAccel * 15 + 70 + 'px',
+ lineHeight: 1,
+ }}>
+ <p>
+ {Math.round(100 * Math.sqrt(this.state.xAccel * this.state.xAccel + this.state.yAccel * this.state.yAccel)) / 100} m/s
+ <sup>2</sup>
+ </p>
+ </div>
+ </div>
+ </div>
+ )}
+ {!this.state.dragging && this.props.showVelocity && (
+ <div>
+ <div
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: 0,
+ top: 0,
+ }}>
+ <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <defs>
+ <marker id="velArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
+ <path d="M0,0 L0,6 L9,3 z" fill="blue" />
+ </marker>
+ </defs>
+ <line
+ x1={this.state.xPosition + this.props.radius}
+ y1={this.state.yPosition + this.props.radius}
+ x2={this.state.xPosition + this.props.radius + this.state.xVelocity * 7}
+ y2={this.state.yPosition + this.props.radius + this.state.yVelocity * 7}
+ stroke={'blue'}
+ strokeWidth="5"
+ markerEnd="url(#velArrow)"
+ />
+ </svg>
+ <div
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: this.state.xPosition + this.props.radius + this.state.xVelocity * 7 + 25 + 'px',
+ top: this.state.yPosition + this.props.radius + this.state.yVelocity * 7 + 'px',
+ lineHeight: 1,
+ }}>
+ <p>{Math.round(100 * Math.sqrt(this.props.displayXVelocity * this.props.displayXVelocity + this.props.displayYVelocity * this.props.displayYVelocity)) / 100} m/s</p>
+ </div>
+ </div>
+ </div>
+ )}
+ {!this.state.dragging &&
+ this.props.showComponentForces &&
+ this.props.componentForces.map((force, index) => {
+ if (force.magnitude < this.epsilon) {
+ return;
+ }
+ let arrowStartY: number = this.state.yPosition + this.props.radius;
+ const arrowStartX: number = this.state.xPosition + this.props.radius;
+ let arrowEndY: number = arrowStartY - Math.abs(force.magnitude) * 20 * Math.sin((force.directionInDegrees * Math.PI) / 180);
+ const arrowEndX: number = arrowStartX + Math.abs(force.magnitude) * 20 * Math.cos((force.directionInDegrees * Math.PI) / 180);
+
+ let color = '#0d0d0d';
+
+ let labelTop = arrowEndY;
+ let labelLeft = arrowEndX;
+ if (force.directionInDegrees > 90 && force.directionInDegrees < 270) {
+ labelLeft -= 120;
+ } else {
+ labelLeft += 30;
+ }
+ if (force.directionInDegrees >= 0 && force.directionInDegrees < 180) {
+ labelTop += 40;
+ } else {
+ labelTop -= 40;
+ }
+ labelTop = Math.min(labelTop, this.props.yMax + 50);
+ labelTop = Math.max(labelTop, this.props.yMin);
+ labelLeft = Math.min(labelLeft, this.props.xMax - 60);
+ labelLeft = Math.max(labelLeft, this.props.xMin);
+
+ return (
+ <div key={index}>
+ <div
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: this.props.xMin,
+ top: this.props.yMin,
+ }}>
+ <svg width={this.props.xMax - this.props.xMin + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <defs>
+ <marker id="forceArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
+ <path d="M0,0 L0,6 L9,3 z" fill={color} />
+ </marker>
+ </defs>
+ {force.component == true && <line x1={arrowStartX} y1={arrowStartY} x2={arrowEndX} y2={arrowEndY} stroke={color} strokeWidth="5" strokeDasharray="10,10" markerEnd="url(#forceArrow)" />}
+ {force.component == false && <line x1={arrowStartX} y1={arrowStartY} x2={arrowEndX} y2={arrowEndY} stroke={color} strokeWidth="5" markerEnd="url(#forceArrow)" />}
+ </svg>
+ </div>
+ <div
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: labelLeft + 'px',
+ top: labelTop + 'px',
+ lineHeight: 1,
+ backgroundColor: this.labelBackgroundColor,
+ }}>
+ {force.description && <p>{force.description}</p>}
+ {!force.description && <p>Force</p>}
+ {this.props.showForceMagnitudes && <p>{Math.round(100 * force.magnitude) / 100} N</p>}
+ </div>
+ </div>
+ );
+ })}
+ {!this.state.dragging &&
+ this.props.showForces &&
+ this.props.updatedForces &&
+ this.props.updatedForces.map((force, index) => {
+ if (force.magnitude < this.epsilon) {
+ return;
+ }
+ let arrowStartY: number = this.state.yPosition + this.props.radius;
+ const arrowStartX: number = this.state.xPosition + this.props.radius;
+ let arrowEndY: number = arrowStartY - Math.abs(force.magnitude) * 20 * Math.sin((force.directionInDegrees * Math.PI) / 180);
+ const arrowEndX: number = arrowStartX + Math.abs(force.magnitude) * 20 * Math.cos((force.directionInDegrees * Math.PI) / 180);
+
+ let color = '#0d0d0d';
+
+ let labelTop = arrowEndY;
+ let labelLeft = arrowEndX;
+ if (force.directionInDegrees > 90 && force.directionInDegrees < 270) {
+ labelLeft -= 120;
+ } else {
+ labelLeft += 30;
+ }
+ if (force.directionInDegrees >= 0 && force.directionInDegrees < 180) {
+ labelTop += 40;
+ } else {
+ labelTop -= 40;
+ }
+ labelTop = Math.min(labelTop, this.props.yMax + 50);
+ labelTop = Math.max(labelTop, this.props.yMin);
+ labelLeft = Math.min(labelLeft, this.props.xMax - 60);
+ labelLeft = Math.max(labelLeft, this.props.xMin);
+
+ return (
+ <div key={index}>
+ <div
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: this.props.xMin,
+ top: this.props.yMin,
+ }}>
+ <svg width={this.props.xMax - this.props.xMin + 'px'} height={this.props.layoutDoc._height + 'px'}>
+ <defs>
+ <marker id="forceArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
+ <path d="M0,0 L0,6 L9,3 z" fill={color} />
+ </marker>
+ </defs>
+ {force.component == true && <line x1={arrowStartX} y1={arrowStartY} x2={arrowEndX} y2={arrowEndY} stroke={color} strokeWidth="5" strokeDasharray="10,10" markerEnd="url(#forceArrow)" />}
+ {force.component == false && <line x1={arrowStartX} y1={arrowStartY} x2={arrowEndX} y2={arrowEndY} stroke={color} strokeWidth="5" markerEnd="url(#forceArrow)" />}
+ </svg>
+ </div>
+ <div
+ style={{
+ pointerEvents: 'none',
+ position: 'absolute',
+ left: labelLeft + 'px',
+ top: labelTop + 'px',
+ lineHeight: 1,
+ backgroundColor: this.labelBackgroundColor,
+ }}>
+ {force.description && <p>{force.description}</p>}
+ {!force.description && <p>Force</p>}
+ {this.props.showForceMagnitudes && <p>{Math.round(100 * force.magnitude) / 100} N</p>}
+ </div>
+ </div>
+ );
+ })}
</div>
- );
- })}
- </div>
- )}
-};
+ );
+ }
+}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 8dd322e05..d0e5d03b3 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -382,7 +382,7 @@ export class Doc extends RefField {
public get [LayoutSym]() {
return this[SelfProxy].__LAYOUT__;
}
- public get [DataSym]() {
+ public get [DataSym](): Doc {
const self = this[SelfProxy];
return self.resolvedDataDoc && !self.isTemplateForField ? self : Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self);
}