From cbce4b61ab4d11f3210ca004b935fae65b023408 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Fri, 20 Jan 2023 10:48:58 -0500
Subject: add new view
---
src/client/views/nodes/DocumentContentsView.tsx | 2 ++
src/client/views/nodes/PhysicsSimulationBox.scss | 0
src/client/views/nodes/PhysicsSimulationBox.tsx | 9 +++++++++
3 files changed, 11 insertions(+)
create mode 100644 src/client/views/nodes/PhysicsSimulationBox.scss
create mode 100644 src/client/views/nodes/PhysicsSimulationBox.tsx
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 569579996..c6818bf3c 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -34,6 +34,7 @@ import { LinkAnchorBox } from './LinkAnchorBox';
import { LinkBox } from './LinkBox';
import { MapBox } from './MapBox/MapBox';
import { PDFBox } from './PDFBox';
+import PhysicsSimulationBox from './PhysicsSimulationBox'
import { RecordingBox } from './RecordingBox';
import { ScreenshotBox } from './ScreenshotBox';
import { ScriptingBox } from './ScriptingBox';
@@ -268,6 +269,7 @@ export class DocumentContentsView extends React.Component<
HTMLtag,
ComparisonBox,
LoadingBox,
+ PhysicsSimulationBox,
}}
bindings={bindings}
jsx={layoutFrame}
diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
new file mode 100644
index 000000000..b62caf926
--- /dev/null
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -0,0 +1,9 @@
+import "./PhysicsSimulationBox.scss";
+import { FieldView, FieldViewProps } from './FieldView';
+import React = require('react');
+
+export default class PhysicsSimulationBox extends React.Component {
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }
+
+ render () { return (Hello world!
)}
+}
\ No newline at end of file
--
cgit v1.2.3-70-g09d2
From a555303c34ec2ac79084100bdf21f9d88dba86b1 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Thu, 26 Jan 2023 22:15:06 -0500
Subject: add option to colon menu
---
src/client/documents/Documents.ts | 14 ++++++++++----
src/client/util/CurrentUserUtils.ts | 3 ++-
src/client/views/nodes/PhysicsSimulationBox.tsx | 6 ++++--
3 files changed, 16 insertions(+), 7 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 46d7c087c..c7556d668 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -657,7 +657,13 @@ export namespace Docs {
options: { _fitWidth: true, _fitHeight: true, nativeDimModifiable: true, links: '@links(self)' },
},
],
- [DocumentType.SIMULATION, { layout: { view: PhysicsSimulationBox, dataField: defaultDataKey }, options: { _height: 150 } }]
+ [
+ DocumentType.SIMULATION,
+ {
+ layout: { view: PhysicsSimulationBox, dataField: defaultDataKey },
+ options: { _height: 150 }
+ }
+ ]
]);
const suffix = 'Proto';
@@ -1178,9 +1184,9 @@ export namespace Docs {
return InstanceFromProto(proto, undefined, options);
}
- // export function SimulationDocument(options: DocumentOptions = {}) {
- // return InstanceFromProto(Prototypes.get(DocumentType.SIMULATION), undefined, { title: document.title, ...options });
- // }
+ export function SimulationDocument(options?: DocumentOptions) {
+ return InstanceFromProto(Prototypes.get(DocumentType.SIMULATION), undefined, { ...(options || {}) });
+ }
}
}
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index a4788d38d..f0397b0c6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -260,7 +260,7 @@ export class CurrentUserUtils {
{key: "Noteboard", creator: opts => Docs.Create.NoteTakingDocument([], opts), opts: { _width: 250, _height: 200 }},
{key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100 }},
{key: "Equation", creator: opts => Docs.Create.EquationDocument(opts), opts: { _width: 300, _height: 35, _backgroundGridShow: true, }},
- // {key: "Simulation", creator: opts => Docs.Create.SimulationDocument(opts), opts: { _width: 300, _height: 35, _backgroundGridShow: true, }},
+ {key: "Simulation", creator: opts => Docs.Create.SimulationDocument(opts), opts: { _width: 300, _height: 35, _backgroundGridShow: true, }},
{key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, useCors: true, }},
{key: "Comparison", creator: Docs.Create.ComparisonDocument, opts: { _width: 300, _height: 300 }},
{key: "Audio", creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, }},
@@ -287,6 +287,7 @@ export class CurrentUserUtils {
{ toolTip: "Tap or drag to create a note board", title: "Notes", icon: "folder", dragFactory: doc.emptyNoteboard as Doc, },
{ toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab), scripts: { onClick: 'openOnRight(copyDragFactory(this.clickFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
{ toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, },
+ { toolTip: "Tap or drag to create a physics simulation", title: "Simulation", icon: "calculator", dragFactory: doc.emptySimulation as Doc, },
{ toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, },
{ toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, },
{ toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, scripts: { onClick: 'openInOverlay(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index b62caf926..568a5b40c 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -1,8 +1,10 @@
import "./PhysicsSimulationBox.scss";
import { FieldView, FieldViewProps } from './FieldView';
import React = require('react');
-
-export default class PhysicsSimulationBox extends React.Component {
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
+import { observer } from 'mobx-react';
+@observer
+export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }
render () { return (Hello world!
)}
--
cgit v1.2.3-70-g09d2
From d2b8f997f1786c813ef5a58acef69501e1c523a3 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Thu, 26 Jan 2023 22:43:53 -0500
Subject: start adding logic
---
src/client/util/CurrentUserUtils.ts | 2 +-
src/client/views/nodes/PhysicsSimulationBox.scss | 3 +
src/client/views/nodes/PhysicsSimulationBox.tsx | 73 +++++++++++++++++++++++-
3 files changed, 76 insertions(+), 2 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index f0397b0c6..23e9a2bea 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -260,7 +260,7 @@ export class CurrentUserUtils {
{key: "Noteboard", creator: opts => Docs.Create.NoteTakingDocument([], opts), opts: { _width: 250, _height: 200 }},
{key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100 }},
{key: "Equation", creator: opts => Docs.Create.EquationDocument(opts), opts: { _width: 300, _height: 35, _backgroundGridShow: true, }},
- {key: "Simulation", creator: opts => Docs.Create.SimulationDocument(opts), opts: { _width: 300, _height: 35, _backgroundGridShow: true, }},
+ {key: "Simulation", creator: opts => Docs.Create.SimulationDocument(opts), opts: { _width: 300, _height: 300, _backgroundGridShow: true, }},
{key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, useCors: true, }},
{key: "Comparison", creator: Docs.Create.ComparisonDocument, opts: { _width: 300, _height: 300 }},
{key: "Audio", creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, }},
diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss
index e69de29bb..2eb6e6ff0 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.scss
+++ b/src/client/views/nodes/PhysicsSimulationBox.scss
@@ -0,0 +1,3 @@
+.physicsSimulationContainer {
+
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 568a5b40c..b16bccdde 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -3,9 +3,80 @@ import { FieldView, FieldViewProps } from './FieldView';
import React = require('react');
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { observer } from 'mobx-react';
+
+export interface IForce {
+ description: string;
+ magnitude: number;
+ directionInDegrees: number;
+}
+export interface IWallProps {
+ length: number;
+ xPos: number;
+ yPos: number;
+ angleInDegrees: number;
+}
@observer
export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() {
+
+ forceOfGravity: IForce = {
+ description: "Gravity",
+ magnitude: 9.81,
+ directionInDegrees: 270,
+};
+
+ // Logic for Dash integration
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }
- render () { return (Hello world!
)}
+ constructor(props: any) {
+ super(props);
+ this.state = {
+ timer: 0,
+ weight: true,
+ pendulum: false,
+ wedge: false,
+ startPosX: 0,
+ startPosY: 0,
+ showVelocity: false,
+ showAcceleration: false,
+ showForces: false,
+ elasticCollisions: false,
+ updatedForces: [this.forceOfGravity],
+ wallPositions: []
+ }
+ }
+
+ // Add one weight to the simulation
+ addWeight = () => {
+ this.setState({weight: true});
+ this.setState({wedge: false});
+ this.setState({pendulum: false});
+ };
+
+// Remove floor and walls from simulation
+removeWalls = () => {
+ this.setState({wallPositions: []});
+};
+
+// Add floor and walls to simulation
+addWalls = () => {
+ const walls: IWallProps[] = [];
+ walls.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 });
+ walls.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 });
+ walls.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 });
+ this.setState({wallPositions: walls});
+};
+
+ // Timer for animating the simulation
+ // setInterval(() => {
+ // const time = this.timer ?? 0
+ // this.setState({timer: time+1});
+ // }, 60);
+
+ render () {
+ return (
+
+
+
+ );
+ }
}
\ No newline at end of file
--
cgit v1.2.3-70-g09d2
From d5ebbf476aeb7ce3f88e2e4c3961ffed4ed8e61a Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Mon, 30 Jan 2023 14:14:46 -0500
Subject: start adding physics sim
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 2154 ++++++++++++++++++++
src/client/views/nodes/PhysicsSimulationBox.scss | 72 +-
src/client/views/nodes/PhysicsSimulationBox.tsx | 53 +-
src/client/views/nodes/PhysicsSimulationWall.tsx | 35 +
src/client/views/nodes/PhysicsSimulationWedge.tsx | 64 +
src/client/views/nodes/PhysicsSimulationWeight.tsx | 913 +++++++++
6 files changed, 3238 insertions(+), 53 deletions(-)
create mode 100644 src/client/views/nodes/PhysicsSimulationApp.tsx
create mode 100644 src/client/views/nodes/PhysicsSimulationWall.tsx
create mode 100644 src/client/views/nodes/PhysicsSimulationWedge.tsx
create mode 100644 src/client/views/nodes/PhysicsSimulationWeight.tsx
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
new file mode 100644
index 000000000..7486aa88d
--- /dev/null
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -0,0 +1,2154 @@
+import AddIcon from "@mui/icons-material/Add";
+import AddCircleIcon from "@mui/icons-material/AddCircle";
+import ClearIcon from "@mui/icons-material/Clear";
+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 { SelectChangeEvent } from "@mui/material/Select";
+import {
+ Alert,
+ Box,
+ Button,
+ Checkbox,
+ CircularProgress,
+ Dialog,
+ DialogTitle,
+ DialogContent,
+ DialogContentText,
+ DialogActions,
+ Divider,
+ FormControl,
+ FormControlLabel,
+ FormGroup,
+ IconButton,
+ InputAdornment,
+ InputLabel,
+ LinearProgress,
+ List,
+ ListItem,
+ ListItemButton,
+ ListItemIcon,
+ ListItemText,
+ MenuItem,
+ Popover,
+ Select,
+ Stack,
+ TextField,
+ Tooltip,
+} from "@mui/material";
+import { styled } from "@mui/material/styles";
+import { tooltipClasses, TooltipProps } from "@mui/material/Tooltip";
+import Typography from "@mui/material/Typography";
+import React, { useEffect, useState } from "react";
+import "./PhysicsSimulationBox.scss";
+import { IForce, Weight } from "./PhysicsSimulationWeight";
+import { Description } from "@mui/icons-material";
+
+interface VectorTemplate {
+ top: number;
+ left: number;
+ width: number;
+ height: number;
+ x1: number;
+ y1: number;
+ x2: number;
+ y2: number;
+ weightX: number;
+ weightY: number;
+}
+interface QuestionTemplate {
+ questionSetup: string[];
+ variablesForQuestionSetup: string[];
+ question: string;
+ answerParts: string[];
+ answerSolutionDescriptions: string[];
+ goal: string;
+ hints: { description: string; content: string }[];
+}
+
+interface TutorialTemplate {
+ question: string;
+ steps: {
+ description: string;
+ content: string;
+ forces: {
+ description: string;
+ magnitude: number;
+ directionInDegrees: number;
+ }[];
+ showMagnitude: boolean;
+ }[];
+}
+
+function App() {
+ // Constants
+ const gravityMagnitude = 9.81;
+ const forceOfGravity: IForce = {
+ description: "Gravity",
+ magnitude: gravityMagnitude,
+ directionInDegrees: 270,
+ };
+ const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => (
+
+ ))(({ theme }) => ({
+ [`& .${tooltipClasses.tooltip}`]: {
+ backgroundColor: "#f5f5f9",
+ color: "rgba(0, 0, 0, 0.87)",
+ maxWidth: 220,
+ fontSize: theme.typography.pxToRem(12),
+ border: "1px solid #dadde9",
+ },
+ }));
+ const xMin = 0;
+ const yMin = 0;
+ const xMax = window.innerWidth * 0.7;
+ const yMax = window.innerHeight * 0.8;
+ const color = `rgba(0,0,0,0.5)`;
+
+ // Variables
+ let questionVariables: number[] = [];
+ let reviewCoefficient: number = 0;
+
+ // State variables
+ const [startPosX, setStartPosX] = useState(0);
+ const [startPosY, setStartPosY] = useState(0);
+ const [accelerationXDisplay, setAccelerationXDisplay] = useState(0);
+ const [accelerationYDisplay, setAccelerationYDisplay] = useState(0);
+ const [positionXDisplay, setPositionXDisplay] = useState(0);
+ const [positionYDisplay, setPositionYDisplay] = useState(0);
+ const [velocityXDisplay, setVelocityXDisplay] = useState(0);
+ const [velocityYDisplay, setVelocityYDisplay] = useState(0);
+
+ const [startPosX2, setStartPosX2] = useState(0);
+ const [startPosY2, setStartPosY2] = useState(0);
+ const [accelerationXDisplay2, setAccelerationXDisplay2] = useState(0);
+ const [accelerationYDisplay2, setAccelerationYDisplay2] = useState(0);
+ const [positionXDisplay2, setPositionXDisplay2] = useState(0);
+ const [positionYDisplay2, setPositionYDisplay2] = useState(0);
+ const [velocityXDisplay2, setVelocityXDisplay2] = useState(0);
+ const [velocityYDisplay2, setVelocityYDisplay2] = useState(0);
+
+ const [adjustPendulumAngle, setAdjustPendulumAngle] = useState<{
+ angle: number;
+ length: number;
+ }>({ angle: 0, length: 0 });
+ const [answerInputFields, setAnswerInputFields] = useState();
+ const [coefficientOfKineticFriction, setCoefficientOfKineticFriction] =
+ React.useState>(0);
+ const [coefficientOfStaticFriction, setCoefficientOfStaticFriction] =
+ React.useState>(0);
+ const [currentForceSketch, setCurrentForceSketch] =
+ useState(null);
+ const [deleteMode, setDeleteMode] = useState(false);
+ const [displayChange, setDisplayChange] = useState<{
+ xDisplay: number;
+ yDisplay: number;
+ }>({ xDisplay: 0, yDisplay: 0 });
+ const [elasticCollisions, setElasticCollisions] = useState(false);
+ const [forceSketches, setForceSketches] = useState([]);
+ const [questionPartOne, setQuestionPartOne] = useState("");
+ const [hintDialogueOpen, setHintDialogueOpen] = useState(false);
+ const [mode, setMode] = useState("Freeform");
+ const [noMovement, setNoMovement] = useState(false);
+ const [weight, setWeight] = useState(false);
+ const [pendulum, setPendulum] = useState(false);
+ const [pendulumAngle, setPendulumAngle] = useState(0);
+ const [pendulumLength, setPendulumLength] = useState(300);
+ const [questionNumber, setQuestionNumber] = useState(0);
+ const [reviewGravityAngle, setReviewGravityAngle] = useState(0);
+ const [reviewGravityMagnitude, setReviewGravityMagnitude] =
+ useState(0);
+ const [reviewNormalAngle, setReviewNormalAngle] = useState(0);
+ const [reviewNormalMagnitude, setReviewNormalMagnitude] = useState(0);
+ const [reviewStaticAngle, setReviewStaticAngle] = useState(0);
+ const [reviewStaticMagnitude, setReviewStaticMagnitude] = useState(0);
+ const [selectedQuestion, setSelectedQuestion] = useState(
+ questions.inclinePlane[0]
+ );
+ const [selectedTutorial, setSelectedTutorial] = useState(
+ tutorials.inclinePlane
+ );
+ const [questionPartTwo, setQuestionPartTwo] = useState("");
+ const [selectedSolutions, setSelectedSolutions] = useState([]);
+ const [showAcceleration, setShowAcceleration] = useState(false);
+ const [showForces, setShowForces] = useState(true);
+ const [showVelocity, setShowVelocity] = useState(false);
+ const [simulationPaused, setSimulationPaused] = useState(true);
+ const [simulationReset, setSimulationReset] = useState(false);
+ const [simulationType, setSimulationType] =
+ useState("Inclined Plane");
+ const [sketching, setSketching] = useState(false);
+ const [startForces, setStartForces] = useState([forceOfGravity]);
+ const [startPendulumAngle, setStartPendulumAngle] = useState(0);
+ const [stepNumber, setStepNumber] = useState(0);
+ const [timer, setTimer] = useState(0);
+ const [updatedForces, setUpdatedForces] = useState([
+ forceOfGravity,
+ ]);
+ const [wallPositions, setWallPositions] = useState([]);
+ const [wedge, setWedge] = useState(false);
+ const [wedgeAngle, setWedgeAngle] = React.useState<
+ number | string | Array
+ >(26);
+ const [wedgeHeight, setWedgeHeight] = useState(
+ Math.tan((26 * Math.PI) / 180) * 400
+ );
+ const [wedgeWidth, setWedgeWidth] = useState(400);
+ const [twoWeights, setTwoWeights] = useState(false);
+
+ // Add one weight to the simulation
+ const addWeight = () => {
+ setWeight(true);
+ setTwoWeights(false);
+ setWedge(false);
+ setPendulum(false);
+ };
+
+ // Add two weights to the simulation
+ const addTwoWeights = () => {
+ setWeight(true);
+ setTwoWeights(true);
+ setWedge(false);
+ setPendulum(false);
+ };
+
+ // Add a wedge with a One Weight to the simulation
+ const addWedge = () => {
+ setWeight(true);
+ setTwoWeights(false);
+ setWedge(true);
+ setPendulum(false);
+ };
+
+ // Add a simple pendulum to the simulation
+ const addPendulum = () => {
+ setWeight(true);
+ setTwoWeights(false);
+ setPendulum(true);
+ setWedge(false);
+ };
+
+ // Update forces when coefficient of static friction changes in freeform mode
+ const updateForcesWithFriction = (
+ coefficient: number,
+ width: number = wedgeWidth,
+ height: number = wedgeHeight
+ ) => {
+ const normalForce: IForce = {
+ description: "Normal Force",
+ magnitude: forceOfGravity.magnitude * Math.cos(Math.atan(height / width)),
+ directionInDegrees:
+ 180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
+ };
+ let frictionForce: IForce = {
+ description: "Static Friction Force",
+ magnitude:
+ coefficient *
+ forceOfGravity.magnitude *
+ Math.cos(Math.atan(height / width)),
+ directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
+ };
+ // reduce magnitude of friction force if necessary such that block cannot slide up plane
+ let yForce = -forceOfGravity.magnitude;
+ 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) +
+ forceOfGravity.magnitude) /
+ Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
+ }
+ if (coefficient != 0) {
+ setStartForces([forceOfGravity, normalForce, frictionForce]);
+ setUpdatedForces([forceOfGravity, normalForce, frictionForce]);
+ } else {
+ setStartForces([forceOfGravity, normalForce]);
+ setUpdatedForces([forceOfGravity, normalForce]);
+ }
+ };
+
+ // Change wedge height and width and weight position to match new wedge angle
+ const changeWedgeBasedOnNewAngle = (angle: number) => {
+ let width = 0;
+ let height = 0;
+ if (angle < 50) {
+ width = 400;
+ height = Math.tan((angle * Math.PI) / 180) * 400;
+ setWedgeWidth(width);
+ setWedgeHeight(height);
+ } else if (angle < 70) {
+ width = 200;
+ height = Math.tan((angle * Math.PI) / 180) * 200;
+ setWedgeWidth(width);
+ setWedgeHeight(height);
+ } else {
+ width = 100;
+ height = Math.tan((angle * Math.PI) / 180) * 100;
+ setWedgeWidth(width);
+ setWedgeHeight(height);
+ }
+
+ // update weight position based on updated wedge width/height
+ let yPos = (width - 50) * Math.tan((angle * Math.PI) / 180);
+ if (angle < 40) {
+ yPos += Math.sqrt(angle);
+ } else if (angle < 58) {
+ yPos += angle / 2;
+ } else if (angle < 68) {
+ yPos += angle;
+ } else if (angle < 70) {
+ yPos += angle * 1.3;
+ } else if (angle < 75) {
+ yPos += angle * 1.5;
+ } else if (angle < 78) {
+ yPos += angle * 2;
+ } else if (angle < 79) {
+ yPos += angle * 2.25;
+ } else if (angle < 80) {
+ yPos += angle * 2.6;
+ } else {
+ yPos += angle * 3;
+ }
+
+ setStartPosX(Math.round((xMax * 0.5 - 200) * 10) / 10);
+ setStartPosY(getDisplayYPos(yPos));
+ if (mode == "Freeform") {
+ updateForcesWithFriction(
+ Number(coefficientOfStaticFriction),
+ width,
+ height
+ );
+ }
+ };
+
+ // Helper function to go between display and real values
+ const getDisplayYPos = (yPos: number) => {
+ return yMax - yPos - 2 * 50 + 5;
+ };
+
+ // In review mode, update forces when coefficient of static friction changed
+ const updateReviewForcesBasedOnCoefficient = (coefficient: number) => {
+ let theta: number = Number(wedgeAngle);
+ let index =
+ selectedQuestion.variablesForQuestionSetup.indexOf("theta - max 45");
+ if (index >= 0) {
+ theta = questionVariables[index];
+ }
+ if (isNaN(theta)) {
+ return;
+ }
+ setReviewGravityMagnitude(forceOfGravity.magnitude);
+ setReviewGravityAngle(270);
+ setReviewNormalMagnitude(
+ forceOfGravity.magnitude * Math.cos((theta * Math.PI) / 180)
+ );
+ setReviewNormalAngle(90 - theta);
+ let yForce = -forceOfGravity.magnitude;
+ yForce +=
+ 9.81 *
+ Math.cos((theta * Math.PI) / 180) *
+ Math.sin(((90 - theta) * Math.PI) / 180);
+ yForce +=
+ coefficient *
+ 9.81 *
+ Math.cos((theta * Math.PI) / 180) *
+ Math.sin(((180 - theta) * Math.PI) / 180);
+ let friction = coefficient * 9.81 * Math.cos((theta * Math.PI) / 180);
+ if (yForce > 0) {
+ friction =
+ (-(forceOfGravity.magnitude * Math.cos((theta * Math.PI) / 180)) *
+ Math.sin(((90 - theta) * Math.PI) / 180) +
+ forceOfGravity.magnitude) /
+ Math.sin(((180 - theta) * Math.PI) / 180);
+ }
+ setReviewStaticMagnitude(friction);
+ setReviewStaticAngle(180 - theta);
+ };
+
+ // In review mode, update forces when wedge angle changed
+ const updateReviewForcesBasedOnAngle = (angle: number) => {
+ setReviewGravityMagnitude(9.81);
+ setReviewGravityAngle(270);
+ setReviewNormalMagnitude(9.81 * Math.cos((Number(angle) * Math.PI) / 180));
+ setReviewNormalAngle(90 - angle);
+ let yForce = -forceOfGravity.magnitude;
+ yForce +=
+ 9.81 *
+ Math.cos((Number(angle) * Math.PI) / 180) *
+ Math.sin(((90 - Number(angle)) * Math.PI) / 180);
+ yForce +=
+ reviewCoefficient *
+ 9.81 *
+ Math.cos((Number(angle) * Math.PI) / 180) *
+ Math.sin(((180 - Number(angle)) * Math.PI) / 180);
+ let friction =
+ reviewCoefficient * 9.81 * Math.cos((Number(angle) * Math.PI) / 180);
+ if (yForce > 0) {
+ friction =
+ (-(9.81 * Math.cos((Number(angle) * Math.PI) / 180)) *
+ Math.sin(((90 - Number(angle)) * Math.PI) / 180) +
+ forceOfGravity.magnitude) /
+ Math.sin(((180 - Number(angle)) * Math.PI) / 180);
+ }
+ setReviewStaticMagnitude(friction);
+ setReviewStaticAngle(180 - angle);
+ };
+
+ // Solve for the correct answers to the generated problem
+ const getAnswersToQuestion = (
+ question: QuestionTemplate,
+ questionVars: number[]
+ ) => {
+ const solutions: number[] = [];
+
+ let theta: number = Number(wedgeAngle);
+ let index = question.variablesForQuestionSetup.indexOf("theta - max 45");
+ if (index >= 0) {
+ theta = questionVars[index];
+ }
+ let muS: number = Number(coefficientOfStaticFriction);
+ index = question.variablesForQuestionSetup.indexOf(
+ "coefficient of static friction"
+ );
+ if (index >= 0) {
+ muS = questionVars[index];
+ }
+
+ for (let i = 0; i < question.answerSolutionDescriptions.length; i++) {
+ const description = question.answerSolutionDescriptions[i];
+ if (!isNaN(Number(description))) {
+ solutions.push(Number(description));
+ } else if (description == "solve normal force angle from wedge angle") {
+ solutions.push(90 - theta);
+ } else if (
+ description == "solve normal force magnitude from wedge angle"
+ ) {
+ solutions.push(
+ forceOfGravity.magnitude * Math.cos((theta / 180) * Math.PI)
+ );
+ } else if (
+ description ==
+ "solve static force magnitude from wedge angle given equilibrium"
+ ) {
+ let normalForceMagnitude =
+ forceOfGravity.magnitude * Math.cos((theta / 180) * Math.PI);
+ let normalForceAngle = 90 - theta;
+ let frictionForceAngle = 180 - theta;
+ let frictionForceMagnitude =
+ (-normalForceMagnitude *
+ Math.sin((normalForceAngle * Math.PI) / 180) +
+ 9.81) /
+ 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 =
+ forceOfGravity.magnitude * Math.cos((theta / 180) * Math.PI);
+ let normalForceAngle = 90 - theta;
+ let frictionForceAngle = 180 - theta;
+ let frictionForceMagnitude =
+ (-normalForceMagnitude *
+ Math.sin((normalForceAngle * Math.PI) / 180) +
+ 9.81) /
+ Math.sin((frictionForceAngle * Math.PI) / 180);
+ let frictionCoefficient = frictionForceMagnitude / normalForceMagnitude;
+ solutions.push(frictionCoefficient);
+ } else if (
+ description ==
+ "solve maximum wedge angle from coefficient of static friction given equilibrium"
+ ) {
+ solutions.push((Math.atan(muS) * 180) / Math.PI);
+ }
+ }
+ setSelectedSolutions(solutions);
+ return solutions;
+ };
+
+ // In review mode, check if input answers match correct answers and optionally generate alert
+ const checkAnswers = (showAlert: boolean = true) => {
+ let error: boolean = false;
+ let epsilon: number = 0.01;
+ if (selectedQuestion) {
+ for (let i = 0; i < selectedQuestion.answerParts.length; i++) {
+ if (selectedQuestion.answerParts[i] == "force of gravity") {
+ if (
+ Math.abs(reviewGravityMagnitude - selectedSolutions[i]) > epsilon
+ ) {
+ error = true;
+ }
+ } else if (selectedQuestion.answerParts[i] == "angle of gravity") {
+ if (Math.abs(reviewGravityAngle - selectedSolutions[i]) > epsilon) {
+ error = true;
+ }
+ } else if (selectedQuestion.answerParts[i] == "normal force") {
+ if (
+ Math.abs(reviewNormalMagnitude - selectedSolutions[i]) > epsilon
+ ) {
+ error = true;
+ }
+ } else if (selectedQuestion.answerParts[i] == "angle of normal force") {
+ if (Math.abs(reviewNormalAngle - selectedSolutions[i]) > epsilon) {
+ error = true;
+ }
+ } else if (
+ selectedQuestion.answerParts[i] == "force of static friction"
+ ) {
+ if (
+ Math.abs(reviewStaticMagnitude - selectedSolutions[i]) > epsilon
+ ) {
+ error = true;
+ }
+ } else if (
+ selectedQuestion.answerParts[i] == "angle of static friction"
+ ) {
+ if (Math.abs(reviewStaticAngle - selectedSolutions[i]) > epsilon) {
+ error = true;
+ }
+ } else if (
+ selectedQuestion.answerParts[i] == "coefficient of static friction"
+ ) {
+ if (
+ Math.abs(
+ Number(coefficientOfStaticFriction) - selectedSolutions[i]
+ ) > epsilon
+ ) {
+ error = true;
+ }
+ } else if (selectedQuestion.answerParts[i] == "wedge angle") {
+ if (Math.abs(Number(wedgeAngle) - selectedSolutions[i]) > epsilon) {
+ error = true;
+ }
+ }
+ }
+ }
+ if (showAlert) {
+ if (!error) {
+ setSimulationPaused(false);
+ setTimeout(() => {
+ setSimulationPaused(true);
+ }, 3000);
+ } else {
+ setSimulationPaused(false);
+ setTimeout(() => {
+ setSimulationPaused(true);
+ }, 3000);
+ }
+ }
+ if (selectedQuestion.goal == "noMovement") {
+ if (!error) {
+ setNoMovement(true);
+ } else {
+ setNoMovement(false);
+ }
+ }
+ };
+
+ const resetReviewValuesToDefault = () => {
+ // Reset all values to default
+ setReviewGravityMagnitude(0);
+ setReviewGravityAngle(0);
+ setReviewNormalMagnitude(0);
+ setReviewNormalAngle(0);
+ setReviewStaticMagnitude(0);
+ setReviewStaticAngle(0);
+ setCoefficientOfKineticFriction(0);
+ setSimulationPaused(true);
+ setAnswerInputFields();
+ };
+
+ // In review mode, edit force arrow sketch on mouse movement
+ const editForce = (element: VectorTemplate) => {
+ if (!sketching) {
+ const sketches = forceSketches.filter((sketch) => sketch != element);
+ setForceSketches(sketches);
+ setCurrentForceSketch(element);
+ setSketching(true);
+ }
+ };
+
+ // In review mode, used to delete force arrow sketch on SHIFT+click
+ const deleteForce = (element: VectorTemplate) => {
+ if (!sketching) {
+ const sketches = forceSketches.filter((sketch) => sketch != element);
+ setForceSketches(sketches);
+ }
+ };
+
+ // In review mode, reset problem variables and generate a new question
+ const generateNewQuestion = () => {
+ resetReviewValuesToDefault();
+
+ const vars: number[] = [];
+ let question: QuestionTemplate = questions.inclinePlane[0];
+
+ if (simulationType == "Inclined Plane") {
+ if (questionNumber == questions.inclinePlane.length - 1) {
+ setQuestionNumber(0);
+ } else {
+ setQuestionNumber(questionNumber + 1);
+ }
+ question = questions.inclinePlane[questionNumber];
+
+ let coefficient = 0;
+ let wedge = 0;
+
+ for (let i = 0; i < question.variablesForQuestionSetup.length; i++) {
+ if (question.variablesForQuestionSetup[i] == "theta - max 45") {
+ let randValue = Math.floor(Math.random() * 44 + 1);
+ vars.push(randValue);
+ wedge = randValue;
+ } else if (
+ question.variablesForQuestionSetup[i] ==
+ "coefficient of static friction"
+ ) {
+ let randValue = Math.round(Math.random() * 1000) / 1000;
+ vars.push(randValue);
+ coefficient = randValue;
+ }
+ }
+ setWedgeAngle(wedge);
+ changeWedgeBasedOnNewAngle(wedge);
+ setCoefficientOfStaticFriction(coefficient);
+ reviewCoefficient = coefficient;
+ }
+ let q = "";
+ for (let i = 0; i < question.questionSetup.length; i++) {
+ q += question.questionSetup[i];
+ if (i != question.questionSetup.length - 1) {
+ q += vars[i];
+ if (question.variablesForQuestionSetup[i].includes("theta")) {
+ q +=
+ " degree (≈" +
+ Math.round((1000 * (vars[i] * Math.PI)) / 180) / 1000 +
+ " rad)";
+ }
+ }
+ }
+ questionVariables = vars;
+ setSelectedQuestion(question);
+ setQuestionPartOne(q);
+ setQuestionPartTwo(question.question);
+ const answers = getAnswersToQuestion(question, vars);
+ generateInputFieldsForQuestion(false, question, answers);
+ };
+
+ // Generate answerInputFields for new review question
+ const generateInputFieldsForQuestion = (
+ showIcon: boolean = false,
+ question: QuestionTemplate = selectedQuestion,
+ answers: number[] = selectedSolutions
+ ) => {
+ let answerInput = [];
+ const d = new Date();
+ for (let i = 0; i < question.answerParts.length; i++) {
+ if (question.answerParts[i] == "force of gravity") {
+ setReviewGravityMagnitude(0);
+ answerInput.push(
+
+
+ FG
+
+ }
+ lowerBound={0}
+ changeValue={setReviewGravityMagnitude}
+ step={0.1}
+ unit={"N"}
+ upperBound={50}
+ value={reviewGravityMagnitude}
+ showIcon={showIcon}
+ correctValue={answers[i]}
+ />
+
+ );
+ } else if (question.answerParts[i] == "angle of gravity") {
+ setReviewGravityAngle(0);
+ answerInput.push(
+
+
+ θG
+
+ }
+ lowerBound={0}
+ changeValue={setReviewGravityAngle}
+ step={1}
+ unit={"°"}
+ upperBound={360}
+ value={reviewGravityAngle}
+ radianEquivalent={true}
+ showIcon={showIcon}
+ correctValue={answers[i]}
+ />
+
+ );
+ } else if (question.answerParts[i] == "normal force") {
+ setReviewNormalMagnitude(0);
+ answerInput.push(
+
+
+ FN
+
+ }
+ lowerBound={0}
+ changeValue={setReviewNormalMagnitude}
+ step={0.1}
+ unit={"N"}
+ upperBound={50}
+ value={reviewNormalMagnitude}
+ showIcon={showIcon}
+ correctValue={answers[i]}
+ />
+
+ );
+ } else if (question.answerParts[i] == "angle of normal force") {
+ setReviewNormalAngle(0);
+ answerInput.push(
+
+
+ θN
+
+ }
+ lowerBound={0}
+ changeValue={setReviewNormalAngle}
+ step={1}
+ unit={"°"}
+ upperBound={360}
+ value={reviewNormalAngle}
+ radianEquivalent={true}
+ showIcon={showIcon}
+ correctValue={answers[i]}
+ />
+
+ );
+ } else if (question.answerParts[i] == "force of static friction") {
+ setReviewStaticMagnitude(0);
+ answerInput.push(
+
+
+ F
+
+ Fs
+
+
+ }
+ lowerBound={0}
+ changeValue={setReviewStaticMagnitude}
+ step={0.1}
+ unit={"N"}
+ upperBound={50}
+ value={reviewStaticMagnitude}
+ showIcon={showIcon}
+ correctValue={answers[i]}
+ />
+
+ );
+ } else if (question.answerParts[i] == "angle of static friction") {
+ setReviewStaticAngle(0);
+ answerInput.push(
+
+
+ θ
+
+ Fs
+
+
+ }
+ lowerBound={0}
+ changeValue={setReviewStaticAngle}
+ step={1}
+ unit={"°"}
+ upperBound={360}
+ value={reviewStaticAngle}
+ radianEquivalent={true}
+ showIcon={showIcon}
+ correctValue={answers[i]}
+ />
+
+ );
+ } else if (question.answerParts[i] == "coefficient of static friction") {
+ updateReviewForcesBasedOnCoefficient(0);
+ answerInput.push(
+
+
+
+ μs
+
+ Coefficient of static friction; between 0 and 1
+
+ }
+ followCursor
+ >
+
+ μs
+
+
+ }
+ lowerBound={0}
+ changeValue={setCoefficientOfStaticFriction}
+ step={0.1}
+ unit={""}
+ upperBound={1}
+ value={coefficientOfStaticFriction}
+ effect={updateReviewForcesBasedOnCoefficient}
+ showIcon={showIcon}
+ correctValue={answers[i]}
+ />
+
+ );
+ } else if (question.answerParts[i] == "wedge angle") {
+ updateReviewForcesBasedOnAngle(0);
+ answerInput.push(
+
+
+ θ
+ Angle of incline plane from the ground, 0-49
+
+ }
+ followCursor
+ >
+ θ
+
+ }
+ lowerBound={0}
+ changeValue={setWedgeAngle}
+ step={1}
+ unit={"°"}
+ upperBound={49}
+ value={wedgeAngle}
+ effect={(val: number) => {
+ changeWedgeBasedOnNewAngle(val);
+ updateReviewForcesBasedOnAngle(val);
+ }}
+ radianEquivalent={true}
+ showIcon={showIcon}
+ correctValue={answers[i]}
+ />
+
+ );
+ }
+ }
+
+ setAnswerInputFields(
+
+ {answerInput}
+
+ );
+ };
+
+ // Remove floor and walls from simulation
+ const removeWalls = () => {
+ setWallPositions([]);
+ };
+
+ // Add floor and walls to simulation
+ const addWalls = () => {
+ if (wallPositions.length == 0) {
+ const walls: IWallProps[] = [];
+ walls.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 });
+ walls.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 });
+ walls.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 });
+ setWallPositions(walls);
+ }
+ };
+
+ // Use effect hook to handle mode/topic change
+ useEffect(() => {
+ if (mode == "Freeform") {
+ setShowForceMagnitudes(true);
+ if (simulationType == "One Weight") {
+ addWeight();
+ setStartPosY(yMin + 50);
+ setStartPosX((xMax + xMin - 50) / 2);
+ setUpdatedForces([forceOfGravity]);
+ setStartForces([forceOfGravity]);
+ addWalls();
+ setSimulationReset(!simulationReset);
+ } else if (simulationType == "Two Weights") {
+ addTwoWeights();
+ setStartPosY(yMax - 100);
+ setStartPosX((xMax + xMin - 200) / 2);
+ setStartPosY2(yMax - 100);
+ setStartPosX2((xMax + xMin + 200) / 2);
+ setUpdatedForces([forceOfGravity]);
+ setStartForces([forceOfGravity]);
+ addWalls();
+ setSimulationReset(!simulationReset);
+ // TODO
+ } else if (simulationType == "Inclined Plane") {
+ addWedge();
+ changeWedgeBasedOnNewAngle(26);
+ addWalls();
+ setStartForces([forceOfGravity]);
+ updateForcesWithFriction(Number(coefficientOfStaticFriction));
+ } else if (simulationType == "Pendulum") {
+ const length = 300;
+ const angle = 50;
+ const x = length * Math.cos(((90 - angle) * Math.PI) / 180);
+ const y = length * Math.sin(((90 - angle) * Math.PI) / 180);
+ const xPos = xMax / 2 - x - 50;
+ const yPos = y - 50 - 5;
+ addPendulum();
+ setStartPosX(xPos);
+ setStartPosY(yPos);
+ const mag = 9.81 * Math.cos((50 * Math.PI) / 180);
+ const forceOfTension: IForce = {
+ description: "Tension",
+ magnitude: mag,
+ directionInDegrees: 90 - angle,
+ };
+ setUpdatedForces([forceOfGravity, forceOfTension]);
+ setStartForces([forceOfGravity, forceOfTension]);
+ setPendulumAngle(50);
+ setPendulumLength(300);
+ setAdjustPendulumAngle({ angle: 50, length: 300 });
+ removeWalls();
+ }
+ } else if (mode == "Review") {
+ setShowForceMagnitudes(true);
+ if (simulationType == "Two Weights") {
+ // TODO
+ } else if (simulationType == "Inclined Plane") {
+ addWedge();
+ setUpdatedForces([]);
+ setStartForces([]);
+ addWalls();
+ }
+ setShowAcceleration(false);
+ setShowVelocity(false);
+ setShowForces(true);
+ generateNewQuestion();
+ } else if (mode == "Tutorial") {
+ setStepNumber(0);
+ if (simulationType == "One Weight") {
+ addWeight();
+ setStartPosY(yMin + 50);
+ setStartPosX((xMax + xMin - 50) / 2);
+ setSelectedTutorial(tutorials.freeWeight);
+ setSelectedTutorial(tutorials.freeWeight);
+ setStartForces(getForceFromJSON(tutorials.freeWeight.steps[0].forces));
+ setShowForceMagnitudes(tutorials.freeWeight.steps[0].showMagnitude);
+ addWalls();
+ } else if (simulationType == "Two Weights") {
+ // TODO
+ } else if (simulationType == "Pendulum") {
+ 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 = xMax / 2 - x - 50;
+ const yPos = y - 50 - 5;
+ addPendulum();
+ setStartPosX(xPos);
+ setStartPosY(yPos);
+ setSelectedTutorial(tutorials.pendulum);
+ setStartForces(getForceFromJSON(tutorials.pendulum.steps[0].forces));
+ setShowForceMagnitudes(tutorials.pendulum.steps[0].showMagnitude);
+ setPendulumAngle(50);
+ setPendulumLength(300);
+ setAdjustPendulumAngle({ angle: 30, length: 300 });
+ removeWalls();
+ } else if (simulationType == "Inclined Plane") {
+ addWedge();
+ setWedgeAngle(26);
+ changeWedgeBasedOnNewAngle(26);
+ setSelectedTutorial(tutorials.inclinePlane);
+ setStartForces(
+ getForceFromJSON(tutorials.inclinePlane.steps[0].forces)
+ );
+ setShowForceMagnitudes(tutorials.inclinePlane.steps[0].showMagnitude);
+ addWalls();
+ }
+ setSimulationReset(!simulationReset);
+ }
+ }, [simulationType, mode]);
+
+ const [showForceMagnitudes, setShowForceMagnitudes] = useState(true);
+
+ const getForceFromJSON = (
+ json: {
+ description: string;
+ magnitude: number;
+ directionInDegrees: number;
+ }[]
+ ): IForce[] => {
+ const forces: IForce[] = [];
+ for (let i = 0; i < json.length; i++) {
+ const force: IForce = {
+ description: json[i].description,
+ magnitude: json[i].magnitude,
+ directionInDegrees: json[i].directionInDegrees,
+ };
+ forces.push(force);
+ }
+ return forces;
+ };
+
+ // Use effect hook to handle force change in review mode
+ useEffect(() => {
+ if (mode == "Review") {
+ const forceOfGravityReview: IForce = {
+ description: "Gravity",
+ magnitude: reviewGravityMagnitude,
+ directionInDegrees: reviewGravityAngle,
+ };
+ const normalForceReview: IForce = {
+ description: "Normal Force",
+ magnitude: reviewNormalMagnitude,
+ directionInDegrees: reviewNormalAngle,
+ };
+ const staticFrictionForceReview: IForce = {
+ description: "Static Friction Force",
+ magnitude: reviewStaticMagnitude,
+ directionInDegrees: reviewStaticAngle,
+ };
+ setStartForces([
+ forceOfGravityReview,
+ normalForceReview,
+ staticFrictionForceReview,
+ ]);
+ setUpdatedForces([
+ forceOfGravityReview,
+ normalForceReview,
+ staticFrictionForceReview,
+ ]);
+ }
+ }, [
+ reviewGravityMagnitude,
+ reviewGravityAngle,
+ reviewNormalMagnitude,
+ reviewNormalAngle,
+ reviewStaticMagnitude,
+ reviewStaticAngle,
+ ]);
+
+ // Use effect to add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
+ useEffect(() => {
+ document.addEventListener("keydown", (e) => {
+ if (e.shiftKey) {
+ setDeleteMode(true);
+ }
+ });
+ document.addEventListener("keyup", (e) => {
+ if (e.shiftKey) {
+ setDeleteMode(false);
+ }
+ });
+ }, []);
+
+ // Timer for animating the simulation
+ setInterval(() => {
+ setTimer(timer + 1);
+ }, 60);
+
+ return (
+
+
+
{
+ if (sketching) {
+ const x1 = positionXDisplay + 50;
+ const y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50;
+ const x2 = e.clientX;
+ const y2 = e.clientY;
+ const height = Math.abs(y1 - y2) + 120;
+ const width = Math.abs(x1 - x2) + 120;
+ const top = Math.min(y1, y2) - 60;
+ const left = Math.min(x1, x2) - 60;
+ const x1Updated = x1 - left;
+ const x2Updated = x2 - left;
+ const y1Updated = y1 - top;
+ const y2Updated = y2 - top;
+ setCurrentForceSketch({
+ top: top,
+ left: left,
+ width: width,
+ height: height,
+ x1: x1Updated,
+ y1: y1Updated,
+ x2: x2Updated,
+ y2: y2Updated,
+ weightX: positionXDisplay,
+ weightY: positionYDisplay,
+ });
+ }
+ }}
+ onPointerDown={(e) => {
+ if (sketching && currentForceSketch) {
+ setSketching(false);
+ const sketches = forceSketches;
+ sketches.push(currentForceSketch);
+ setForceSketches(sketches);
+ setCurrentForceSketch(null);
+ }
+ }}
+ >
+
+
+ {!simulationPaused && (
+
+
+
+ )}
+
+
+
+
+
+
+
+ {showForces && currentForceSketch && simulationPaused && (
+
+ )}
+ {showForces &&
+ forceSketches.length > 0 &&
+ simulationPaused &&
+ forceSketches.map((element: VectorTemplate, index) => {
+ return (
+
+
+
+ );
+ })}
+ {weight && (
+
+ )}
+ {twoWeights && (
+
+ )}
+ {wedge && (
+
+ )}
+
+
+ {wallPositions.map((element, index) => {
+ return (
+
+ );
+ })}
+
+
+
+
+
+
+ {simulationPaused && mode != "Tutorial" && (
+
+ {
+ setSimulationPaused(false);
+ }}
+ >
+
+
+
+ )}
+ {!simulationPaused && mode != "Tutorial" && (
+
+ {
+ setSimulationPaused(true);
+ }}
+ >
+
+
+
+ )}
+ {simulationPaused && mode != "Tutorial" && (
+
+ {
+ setSimulationReset(!simulationReset);
+ }}
+ >
+
+
+
+ )}
+
+
+
+
+
+ {mode == "Review" && (
+
+ {!hintDialogueOpen && (
+
{
+ setHintDialogueOpen(true);
+ }}
+ sx={{
+ position: "fixed",
+ left: xMax - 50 + "px",
+ top: yMin + 14 + "px",
+ }}
+ >
+
+
+ )}
+
+
+
+
{questionPartOne}
+
{questionPartTwo}
+
+
{answerInputFields}
+
+
+ )}
+ {mode == "Tutorial" && (
+
+
+
Problem
+
{selectedTutorial.question}
+
+
+
{
+ let step = stepNumber - 1;
+ step = Math.max(step, 0);
+ step = Math.min(step, selectedTutorial.steps.length - 1);
+ setStepNumber(step);
+ setStartForces(
+ getForceFromJSON(selectedTutorial.steps[step].forces)
+ );
+ setUpdatedForces(
+ getForceFromJSON(selectedTutorial.steps[step].forces)
+ );
+ setShowForceMagnitudes(
+ selectedTutorial.steps[step].showMagnitude
+ );
+ }}
+ disabled={stepNumber == 0}
+ >
+
+
+
+
+ Step {stepNumber + 1}:{" "}
+ {selectedTutorial.steps[stepNumber].description}
+
+
{selectedTutorial.steps[stepNumber].content}
+
+
{
+ let step = stepNumber + 1;
+ step = Math.max(step, 0);
+ step = Math.min(step, selectedTutorial.steps.length - 1);
+ setStepNumber(step);
+ setStartForces(
+ getForceFromJSON(selectedTutorial.steps[step].forces)
+ );
+ setUpdatedForces(
+ getForceFromJSON(selectedTutorial.steps[step].forces)
+ );
+ setShowForceMagnitudes(
+ selectedTutorial.steps[step].showMagnitude
+ );
+ }}
+ disabled={stepNumber == selectedTutorial.steps.length - 1}
+ >
+
+
+
+
+
Resources
+ {simulationType == "One Weight" && (
+
+ )}
+ {simulationType == "Inclined Plane" && (
+
+ )}
+ {simulationType == "Pendulum" && (
+
+ )}
+
+
+ )}
+ {mode == "Review" && (
+
+
setMode("Tutorial")}
+ >
+ {" "}
+ Go to walkthrough{" "}
+
+
+
+
+
+
+ )}
+
+ {mode == "Freeform" && (
+
+
+
+ {!wedge && !pendulum && (
+
+ setElasticCollisions(!elasticCollisions)
+ }
+ />
+ }
+ label="Make collisions elastic"
+ labelPlacement="start"
+ />
+ )}
+ {!wedge && !pendulum && }
+ setShowForces(!showForces)}
+ defaultChecked
+ />
+ }
+ label="Show force vectors"
+ labelPlacement="start"
+ />
+ setShowAcceleration(!showAcceleration)}
+ />
+ }
+ label="Show acceleration vector"
+ labelPlacement="start"
+ />
+ setShowVelocity(!showVelocity)}
+ />
+ }
+ label="Show velocity vector"
+ labelPlacement="start"
+ />
+
+
+ {wedge && simulationPaused && (
+
+
+ θ
+ Angle of incline plane from the ground, 0-49
+
+ }
+ followCursor
+ >
+ θ
+
+ }
+ lowerBound={0}
+ changeValue={setWedgeAngle}
+ step={1}
+ unit={"°"}
+ upperBound={49}
+ value={wedgeAngle}
+ effect={changeWedgeBasedOnNewAngle}
+ radianEquivalent={true}
+ mode={"Freeform"}
+ />
+
+
+ μs
+
+ Coefficient of static friction, between 0 and 1
+
+ }
+ followCursor
+ >
+
+ μs
+
+
+ }
+ lowerBound={0}
+ changeValue={setCoefficientOfStaticFriction}
+ step={0.1}
+ unit={""}
+ upperBound={1}
+ value={coefficientOfStaticFriction}
+ effect={updateForcesWithFriction}
+ mode={"Freeform"}
+ />
+
+
+ μk
+
+ Coefficient of kinetic friction, between 0 and
+ coefficient of static friction
+
+ }
+ followCursor
+ >
+
+ μk
+
+
+ }
+ lowerBound={0}
+ changeValue={setCoefficientOfKineticFriction}
+ step={0.1}
+ unit={""}
+ upperBound={Number(coefficientOfStaticFriction)}
+ value={coefficientOfKineticFriction}
+ mode={"Freeform"}
+ />
+
+ )}
+ {wedge && !simulationPaused && (
+
+ θ: {Math.round(Number(wedgeAngle) * 100) / 100}° ≈{" "}
+ {Math.round(((Number(wedgeAngle) * Math.PI) / 180) * 100) /
+ 100}{" "}
+ rad
+
+ μ s: {coefficientOfStaticFriction}
+
+ μ k: {coefficientOfKineticFriction}
+
+ )}
+ {pendulum && !simulationPaused && (
+
+ θ: {Math.round(pendulumAngle * 100) / 100}° ≈{" "}
+ {Math.round(((pendulumAngle * Math.PI) / 180) * 100) / 100}{" "}
+ rad
+
+ )}
+ {pendulum && simulationPaused && (
+
+
+ θ
+ Pendulum angle offest from equilibrium
+
+ }
+ followCursor
+ >
+ θ
+
+ }
+ lowerBound={0}
+ changeValue={setPendulumAngle}
+ step={1}
+ unit={"°"}
+ upperBound={59}
+ value={pendulumAngle}
+ effect={(value) => {
+ if (pendulum) {
+ const mag =
+ 1 * 9.81 * Math.cos((value * Math.PI) / 180);
+
+ const forceOfTension: IForce = {
+ description: "Tension",
+ magnitude: mag,
+ directionInDegrees: 90 - value,
+ };
+ setUpdatedForces([forceOfGravity, forceOfTension]);
+ setAdjustPendulumAngle({
+ angle: value,
+ length: pendulumLength,
+ });
+ }
+ }}
+ radianEquivalent={true}
+ mode={"Freeform"}
+ />
+
+ Length
+ Pendulum rod length
+
+ }
+ followCursor
+ >
+ Length
+
+ }
+ lowerBound={0}
+ changeValue={setPendulumLength}
+ step={1}
+ unit={"m"}
+ upperBound={400}
+ value={pendulumLength}
+ effect={(value) => {
+ if (pendulum) {
+ setAdjustPendulumAngle({
+ angle: pendulumAngle,
+ length: value,
+ });
+ }
+ }}
+ radianEquivalent={false}
+ mode={"Freeform"}
+ />
+
+ )}
+
+ )}
+
+ {mode == "Freeform" && twoWeights &&
Red Weight
}
+ {mode == "Freeform" && weight && (
+
+
+
+ | |
+ X |
+ Y |
+
+
+ {
+ window.open(
+ "https://www.khanacademy.org/science/physics/two-dimensional-motion"
+ );
+ }}
+ >
+
+ Position
+ Equation: x1
+ =x
+ 0
+ +v
+ 0
+ t+0.5at
+ 2
+
+ Units: m
+
+ }
+ followCursor
+ >
+ Position
+
+ |
+
+ {(!simulationPaused || wedge) && (
+
+ {positionXDisplay} m
+
+ )}{" "}
+ {simulationPaused && !wedge && (
+ {
+ setDisplayChange({
+ xDisplay: value,
+ yDisplay: positionYDisplay,
+ });
+ }}
+ small={true}
+ mode={"Freeform"}
+ />
+ )}{" "}
+ |
+
+ {(!simulationPaused || wedge) && (
+
+ {positionYDisplay} m
+
+ )}{" "}
+ {simulationPaused && !wedge && (
+ {
+ setDisplayChange({
+ xDisplay: positionXDisplay,
+ yDisplay: value,
+ });
+ }}
+ small={true}
+ mode={"Freeform"}
+ />
+ )}{" "}
+ |
+
+
+ {
+ window.open(
+ "https://www.khanacademy.org/science/physics/two-dimensional-motion"
+ );
+ }}
+ >
+
+ Velocity
+ Equation: v1
+ =v
+ 0
+ +at
+
+ Units: m/s
+
+ }
+ followCursor
+ >
+ Velocity
+
+ |
+
+ {(!simulationPaused || pendulum || wedge) && (
+
+ {velocityXDisplay} m/s
+
+ )}{" "}
+ {simulationPaused && !pendulum && !wedge && (
+
+ setDisplayChange({
+ xDisplay: positionXDisplay,
+ yDisplay: positionYDisplay,
+ })
+ }
+ small={true}
+ mode={"Freeform"}
+ />
+ )}{" "}
+ |
+
+ {(!simulationPaused || pendulum || wedge) && (
+
+ {velocityYDisplay} m/s
+
+ )}{" "}
+ {simulationPaused && !pendulum && !wedge && (
+
+ setDisplayChange({
+ xDisplay: positionXDisplay,
+ yDisplay: positionYDisplay,
+ })
+ }
+ small={true}
+ mode={"Freeform"}
+ />
+ )}{" "}
+ |
+
+
+ {
+ window.open(
+ "https://www.khanacademy.org/science/physics/two-dimensional-motion"
+ );
+ }}
+ >
+
+
+ Acceleration
+
+ Equation: a=F/m
+
+ Units: m/s
+ 2
+
+ }
+ followCursor
+ >
+ Acceleration
+
+ |
+
+ {accelerationXDisplay} m/s2
+ |
+
+ {accelerationYDisplay} m/s2
+ |
+
+
+
+ )}
+
+ {/* {mode == "Freeform" &&
+ simulationElements.length > 0 &&
+ simulationElements[0].pendulum && (
+
+
+
+
+ | |
+ Value |
+
+
+ | Potential Energy |
+
+ {Math.round(
+ pendulumLength *
+ (1 - Math.cos(pendulumAngle)) *
+ 9.81 *
+ 10
+ ) / 10}{" "}
+ J
+ |
+
+
+ | Kinetic Energy |
+
+ {Math.round(
+ (Math.round(
+ pendulumLength *
+ (1 - Math.cos(startPendulumAngle)) *
+ 9.81 *
+ 10
+ ) /
+ 10 -
+ Math.round(
+ pendulumLength *
+ (1 - Math.cos(pendulumAngle)) *
+ 9.81 *
+ 10
+ ) /
+ 10) *
+ 10
+ ) / 10}{" "}
+ J
+ |
+
+
+ |
+ Total Energy
+ |
+
+ {Math.round(
+ pendulumLength *
+ (1 - Math.cos(startPendulumAngle)) *
+ 9.81 *
+ 10
+ ) / 10}{" "}
+ J
+ |
+
+
+
+
+ )}*/}
+
+
+
+
+ );
+}
+
+export default App;
diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss
index 2eb6e6ff0..f756d59fc 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.scss
+++ b/src/client/views/nodes/PhysicsSimulationBox.scss
@@ -1,3 +1,69 @@
-.physicsSimulationContainer {
-
-}
\ No newline at end of file
+* {
+ box-sizing: border-box;
+ font-size: 14px;
+}
+
+.mechanicsSimulationContainer {
+ height: 100vh;
+ width: 100vw;
+ display: flex;
+
+ .mechanicsSimulationContentContainer {
+ width: 70%;
+
+ .mechanicsSimulationButtons {
+ display: flex;
+ justify-content: space-between;
+ }
+ }
+
+ .mechanicsSimulationEquationContainer {
+ width: 30%;
+ padding: 1em;
+ display: flex;
+ flex-direction: column;
+
+ .mechanicsSimulationControls {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ .slider {
+ margin-top: 0.5em;
+ }
+ }
+}
+
+.coordinateSystem {
+ z-index: -100;
+}
+
+th,
+td {
+ border-collapse: collapse;
+ padding: 1em;
+}
+
+table {
+ min-width: 300px;
+}
+
+tr:nth-child(even) {
+ background-color: #d6eeee;
+}
+
+button {
+ z-index: 5000;
+}
+
+.wordProblemBox {
+ border-style: solid;
+ border-color: black;
+ border-width: 1px;
+ margin-top: 10px;
+ padding: 10px;
+}
+
+.answer-inactive {
+ pointer-events: none;
+}
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index b16bccdde..4a68ba5aa 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -3,6 +3,7 @@ import { FieldView, FieldViewProps } from './FieldView';
import React = require('react');
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { observer } from 'mobx-react';
+import App from './PhysicsSimulationApp';
export interface IForce {
description: string;
@@ -18,65 +19,17 @@ export interface IWallProps {
@observer
export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() {
- forceOfGravity: IForce = {
- description: "Gravity",
- magnitude: 9.81,
- directionInDegrees: 270,
-};
-
- // Logic for Dash integration
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }
constructor(props: any) {
super(props);
- this.state = {
- timer: 0,
- weight: true,
- pendulum: false,
- wedge: false,
- startPosX: 0,
- startPosY: 0,
- showVelocity: false,
- showAcceleration: false,
- showForces: false,
- elasticCollisions: false,
- updatedForces: [this.forceOfGravity],
- wallPositions: []
- }
}
- // Add one weight to the simulation
- addWeight = () => {
- this.setState({weight: true});
- this.setState({wedge: false});
- this.setState({pendulum: false});
- };
-
-// Remove floor and walls from simulation
-removeWalls = () => {
- this.setState({wallPositions: []});
-};
-
-// Add floor and walls to simulation
-addWalls = () => {
- const walls: IWallProps[] = [];
- walls.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 });
- walls.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 });
- walls.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 });
- this.setState({wallPositions: walls});
-};
-
- // Timer for animating the simulation
- // setInterval(() => {
- // const time = this.timer ?? 0
- // this.setState({timer: time+1});
- // }, 60);
-
render () {
return (
-
-
+
+
);
}
}
\ No newline at end of file
diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx
new file mode 100644
index 000000000..c63538cc0
--- /dev/null
+++ b/src/client/views/nodes/PhysicsSimulationWall.tsx
@@ -0,0 +1,35 @@
+import { useState, useEffect } from "react";
+import "./Weight.scss";
+
+export interface Force {
+ magnitude: number;
+ directionInDegrees: number;
+}
+export interface IWallProps {
+ length: number;
+ xPos: number;
+ yPos: number;
+ angleInDegrees: number;
+}
+
+export const Wall = (props: IWallProps) => {
+ const { length, xPos, yPos, angleInDegrees } = props;
+
+ let wallStyle = {
+ width: length + "%",
+ height: 0.5 + "vw",
+ position: "absolute" as "absolute",
+ left: xPos + "%",
+ top: yPos + "%",
+ backgroundColor: "#6c7b8b",
+ zIndex: -1000,
+ margin: 0,
+ padding: 0,
+ };
+ if (angleInDegrees != 0) {
+ wallStyle.width = 0.5 + "vw";
+ wallStyle.height = length + "%";
+ }
+
+ return ;
+};
diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx
new file mode 100644
index 000000000..af01c1c51
--- /dev/null
+++ b/src/client/views/nodes/PhysicsSimulationWedge.tsx
@@ -0,0 +1,64 @@
+import { useState, useEffect, useCallback } from "react";
+import "./Wedge.scss";
+
+export interface IWedgeProps {
+ startHeight: number;
+ startWidth: number;
+ startLeft: number;
+}
+
+export const Wedge = (props: IWedgeProps) => {
+ const { startHeight, startWidth, startLeft } = props;
+
+ const [angleInRadians, setAngleInRadians] = useState(
+ Math.atan(startHeight / startWidth)
+ );
+ const [left, setLeft] = useState(startLeft);
+ const [coordinates, setCoordinates] = useState("");
+
+ const color = "#deb887";
+
+ useEffect(() => {
+ const coordinatePair1 =
+ Math.round(left) + "," + Math.round(window.innerHeight * 0.8) + " ";
+ const coordinatePair2 =
+ Math.round(left + startWidth) +
+ "," +
+ Math.round(window.innerHeight * 0.8) +
+ " ";
+ const coordinatePair3 =
+ Math.round(left) +
+ "," +
+ Math.round(window.innerHeight * 0.8 - startHeight);
+ const coord = coordinatePair1 + coordinatePair2 + coordinatePair3;
+ setCoordinates(coord);
+ }, [left, startWidth, startHeight]);
+
+ useEffect(() => {
+ setAngleInRadians(Math.atan(startHeight / startWidth));
+ }, [startWidth, startHeight]);
+
+ return (
+
+
+
+
+ {Math.round(((angleInRadians * 180) / Math.PI) * 100) / 100}°
+
+
+ );
+};
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
new file mode 100644
index 000000000..227f20901
--- /dev/null
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -0,0 +1,913 @@
+import { InputAdornment, TextField } from "@mui/material";
+import { useEffect, useState } from "react";
+import { IWallProps } from "./PhysicsSimulationWall";
+import { Wedge } from "./PhysicsSimulationWedge";
+
+export interface IForce {
+ description: string;
+ magnitude: number;
+ directionInDegrees: number;
+}
+export interface IWeightProps {
+ adjustPendulumAngle: { angle: number; length: number };
+ color: string;
+ displayXPosition: number;
+ displayYPosition: number;
+ displayXVelocity: number;
+ displayYVelocity: number;
+ elasticCollisions: boolean;
+ startForces: IForce[];
+ incrementTime: number;
+ mass: number;
+ paused: boolean;
+ pendulum: boolean;
+ pendulumLength: number;
+ wedge: boolean;
+ radius: number;
+ reset: boolean;
+ setDisplayXAcceleration: (val: number) => any;
+ setDisplayXPosition: (val: number) => any;
+ setDisplayXVelocity: (val: number) => any;
+ setDisplayYAcceleration: (val: number) => any;
+ setDisplayYPosition: (val: number) => any;
+ setDisplayYVelocity: (val: number) => any;
+ setPaused: (bool: boolean) => any;
+ setPendulumAngle: (val: number) => any;
+ setPendulumLength: (val: number) => any;
+ setStartPendulumAngle: (val: number) => any;
+ showAcceleration: boolean;
+ mode: string;
+ noMovement: boolean;
+ pendulumAngle: number;
+ setSketching: (val: boolean) => any;
+ showForces: boolean;
+ showForceMagnitudes: boolean;
+ showVelocity: boolean;
+ startPosX: number;
+ startPosY: number;
+ startVelX?: number;
+ startVelY?: number;
+ timestepSize: number;
+ updateDisplay: { xDisplay: number; yDisplay: number };
+ updatedForces: IForce[];
+ setUpdatedForces: (val: IForce[]) => any;
+ walls: IWallProps[];
+ coefficientOfKineticFriction: number;
+ wedgeWidth: number;
+ wedgeHeight: number;
+}
+
+export const Weight = (props: IWeightProps) => {
+ const {
+ adjustPendulumAngle,
+ color,
+ displayXPosition,
+ displayYPosition,
+ displayXVelocity,
+ displayYVelocity,
+ elasticCollisions,
+ startForces,
+ incrementTime,
+ mass,
+ paused,
+ pendulum,
+ pendulumLength,
+ wedge,
+ radius,
+ mode,
+ noMovement,
+ pendulumAngle,
+ reset,
+ setSketching,
+ setDisplayXAcceleration,
+ setDisplayXPosition,
+ setDisplayXVelocity,
+ setDisplayYAcceleration,
+ setDisplayYPosition,
+ setDisplayYVelocity,
+ setPaused,
+ setPendulumAngle,
+ setPendulumLength,
+ setStartPendulumAngle,
+ showAcceleration,
+ showForces,
+ showForceMagnitudes,
+ showVelocity,
+ startPosX,
+ startPosY,
+ startVelX,
+ startVelY,
+ timestepSize,
+ updateDisplay,
+ updatedForces,
+ setUpdatedForces,
+ walls,
+ coefficientOfKineticFriction,
+ wedgeWidth,
+ wedgeHeight,
+ } = props;
+
+ // Constants
+ const draggable = !wedge && mode == "Freeform";
+ const epsilon = 0.0001;
+
+ const forceOfGravity: IForce = {
+ description: "Gravity",
+ magnitude: mass * 9.81,
+ directionInDegrees: 270,
+ };
+ const xMax = window.innerWidth * 0.7;
+ const xMin = 0;
+ const yMax = window.innerHeight * 0.8;
+ const yMin = 0;
+
+ // State hooks
+ const [dragging, setDragging] = useState(false);
+ const [kineticFriction, setKineticFriction] = useState(false);
+ const [updatedStartPosX, setUpdatedStartPosX] = useState(startPosX);
+ const [updatedStartPosY, setUpdatedStartPosY] = useState(startPosY);
+ const [xPosition, setXPosition] = useState(startPosX);
+ const [xVelocity, setXVelocity] = useState(startVelX ?? 0);
+ const [yPosition, setYPosition] = useState(startPosY);
+ const [yVelocity, setYVelocity] = useState(startVelY ?? 0);
+
+ // Helper function to go between display and real values
+ const getDisplayYPos = (yPos: number) => {
+ return yMax - yPos - 2 * radius + 5;
+ };
+ const getYPosFromDisplay = (yDisplay: number) => {
+ return yMax - yDisplay - 2 * radius + 5;
+ };
+
+ // Set display values based on real values
+ const setYPosDisplay = (yPos: number) => {
+ const displayPos = getDisplayYPos(yPos);
+ setDisplayYPosition(Math.round(displayPos * 100) / 100);
+ };
+ const setXPosDisplay = (xPos: number) => {
+ setDisplayXPosition(Math.round(xPos * 100) / 100);
+ };
+ const setYVelDisplay = (yVel: number) => {
+ setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100);
+ };
+ const setXVelDisplay = (xVel: number) => {
+ setDisplayXVelocity(Math.round(xVel * 100) / 100);
+ };
+
+ const setDisplayValues = (
+ xPos: number = xPosition,
+ yPos: number = yPosition,
+ xVel: number = xVelocity,
+ yVel: number = yVelocity
+ ) => {
+ setYPosDisplay(yPos);
+ setXPosDisplay(xPos);
+ setYVelDisplay(yVel);
+ setXVelDisplay(xVel);
+ setDisplayYAcceleration(
+ (-1 * Math.round(getNewAccelerationY(updatedForces) * 100)) / 100
+ );
+ setDisplayXAcceleration(
+ Math.round(getNewAccelerationX(updatedForces) * 100) / 100
+ );
+ };
+
+ // When display values updated by user, update real values
+ useEffect(() => {
+ if (updateDisplay.xDisplay != xPosition) {
+ let x = updateDisplay.xDisplay;
+ x = Math.max(0, x);
+ x = Math.min(x, xMax - 2 * radius);
+ setUpdatedStartPosX(x);
+ setXPosition(x);
+ setDisplayXPosition(x);
+ }
+
+ if (updateDisplay.yDisplay != getDisplayYPos(yPosition)) {
+ let y = updateDisplay.yDisplay;
+ y = Math.max(0, y);
+ y = Math.min(y, yMax - 2 * radius);
+ setDisplayYPosition(y);
+ let coordinatePosition = getYPosFromDisplay(y);
+ setUpdatedStartPosY(coordinatePosition);
+ setYPosition(coordinatePosition);
+ }
+
+ if (displayXVelocity != xVelocity) {
+ let x = displayXVelocity;
+ setXVelocity(x);
+ setDisplayXVelocity(x);
+ }
+
+ if (displayYVelocity != -yVelocity) {
+ let y = displayYVelocity;
+ setYVelocity(-y);
+ setDisplayYVelocity(y);
+ }
+ }, [updateDisplay]);
+
+ // Check for collisions and update
+ useEffect(() => {
+ if (!paused && !noMovement) {
+ let collisions = false;
+ if (!pendulum) {
+ const collisionsWithGround = checkForCollisionsWithGround();
+ const collisionsWithWalls = checkForCollisionsWithWall();
+ collisions = collisionsWithGround || collisionsWithWalls;
+ }
+ if (!collisions) {
+ update();
+ }
+ setDisplayValues();
+ }
+ }, [incrementTime]);
+
+ useEffect(() => {
+ resetEverything();
+ }, [reset]);
+
+ useEffect(() => {
+ setXVelocity(startVelX ?? 0);
+ setYVelocity(startVelY ?? 0);
+ setDisplayValues();
+ }, [startForces]);
+
+ const resetEverything = () => {
+ setKineticFriction(false);
+ setXPosition(updatedStartPosX);
+ setYPosition(updatedStartPosY);
+ setXVelocity(startVelX ?? 0);
+ setYVelocity(startVelY ?? 0);
+ setUpdatedForces(startForces);
+ setDisplayValues();
+ };
+
+ // Change pendulum angle based on input field
+ useEffect(() => {
+ let length = adjustPendulumAngle.length;
+ const x =
+ length * Math.cos(((90 - adjustPendulumAngle.angle) * Math.PI) / 180);
+ const y =
+ length * Math.sin(((90 - adjustPendulumAngle.angle) * Math.PI) / 180);
+ const xPos = xMax / 2 - x - radius;
+ const yPos = y - radius - 5;
+ setXPosition(xPos);
+ setYPosition(yPos);
+ setUpdatedStartPosX(xPos);
+ setUpdatedStartPosY(yPos);
+ setPendulumAngle(adjustPendulumAngle.angle);
+ setPendulumLength(adjustPendulumAngle.length);
+ }, [adjustPendulumAngle]);
+
+ const getNewAccelerationX = (forceList: IForce[]) => {
+ let newXAcc = 0;
+ forceList.forEach((force) => {
+ newXAcc +=
+ (force.magnitude *
+ Math.cos((force.directionInDegrees * Math.PI) / 180)) /
+ mass;
+ });
+ return newXAcc;
+ };
+
+ const getNewAccelerationY = (forceList: IForce[]) => {
+ let newYAcc = 0;
+ forceList.forEach((force) => {
+ newYAcc +=
+ (-1 *
+ (force.magnitude *
+ Math.sin((force.directionInDegrees * Math.PI) / 180))) /
+ mass;
+ });
+ return newYAcc;
+ };
+
+ const getNewForces = (
+ xPos: number,
+ yPos: number,
+ xVel: number,
+ yVel: number
+ ) => {
+ if (!pendulum) {
+ return updatedForces;
+ }
+ const x = xMax / 2 - xPos - radius;
+ const y = yPos + 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);
+ setPendulumAngle(oppositeAngle);
+ setPendulumLength(Math.sqrt(x * x + y * y));
+
+ const mag =
+ mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) +
+ (mass * (xVel * xVel + yVel * yVel)) / pendulumLength;
+
+ const forceOfTension: IForce = {
+ description: "Tension",
+ magnitude: mag,
+ directionInDegrees: angle,
+ };
+
+ return [forceOfGravity, forceOfTension];
+ };
+
+ const getNewPosition = (pos: number, vel: number) => {
+ return pos + vel * timestepSize;
+ };
+
+ const getNewVelocity = (vel: number, acc: number) => {
+ return vel + acc * timestepSize;
+ };
+
+ const checkForCollisionsWithWall = () => {
+ let collision = false;
+ const minX = xPosition;
+ const maxX = xPosition + 2 * radius;
+ const containerWidth = window.innerWidth;
+ if (xVelocity != 0) {
+ walls.forEach((wall) => {
+ if (wall.angleInDegrees == 90) {
+ const wallX = (wall.xPos / 100) * window.innerWidth;
+ if (wall.xPos < 0.35) {
+ if (minX <= wallX) {
+ if (elasticCollisions) {
+ setXVelocity(-xVelocity);
+ } else {
+ setXVelocity(0);
+ setXPosition(wallX + 5);
+ }
+ collision = true;
+ }
+ } else {
+ if (maxX >= wallX) {
+ if (elasticCollisions) {
+ setXVelocity(-xVelocity);
+ } else {
+ setXVelocity(0);
+ setXPosition(wallX - 2 * radius + 5);
+ }
+ collision = true;
+ }
+ }
+ }
+ });
+ }
+ return collision;
+ };
+
+ const checkForCollisionsWithGround = () => {
+ let collision = false;
+ const maxY = yPosition + 2 * radius;
+ if (yVelocity > 0) {
+ walls.forEach((wall) => {
+ if (wall.angleInDegrees == 0) {
+ const groundY = (wall.yPos / 100) * window.innerHeight;
+ if (maxY >= groundY) {
+ if (elasticCollisions) {
+ setYVelocity(-yVelocity);
+ } else {
+ setYVelocity(0);
+ setYPosition(groundY - 2 * radius + 5);
+ const forceOfGravity: IForce = {
+ description: "Gravity",
+ magnitude: 9.81 * mass,
+ directionInDegrees: 270,
+ };
+ const normalForce: IForce = {
+ description: "Normal force",
+ magnitude: 9.81 * mass,
+ directionInDegrees: wall.angleInDegrees + 90,
+ };
+ setUpdatedForces([forceOfGravity, normalForce]);
+ }
+ collision = true;
+ }
+ }
+ });
+ }
+ return collision;
+ };
+
+ useEffect(() => {
+ if (wedge && xVelocity != 0 && mode != "Review" && !kineticFriction) {
+ setKineticFriction(true);
+ //switch from static to kinetic friction
+ const normalForce: IForce = {
+ description: "Normal Force",
+ magnitude:
+ forceOfGravity.magnitude *
+ Math.cos(Math.atan(wedgeHeight / wedgeWidth)),
+ directionInDegrees:
+ 180 - 90 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI,
+ };
+ let frictionForce: IForce = {
+ description: "Kinetic Friction Force",
+ magnitude:
+ coefficientOfKineticFriction *
+ forceOfGravity.magnitude *
+ Math.cos(Math.atan(wedgeHeight / wedgeWidth)),
+ directionInDegrees:
+ 180 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI,
+ };
+ // reduce magnitude of friction force if necessary such that block cannot slide up plane
+ let yForce = -forceOfGravity.magnitude;
+ 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) +
+ forceOfGravity.magnitude) /
+ Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
+ }
+ if (coefficientOfKineticFriction != 0) {
+ setUpdatedForces([forceOfGravity, normalForce, frictionForce]);
+ } else {
+ setUpdatedForces([forceOfGravity, normalForce]);
+ }
+ }
+ }, [xVelocity]);
+
+ const update = () => {
+ // RK4 update
+ let xPos = xPosition;
+ let yPos = yPosition;
+ let xVel = xVelocity;
+ let yVel = yVelocity;
+ for (let i = 0; i < 60; i++) {
+ let forces1 = getNewForces(xPos, yPos, xVel, yVel);
+ const xAcc1 = getNewAccelerationX(forces1);
+ const yAcc1 = getNewAccelerationY(forces1);
+ const xVel1 = getNewVelocity(xVel, xAcc1);
+ const yVel1 = getNewVelocity(yVel, yAcc1);
+
+ let xVel2 = getNewVelocity(xVel, xAcc1 / 2);
+ let yVel2 = getNewVelocity(yVel, yAcc1 / 2);
+ let xPos2 = getNewPosition(xPos, xVel1 / 2);
+ let yPos2 = getNewPosition(yPos, yVel1 / 2);
+ const forces2 = getNewForces(xPos2, yPos2, xVel2, yVel2);
+ const xAcc2 = getNewAccelerationX(forces2);
+ const yAcc2 = getNewAccelerationY(forces2);
+ xVel2 = getNewVelocity(xVel2, xAcc2);
+ yVel2 = getNewVelocity(yVel2, yAcc2);
+ xPos2 = getNewPosition(xPos2, xVel2);
+ yPos2 = getNewPosition(yPos2, yVel2);
+
+ let xVel3 = getNewVelocity(xVel, xAcc2 / 2);
+ let yVel3 = getNewVelocity(yVel, yAcc2 / 2);
+ let xPos3 = getNewPosition(xPos, xVel2 / 2);
+ let yPos3 = getNewPosition(yPos, yVel2 / 2);
+ const forces3 = getNewForces(xPos3, yPos3, xVel3, yVel3);
+ const xAcc3 = getNewAccelerationX(forces3);
+ const yAcc3 = getNewAccelerationY(forces3);
+ xVel3 = getNewVelocity(xVel3, xAcc3);
+ yVel3 = getNewVelocity(yVel3, yAcc3);
+ xPos3 = getNewPosition(xPos3, xVel3);
+ yPos3 = getNewPosition(yPos3, yVel3);
+
+ let xVel4 = getNewVelocity(xVel, xAcc3);
+ let yVel4 = getNewVelocity(yVel, yAcc3);
+ let xPos4 = getNewPosition(xPos, xVel3);
+ let yPos4 = getNewPosition(yPos, yVel3);
+ const forces4 = getNewForces(xPos4, yPos4, xVel4, yVel4);
+ const xAcc4 = getNewAccelerationX(forces4);
+ const yAcc4 = getNewAccelerationY(forces4);
+ xVel4 = getNewVelocity(xVel4, xAcc4);
+ yVel4 = getNewVelocity(yVel4, yAcc4);
+ xPos4 = getNewPosition(xPos4, xVel4);
+ yPos4 = getNewPosition(yPos4, yVel4);
+
+ xVel +=
+ timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0);
+ yVel +=
+ timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0);
+ xPos +=
+ timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0);
+ yPos +=
+ timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0);
+ }
+
+ setXVelocity(xVel);
+ setYVelocity(yVel);
+ setXPosition(xPos);
+ setYPosition(yPos);
+ setUpdatedForces(getNewForces(xPos, yPos, xVel, yVel));
+ };
+
+ let weightStyle = {
+ backgroundColor: color,
+ borderStyle: "solid",
+ borderColor: "black",
+ position: "absolute" as "absolute",
+ left: xPosition + "px",
+ top: yPosition + "px",
+ width: 2 * radius + "px",
+ height: 2 * radius + "px",
+ borderRadius: 50 + "%",
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center",
+ touchAction: "none",
+ };
+ if (dragging) {
+ weightStyle.borderColor = "lightblue";
+ }
+
+ const [clickPositionX, setClickPositionX] = useState(0);
+ const [clickPositionY, setClickPositionY] = useState(0);
+ const labelBackgroundColor = `rgba(255,255,255,0.5)`;
+
+ // Update x start position
+ useEffect(() => {
+ setUpdatedStartPosX(startPosX);
+ setXPosition(startPosX);
+ setXPosDisplay(startPosX);
+ }, [startPosX]);
+
+ // Update y start position
+ useEffect(() => {
+ setUpdatedStartPosY(startPosY);
+ setYPosition(startPosY);
+ setYPosDisplay(startPosY);
+ }, [startPosY]);
+
+ return (
+
+
{
+ if (draggable) {
+ e.preventDefault();
+ setPaused(true);
+ setDragging(true);
+ setClickPositionX(e.clientX);
+ setClickPositionY(e.clientY);
+ } else if (mode == "Review") {
+ setSketching(true);
+ }
+ }}
+ onPointerMove={(e) => {
+ e.preventDefault();
+ if (dragging) {
+ let newY = yPosition + e.clientY - clickPositionY;
+ if (newY > yMax - 2 * radius) {
+ newY = yMax - 2 * radius;
+ }
+
+ let newX = xPosition + e.clientX - clickPositionX;
+ if (newX > xMax - 2 * radius) {
+ newX = xMax - 2 * radius;
+ } else if (newX < 0) {
+ newX = 0;
+ }
+
+ setXPosition(newX);
+ setYPosition(newY);
+ setUpdatedStartPosX(newX);
+ setUpdatedStartPosY(newY);
+ setDisplayYPosition(
+ Math.round((yMax - 2 * radius - newY + 5) * 100) / 100
+ );
+ setClickPositionX(e.clientX);
+ setClickPositionY(e.clientY);
+ setDisplayValues();
+ }
+ }}
+ onPointerUp={(e) => {
+ if (dragging) {
+ e.preventDefault();
+ if (!pendulum) {
+ resetEverything();
+ }
+ setDragging(false);
+ let newY = yPosition + e.clientY - clickPositionY;
+ if (newY > yMax - 2 * radius) {
+ newY = yMax - 2 * radius;
+ }
+
+ let newX = xPosition + e.clientX - clickPositionX;
+ if (newX > xMax - 2 * radius) {
+ newX = xMax - 2 * radius;
+ } else if (newX < 0) {
+ newX = 0;
+ }
+ if (pendulum) {
+ const x = xMax / 2 - newX - radius;
+ const y = newY + 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);
+ setPendulumAngle(oppositeAngle);
+ setPendulumLength(Math.sqrt(x * x + y * y));
+ const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180);
+ const forceOfTension: IForce = {
+ description: "Tension",
+ magnitude: mag,
+ directionInDegrees: angle,
+ };
+
+ setKineticFriction(false);
+ setXVelocity(startVelX ?? 0);
+ setYVelocity(startVelY ?? 0);
+ setDisplayValues();
+ setUpdatedForces([forceOfGravity, forceOfTension]);
+ }
+ }
+ }}
+ >
+
+
+ {pendulum && (
+
+
+ {!dragging && (
+
+
+ {Math.round(pendulumLength)} m
+
+
+ {Math.round(pendulumAngle * 100) / 100}°
+
+
+ )}
+
+ )}
+ {!dragging && showAcceleration && (
+
+
+
+
+
+ {Math.round(
+ 100 *
+ Math.sqrt(
+ Math.pow(getNewAccelerationX(updatedForces) * 3, 2) +
+ Math.pow(getNewAccelerationY(updatedForces) * 3, 2)
+ )
+ ) / 100}{" "}
+ m/s2
+
+
+
+
+ )}
+ {!dragging && showVelocity && (
+
+
+
+
+
+ {Math.round(
+ 100 * Math.sqrt(xVelocity * xVelocity + yVelocity * yVelocity)
+ ) / 100}{" "}
+ m/s
+
+
+
+
+ )}
+ {!dragging &&
+ showForces &&
+ updatedForces.map((force, index) => {
+ if (force.magnitude < epsilon) {
+ return;
+ }
+ let arrowStartY: number = yPosition + radius;
+ const arrowStartX: number = xPosition + 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, yMax + 50);
+ labelTop = Math.max(labelTop, yMin);
+ labelLeft = Math.min(labelLeft, xMax - 60);
+ labelLeft = Math.max(labelLeft, xMin);
+
+ return (
+
+
+
+ {force.description &&
{force.description}
}
+ {!force.description &&
Force
}
+ {showForceMagnitudes && (
+
{Math.round(100 * force.magnitude) / 100} N
+ )}
+
+
+ );
+ })}
+
+ );
+};
--
cgit v1.2.3-70-g09d2
From 136d946b88ff817c2dd738553ddb2aea0a11f0e7 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Mon, 30 Jan 2023 14:29:43 -0500
Subject: remove extraneous code
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 1353 +-------------------
src/client/views/nodes/PhysicsSimulationBox.scss | 7 +
src/client/views/nodes/PhysicsSimulationWall.tsx | 1 -
src/client/views/nodes/PhysicsSimulationWedge.tsx | 2 +-
src/client/views/nodes/PhysicsSimulationWeight.tsx | 1 -
5 files changed, 27 insertions(+), 1337 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index 7486aa88d..0a39b3291 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -1,51 +1,8 @@
-import AddIcon from "@mui/icons-material/Add";
-import AddCircleIcon from "@mui/icons-material/AddCircle";
-import ClearIcon from "@mui/icons-material/Clear";
-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 { SelectChangeEvent } from "@mui/material/Select";
-import {
- Alert,
- Box,
- Button,
- Checkbox,
- CircularProgress,
- Dialog,
- DialogTitle,
- DialogContent,
- DialogContentText,
- DialogActions,
- Divider,
- FormControl,
- FormControlLabel,
- FormGroup,
- IconButton,
- InputAdornment,
- InputLabel,
- LinearProgress,
- List,
- ListItem,
- ListItemButton,
- ListItemIcon,
- ListItemText,
- MenuItem,
- Popover,
- Select,
- Stack,
- TextField,
- Tooltip,
-} from "@mui/material";
-import { styled } from "@mui/material/styles";
-import { tooltipClasses, TooltipProps } from "@mui/material/Tooltip";
-import Typography from "@mui/material/Typography";
import React, { useEffect, useState } from "react";
import "./PhysicsSimulationBox.scss";
import { IForce, Weight } from "./PhysicsSimulationWeight";
-import { Description } from "@mui/icons-material";
+import {Wall, IWallProps } from "./PhysicsSimulationWall"
+import {Wedge} from "./PhysicsSimulationWedge"
interface VectorTemplate {
top: number;
@@ -91,17 +48,6 @@ function App() {
magnitude: gravityMagnitude,
directionInDegrees: 270,
};
- const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => (
-
- ))(({ theme }) => ({
- [`& .${tooltipClasses.tooltip}`]: {
- backgroundColor: "#f5f5f9",
- color: "rgba(0, 0, 0, 0.87)",
- maxWidth: 220,
- fontSize: theme.typography.pxToRem(12),
- border: "1px solid #dadde9",
- },
- }));
const xMin = 0;
const yMin = 0;
const xMax = window.innerWidth * 0.7;
@@ -165,12 +111,6 @@ function App() {
const [reviewNormalMagnitude, setReviewNormalMagnitude] = useState(0);
const [reviewStaticAngle, setReviewStaticAngle] = useState(0);
const [reviewStaticMagnitude, setReviewStaticMagnitude] = useState(0);
- const [selectedQuestion, setSelectedQuestion] = useState(
- questions.inclinePlane[0]
- );
- const [selectedTutorial, setSelectedTutorial] = useState(
- tutorials.inclinePlane
- );
const [questionPartTwo, setQuestionPartTwo] = useState("");
const [selectedSolutions, setSelectedSolutions] = useState([]);
const [showAcceleration, setShowAcceleration] = useState(false);
@@ -333,244 +273,7 @@ function App() {
const getDisplayYPos = (yPos: number) => {
return yMax - yPos - 2 * 50 + 5;
};
-
- // In review mode, update forces when coefficient of static friction changed
- const updateReviewForcesBasedOnCoefficient = (coefficient: number) => {
- let theta: number = Number(wedgeAngle);
- let index =
- selectedQuestion.variablesForQuestionSetup.indexOf("theta - max 45");
- if (index >= 0) {
- theta = questionVariables[index];
- }
- if (isNaN(theta)) {
- return;
- }
- setReviewGravityMagnitude(forceOfGravity.magnitude);
- setReviewGravityAngle(270);
- setReviewNormalMagnitude(
- forceOfGravity.magnitude * Math.cos((theta * Math.PI) / 180)
- );
- setReviewNormalAngle(90 - theta);
- let yForce = -forceOfGravity.magnitude;
- yForce +=
- 9.81 *
- Math.cos((theta * Math.PI) / 180) *
- Math.sin(((90 - theta) * Math.PI) / 180);
- yForce +=
- coefficient *
- 9.81 *
- Math.cos((theta * Math.PI) / 180) *
- Math.sin(((180 - theta) * Math.PI) / 180);
- let friction = coefficient * 9.81 * Math.cos((theta * Math.PI) / 180);
- if (yForce > 0) {
- friction =
- (-(forceOfGravity.magnitude * Math.cos((theta * Math.PI) / 180)) *
- Math.sin(((90 - theta) * Math.PI) / 180) +
- forceOfGravity.magnitude) /
- Math.sin(((180 - theta) * Math.PI) / 180);
- }
- setReviewStaticMagnitude(friction);
- setReviewStaticAngle(180 - theta);
- };
-
- // In review mode, update forces when wedge angle changed
- const updateReviewForcesBasedOnAngle = (angle: number) => {
- setReviewGravityMagnitude(9.81);
- setReviewGravityAngle(270);
- setReviewNormalMagnitude(9.81 * Math.cos((Number(angle) * Math.PI) / 180));
- setReviewNormalAngle(90 - angle);
- let yForce = -forceOfGravity.magnitude;
- yForce +=
- 9.81 *
- Math.cos((Number(angle) * Math.PI) / 180) *
- Math.sin(((90 - Number(angle)) * Math.PI) / 180);
- yForce +=
- reviewCoefficient *
- 9.81 *
- Math.cos((Number(angle) * Math.PI) / 180) *
- Math.sin(((180 - Number(angle)) * Math.PI) / 180);
- let friction =
- reviewCoefficient * 9.81 * Math.cos((Number(angle) * Math.PI) / 180);
- if (yForce > 0) {
- friction =
- (-(9.81 * Math.cos((Number(angle) * Math.PI) / 180)) *
- Math.sin(((90 - Number(angle)) * Math.PI) / 180) +
- forceOfGravity.magnitude) /
- Math.sin(((180 - Number(angle)) * Math.PI) / 180);
- }
- setReviewStaticMagnitude(friction);
- setReviewStaticAngle(180 - angle);
- };
-
- // Solve for the correct answers to the generated problem
- const getAnswersToQuestion = (
- question: QuestionTemplate,
- questionVars: number[]
- ) => {
- const solutions: number[] = [];
-
- let theta: number = Number(wedgeAngle);
- let index = question.variablesForQuestionSetup.indexOf("theta - max 45");
- if (index >= 0) {
- theta = questionVars[index];
- }
- let muS: number = Number(coefficientOfStaticFriction);
- index = question.variablesForQuestionSetup.indexOf(
- "coefficient of static friction"
- );
- if (index >= 0) {
- muS = questionVars[index];
- }
-
- for (let i = 0; i < question.answerSolutionDescriptions.length; i++) {
- const description = question.answerSolutionDescriptions[i];
- if (!isNaN(Number(description))) {
- solutions.push(Number(description));
- } else if (description == "solve normal force angle from wedge angle") {
- solutions.push(90 - theta);
- } else if (
- description == "solve normal force magnitude from wedge angle"
- ) {
- solutions.push(
- forceOfGravity.magnitude * Math.cos((theta / 180) * Math.PI)
- );
- } else if (
- description ==
- "solve static force magnitude from wedge angle given equilibrium"
- ) {
- let normalForceMagnitude =
- forceOfGravity.magnitude * Math.cos((theta / 180) * Math.PI);
- let normalForceAngle = 90 - theta;
- let frictionForceAngle = 180 - theta;
- let frictionForceMagnitude =
- (-normalForceMagnitude *
- Math.sin((normalForceAngle * Math.PI) / 180) +
- 9.81) /
- 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 =
- forceOfGravity.magnitude * Math.cos((theta / 180) * Math.PI);
- let normalForceAngle = 90 - theta;
- let frictionForceAngle = 180 - theta;
- let frictionForceMagnitude =
- (-normalForceMagnitude *
- Math.sin((normalForceAngle * Math.PI) / 180) +
- 9.81) /
- Math.sin((frictionForceAngle * Math.PI) / 180);
- let frictionCoefficient = frictionForceMagnitude / normalForceMagnitude;
- solutions.push(frictionCoefficient);
- } else if (
- description ==
- "solve maximum wedge angle from coefficient of static friction given equilibrium"
- ) {
- solutions.push((Math.atan(muS) * 180) / Math.PI);
- }
- }
- setSelectedSolutions(solutions);
- return solutions;
- };
-
- // In review mode, check if input answers match correct answers and optionally generate alert
- const checkAnswers = (showAlert: boolean = true) => {
- let error: boolean = false;
- let epsilon: number = 0.01;
- if (selectedQuestion) {
- for (let i = 0; i < selectedQuestion.answerParts.length; i++) {
- if (selectedQuestion.answerParts[i] == "force of gravity") {
- if (
- Math.abs(reviewGravityMagnitude - selectedSolutions[i]) > epsilon
- ) {
- error = true;
- }
- } else if (selectedQuestion.answerParts[i] == "angle of gravity") {
- if (Math.abs(reviewGravityAngle - selectedSolutions[i]) > epsilon) {
- error = true;
- }
- } else if (selectedQuestion.answerParts[i] == "normal force") {
- if (
- Math.abs(reviewNormalMagnitude - selectedSolutions[i]) > epsilon
- ) {
- error = true;
- }
- } else if (selectedQuestion.answerParts[i] == "angle of normal force") {
- if (Math.abs(reviewNormalAngle - selectedSolutions[i]) > epsilon) {
- error = true;
- }
- } else if (
- selectedQuestion.answerParts[i] == "force of static friction"
- ) {
- if (
- Math.abs(reviewStaticMagnitude - selectedSolutions[i]) > epsilon
- ) {
- error = true;
- }
- } else if (
- selectedQuestion.answerParts[i] == "angle of static friction"
- ) {
- if (Math.abs(reviewStaticAngle - selectedSolutions[i]) > epsilon) {
- error = true;
- }
- } else if (
- selectedQuestion.answerParts[i] == "coefficient of static friction"
- ) {
- if (
- Math.abs(
- Number(coefficientOfStaticFriction) - selectedSolutions[i]
- ) > epsilon
- ) {
- error = true;
- }
- } else if (selectedQuestion.answerParts[i] == "wedge angle") {
- if (Math.abs(Number(wedgeAngle) - selectedSolutions[i]) > epsilon) {
- error = true;
- }
- }
- }
- }
- if (showAlert) {
- if (!error) {
- setSimulationPaused(false);
- setTimeout(() => {
- setSimulationPaused(true);
- }, 3000);
- } else {
- setSimulationPaused(false);
- setTimeout(() => {
- setSimulationPaused(true);
- }, 3000);
- }
- }
- if (selectedQuestion.goal == "noMovement") {
- if (!error) {
- setNoMovement(true);
- } else {
- setNoMovement(false);
- }
- }
- };
-
- const resetReviewValuesToDefault = () => {
- // Reset all values to default
- setReviewGravityMagnitude(0);
- setReviewGravityAngle(0);
- setReviewNormalMagnitude(0);
- setReviewNormalAngle(0);
- setReviewStaticMagnitude(0);
- setReviewStaticAngle(0);
- setCoefficientOfKineticFriction(0);
- setSimulationPaused(true);
- setAnswerInputFields();
- };
-
+
// In review mode, edit force arrow sketch on mouse movement
const editForce = (element: VectorTemplate) => {
if (!sketching) {
@@ -589,288 +292,6 @@ function App() {
}
};
- // In review mode, reset problem variables and generate a new question
- const generateNewQuestion = () => {
- resetReviewValuesToDefault();
-
- const vars: number[] = [];
- let question: QuestionTemplate = questions.inclinePlane[0];
-
- if (simulationType == "Inclined Plane") {
- if (questionNumber == questions.inclinePlane.length - 1) {
- setQuestionNumber(0);
- } else {
- setQuestionNumber(questionNumber + 1);
- }
- question = questions.inclinePlane[questionNumber];
-
- let coefficient = 0;
- let wedge = 0;
-
- for (let i = 0; i < question.variablesForQuestionSetup.length; i++) {
- if (question.variablesForQuestionSetup[i] == "theta - max 45") {
- let randValue = Math.floor(Math.random() * 44 + 1);
- vars.push(randValue);
- wedge = randValue;
- } else if (
- question.variablesForQuestionSetup[i] ==
- "coefficient of static friction"
- ) {
- let randValue = Math.round(Math.random() * 1000) / 1000;
- vars.push(randValue);
- coefficient = randValue;
- }
- }
- setWedgeAngle(wedge);
- changeWedgeBasedOnNewAngle(wedge);
- setCoefficientOfStaticFriction(coefficient);
- reviewCoefficient = coefficient;
- }
- let q = "";
- for (let i = 0; i < question.questionSetup.length; i++) {
- q += question.questionSetup[i];
- if (i != question.questionSetup.length - 1) {
- q += vars[i];
- if (question.variablesForQuestionSetup[i].includes("theta")) {
- q +=
- " degree (≈" +
- Math.round((1000 * (vars[i] * Math.PI)) / 180) / 1000 +
- " rad)";
- }
- }
- }
- questionVariables = vars;
- setSelectedQuestion(question);
- setQuestionPartOne(q);
- setQuestionPartTwo(question.question);
- const answers = getAnswersToQuestion(question, vars);
- generateInputFieldsForQuestion(false, question, answers);
- };
-
- // Generate answerInputFields for new review question
- const generateInputFieldsForQuestion = (
- showIcon: boolean = false,
- question: QuestionTemplate = selectedQuestion,
- answers: number[] = selectedSolutions
- ) => {
- let answerInput = [];
- const d = new Date();
- for (let i = 0; i < question.answerParts.length; i++) {
- if (question.answerParts[i] == "force of gravity") {
- setReviewGravityMagnitude(0);
- answerInput.push(
-
-
- FG
-
- }
- lowerBound={0}
- changeValue={setReviewGravityMagnitude}
- step={0.1}
- unit={"N"}
- upperBound={50}
- value={reviewGravityMagnitude}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
-
- );
- } else if (question.answerParts[i] == "angle of gravity") {
- setReviewGravityAngle(0);
- answerInput.push(
-
-
- θG
-
- }
- lowerBound={0}
- changeValue={setReviewGravityAngle}
- step={1}
- unit={"°"}
- upperBound={360}
- value={reviewGravityAngle}
- radianEquivalent={true}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
-
- );
- } else if (question.answerParts[i] == "normal force") {
- setReviewNormalMagnitude(0);
- answerInput.push(
-
-
- FN
-
- }
- lowerBound={0}
- changeValue={setReviewNormalMagnitude}
- step={0.1}
- unit={"N"}
- upperBound={50}
- value={reviewNormalMagnitude}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
-
- );
- } else if (question.answerParts[i] == "angle of normal force") {
- setReviewNormalAngle(0);
- answerInput.push(
-
-
- θN
-
- }
- lowerBound={0}
- changeValue={setReviewNormalAngle}
- step={1}
- unit={"°"}
- upperBound={360}
- value={reviewNormalAngle}
- radianEquivalent={true}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
-
- );
- } else if (question.answerParts[i] == "force of static friction") {
- setReviewStaticMagnitude(0);
- answerInput.push(
-
-
- F
-
- Fs
-
-
- }
- lowerBound={0}
- changeValue={setReviewStaticMagnitude}
- step={0.1}
- unit={"N"}
- upperBound={50}
- value={reviewStaticMagnitude}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
-
- );
- } else if (question.answerParts[i] == "angle of static friction") {
- setReviewStaticAngle(0);
- answerInput.push(
-
-
- θ
-
- Fs
-
-
- }
- lowerBound={0}
- changeValue={setReviewStaticAngle}
- step={1}
- unit={"°"}
- upperBound={360}
- value={reviewStaticAngle}
- radianEquivalent={true}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
-
- );
- } else if (question.answerParts[i] == "coefficient of static friction") {
- updateReviewForcesBasedOnCoefficient(0);
- answerInput.push(
-
-
-
- μs
-
- Coefficient of static friction; between 0 and 1
-
- }
- followCursor
- >
-
- μs
-
-
- }
- lowerBound={0}
- changeValue={setCoefficientOfStaticFriction}
- step={0.1}
- unit={""}
- upperBound={1}
- value={coefficientOfStaticFriction}
- effect={updateReviewForcesBasedOnCoefficient}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
-
- );
- } else if (question.answerParts[i] == "wedge angle") {
- updateReviewForcesBasedOnAngle(0);
- answerInput.push(
-
-
- θ
- Angle of incline plane from the ground, 0-49
-
- }
- followCursor
- >
- θ
-
- }
- lowerBound={0}
- changeValue={setWedgeAngle}
- step={1}
- unit={"°"}
- upperBound={49}
- value={wedgeAngle}
- effect={(val: number) => {
- changeWedgeBasedOnNewAngle(val);
- updateReviewForcesBasedOnAngle(val);
- }}
- radianEquivalent={true}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
-
- );
- }
- }
-
- setAnswerInputFields(
-
- {answerInput}
-
- );
- };
-
// Remove floor and walls from simulation
const removeWalls = () => {
setWallPositions([]);
@@ -939,62 +360,6 @@ function App() {
setAdjustPendulumAngle({ angle: 50, length: 300 });
removeWalls();
}
- } else if (mode == "Review") {
- setShowForceMagnitudes(true);
- if (simulationType == "Two Weights") {
- // TODO
- } else if (simulationType == "Inclined Plane") {
- addWedge();
- setUpdatedForces([]);
- setStartForces([]);
- addWalls();
- }
- setShowAcceleration(false);
- setShowVelocity(false);
- setShowForces(true);
- generateNewQuestion();
- } else if (mode == "Tutorial") {
- setStepNumber(0);
- if (simulationType == "One Weight") {
- addWeight();
- setStartPosY(yMin + 50);
- setStartPosX((xMax + xMin - 50) / 2);
- setSelectedTutorial(tutorials.freeWeight);
- setSelectedTutorial(tutorials.freeWeight);
- setStartForces(getForceFromJSON(tutorials.freeWeight.steps[0].forces));
- setShowForceMagnitudes(tutorials.freeWeight.steps[0].showMagnitude);
- addWalls();
- } else if (simulationType == "Two Weights") {
- // TODO
- } else if (simulationType == "Pendulum") {
- 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 = xMax / 2 - x - 50;
- const yPos = y - 50 - 5;
- addPendulum();
- setStartPosX(xPos);
- setStartPosY(yPos);
- setSelectedTutorial(tutorials.pendulum);
- setStartForces(getForceFromJSON(tutorials.pendulum.steps[0].forces));
- setShowForceMagnitudes(tutorials.pendulum.steps[0].showMagnitude);
- setPendulumAngle(50);
- setPendulumLength(300);
- setAdjustPendulumAngle({ angle: 30, length: 300 });
- removeWalls();
- } else if (simulationType == "Inclined Plane") {
- addWedge();
- setWedgeAngle(26);
- changeWedgeBasedOnNewAngle(26);
- setSelectedTutorial(tutorials.inclinePlane);
- setStartForces(
- getForceFromJSON(tutorials.inclinePlane.steps[0].forces)
- );
- setShowForceMagnitudes(tutorials.inclinePlane.steps[0].showMagnitude);
- addWalls();
- }
- setSimulationReset(!simulationReset);
}
}, [simulationType, mode]);
@@ -1130,7 +495,7 @@ function App() {
width: "50vw",
}}
>
-
+ SIMULATION IN PROGRESS
)}
-
- {simulationPaused && mode != "Tutorial" && (
-
- {
- setSimulationPaused(false);
- }}
- >
-
-
-
+
+ {simulationPaused && (
+
)}
- {!simulationPaused && mode != "Tutorial" && (
-
- {
- setSimulationPaused(true);
- }}
- >
-
-
-
+ {!simulationPaused && (
+
)}
- {simulationPaused && mode != "Tutorial" && (
-
- {
- setSimulationReset(!simulationReset);
- }}
- >
-
-
-
+ {simulationPaused && (
+
)}
-
+
- {mode == "Review" && (
-
- {!hintDialogueOpen && (
-
{
- setHintDialogueOpen(true);
- }}
- sx={{
- position: "fixed",
- left: xMax - 50 + "px",
- top: yMin + 14 + "px",
- }}
- >
-
-
- )}
-
-
-
-
{questionPartOne}
-
{questionPartTwo}
-
-
{answerInputFields}
-
-
- )}
- {mode == "Tutorial" && (
-
-
-
Problem
-
{selectedTutorial.question}
-
-
-
{
- let step = stepNumber - 1;
- step = Math.max(step, 0);
- step = Math.min(step, selectedTutorial.steps.length - 1);
- setStepNumber(step);
- setStartForces(
- getForceFromJSON(selectedTutorial.steps[step].forces)
- );
- setUpdatedForces(
- getForceFromJSON(selectedTutorial.steps[step].forces)
- );
- setShowForceMagnitudes(
- selectedTutorial.steps[step].showMagnitude
- );
- }}
- disabled={stepNumber == 0}
- >
-
-
-
-
- Step {stepNumber + 1}:{" "}
- {selectedTutorial.steps[stepNumber].description}
-
-
{selectedTutorial.steps[stepNumber].content}
-
-
{
- let step = stepNumber + 1;
- step = Math.max(step, 0);
- step = Math.min(step, selectedTutorial.steps.length - 1);
- setStepNumber(step);
- setStartForces(
- getForceFromJSON(selectedTutorial.steps[step].forces)
- );
- setUpdatedForces(
- getForceFromJSON(selectedTutorial.steps[step].forces)
- );
- setShowForceMagnitudes(
- selectedTutorial.steps[step].showMagnitude
- );
- }}
- disabled={stepNumber == selectedTutorial.steps.length - 1}
- >
-
-
-
-
-
Resources
- {simulationType == "One Weight" && (
-
- )}
- {simulationType == "Inclined Plane" && (
-
- )}
- {simulationType == "Pendulum" && (
-
- )}
-
-
- )}
- {mode == "Review" && (
-
-
setMode("Tutorial")}
- >
- {" "}
- Go to walkthrough{" "}
-
-
-
-
-
-
- )}
-
- {mode == "Freeform" && (
-
-
-
- {!wedge && !pendulum && (
-
- setElasticCollisions(!elasticCollisions)
- }
- />
- }
- label="Make collisions elastic"
- labelPlacement="start"
- />
- )}
- {!wedge && !pendulum && }
- setShowForces(!showForces)}
- defaultChecked
- />
- }
- label="Show force vectors"
- labelPlacement="start"
- />
- setShowAcceleration(!showAcceleration)}
- />
- }
- label="Show acceleration vector"
- labelPlacement="start"
- />
- setShowVelocity(!showVelocity)}
- />
- }
- label="Show velocity vector"
- labelPlacement="start"
- />
-
-
- {wedge && simulationPaused && (
-
-
- θ
- Angle of incline plane from the ground, 0-49
-
- }
- followCursor
- >
- θ
-
- }
- lowerBound={0}
- changeValue={setWedgeAngle}
- step={1}
- unit={"°"}
- upperBound={49}
- value={wedgeAngle}
- effect={changeWedgeBasedOnNewAngle}
- radianEquivalent={true}
- mode={"Freeform"}
- />
-
-
- μs
-
- Coefficient of static friction, between 0 and 1
-
- }
- followCursor
- >
-
- μs
-
-
- }
- lowerBound={0}
- changeValue={setCoefficientOfStaticFriction}
- step={0.1}
- unit={""}
- upperBound={1}
- value={coefficientOfStaticFriction}
- effect={updateForcesWithFriction}
- mode={"Freeform"}
- />
-
-
- μk
-
- Coefficient of kinetic friction, between 0 and
- coefficient of static friction
-
- }
- followCursor
- >
-
- μk
-
-
- }
- lowerBound={0}
- changeValue={setCoefficientOfKineticFriction}
- step={0.1}
- unit={""}
- upperBound={Number(coefficientOfStaticFriction)}
- value={coefficientOfKineticFriction}
- mode={"Freeform"}
- />
-
- )}
- {wedge && !simulationPaused && (
-
- θ: {Math.round(Number(wedgeAngle) * 100) / 100}° ≈{" "}
- {Math.round(((Number(wedgeAngle) * Math.PI) / 180) * 100) /
- 100}{" "}
- rad
-
- μ s: {coefficientOfStaticFriction}
-
- μ k: {coefficientOfKineticFriction}
-
- )}
- {pendulum && !simulationPaused && (
-
- θ: {Math.round(pendulumAngle * 100) / 100}° ≈{" "}
- {Math.round(((pendulumAngle * Math.PI) / 180) * 100) / 100}{" "}
- rad
-
- )}
- {pendulum && simulationPaused && (
-
-
- θ
- Pendulum angle offest from equilibrium
-
- }
- followCursor
- >
- θ
-
- }
- lowerBound={0}
- changeValue={setPendulumAngle}
- step={1}
- unit={"°"}
- upperBound={59}
- value={pendulumAngle}
- effect={(value) => {
- if (pendulum) {
- const mag =
- 1 * 9.81 * Math.cos((value * Math.PI) / 180);
-
- const forceOfTension: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: 90 - value,
- };
- setUpdatedForces([forceOfGravity, forceOfTension]);
- setAdjustPendulumAngle({
- angle: value,
- length: pendulumLength,
- });
- }
- }}
- radianEquivalent={true}
- mode={"Freeform"}
- />
-
- Length
- Pendulum rod length
-
- }
- followCursor
- >
- Length
-
- }
- lowerBound={0}
- changeValue={setPendulumLength}
- step={1}
- unit={"m"}
- upperBound={400}
- value={pendulumLength}
- effect={(value) => {
- if (pendulum) {
- setAdjustPendulumAngle({
- angle: pendulumAngle,
- length: value,
- });
- }
- }}
- radianEquivalent={false}
- mode={"Freeform"}
- />
-
- )}
-
- )}
-
- {mode == "Freeform" && twoWeights &&
Red Weight
}
- {mode == "Freeform" && weight && (
-
-
-
- | |
- X |
- Y |
-
-
- {
- window.open(
- "https://www.khanacademy.org/science/physics/two-dimensional-motion"
- );
- }}
- >
-
- Position
- Equation: x1
- =x
- 0
- +v
- 0
- t+0.5at
- 2
-
- Units: m
-
- }
- followCursor
- >
- Position
-
- |
-
- {(!simulationPaused || wedge) && (
-
- {positionXDisplay} m
-
- )}{" "}
- {simulationPaused && !wedge && (
- {
- setDisplayChange({
- xDisplay: value,
- yDisplay: positionYDisplay,
- });
- }}
- small={true}
- mode={"Freeform"}
- />
- )}{" "}
- |
-
- {(!simulationPaused || wedge) && (
-
- {positionYDisplay} m
-
- )}{" "}
- {simulationPaused && !wedge && (
- {
- setDisplayChange({
- xDisplay: positionXDisplay,
- yDisplay: value,
- });
- }}
- small={true}
- mode={"Freeform"}
- />
- )}{" "}
- |
-
-
- {
- window.open(
- "https://www.khanacademy.org/science/physics/two-dimensional-motion"
- );
- }}
- >
-
- Velocity
- Equation: v1
- =v
- 0
- +at
-
- Units: m/s
-
- }
- followCursor
- >
- Velocity
-
- |
-
- {(!simulationPaused || pendulum || wedge) && (
-
- {velocityXDisplay} m/s
-
- )}{" "}
- {simulationPaused && !pendulum && !wedge && (
-
- setDisplayChange({
- xDisplay: positionXDisplay,
- yDisplay: positionYDisplay,
- })
- }
- small={true}
- mode={"Freeform"}
- />
- )}{" "}
- |
-
- {(!simulationPaused || pendulum || wedge) && (
-
- {velocityYDisplay} m/s
-
- )}{" "}
- {simulationPaused && !pendulum && !wedge && (
-
- setDisplayChange({
- xDisplay: positionXDisplay,
- yDisplay: positionYDisplay,
- })
- }
- small={true}
- mode={"Freeform"}
- />
- )}{" "}
- |
-
-
- {
- window.open(
- "https://www.khanacademy.org/science/physics/two-dimensional-motion"
- );
- }}
- >
-
-
- Acceleration
-
- Equation: a=F/m
-
- Units: m/s
- 2
-
- }
- followCursor
- >
- Acceleration
-
- |
-
- {accelerationXDisplay} m/s2
- |
-
- {accelerationYDisplay} m/s2
- |
-
-
-
- )}
-
{/* {mode == "Freeform" &&
simulationElements.length > 0 &&
simulationElements[0].pendulum && (
@@ -2146,7 +831,7 @@ function App() {
)}*/}
-
+ {/* */}
);
}
diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss
index f756d59fc..1db758540 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.scss
+++ b/src/client/views/nodes/PhysicsSimulationBox.scss
@@ -67,3 +67,10 @@ button {
.answer-inactive {
pointer-events: none;
}
+
+.angleLabel {
+ font-weight: bold;
+ font-size: 20px;
+ user-select: none;
+ pointer-events: none;
+}
diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx
index c63538cc0..c2d3567f1 100644
--- a/src/client/views/nodes/PhysicsSimulationWall.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWall.tsx
@@ -1,5 +1,4 @@
import { useState, useEffect } from "react";
-import "./Weight.scss";
export interface Force {
magnitude: number;
diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx
index af01c1c51..0dc7751f3 100644
--- a/src/client/views/nodes/PhysicsSimulationWedge.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWedge.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect, useCallback } from "react";
-import "./Wedge.scss";
+import "./PhysicsSimulationBox.scss";
export interface IWedgeProps {
startHeight: number;
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index 227f20901..cc024f29a 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -1,4 +1,3 @@
-import { InputAdornment, TextField } from "@mui/material";
import { useEffect, useState } from "react";
import { IWallProps } from "./PhysicsSimulationWall";
import { Wedge } from "./PhysicsSimulationWedge";
--
cgit v1.2.3-70-g09d2
From e9210bd3c77bac0ad1bae17816baa5faa80bb706 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Tue, 31 Jan 2023 08:16:00 -0500
Subject: start converting from functional to class components
---
.vscode/settings.json | 3 +-
src/client/views/nodes/PhysicsSimulationApp.tsx | 1130 +++++++++--------------
2 files changed, 429 insertions(+), 704 deletions(-)
(limited to 'src/client/views')
diff --git a/.vscode/settings.json b/.vscode/settings.json
index f0cebd6fd..9c6542b85 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -10,5 +10,6 @@
"editor.detectIndentation": false,
"search.usePCRE2": true,
"typescript.tsdk": "node_modules/typescript/lib",
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.tabSize": 2
}
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index 0a39b3291..2a314a723 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -1,10 +1,12 @@
-import React, { useEffect, useState } from "react";
+import React = require('react');
import "./PhysicsSimulationBox.scss";
import { IForce, Weight } from "./PhysicsSimulationWeight";
import {Wall, IWallProps } from "./PhysicsSimulationWall"
import {Wedge} from "./PhysicsSimulationWedge"
+import { props, any } from 'bluebird';
+import { render } from 'react-dom';
-interface VectorTemplate {
+interface PhysicsVectorTemplate {
top: number;
left: number;
width: number;
@@ -16,170 +18,169 @@ interface VectorTemplate {
weightX: number;
weightY: number;
}
-interface QuestionTemplate {
- questionSetup: string[];
- variablesForQuestionSetup: string[];
- question: string;
- answerParts: string[];
- answerSolutionDescriptions: string[];
- goal: string;
- hints: { description: string; content: string }[];
-}
-interface TutorialTemplate {
- question: string;
- steps: {
- description: string;
- content: string;
- forces: {
- description: string;
- magnitude: number;
- directionInDegrees: number;
- }[];
- showMagnitude: boolean;
- }[];
+interface IState {
+ accelerationXDisplay: number,
+ accelerationYDisplay: number,
+ adjustPendulumAngle: {angle: number, length: number},
+ coefficientOfKineticFriction: number,
+ coefficientOfStaticFriction: number,
+ currentForceSketch: PhysicsVectorTemplate | null,
+ deleteMode: boolean,
+ displayChange: {xDisplay: number, yDisplay: number},
+ elasticCollisions: boolean,
+ forceSketches: PhysicsVectorTemplate[],
+ pendulum: boolean,
+ pendulumAngle: number,
+ pendulumLength: number,
+ positionXDisplay: number,
+ positionYDisplay: number,
+ showAcceleration: boolean,
+ showForceMagnitudes: boolean,
+ showForces: boolean,
+ showVelocity: boolean,
+ simulationPaused: boolean,
+ simulationReset: boolean,
+ simulationType: "Inclined Plane",
+ sketching: boolean,
+ startForces: IForce[],
+ startPendulumAngle: number,
+ startPosX: number,
+ startPosY: number,
+ stepNumber: number,
+ timer: number,
+ updatedForces: IForce[],
+ velocityXDisplay: number,
+ velocityYDisplay: number,
+ wallPositions: IWallProps[],
+ wedge: boolean,
+ wedgeAngle: number,
+ wedgeHeight: number,
+ wedgeWidth: number,
+ weight: boolean,
}
+export default class App extends React.Component<{}, IState> {
-function App() {
// Constants
- const gravityMagnitude = 9.81;
- const forceOfGravity: IForce = {
+ gravityMagnitude = 9.81;
+ forceOfGravity: IForce = {
description: "Gravity",
- magnitude: gravityMagnitude,
+ magnitude: this.gravityMagnitude,
directionInDegrees: 270,
};
- const xMin = 0;
- const yMin = 0;
- const xMax = window.innerWidth * 0.7;
- const yMax = window.innerHeight * 0.8;
- const color = `rgba(0,0,0,0.5)`;
-
- // Variables
- let questionVariables: number[] = [];
- let reviewCoefficient: number = 0;
-
- // State variables
- const [startPosX, setStartPosX] = useState(0);
- const [startPosY, setStartPosY] = useState(0);
- const [accelerationXDisplay, setAccelerationXDisplay] = useState(0);
- const [accelerationYDisplay, setAccelerationYDisplay] = useState(0);
- const [positionXDisplay, setPositionXDisplay] = useState(0);
- const [positionYDisplay, setPositionYDisplay] = useState(0);
- const [velocityXDisplay, setVelocityXDisplay] = useState(0);
- const [velocityYDisplay, setVelocityYDisplay] = useState(0);
+ xMin = 0;
+ yMin = 0;
+ xMax = window.innerWidth * 0.7;
+ yMax = window.innerHeight * 0.8;
+ color = `rgba(0,0,0,0.5)`;
+ radius = 50
- const [startPosX2, setStartPosX2] = useState(0);
- const [startPosY2, setStartPosY2] = useState(0);
- const [accelerationXDisplay2, setAccelerationXDisplay2] = useState(0);
- const [accelerationYDisplay2, setAccelerationYDisplay2] = useState(0);
- const [positionXDisplay2, setPositionXDisplay2] = useState(0);
- const [positionYDisplay2, setPositionYDisplay2] = useState(0);
- const [velocityXDisplay2, setVelocityXDisplay2] = useState(0);
- const [velocityYDisplay2, setVelocityYDisplay2] = useState(0);
- const [adjustPendulumAngle, setAdjustPendulumAngle] = useState<{
- angle: number;
- length: number;
- }>({ angle: 0, length: 0 });
- const [answerInputFields, setAnswerInputFields] = useState();
- const [coefficientOfKineticFriction, setCoefficientOfKineticFriction] =
- React.useState>(0);
- const [coefficientOfStaticFriction, setCoefficientOfStaticFriction] =
- React.useState>(0);
- const [currentForceSketch, setCurrentForceSketch] =
- useState(null);
- const [deleteMode, setDeleteMode] = useState(false);
- const [displayChange, setDisplayChange] = useState<{
- xDisplay: number;
- yDisplay: number;
- }>({ xDisplay: 0, yDisplay: 0 });
- const [elasticCollisions, setElasticCollisions] = useState(false);
- const [forceSketches, setForceSketches] = useState([]);
- const [questionPartOne, setQuestionPartOne] = useState("");
- const [hintDialogueOpen, setHintDialogueOpen] = useState(false);
- const [mode, setMode] = useState("Freeform");
- const [noMovement, setNoMovement] = useState(false);
- const [weight, setWeight] = useState(false);
- const [pendulum, setPendulum] = useState(false);
- const [pendulumAngle, setPendulumAngle] = useState(0);
- const [pendulumLength, setPendulumLength] = useState(300);
- const [questionNumber, setQuestionNumber] = useState(0);
- const [reviewGravityAngle, setReviewGravityAngle] = useState(0);
- const [reviewGravityMagnitude, setReviewGravityMagnitude] =
- useState(0);
- const [reviewNormalAngle, setReviewNormalAngle] = useState(0);
- const [reviewNormalMagnitude, setReviewNormalMagnitude] = useState(0);
- const [reviewStaticAngle, setReviewStaticAngle] = useState(0);
- const [reviewStaticMagnitude, setReviewStaticMagnitude] = useState(0);
- const [questionPartTwo, setQuestionPartTwo] = useState("");
- const [selectedSolutions, setSelectedSolutions] = useState([]);
- const [showAcceleration, setShowAcceleration] = useState(false);
- const [showForces, setShowForces] = useState(true);
- const [showVelocity, setShowVelocity] = useState(false);
- const [simulationPaused, setSimulationPaused] = useState(true);
- const [simulationReset, setSimulationReset] = useState(false);
- const [simulationType, setSimulationType] =
- useState("Inclined Plane");
- const [sketching, setSketching] = useState(false);
- const [startForces, setStartForces] = useState([forceOfGravity]);
- const [startPendulumAngle, setStartPendulumAngle] = useState(0);
- const [stepNumber, setStepNumber] = useState(0);
- const [timer, setTimer] = useState(0);
- const [updatedForces, setUpdatedForces] = useState([
- forceOfGravity,
- ]);
- const [wallPositions, setWallPositions] = useState([]);
- const [wedge, setWedge] = useState(false);
- const [wedgeAngle, setWedgeAngle] = React.useState<
- number | string | Array
- >(26);
- const [wedgeHeight, setWedgeHeight] = useState(
- Math.tan((26 * Math.PI) / 180) * 400
- );
- const [wedgeWidth, setWedgeWidth] = useState(400);
- const [twoWeights, setTwoWeights] = useState(false);
+ constructor(props: any) {
+ super(props)
+ this.state = {
+ accelerationXDisplay: 0,
+ accelerationYDisplay: 0,
+ adjustPendulumAngle: {angle: 0, length: 0},
+ coefficientOfKineticFriction: 0,
+ coefficientOfStaticFriction: 0,
+ currentForceSketch: null,
+ deleteMode: false,
+ displayChange: {xDisplay: 0, yDisplay: 0},
+ elasticCollisions: false,
+ forceSketches: [],
+ pendulum: false,
+ pendulumAngle: 0,
+ pendulumLength: 300,
+ positionXDisplay: 0,
+ positionYDisplay: 0,
+ showAcceleration: false,
+ showForceMagnitudes: false,
+ showForces: false,
+ showVelocity: false,
+ simulationPaused: false,
+ simulationReset: false,
+ simulationType: "Inclined Plane",
+ sketching: false,
+ startForces: [this.forceOfGravity],
+ startPendulumAngle: 0,
+ startPosX: 0,
+ startPosY: 0,
+ stepNumber: 0,
+ timer: 0,
+ updatedForces: [this.forceOfGravity],
+ velocityXDisplay: 0,
+ velocityYDisplay: 0,
+ wallPositions: [],
+ wedge: false,
+ wedgeAngle: 26,
+ wedgeHeight: Math.tan((26 * Math.PI) / 180) * 400,
+ wedgeWidth: 400,
+ weight: false,
+ }
+ }
// Add one weight to the simulation
- const addWeight = () => {
- setWeight(true);
- setTwoWeights(false);
- setWedge(false);
- setPendulum(false);
- };
-
- // Add two weights to the simulation
- const addTwoWeights = () => {
- setWeight(true);
- setTwoWeights(true);
- setWedge(false);
- setPendulum(false);
+ addWeight () {
+ this.setState({weight: true})
+ this.setState({wedge: false})
+ this.setState({pendulum: false})
+ this.setState({startPosY: this.yMin+this.radius})
+ this.setState({startPosX: (this.xMax+this.xMin-this.radius)/2})
+ this.setState({updatedForces: [this.forceOfGravity]})
+ this.setState({startForces: [this.forceOfGravity]})
+ this.addWalls();
+ this.setState({simulationReset: !this.state.simulationReset})
};
// Add a wedge with a One Weight to the simulation
- const addWedge = () => {
- setWeight(true);
- setTwoWeights(false);
- setWedge(true);
- setPendulum(false);
+ addWedge () {
+ this.setState({weight: true})
+ this.setState({wedge: true})
+ this.setState({pendulum: false})
+ this.changeWedgeBasedOnNewAngle(26);
+ this.addWalls();
+ this.setState({startForces: [this.forceOfGravity]})
+ this.updateForcesWithFriction(this.state.coefficientOfStaticFriction);
};
// Add a simple pendulum to the simulation
- const addPendulum = () => {
- setWeight(true);
- setTwoWeights(false);
- setPendulum(true);
- setWedge(false);
+ addPendulum = () => {
+ this.setState({weight: true})
+ this.setState({wedge: false})
+ this.setState({pendulum: true})
+ let length = 300;
+ let angle = 50;
+ let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
+ let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
+ let xPos = xMax / 2 - x - 50;
+ let yPos = y - 50 - 5;
+ this.addPendulum();
+ this.setState({startPosX: xPos})
+ this.setState({startPosY: yPos})
+ let mag = 9.81 * Math.cos((50 * Math.PI) / 180);
+ let forceOfTension: IForce = {
+ description: "Tension",
+ magnitude: mag,
+ directionInDegrees: 90 - angle,
+ };
+ this.setState({updatedForces: [this.forceOfGravity, forceOfTension]})
+ this.setState({startForces: [this.forceOfGravity, forceOfTension]})
+ this.setState({pendulumAngle: 50})
+ this.setState({pendulumLength: 300})
+ this.setState({adjustPendulumAngle: {angle: 50, length: 300}})
+ this.removeWalls();
};
// Update forces when coefficient of static friction changes in freeform mode
- const updateForcesWithFriction = (
+ updateForcesWithFriction (
coefficient: number,
- width: number = wedgeWidth,
- height: number = wedgeHeight
- ) => {
- const normalForce: IForce = {
+ width: number = this.state.wedgeWidth,
+ height: number = this.state.wedgeHeight
+ ) {
+ let normalForce = {
description: "Normal Force",
- magnitude: forceOfGravity.magnitude * Math.cos(Math.atan(height / width)),
+ magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)),
directionInDegrees:
180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
};
@@ -187,12 +188,12 @@ function App() {
description: "Static Friction Force",
magnitude:
coefficient *
- forceOfGravity.magnitude *
+ this.forceOfGravity.magnitude *
Math.cos(Math.atan(height / width)),
directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
};
// reduce magnitude of friction force if necessary such that block cannot slide up plane
- let yForce = -forceOfGravity.magnitude;
+ let yForce = -this.forceOfGravity.magnitude;
yForce +=
normalForce.magnitude *
Math.sin((normalForce.directionInDegrees * Math.PI) / 180);
@@ -203,37 +204,37 @@ function App() {
frictionForce.magnitude =
(-normalForce.magnitude *
Math.sin((normalForce.directionInDegrees * Math.PI) / 180) +
- forceOfGravity.magnitude) /
+ this.forceOfGravity.magnitude) /
Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
}
if (coefficient != 0) {
- setStartForces([forceOfGravity, normalForce, frictionForce]);
- setUpdatedForces([forceOfGravity, normalForce, frictionForce]);
+ this.setState({startForces: [this.forceOfGravity, normalForce, frictionForce]})
+ this.setState({updatedForces: [this.forceOfGravity, normalForce, frictionForce]});
} else {
- setStartForces([forceOfGravity, normalForce]);
- setUpdatedForces([forceOfGravity, normalForce]);
+ this.setState({startForces: [this.forceOfGravity, normalForce]})
+ this.setState({updatedForces: [this.forceOfGravity, normalForce]});
}
};
// Change wedge height and width and weight position to match new wedge angle
- const changeWedgeBasedOnNewAngle = (angle: number) => {
+ changeWedgeBasedOnNewAngle = (angle: number) => {
let width = 0;
let height = 0;
if (angle < 50) {
width = 400;
height = Math.tan((angle * Math.PI) / 180) * 400;
- setWedgeWidth(width);
- setWedgeHeight(height);
+ this.setState({wedgeWidth: width})
+ this.setState({wedgeHeight: height})
} else if (angle < 70) {
width = 200;
height = Math.tan((angle * Math.PI) / 180) * 200;
- setWedgeWidth(width);
- setWedgeHeight(height);
+ this.setState({wedgeWidth: width})
+ this.setState({wedgeHeight: height})
} else {
width = 100;
height = Math.tan((angle * Math.PI) / 180) * 100;
- setWedgeWidth(width);
- setWedgeHeight(height);
+ this.setState({wedgeWidth: width})
+ this.setState({wedgeHeight: height})
}
// update weight position based on updated wedge width/height
@@ -258,582 +259,305 @@ function App() {
yPos += angle * 3;
}
- setStartPosX(Math.round((xMax * 0.5 - 200) * 10) / 10);
- setStartPosY(getDisplayYPos(yPos));
- if (mode == "Freeform") {
- updateForcesWithFriction(
- Number(coefficientOfStaticFriction),
- width,
- height
- );
- }
+ this.setState({startPosX: Math.round((this.xMax * 0.5 - 200) * 10) / 10});
+ this.setState({startPosY: this.getDisplayYPos(yPos)});
+ this.updateForcesWithFriction(
+ Number(this.state.coefficientOfStaticFriction),
+ width,
+ height
+ );
};
// Helper function to go between display and real values
- const getDisplayYPos = (yPos: number) => {
- return yMax - yPos - 2 * 50 + 5;
+ getDisplayYPos = (yPos: number) => {
+ return this.yMax - yPos - 2 * 50 + 5;
};
// In review mode, edit force arrow sketch on mouse movement
- const editForce = (element: VectorTemplate) => {
- if (!sketching) {
- const sketches = forceSketches.filter((sketch) => sketch != element);
- setForceSketches(sketches);
- setCurrentForceSketch(element);
- setSketching(true);
+ editForce = (element: PhysicsVectorTemplate) => {
+ if (!this.state.sketching) {
+ let sketches = this.state.forceSketches.filter((sketch) => sketch != element);
+ this.setState({forceSketches: sketches})
+ this.setState({currentForceSketch: element})
+ this.setState({sketching: true})
}
};
// In review mode, used to delete force arrow sketch on SHIFT+click
- const deleteForce = (element: VectorTemplate) => {
- if (!sketching) {
- const sketches = forceSketches.filter((sketch) => sketch != element);
- setForceSketches(sketches);
+ deleteForce = (element: PhysicsVectorTemplate) => {
+ if (!this.state.sketching) {
+ let sketches = this.state.forceSketches.filter((sketch) => sketch != element);
+ this.setState({forceSketches: sketches})
}
};
// Remove floor and walls from simulation
- const removeWalls = () => {
- setWallPositions([]);
+ removeWalls = () => {
+ this.setState({wallPositions: []})
};
// Add floor and walls to simulation
- const addWalls = () => {
- if (wallPositions.length == 0) {
- const walls: IWallProps[] = [];
+ addWalls = () => {
+ if (this.state.wallPositions.length == 0) {
+ let walls = [];
walls.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 });
walls.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 });
walls.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 });
- setWallPositions(walls);
- }
- };
-
- // Use effect hook to handle mode/topic change
- useEffect(() => {
- if (mode == "Freeform") {
- setShowForceMagnitudes(true);
- if (simulationType == "One Weight") {
- addWeight();
- setStartPosY(yMin + 50);
- setStartPosX((xMax + xMin - 50) / 2);
- setUpdatedForces([forceOfGravity]);
- setStartForces([forceOfGravity]);
- addWalls();
- setSimulationReset(!simulationReset);
- } else if (simulationType == "Two Weights") {
- addTwoWeights();
- setStartPosY(yMax - 100);
- setStartPosX((xMax + xMin - 200) / 2);
- setStartPosY2(yMax - 100);
- setStartPosX2((xMax + xMin + 200) / 2);
- setUpdatedForces([forceOfGravity]);
- setStartForces([forceOfGravity]);
- addWalls();
- setSimulationReset(!simulationReset);
- // TODO
- } else if (simulationType == "Inclined Plane") {
- addWedge();
- changeWedgeBasedOnNewAngle(26);
- addWalls();
- setStartForces([forceOfGravity]);
- updateForcesWithFriction(Number(coefficientOfStaticFriction));
- } else if (simulationType == "Pendulum") {
- const length = 300;
- const angle = 50;
- const x = length * Math.cos(((90 - angle) * Math.PI) / 180);
- const y = length * Math.sin(((90 - angle) * Math.PI) / 180);
- const xPos = xMax / 2 - x - 50;
- const yPos = y - 50 - 5;
- addPendulum();
- setStartPosX(xPos);
- setStartPosY(yPos);
- const mag = 9.81 * Math.cos((50 * Math.PI) / 180);
- const forceOfTension: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: 90 - angle,
- };
- setUpdatedForces([forceOfGravity, forceOfTension]);
- setStartForces([forceOfGravity, forceOfTension]);
- setPendulumAngle(50);
- setPendulumLength(300);
- setAdjustPendulumAngle({ angle: 50, length: 300 });
- removeWalls();
- }
+ this.setState({wallPositions: walls})
}
- }, [simulationType, mode]);
-
- const [showForceMagnitudes, setShowForceMagnitudes] = useState(true);
-
- const getForceFromJSON = (
- json: {
- description: string;
- magnitude: number;
- directionInDegrees: number;
- }[]
- ): IForce[] => {
- const forces: IForce[] = [];
- for (let i = 0; i < json.length; i++) {
- const force: IForce = {
- description: json[i].description,
- magnitude: json[i].magnitude,
- directionInDegrees: json[i].directionInDegrees,
- };
- forces.push(force);
- }
- return forces;
};
- // Use effect hook to handle force change in review mode
- useEffect(() => {
- if (mode == "Review") {
- const forceOfGravityReview: IForce = {
- description: "Gravity",
- magnitude: reviewGravityMagnitude,
- directionInDegrees: reviewGravityAngle,
- };
- const normalForceReview: IForce = {
- description: "Normal Force",
- magnitude: reviewNormalMagnitude,
- directionInDegrees: reviewNormalAngle,
- };
- const staticFrictionForceReview: IForce = {
- description: "Static Friction Force",
- magnitude: reviewStaticMagnitude,
- directionInDegrees: reviewStaticAngle,
- };
- setStartForces([
- forceOfGravityReview,
- normalForceReview,
- staticFrictionForceReview,
- ]);
- setUpdatedForces([
- forceOfGravityReview,
- normalForceReview,
- staticFrictionForceReview,
- ]);
- }
- }, [
- reviewGravityMagnitude,
- reviewGravityAngle,
- reviewNormalMagnitude,
- reviewNormalAngle,
- reviewStaticMagnitude,
- reviewStaticAngle,
- ]);
-
- // Use effect to add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
- useEffect(() => {
+
+ componentDidMount() {
+ // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
document.addEventListener("keydown", (e) => {
if (e.shiftKey) {
- setDeleteMode(true);
+ this.setState({deleteMode: true})
}
});
document.addEventListener("keyup", (e) => {
if (e.shiftKey) {
- setDeleteMode(false);
+ this.setState({deleteMode: false})
}
});
- }, []);
- // Timer for animating the simulation
- setInterval(() => {
- setTimer(timer + 1);
- }, 60);
+ // Timer for animating the simulation
+ setInterval(() => {
+ this.setState({timer: this.state.timer+1})
+ }, 60);
+ }
- return (
-
-
-
{
- if (sketching) {
- const x1 = positionXDisplay + 50;
- const y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50;
- const x2 = e.clientX;
- const y2 = e.clientY;
- const height = Math.abs(y1 - y2) + 120;
- const width = Math.abs(x1 - x2) + 120;
- const top = Math.min(y1, y2) - 60;
- const left = Math.min(x1, x2) - 60;
- const x1Updated = x1 - left;
- const x2Updated = x2 - left;
- const y1Updated = y1 - top;
- const y2Updated = y2 - top;
- setCurrentForceSketch({
- top: top,
- left: left,
- width: width,
- height: height,
- x1: x1Updated,
- y1: y1Updated,
- x2: x2Updated,
- y2: y2Updated,
- weightX: positionXDisplay,
- weightY: positionYDisplay,
- });
- }
- }}
- onPointerDown={(e) => {
- if (sketching && currentForceSketch) {
- setSketching(false);
- const sketches = forceSketches;
- sketches.push(currentForceSketch);
- setForceSketches(sketches);
- setCurrentForceSketch(null);
- }
- }}
- >
-
-
- {!simulationPaused && (
-
-
SIMULATION IN PROGRESS
-
- )}
-
-
-
-
-
-
-
- {showForces && currentForceSketch && simulationPaused && (
-
- )}
- {showForces &&
- forceSketches.length > 0 &&
- simulationPaused &&
- forceSketches.map((element: VectorTemplate, index) => {
- return (
-
-
-
- );
- })}
- {weight && (
-
- )}
- {twoWeights && (
-
- )}
- {wedge && (
-
- )}
-
-
- {wallPositions.map((element, index) => {
- return (
-
- );
- })}
-
-
-
-
-
-
- {simulationPaused && (
-
- )}
- {!simulationPaused && (
-
- )}
- {simulationPaused && (
-
- )}
-
-
-
-
-
- {/* {mode == "Freeform" &&
- simulationElements.length > 0 &&
- simulationElements[0].pendulum && (
-
-
-
-
- | |
- Value |
-
-
- | Potential Energy |
-
- {Math.round(
- pendulumLength *
- (1 - Math.cos(pendulumAngle)) *
- 9.81 *
- 10
- ) / 10}{" "}
- J
- |
-
-
- | Kinetic Energy |
-
- {Math.round(
- (Math.round(
- pendulumLength *
- (1 - Math.cos(startPendulumAngle)) *
- 9.81 *
- 10
- ) /
- 10 -
- Math.round(
- pendulumLength *
- (1 - Math.cos(pendulumAngle)) *
- 9.81 *
- 10
- ) /
- 10) *
- 10
- ) / 10}{" "}
- J
- |
-
-
- |
- Total Energy
- |
-
- {Math.round(
- pendulumLength *
- (1 - Math.cos(startPendulumAngle)) *
- 9.81 *
- 10
- ) / 10}{" "}
- J
- |
-
-
-
-
- )}*/}
-
-
- {/*
*/}
-
- );
+ render () {
+ return (
+
+ );
+ }
+ //
+ //
+ //
{
+ // // if (sketching) {
+ // // x1 = positionXDisplay + 50;
+ // // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50;
+ // // x2 = e.clientX;
+ // // y2 = e.clientY;
+ // // height = Math.abs(y1 - y2) + 120;
+ // // width = Math.abs(x1 - x2) + 120;
+ // // top = Math.min(y1, y2) - 60;
+ // // left = Math.min(x1, x2) - 60;
+ // // x1Updated = x1 - left;
+ // // x2Updated = x2 - left;
+ // // y1Updated = y1 - top;
+ // // y2Updated = y2 - top;
+ // // setCurrentForceSketch({
+ // // top: top,
+ // // left: left,
+ // // width: width,
+ // // height: height,
+ // // x1: x1Updated,
+ // // y1: y1Updated,
+ // // x2: x2Updated,
+ // // y2: y2Updated,
+ // // weightX: positionXDisplay,
+ // // weightY: positionYDisplay,
+ // // });
+ // // }
+ // }}
+ // onPointerDown={(e) => {
+ // // if (sketching && currentForceSketch) {
+ // // setSketching(false);
+ // // sketches = forceSketches;
+ // // sketches.push(currentForceSketch);
+ // // setForceSketches(sketches);
+ // // setCurrentForceSketch(null);
+ // // }
+ // }}
+ // >
+ //
+ //
+ // {/* {showForces && currentForceSketch && simulationPaused && (
+ //
+ //
+ //
+ // )} */}
+ // {/* {showForces &&
+ // forceSketches.length > 0 &&
+ // simulationPaused &&
+ // forceSketches.map((element: PhysicsVectorTemplate, index) => {
+ // return (
+ //
+ //
+ //
+ // );
+ // })} */}
+ // {weight && (
+ //
+ // )}
+ // {wedge && (
+ //
+ // )}
+ //
+ //
+ // {wallPositions.map((element, index) => {
+ // return (
+ //
+ // );
+ // })}
+ //
+ //
+ //
+ //
+ //
+ //
+ // {simulationPaused && (
+ //
+ // )}
+ // {!simulationPaused && (
+ //
+ // )}
+ // {simulationPaused && (
+ //
+ // )}
+ //
+ //
+ //
+ //
+ //
}
-
-export default App;
--
cgit v1.2.3-70-g09d2
From 6fba3c7fdaaed12d94dee359f520591e55cb76d8 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Tue, 31 Jan 2023 12:42:45 -0500
Subject: convert from functional to class components
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 6 +-
src/client/views/nodes/PhysicsSimulationWall.tsx | 26 +++---
src/client/views/nodes/PhysicsSimulationWedge.tsx | 96 ++++++++++++++---------
3 files changed, 74 insertions(+), 54 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index 2a314a723..414d61809 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -329,9 +329,7 @@ export default class App extends React.Component<{}, IState> {
render () {
return (
-
- );
- }
+ Hello world!
//
+ );
+ }
}
diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx
index c2d3567f1..a31704d2f 100644
--- a/src/client/views/nodes/PhysicsSimulationWall.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWall.tsx
@@ -1,3 +1,4 @@
+import React from "react";
import { useState, useEffect } from "react";
export interface Force {
@@ -11,24 +12,25 @@ export interface IWallProps {
angleInDegrees: number;
}
-export const Wall = (props: IWallProps) => {
- const { length, xPos, yPos, angleInDegrees } = props;
+export default class App extends React.Component {
- let wallStyle = {
- width: length + "%",
- height: 0.5 + "vw",
+ constructor(props: any) {
+ super(props)
+ }
+
+ wallStyle = {
+ width: this.props.angleInDegrees == 0 ? this.props.length + "%" : 0.5 + "vw",
+ height: this.props.angleInDegrees == 0 ? 0.5 + "vw" : this.props.length + "%",
position: "absolute" as "absolute",
- left: xPos + "%",
- top: yPos + "%",
+ left: this.props.xPos + "%",
+ top: this.props.yPos + "%",
backgroundColor: "#6c7b8b",
zIndex: -1000,
margin: 0,
padding: 0,
};
- if (angleInDegrees != 0) {
- wallStyle.width = 0.5 + "vw";
- wallStyle.height = length + "%";
- }
- return ;
+ render () {
+ return ();
+ }
};
diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx
index 0dc7751f3..bf0cadce2 100644
--- a/src/client/views/nodes/PhysicsSimulationWedge.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWedge.tsx
@@ -1,3 +1,4 @@
+import React from "react";
import { useState, useEffect, useCallback } from "react";
import "./PhysicsSimulationBox.scss";
@@ -7,58 +8,75 @@ export interface IWedgeProps {
startLeft: number;
}
-export const Wedge = (props: IWedgeProps) => {
- const { startHeight, startWidth, startLeft } = props;
+interface IState {
+ angleInRadians: number,
+ left: number,
+ coordinates: string,
+}
+
+export default class Wedge extends React.Component {
- const [angleInRadians, setAngleInRadians] = useState(
- Math.atan(startHeight / startWidth)
- );
- const [left, setLeft] = useState(startLeft);
- const [coordinates, setCoordinates] = useState("");
+ constructor(props: any) {
+ super(props)
+ this.state = {
+ angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth),
+ left: this.props.startLeft,
+ coordinates: "",
+ }
+ }
- const color = "#deb887";
+ color = "#deb887";
- useEffect(() => {
+ updateCoordinates() {
const coordinatePair1 =
- Math.round(left) + "," + Math.round(window.innerHeight * 0.8) + " ";
+ Math.round(this.state.left) + "," + Math.round(window.innerHeight * 0.8) + " ";
const coordinatePair2 =
- Math.round(left + startWidth) +
+ Math.round(this.state.left + this.props.startWidth) +
"," +
Math.round(window.innerHeight * 0.8) +
" ";
const coordinatePair3 =
- Math.round(left) +
+ Math.round(this.state.left) +
"," +
- Math.round(window.innerHeight * 0.8 - startHeight);
+ Math.round(window.innerHeight * 0.8 - this.props.startHeight);
const coord = coordinatePair1 + coordinatePair2 + coordinatePair3;
- setCoordinates(coord);
- }, [left, startWidth, startHeight]);
+ this.setState({coordinates: coord});
+ }
- useEffect(() => {
- setAngleInRadians(Math.atan(startHeight / startWidth));
- }, [startWidth, startHeight]);
+ componentDidMount() {
+ this.updateCoordinates()
+ }
- return (
-
-
-
- );
+ );
+ }
};
--
cgit v1.2.3-70-g09d2
From 60ed47bf843704f2f4a4ccd152e15fb96a5c375e Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Tue, 31 Jan 2023 13:11:44 -0500
Subject: start converting weight file to class
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 461 ++++++++++-----------
src/client/views/nodes/PhysicsSimulationWeight.tsx | 397 ++++++++----------
2 files changed, 409 insertions(+), 449 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index 414d61809..2277c7875 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -1,8 +1,8 @@
import React = require('react');
import "./PhysicsSimulationBox.scss";
-import { IForce, Weight } from "./PhysicsSimulationWeight";
-import {Wall, IWallProps } from "./PhysicsSimulationWall"
-import {Wedge} from "./PhysicsSimulationWedge"
+import Weight from "./PhysicsSimulationWeight";
+import Wall from "./PhysicsSimulationWall"
+import Wedge from "./PhysicsSimulationWedge"
import { props, any } from 'bluebird';
import { render } from 'react-dom';
@@ -329,235 +329,232 @@ export default class App extends React.Component<{}, IState> {
render () {
return (
-
Hello world!
- //
- //
- //
{
- // // if (sketching) {
- // // x1 = positionXDisplay + 50;
- // // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50;
- // // x2 = e.clientX;
- // // y2 = e.clientY;
- // // height = Math.abs(y1 - y2) + 120;
- // // width = Math.abs(x1 - x2) + 120;
- // // top = Math.min(y1, y2) - 60;
- // // left = Math.min(x1, x2) - 60;
- // // x1Updated = x1 - left;
- // // x2Updated = x2 - left;
- // // y1Updated = y1 - top;
- // // y2Updated = y2 - top;
- // // setCurrentForceSketch({
- // // top: top,
- // // left: left,
- // // width: width,
- // // height: height,
- // // x1: x1Updated,
- // // y1: y1Updated,
- // // x2: x2Updated,
- // // y2: y2Updated,
- // // weightX: positionXDisplay,
- // // weightY: positionYDisplay,
- // // });
- // // }
- // }}
- // onPointerDown={(e) => {
- // // if (sketching && currentForceSketch) {
- // // setSketching(false);
- // // sketches = forceSketches;
- // // sketches.push(currentForceSketch);
- // // setForceSketches(sketches);
- // // setCurrentForceSketch(null);
- // // }
- // }}
- // >
- //
- //
- // {/* {showForces && currentForceSketch && simulationPaused && (
- //
- //
- //
- // )} */}
- // {/* {showForces &&
- // forceSketches.length > 0 &&
- // simulationPaused &&
- // forceSketches.map((element: PhysicsVectorTemplate, index) => {
- // return (
- //
- //
- //
- // );
- // })} */}
- // {weight && (
- //
- // )}
- // {wedge && (
- //
- // )}
- //
- //
- // {wallPositions.map((element, index) => {
- // return (
- //
- // );
- // })}
- //
- //
- //
- //
- //
- //
- // {simulationPaused && (
- //
- // )}
- // {!simulationPaused && (
- //
- // )}
- // {simulationPaused && (
- //
- // )}
- //
- //
- //
- //
- //
+
+
+
{
+ // if (sketching) {
+ // x1 = positionXDisplay + 50;
+ // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50;
+ // x2 = e.clientX;
+ // y2 = e.clientY;
+ // height = Math.abs(y1 - y2) + 120;
+ // width = Math.abs(x1 - x2) + 120;
+ // top = Math.min(y1, y2) - 60;
+ // left = Math.min(x1, x2) - 60;
+ // x1Updated = x1 - left;
+ // x2Updated = x2 - left;
+ // y1Updated = y1 - top;
+ // y2Updated = y2 - top;
+ // setCurrentForceSketch({
+ // top: top,
+ // left: left,
+ // width: width,
+ // height: height,
+ // x1: x1Updated,
+ // y1: y1Updated,
+ // x2: x2Updated,
+ // y2: y2Updated,
+ // weightX: positionXDisplay,
+ // weightY: positionYDisplay,
+ // });
+ // }
+ }}
+ onPointerDown={(e) => {
+ // if (sketching && currentForceSketch) {
+ // setSketching(false);
+ // sketches = forceSketches;
+ // sketches.push(currentForceSketch);
+ // setForceSketches(sketches);
+ // setCurrentForceSketch(null);
+ // }
+ }}
+ >
+
+
+ {/* {showForces && currentForceSketch && simulationPaused && (
+
+ )} */}
+ {/* {showForces &&
+ forceSketches.length > 0 &&
+ simulationPaused &&
+ forceSketches.map((element: PhysicsVectorTemplate, index) => {
+ return (
+
+
+
+ );
+ })} */}
+ {/* {weight && (
+
+ )} */}
+ {this.state.wedge && (
+
+ )}
+
+
+ {this.state.wallPositions.map((element, index) => {
+ return (
+
+ );
+ })}
+
+
+
+
+
+
+ {this.state.simulationPaused && (
+
+ )}
+ {!this.state.simulationPaused && (
+
+ )}
+ {this.state.simulationPaused && (
+
+ )}
+
+
+
+
+
);
}
}
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index cc024f29a..d234c1395 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -1,6 +1,8 @@
+import React from "react";
import { useEffect, useState } from "react";
+import { render } from "react-dom";
import { IWallProps } from "./PhysicsSimulationWall";
-import { Wedge } from "./PhysicsSimulationWedge";
+import Wedge from "./PhysicsSimulationWedge";
export interface IForce {
description: string;
@@ -35,8 +37,6 @@ export interface IWeightProps {
setPendulumLength: (val: number) => any;
setStartPendulumAngle: (val: number) => any;
showAcceleration: boolean;
- mode: string;
- noMovement: boolean;
pendulumAngle: number;
setSketching: (val: boolean) => any;
showForces: boolean;
@@ -56,154 +56,121 @@ export interface IWeightProps {
wedgeHeight: number;
}
-export const Weight = (props: IWeightProps) => {
- const {
- adjustPendulumAngle,
- color,
- displayXPosition,
- displayYPosition,
- displayXVelocity,
- displayYVelocity,
- elasticCollisions,
- startForces,
- incrementTime,
- mass,
- paused,
- pendulum,
- pendulumLength,
- wedge,
- radius,
- mode,
- noMovement,
- pendulumAngle,
- reset,
- setSketching,
- setDisplayXAcceleration,
- setDisplayXPosition,
- setDisplayXVelocity,
- setDisplayYAcceleration,
- setDisplayYPosition,
- setDisplayYVelocity,
- setPaused,
- setPendulumAngle,
- setPendulumLength,
- setStartPendulumAngle,
- showAcceleration,
- showForces,
- showForceMagnitudes,
- showVelocity,
- startPosX,
- startPosY,
- startVelX,
- startVelY,
- timestepSize,
- updateDisplay,
- updatedForces,
- setUpdatedForces,
- walls,
- coefficientOfKineticFriction,
- wedgeWidth,
- wedgeHeight,
- } = props;
+interface IState {
+ dragging: boolean,
+ kineticFriction: boolean,
+ updatedStartPosX: number,
+ updatedStartPosY: number,
+ xPosition: number,
+ yPosition: number,
+ xVelocity: number,
+ yVelocity: number,
+}
+export default class Weight extends React.Component
{
+
+ constructor(props: any) {
+ super(props)
+ this.state = {
+ dragging: false,
+ kineticFriction: false,
+ updatedStartPosX: this.props.startPosX,
+ updatedStartPosY: this.props.startPosY,
+ xPosition: this.props.startPosX,
+ yPosition: this.props.startPosY,
+ xVelocity: this.props.startVelX ? this.props.startVelX: 0,
+ yVelocity: this.props.startVelY ? this.props.startVelY: 0,
+ }
+ }
// Constants
- const draggable = !wedge && mode == "Freeform";
- const epsilon = 0.0001;
-
- const forceOfGravity: IForce = {
+ draggable = !this.props.wedge;
+ epsilon = 0.0001;
+ forceOfGravity: IForce = {
description: "Gravity",
- magnitude: mass * 9.81,
+ magnitude: this.props.mass * 9.81,
directionInDegrees: 270,
};
- const xMax = window.innerWidth * 0.7;
- const xMin = 0;
- const yMax = window.innerHeight * 0.8;
- const yMin = 0;
-
- // State hooks
- const [dragging, setDragging] = useState(false);
- const [kineticFriction, setKineticFriction] = useState(false);
- const [updatedStartPosX, setUpdatedStartPosX] = useState(startPosX);
- const [updatedStartPosY, setUpdatedStartPosY] = useState(startPosY);
- const [xPosition, setXPosition] = useState(startPosX);
- const [xVelocity, setXVelocity] = useState(startVelX ?? 0);
- const [yPosition, setYPosition] = useState(startPosY);
- const [yVelocity, setYVelocity] = useState(startVelY ?? 0);
+ xMax = window.innerWidth * 0.7;
+ xMin = 0;
+ yMax = window.innerHeight * 0.8;
+ yMin = 0;
// Helper function to go between display and real values
const getDisplayYPos = (yPos: number) => {
- return yMax - yPos - 2 * radius + 5;
+ return this.yMax - yPos - 2 * this.props.radius + 5;
};
const getYPosFromDisplay = (yDisplay: number) => {
- return yMax - yDisplay - 2 * radius + 5;
+ return this.yMax - yDisplay - 2 * this.props.radius + 5;
};
// Set display values based on real values
const setYPosDisplay = (yPos: number) => {
- const displayPos = getDisplayYPos(yPos);
- setDisplayYPosition(Math.round(displayPos * 100) / 100);
+ const displayPos = this.getDisplayYPos(yPos);
+ this.props.setDisplayYPosition(Math.round(displayPos * 100) / 100)
};
const setXPosDisplay = (xPos: number) => {
- setDisplayXPosition(Math.round(xPos * 100) / 100);
+ this.props.setDisplayXPosition(Math.round(xPos * 100) / 100);
};
const setYVelDisplay = (yVel: number) => {
- setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100);
+ this.props.setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100);
};
const setXVelDisplay = (xVel: number) => {
- setDisplayXVelocity(Math.round(xVel * 100) / 100);
+ this.props.setDisplayXVelocity(Math.round(xVel * 100) / 100);
};
const setDisplayValues = (
- xPos: number = xPosition,
- yPos: number = yPosition,
- xVel: number = xVelocity,
- yVel: number = yVelocity
+ xPos: number = this.state.xPosition,
+ yPos: number = this.state.yPosition,
+ xVel: number = this.state.xVelocity,
+ yVel: number = this.state.yVelocity
) => {
- setYPosDisplay(yPos);
- setXPosDisplay(xPos);
- setYVelDisplay(yVel);
- setXVelDisplay(xVel);
- setDisplayYAcceleration(
- (-1 * Math.round(getNewAccelerationY(updatedForces) * 100)) / 100
+ this.setYPosDisplay(yPos);
+ this.setXPosDisplay(xPos);
+ this.setYVelDisplay(yVel);
+ this.setXVelDisplay(xVel);
+ this.props.setDisplayYAcceleration(
+ (-1 * Math.round(getNewAccelerationY(this.props.updatedForces) * 100)) / 100
);
- setDisplayXAcceleration(
- Math.round(getNewAccelerationX(updatedForces) * 100) / 100
+ this.props.setDisplayXAcceleration(
+ Math.round(getNewAccelerationX(this.props.updatedForces) * 100) / 100
);
};
// When display values updated by user, update real values
- useEffect(() => {
- if (updateDisplay.xDisplay != xPosition) {
- let x = updateDisplay.xDisplay;
- x = Math.max(0, x);
- x = Math.min(x, xMax - 2 * radius);
- setUpdatedStartPosX(x);
- setXPosition(x);
- setDisplayXPosition(x);
- }
-
- if (updateDisplay.yDisplay != getDisplayYPos(yPosition)) {
- let y = updateDisplay.yDisplay;
- y = Math.max(0, y);
- y = Math.min(y, yMax - 2 * radius);
- setDisplayYPosition(y);
- let coordinatePosition = getYPosFromDisplay(y);
- setUpdatedStartPosY(coordinatePosition);
- setYPosition(coordinatePosition);
- }
-
- if (displayXVelocity != xVelocity) {
- let x = displayXVelocity;
- setXVelocity(x);
- setDisplayXVelocity(x);
- }
-
- if (displayYVelocity != -yVelocity) {
- let y = displayYVelocity;
- setYVelocity(-y);
- setDisplayYVelocity(y);
+ componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void {
+ if (this.props.updateDisplay != prevProps.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.xMax - 2 * this.props.radius);
+ this.setState({updatedStartPosX: x})
+ this.setState({xPosition: x})
+ this.props.setDisplayXPosition(x);
+ }
+
+ 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.yMax - 2 * this.props.radius);
+ this.props.setDisplayYPosition(y);
+ let coordinatePosition = this.getYPosFromDisplay(y);
+ this.setState({updatedStartPosY: coordinatePosition})
+ this.setState({yPosition: coordinatePosition})
+ }
+
+ if (this.props.displayXVelocity != this.state.xVelocity) {
+ let x = this.props.displayXVelocity;
+ this.setState({xVelocity: x})
+ this.props.setDisplayXVelocity(x);
+ }
+
+ if (this.props.displayYVelocity != this.state.yVelocity) {
+ let y = this.props.displayYVelocity;
+ this.setState({yVelocity: -y})
+ this.props.setDisplayXVelocity(y);
+ }
}
- }, [updateDisplay]);
+ }
// Check for collisions and update
useEffect(() => {
@@ -264,7 +231,7 @@ export const Weight = (props: IWeightProps) => {
newXAcc +=
(force.magnitude *
Math.cos((force.directionInDegrees * Math.PI) / 180)) /
- mass;
+ this.props.mass;
});
return newXAcc;
};
@@ -276,7 +243,7 @@ export const Weight = (props: IWeightProps) => {
(-1 *
(force.magnitude *
Math.sin((force.directionInDegrees * Math.PI) / 180))) /
- mass;
+ this.props.mass;
});
return newYAcc;
};
@@ -287,11 +254,11 @@ export const Weight = (props: IWeightProps) => {
xVel: number,
yVel: number
) => {
- if (!pendulum) {
- return updatedForces;
+ if (!this.props.pendulum) {
+ return this.state.updatedForces;
}
- const x = xMax / 2 - xPos - radius;
- const y = yPos + radius + 5;
+ const x = this.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;
@@ -306,8 +273,8 @@ export const Weight = (props: IWeightProps) => {
setPendulumLength(Math.sqrt(x * x + y * y));
const mag =
- mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) +
- (mass * (xVel * xVel + yVel * yVel)) / pendulumLength;
+ this.props.mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) +
+ (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength;
const forceOfTension: IForce = {
description: "Tension",
@@ -315,24 +282,24 @@ export const Weight = (props: IWeightProps) => {
directionInDegrees: angle,
};
- return [forceOfGravity, forceOfTension];
+ return [this.forceOfGravity, forceOfTension];
};
const getNewPosition = (pos: number, vel: number) => {
- return pos + vel * timestepSize;
+ return pos + vel * this.props.timestepSize;
};
const getNewVelocity = (vel: number, acc: number) => {
- return vel + acc * timestepSize;
+ return vel + acc * this.props.timestepSize;
};
const checkForCollisionsWithWall = () => {
let collision = false;
- const minX = xPosition;
- const maxX = xPosition + 2 * radius;
+ const minX = this.state.xPosition;
+ const maxX = this.state.xPosition + 2 * this.props.radius;
const containerWidth = window.innerWidth;
- if (xVelocity != 0) {
- walls.forEach((wall) => {
+ if (this.state.xVelocity != 0) {
+ this.props.walls.forEach((wall) => {
if (wall.angleInDegrees == 90) {
const wallX = (wall.xPos / 100) * window.innerWidth;
if (wall.xPos < 0.35) {
@@ -542,43 +509,39 @@ export const Weight = (props: IWeightProps) => {
setYPosDisplay(startPosY);
}, [startPosY]);
- return (
+ render () {
+ return (
{
- if (draggable) {
+ if (this.props.draggable) {
e.preventDefault();
- setPaused(true);
- setDragging(true);
+ this.props.setPaused(true);
+ this.setState({dragging: true});
setClickPositionX(e.clientX);
setClickPositionY(e.clientY);
- } else if (mode == "Review") {
- setSketching(true);
}
}}
onPointerMove={(e) => {
e.preventDefault();
- if (dragging) {
- let newY = yPosition + e.clientY - clickPositionY;
- if (newY > yMax - 2 * radius) {
- newY = yMax - 2 * radius;
+ if (this.state.dragging) {
+ let newY = this.state.yPosition + e.clientY - clickPositionY;
+ if (newY > this.yMax - 2 * this.props.radius) {
+ newY = this.yMax - 2 * this.props.radius;
}
- let newX = xPosition + e.clientX - clickPositionX;
- if (newX > xMax - 2 * radius) {
- newX = xMax - 2 * radius;
+ let newX = this.state.xPosition + e.clientX - clickPositionX;
+ if (newX > this.xMax - 2 * this.props.radius) {
+ newX = this.xMax - 2 * this.props.radius;
} else if (newX < 0) {
newX = 0;
}
-
- setXPosition(newX);
- setYPosition(newY);
- setUpdatedStartPosX(newX);
- setUpdatedStartPosY(newY);
- setDisplayYPosition(
- Math.round((yMax - 2 * radius - newY + 5) * 100) / 100
- );
+ this.setState({xPosition: newX})
+ this.setState({yPosition: newY})
+ this.setState({updatedStartPosX: newX})
+ this.setState({updatedStartPosY: newY})
+ this.setState({displayYPosition: Math.round((yMax - 2 * radius - newY + 5) * 100) / 100})
setClickPositionX(e.clientX);
setClickPositionY(e.clientY);
setDisplayValues();
@@ -591,20 +554,20 @@ export const Weight = (props: IWeightProps) => {
resetEverything();
}
setDragging(false);
- let newY = yPosition + e.clientY - clickPositionY;
- if (newY > yMax - 2 * radius) {
- newY = yMax - 2 * radius;
+ let newY = this.state.yPosition + e.clientY - clickPositionY;
+ if (newY > this.yMax - 2 * this.props.radius) {
+ newY = this.yMax - 2 * this.props.radius;
}
let newX = xPosition + e.clientX - clickPositionX;
- if (newX > xMax - 2 * radius) {
- newX = xMax - 2 * radius;
+ if (newX > this.xMax - 2 * this.props.radius) {
+ newX = this.xMax - 2 * this.props.radius;
} else if (newX < 0) {
newX = 0;
}
- if (pendulum) {
- const x = xMax / 2 - newX - radius;
- const y = newY + radius + 5;
+ if (this.state.pendulum) {
+ const x = this.xMax / 2 - newX - this.props.radius;
+ const y = newY + this.props.radius + 5;
let angle = (Math.atan(y / x) * 180) / Math.PI;
if (angle < 0) {
angle += 180;
@@ -615,20 +578,19 @@ export const Weight = (props: IWeightProps) => {
}
const pendulumLength = Math.sqrt(x * x + y * y);
- setPendulumAngle(oppositeAngle);
- setPendulumLength(Math.sqrt(x * x + y * y));
+ this.props.setPendulumAngle(oppositeAngle);
+ this.props.setPendulumLength(Math.sqrt(x * x + y * y));
const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180);
const forceOfTension: IForce = {
description: "Tension",
magnitude: mag,
directionInDegrees: angle,
};
-
- setKineticFriction(false);
- setXVelocity(startVelX ?? 0);
- setYVelocity(startVelY ?? 0);
+ this.setState({kineticFriction: false})
+ this.setState({xVelocity: startVelX ?? 0})
+ this.setState({yVelocity: startVelY ?? 0})
setDisplayValues();
- setUpdatedForces([forceOfGravity, forceOfTension]);
+ this.setState({updatedForces :[forceOfGravity, forceOfTension]});
}
}
}}
@@ -637,7 +599,7 @@ export const Weight = (props: IWeightProps) => {
{mass} kg
- {pendulum && (
+ {this.state.pendulum && (
{
zIndex: -2,
}}
>
-
)}
- {!dragging && showAcceleration && (
+ {!this.state.dragging && this.props.showAcceleration && (
{
top: 0,
}}
>
-
+
{
{
pointerEvents: "none",
position: "absolute",
left:
- xPosition +
- radius +
- getNewAccelerationX(updatedForces) * 5 +
+ this.state.xPosition +
+ this.props.radius +
+ getNewAccelerationX(this.state.updatedForces) * 5 +
25 +
"px",
top:
- yPosition +
- radius +
- getNewAccelerationY(updatedForces) * 5 +
+ this.state.yPosition +
+ this.props.radius +
+ getNewAccelerationY(this.state.updatedForces) * 5 +
25 +
"px",
zIndex: -1,
@@ -745,8 +707,8 @@ export const Weight = (props: IWeightProps) => {
{Math.round(
100 *
Math.sqrt(
- Math.pow(getNewAccelerationX(updatedForces) * 3, 2) +
- Math.pow(getNewAccelerationY(updatedForces) * 3, 2)
+ Math.pow(getNewAccelerationX(this.state.updatedForces) * 3, 2) +
+ Math.pow(getNewAccelerationY(this.state.updatedForces) * 3, 2)
)
) / 100}{" "}
m/s2
@@ -755,7 +717,7 @@ export const Weight = (props: IWeightProps) => {
)}
- {!dragging && showVelocity && (
+ {!this.state.dragging && this.props.showVelocity && (
{
top: 0,
}}
>
-
+
{
{
style={{
pointerEvents: "none",
position: "absolute",
- left: xPosition + radius + xVelocity * 3 + 25 + "px",
- top: yPosition + radius + yVelocity * 3 + "px",
+ left: this.state.xPosition + this.props.radius + this.state.xVelocity * 3 + 25 + "px",
+ top: this.state.yPosition + this.props.radius + this.state.yVelocity * 3 + "px",
zIndex: -1,
lineHeight: 0.5,
}}
>
{Math.round(
- 100 * Math.sqrt(xVelocity * xVelocity + yVelocity * yVelocity)
+ 100 * Math.sqrt(this.state.xVelocity**2 + this.state.yVelocity**2)
) / 100}{" "}
m/s
@@ -810,14 +772,14 @@ export const Weight = (props: IWeightProps) => {
)}
- {!dragging &&
- showForces &&
- updatedForces.map((force, index) => {
- if (force.magnitude < epsilon) {
+ {!this.state.dragging &&
+ this.props.showForces &&
+ this.props.updatedForces.map((force, index) => {
+ if (force.magnitude < this.epsilon) {
return;
}
- let arrowStartY: number = yPosition + radius;
- const arrowStartX: number = xPosition + radius;
+ 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) *
@@ -843,10 +805,10 @@ export const Weight = (props: IWeightProps) => {
} else {
labelTop -= 40;
}
- labelTop = Math.min(labelTop, yMax + 50);
- labelTop = Math.max(labelTop, yMin);
- labelLeft = Math.min(labelLeft, xMax - 60);
- labelLeft = Math.max(labelLeft, xMin);
+ labelTop = Math.min(labelTop, this.yMax + 50);
+ labelTop = Math.max(labelTop, this.yMin);
+ labelLeft = Math.min(labelLeft, this.xMax - 60);
+ labelLeft = Math.max(labelLeft, this.xMin);
return (
@@ -908,5 +870,6 @@ export const Weight = (props: IWeightProps) => {
);
})}
- );
+ );
+ }
};
--
cgit v1.2.3-70-g09d2
From 6000ce6b65e6bd4c87fadc9c41f3508037854470 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Wed, 1 Feb 2023 14:43:25 -0500
Subject: keep switching to class components
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 2 +-
src/client/views/nodes/PhysicsSimulationWeight.tsx | 566 ++++++++++-----------
2 files changed, 282 insertions(+), 286 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index 2277c7875..bd218f63b 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -1,6 +1,6 @@
import React = require('react');
import "./PhysicsSimulationBox.scss";
-import Weight from "./PhysicsSimulationWeight";
+import Weight, { IForce } from "./PhysicsSimulationWeight";
import Wall from "./PhysicsSimulationWall"
import Wedge from "./PhysicsSimulationWedge"
import { props, any } from 'bluebird';
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index d234c1395..fb040c850 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -57,6 +57,8 @@ export interface IWeightProps {
}
interface IState {
+ clickPositionX: number,
+ clickPositionY: number,
dragging: boolean,
kineticFriction: boolean,
updatedStartPosX: number,
@@ -71,6 +73,8 @@ export default class Weight extends React.Component {
constructor(props: any) {
super(props)
this.state = {
+ clickPositionX: 0,
+ clickPositionY: 0,
dragging: false,
kineticFriction: false,
updatedStartPosX: this.props.startPosX,
@@ -96,29 +100,29 @@ export default class Weight extends React.Component {
yMin = 0;
// Helper function to go between display and real values
- const getDisplayYPos = (yPos: number) => {
+ getDisplayYPos = (yPos: number) => {
return this.yMax - yPos - 2 * this.props.radius + 5;
};
- const getYPosFromDisplay = (yDisplay: number) => {
+ getYPosFromDisplay = (yDisplay: number) => {
return this.yMax - yDisplay - 2 * this.props.radius + 5;
};
// Set display values based on real values
- const setYPosDisplay = (yPos: number) => {
+ setYPosDisplay = (yPos: number) => {
const displayPos = this.getDisplayYPos(yPos);
this.props.setDisplayYPosition(Math.round(displayPos * 100) / 100)
};
- const setXPosDisplay = (xPos: number) => {
+ setXPosDisplay = (xPos: number) => {
this.props.setDisplayXPosition(Math.round(xPos * 100) / 100);
};
- const setYVelDisplay = (yVel: number) => {
+ setYVelDisplay = (yVel: number) => {
this.props.setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100);
};
- const setXVelDisplay = (xVel: number) => {
+ setXVelDisplay = (xVel: number) => {
this.props.setDisplayXVelocity(Math.round(xVel * 100) / 100);
};
- const setDisplayValues = (
+ setDisplayValues = (
xPos: number = this.state.xPosition,
yPos: number = this.state.yPosition,
xVel: number = this.state.xVelocity,
@@ -129,10 +133,10 @@ export default class Weight extends React.Component {
this.setYVelDisplay(yVel);
this.setXVelDisplay(xVel);
this.props.setDisplayYAcceleration(
- (-1 * Math.round(getNewAccelerationY(this.props.updatedForces) * 100)) / 100
+ (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100
);
this.props.setDisplayXAcceleration(
- Math.round(getNewAccelerationX(this.props.updatedForces) * 100) / 100
+ Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100
);
};
@@ -170,62 +174,59 @@ export default class Weight extends React.Component {
this.props.setDisplayXVelocity(y);
}
}
- }
-
- // Check for collisions and update
- useEffect(() => {
- if (!paused && !noMovement) {
- let collisions = false;
- if (!pendulum) {
- const collisionsWithGround = checkForCollisionsWithGround();
- const collisionsWithWalls = checkForCollisionsWithWall();
- collisions = collisionsWithGround || collisionsWithWalls;
- }
- if (!collisions) {
- update();
+ // Update sim
+ if (this.props.incrementTime != prevProps.incrementTime) {
+ if (!this.props.paused) {
+ let collisions = false;
+ if (!this.props.pendulum) {
+ const collisionsWithGround = this.checkForCollisionsWithGround();
+ const collisionsWithWalls = this.checkForCollisionsWithWall();
+ collisions = collisionsWithGround || collisionsWithWalls;
+ }
+ if (!collisions) {
+ this.update();
+ }
+ this.setDisplayValues();
}
- setDisplayValues();
}
- }, [incrementTime]);
-
- useEffect(() => {
- resetEverything();
- }, [reset]);
-
- useEffect(() => {
- setXVelocity(startVelX ?? 0);
- setYVelocity(startVelY ?? 0);
- setDisplayValues();
- }, [startForces]);
-
- const resetEverything = () => {
- setKineticFriction(false);
- setXPosition(updatedStartPosX);
- setYPosition(updatedStartPosY);
- setXVelocity(startVelX ?? 0);
- setYVelocity(startVelY ?? 0);
- setUpdatedForces(startForces);
- setDisplayValues();
+ if (this.props.reset != prevProps.reset) {
+ this.resetEverything();
+ }
+ if (this.props.startForces != prevProps.startForces) {
+ this.setState({xVelocity: this.props.startVelX ?? 0})
+ this.setState({yVelocity: this.props.startVelY ?? 0})
+ this.setDisplayValues();
+ }
+ }
+
+ 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.setUpdatedForces(this.props.startForces)
+ this.setDisplayValues();
};
- // Change pendulum angle based on input field
- useEffect(() => {
- let length = adjustPendulumAngle.length;
- const x =
- length * Math.cos(((90 - adjustPendulumAngle.angle) * Math.PI) / 180);
- const y =
- length * Math.sin(((90 - adjustPendulumAngle.angle) * Math.PI) / 180);
- const xPos = xMax / 2 - x - radius;
- const yPos = y - radius - 5;
- setXPosition(xPos);
- setYPosition(yPos);
- setUpdatedStartPosX(xPos);
- setUpdatedStartPosY(yPos);
- setPendulumAngle(adjustPendulumAngle.angle);
- setPendulumLength(adjustPendulumAngle.length);
- }, [adjustPendulumAngle]);
-
- const getNewAccelerationX = (forceList: IForce[]) => {
+ // // Change pendulum angle based on input field
+ // useEffect(() => {
+ // let length = adjustPendulumAngle.length;
+ // const x =
+ // length * Math.cos(((90 - adjustPendulumAngle.angle) * Math.PI) / 180);
+ // const y =
+ // length * Math.sin(((90 - adjustPendulumAngle.angle) * Math.PI) / 180);
+ // const xPos = xMax / 2 - x - radius;
+ // const yPos = y - radius - 5;
+ // setXPosition(xPos);
+ // setYPosition(yPos);
+ // setUpdatedStartPosX(xPos);
+ // setUpdatedStartPosY(yPos);
+ // setPendulumAngle(adjustPendulumAngle.angle);
+ // setPendulumLength(adjustPendulumAngle.length);
+ // }, [adjustPendulumAngle]);
+
+ getNewAccelerationX = (forceList: IForce[]) => {
let newXAcc = 0;
forceList.forEach((force) => {
newXAcc +=
@@ -236,7 +237,7 @@ export default class Weight extends React.Component {
return newXAcc;
};
- const getNewAccelerationY = (forceList: IForce[]) => {
+ getNewAccelerationY = (forceList: IForce[]) => {
let newYAcc = 0;
forceList.forEach((force) => {
newYAcc +=
@@ -248,14 +249,14 @@ export default class Weight extends React.Component {
return newYAcc;
};
- const getNewForces = (
+ getNewForces = (
xPos: number,
yPos: number,
xVel: number,
yVel: number
) => {
if (!this.props.pendulum) {
- return this.state.updatedForces;
+ return this.props.updatedForces;
}
const x = this.xMax / 2 - xPos - this.props.radius;
const y = yPos + this.props.radius + 5;
@@ -269,8 +270,8 @@ export default class Weight extends React.Component {
}
const pendulumLength = Math.sqrt(x * x + y * y);
- setPendulumAngle(oppositeAngle);
- setPendulumLength(Math.sqrt(x * x + y * y));
+ this.props.setPendulumAngle(oppositeAngle);
+ this.props.setPendulumLength(Math.sqrt(x * x + y * y));
const mag =
this.props.mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) +
@@ -285,74 +286,74 @@ export default class Weight extends React.Component {
return [this.forceOfGravity, forceOfTension];
};
- const getNewPosition = (pos: number, vel: number) => {
+ getNewPosition = (pos: number, vel: number) => {
return pos + vel * this.props.timestepSize;
};
- const getNewVelocity = (vel: number, acc: number) => {
+ getNewVelocity = (vel: number, acc: number) => {
return vel + acc * this.props.timestepSize;
};
- const checkForCollisionsWithWall = () => {
+ // const checkForCollisionsWithWall = () => {
+ // let collision = false;
+ // const minX = this.state.xPosition;
+ // const maxX = this.state.xPosition + 2 * this.props.radius;
+ // const containerWidth = window.innerWidth;
+ // if (this.state.xVelocity != 0) {
+ // this.props.walls.forEach((wall) => {
+ // if (wall.angleInDegrees == 90) {
+ // const wallX = (wall.xPos / 100) * window.innerWidth;
+ // if (wall.xPos < 0.35) {
+ // if (minX <= wallX) {
+ // if (elasticCollisions) {
+ // setXVelocity(-xVelocity);
+ // } else {
+ // setXVelocity(0);
+ // setXPosition(wallX + 5);
+ // }
+ // collision = true;
+ // }
+ // } else {
+ // if (maxX >= wallX) {
+ // if (elasticCollisions) {
+ // setXVelocity(-xVelocity);
+ // } else {
+ // setXVelocity(0);
+ // setXPosition(wallX - 2 * radius + 5);
+ // }
+ // collision = true;
+ // }
+ // }
+ // }
+ // });
+ // }
+ // return collision;
+ // };
+
+ checkForCollisionsWithGround = () => {
let collision = false;
- const minX = this.state.xPosition;
- const maxX = this.state.xPosition + 2 * this.props.radius;
- const containerWidth = window.innerWidth;
- if (this.state.xVelocity != 0) {
+ const maxY = this.state.yPosition + 2 * this.props.radius;
+ if (this.state.yVelocity > 0) {
this.props.walls.forEach((wall) => {
- if (wall.angleInDegrees == 90) {
- const wallX = (wall.xPos / 100) * window.innerWidth;
- if (wall.xPos < 0.35) {
- if (minX <= wallX) {
- if (elasticCollisions) {
- setXVelocity(-xVelocity);
- } else {
- setXVelocity(0);
- setXPosition(wallX + 5);
- }
- collision = true;
- }
- } else {
- if (maxX >= wallX) {
- if (elasticCollisions) {
- setXVelocity(-xVelocity);
- } else {
- setXVelocity(0);
- setXPosition(wallX - 2 * radius + 5);
- }
- collision = true;
- }
- }
- }
- });
- }
- return collision;
- };
-
- const checkForCollisionsWithGround = () => {
- let collision = false;
- const maxY = yPosition + 2 * radius;
- if (yVelocity > 0) {
- walls.forEach((wall) => {
if (wall.angleInDegrees == 0) {
const groundY = (wall.yPos / 100) * window.innerHeight;
if (maxY >= groundY) {
- if (elasticCollisions) {
- setYVelocity(-yVelocity);
+ if (this.props.elasticCollisions) {
+ this.setState({yVelocity: -this.state.yVelocity})
} else {
- setYVelocity(0);
- setYPosition(groundY - 2 * radius + 5);
+ this.setState({yVelocity: 0})
+ this.setState({yPosition: groundY - 2 * this.props.radius + 5})
const forceOfGravity: IForce = {
description: "Gravity",
- magnitude: 9.81 * mass,
+ magnitude: 9.81 * this.props.mass,
directionInDegrees: 270,
};
const normalForce: IForce = {
description: "Normal force",
- magnitude: 9.81 * mass,
+ magnitude: 9.81 * this.props.mass,
directionInDegrees: wall.angleInDegrees + 90,
};
- setUpdatedForces([forceOfGravity, normalForce]);
+ this.props.setUpdatedForces([forceOfGravity, normalForce]);
}
collision = true;
}
@@ -362,152 +363,147 @@ export default class Weight extends React.Component {
return collision;
};
- useEffect(() => {
- if (wedge && xVelocity != 0 && mode != "Review" && !kineticFriction) {
- setKineticFriction(true);
- //switch from static to kinetic friction
- const normalForce: IForce = {
- description: "Normal Force",
- magnitude:
- forceOfGravity.magnitude *
- Math.cos(Math.atan(wedgeHeight / wedgeWidth)),
- directionInDegrees:
- 180 - 90 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI,
- };
- let frictionForce: IForce = {
- description: "Kinetic Friction Force",
- magnitude:
- coefficientOfKineticFriction *
- forceOfGravity.magnitude *
- Math.cos(Math.atan(wedgeHeight / wedgeWidth)),
- directionInDegrees:
- 180 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI,
- };
- // reduce magnitude of friction force if necessary such that block cannot slide up plane
- let yForce = -forceOfGravity.magnitude;
- 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) +
- forceOfGravity.magnitude) /
- Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
- }
- if (coefficientOfKineticFriction != 0) {
- setUpdatedForces([forceOfGravity, normalForce, frictionForce]);
- } else {
- setUpdatedForces([forceOfGravity, normalForce]);
- }
- }
- }, [xVelocity]);
-
- const update = () => {
- // RK4 update
- let xPos = xPosition;
- let yPos = yPosition;
- let xVel = xVelocity;
- let yVel = yVelocity;
- for (let i = 0; i < 60; i++) {
- let forces1 = getNewForces(xPos, yPos, xVel, yVel);
- const xAcc1 = getNewAccelerationX(forces1);
- const yAcc1 = getNewAccelerationY(forces1);
- const xVel1 = getNewVelocity(xVel, xAcc1);
- const yVel1 = getNewVelocity(yVel, yAcc1);
-
- let xVel2 = getNewVelocity(xVel, xAcc1 / 2);
- let yVel2 = getNewVelocity(yVel, yAcc1 / 2);
- let xPos2 = getNewPosition(xPos, xVel1 / 2);
- let yPos2 = getNewPosition(yPos, yVel1 / 2);
- const forces2 = getNewForces(xPos2, yPos2, xVel2, yVel2);
- const xAcc2 = getNewAccelerationX(forces2);
- const yAcc2 = getNewAccelerationY(forces2);
- xVel2 = getNewVelocity(xVel2, xAcc2);
- yVel2 = getNewVelocity(yVel2, yAcc2);
- xPos2 = getNewPosition(xPos2, xVel2);
- yPos2 = getNewPosition(yPos2, yVel2);
-
- let xVel3 = getNewVelocity(xVel, xAcc2 / 2);
- let yVel3 = getNewVelocity(yVel, yAcc2 / 2);
- let xPos3 = getNewPosition(xPos, xVel2 / 2);
- let yPos3 = getNewPosition(yPos, yVel2 / 2);
- const forces3 = getNewForces(xPos3, yPos3, xVel3, yVel3);
- const xAcc3 = getNewAccelerationX(forces3);
- const yAcc3 = getNewAccelerationY(forces3);
- xVel3 = getNewVelocity(xVel3, xAcc3);
- yVel3 = getNewVelocity(yVel3, yAcc3);
- xPos3 = getNewPosition(xPos3, xVel3);
- yPos3 = getNewPosition(yPos3, yVel3);
-
- let xVel4 = getNewVelocity(xVel, xAcc3);
- let yVel4 = getNewVelocity(yVel, yAcc3);
- let xPos4 = getNewPosition(xPos, xVel3);
- let yPos4 = getNewPosition(yPos, yVel3);
- const forces4 = getNewForces(xPos4, yPos4, xVel4, yVel4);
- const xAcc4 = getNewAccelerationX(forces4);
- const yAcc4 = getNewAccelerationY(forces4);
- xVel4 = getNewVelocity(xVel4, xAcc4);
- yVel4 = getNewVelocity(yVel4, yAcc4);
- xPos4 = getNewPosition(xPos4, xVel4);
- yPos4 = getNewPosition(yPos4, yVel4);
-
- xVel +=
- timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0);
- yVel +=
- timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0);
- xPos +=
- timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0);
- yPos +=
- timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0);
- }
-
- setXVelocity(xVel);
- setYVelocity(yVel);
- setXPosition(xPos);
- setYPosition(yPos);
- setUpdatedForces(getNewForces(xPos, yPos, xVel, yVel));
- };
-
- let weightStyle = {
- backgroundColor: color,
+ // useEffect(() => {
+ // if (wedge && xVelocity != 0 && mode != "Review" && !kineticFriction) {
+ // setKineticFriction(true);
+ // //switch from static to kinetic friction
+ // const normalForce: IForce = {
+ // description: "Normal Force",
+ // magnitude:
+ // forceOfGravity.magnitude *
+ // Math.cos(Math.atan(wedgeHeight / wedgeWidth)),
+ // directionInDegrees:
+ // 180 - 90 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI,
+ // };
+ // let frictionForce: IForce = {
+ // description: "Kinetic Friction Force",
+ // magnitude:
+ // coefficientOfKineticFriction *
+ // forceOfGravity.magnitude *
+ // Math.cos(Math.atan(wedgeHeight / wedgeWidth)),
+ // directionInDegrees:
+ // 180 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI,
+ // };
+ // // reduce magnitude of friction force if necessary such that block cannot slide up plane
+ // let yForce = -forceOfGravity.magnitude;
+ // 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) +
+ // forceOfGravity.magnitude) /
+ // Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
+ // }
+ // if (coefficientOfKineticFriction != 0) {
+ // this.props.setUpdatedForces([forceOfGravity, normalForce, frictionForce]);
+ // } else {
+ // this.props.setUpdatedForces([forceOfGravity, normalForce]);
+ // }
+ // }
+ // }, [xVelocity]);
+
+ // const update = () => {
+ // // RK4 update
+ // let xPos = xPosition;
+ // let yPos = yPosition;
+ // let xVel = xVelocity;
+ // let yVel = yVelocity;
+ // for (let i = 0; i < 60; i++) {
+ // let forces1 = this.getNewForces(xPos, yPos, xVel, yVel);
+ // const xAcc1 = this.getNewAccelerationX(forces1);
+ // const yAcc1 = this.getNewAccelerationY(forces1);
+ // const xVel1 = this.getNewVelocity(xVel, xAcc1);
+ // const yVel1 = this.getNewVelocity(yVel, yAcc1);
+
+ // let xVel2 = getNewVelocity(xVel, xAcc1 / 2);
+ // let yVel2 = getNewVelocity(yVel, yAcc1 / 2);
+ // let xPos2 = getNewPosition(xPos, xVel1 / 2);
+ // let yPos2 = getNewPosition(yPos, yVel1 / 2);
+ // const forces2 = this.getNewForces(xPos2, yPos2, xVel2, yVel2);
+ // const xAcc2 = this.getNewAccelerationX(forces2);
+ // const yAcc2 = this.getNewAccelerationY(forces2);
+ // xVel2 = this.getNewVelocity(xVel2, xAcc2);
+ // yVel2 = this.getNewVelocity(yVel2, yAcc2);
+ // xPos2 = this.getNewPosition(xPos2, xVel2);
+ // yPos2 = this.getNewPosition(yPos2, yVel2);
+
+ // let xVel3 = this.getNewVelocity(xVel, xAcc2 / 2);
+ // let yVel3 = this.getNewVelocity(yVel, yAcc2 / 2);
+ // let xPos3 = this.getNewPosition(xPos, xVel2 / 2);
+ // let yPos3 = this.getNewPosition(yPos, yVel2 / 2);
+ // const forces3 = this.getNewForces(xPos3, yPos3, xVel3, yVel3);
+ // const xAcc3 = this.getNewAccelerationX(forces3);
+ // const yAcc3 = this.getNewAccelerationY(forces3);
+ // xVel3 = this.getNewVelocity(xVel3, xAcc3);
+ // yVel3 = this.getNewVelocity(yVel3, yAcc3);
+ // xPos3 = this.getNewPosition(xPos3, xVel3);
+ // yPos3 = this.getNewPosition(yPos3, yVel3);
+
+ // let xVel4 = this.getNewVelocity(xVel, xAcc3);
+ // let yVel4 = this.getNewVelocity(yVel, yAcc3);
+ // let xPos4 = this.getNewPosition(xPos, xVel3);
+ // let yPos4 = this.getNewPosition(yPos, yVel3);
+ // const forces4 = this.getNewForces(xPos4, yPos4, xVel4, yVel4);
+ // const xAcc4 = this.getNewAccelerationX(forces4);
+ // const yAcc4 = this.getNewAccelerationY(forces4);
+ // xVel4 = this.getNewVelocity(xVel4, xAcc4);
+ // yVel4 = this.getNewVelocity(yVel4, yAcc4);
+ // xPos4 = this.getNewPosition(xPos4, xVel4);
+ // yPos4 = this.getNewPosition(yPos4, yVel4);
+
+ // xVel +=
+ // timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0);
+ // yVel +=
+ // timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0);
+ // xPos +=
+ // timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0);
+ // yPos +=
+ // timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0);
+ // }
+
+ // setXVelocity(xVel);
+ // setYVelocity(yVel);
+ // setXPosition(xPos);
+ // setYPosition(yPos);
+ // this.props.setUpdatedForces(getNewForces(xPos, yPos, xVel, yVel));
+ // };
+
+ weightStyle = {
+ backgroundColor: this.props.color,
borderStyle: "solid",
- borderColor: "black",
+ borderColor: this.state.dragging ? "lightblue" : "black",
position: "absolute" as "absolute",
- left: xPosition + "px",
- top: yPosition + "px",
- width: 2 * radius + "px",
- height: 2 * radius + "px",
+ left: this.state.xPosition + "px",
+ top: this.state.yPosition + "px",
+ width: 2 * this.props.radius + "px",
+ height: 2 * this.props.radius + "px",
borderRadius: 50 + "%",
display: "flex",
justifyContent: "center",
alignItems: "center",
touchAction: "none",
};
- if (dragging) {
- weightStyle.borderColor = "lightblue";
- }
- const [clickPositionX, setClickPositionX] = useState(0);
- const [clickPositionY, setClickPositionY] = useState(0);
- const labelBackgroundColor = `rgba(255,255,255,0.5)`;
+ labelBackgroundColor = `rgba(255,255,255,0.5)`;
- // Update x start position
- useEffect(() => {
- setUpdatedStartPosX(startPosX);
- setXPosition(startPosX);
- setXPosDisplay(startPosX);
- }, [startPosX]);
+ // // Update x start position
+ // useEffect(() => {
+ // setUpdatedStartPosX(startPosX);
+ // setXPosition(startPosX);
+ // setXPosDisplay(startPosX);
+ // }, [startPosX]);
- // Update y start position
- useEffect(() => {
- setUpdatedStartPosY(startPosY);
- setYPosition(startPosY);
- setYPosDisplay(startPosY);
- }, [startPosY]);
+ // // Update y start position
+ // useEffect(() => {
+ // setUpdatedStartPosY(startPosY);
+ // setYPosition(startPosY);
+ // setYPosDisplay(startPosY);
+ // }, [startPosY]);
render () {
return (
@@ -515,23 +511,23 @@ export default class Weight extends React.Component {
{
- if (this.props.draggable) {
+ if (this.draggable) {
e.preventDefault();
this.props.setPaused(true);
this.setState({dragging: true});
- setClickPositionX(e.clientX);
- setClickPositionY(e.clientY);
+ this.setState({clickPositionX: e.clientX})
+ this.setState({clickPositionY: e.clientY})
}
}}
onPointerMove={(e) => {
e.preventDefault();
if (this.state.dragging) {
- let newY = this.state.yPosition + e.clientY - clickPositionY;
+ let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
if (newY > this.yMax - 2 * this.props.radius) {
newY = this.yMax - 2 * this.props.radius;
}
- let newX = this.state.xPosition + e.clientX - clickPositionX;
+ let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
if (newX > this.xMax - 2 * this.props.radius) {
newX = this.xMax - 2 * this.props.radius;
} else if (newX < 0) {
@@ -541,31 +537,31 @@ export default class Weight extends React.Component
{
this.setState({yPosition: newY})
this.setState({updatedStartPosX: newX})
this.setState({updatedStartPosY: newY})
- this.setState({displayYPosition: Math.round((yMax - 2 * radius - newY + 5) * 100) / 100})
- setClickPositionX(e.clientX);
- setClickPositionY(e.clientY);
- setDisplayValues();
+ this.props.setDisplayYPosition(Math.round((this.yMax - 2 * this.props.radius - newY + 5) * 100) / 100)
+ this.setState({clickPositionX: e.clientX})
+ this.setState({clickPositionY: e.clientY})
+ this.setDisplayValues();
}
}}
onPointerUp={(e) => {
- if (dragging) {
+ if (this.state.dragging) {
e.preventDefault();
- if (!pendulum) {
- resetEverything();
+ if (!this.props.pendulum) {
+ this.resetEverything();
}
- setDragging(false);
- let newY = this.state.yPosition + e.clientY - clickPositionY;
+ this.setState({dragging: false});
+ let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
if (newY > this.yMax - 2 * this.props.radius) {
newY = this.yMax - 2 * this.props.radius;
}
- let newX = xPosition + e.clientX - clickPositionX;
+ let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
if (newX > this.xMax - 2 * this.props.radius) {
newX = this.xMax - 2 * this.props.radius;
} else if (newX < 0) {
newX = 0;
}
- if (this.state.pendulum) {
+ if (this.props.pendulum) {
const x = this.xMax / 2 - newX - this.props.radius;
const y = newY + this.props.radius + 5;
let angle = (Math.atan(y / x) * 180) / Math.PI;
@@ -587,19 +583,19 @@ export default class Weight extends React.Component {
directionInDegrees: angle,
};
this.setState({kineticFriction: false})
- this.setState({xVelocity: startVelX ?? 0})
- this.setState({yVelocity: startVelY ?? 0})
- setDisplayValues();
- this.setState({updatedForces :[forceOfGravity, forceOfTension]});
+ this.setState({xVelocity: this.props.startVelX ?? 0})
+ this.setState({yVelocity: this.props.startVelY ?? 0})
+ this.setDisplayValues();
+ this.props.setUpdatedForces([this.forceOfGravity, forceOfTension]);
}
}
}}
>
-
- {this.state.pendulum && (
+ {this.props.pendulum && (
{
zIndex: 5,
left: this.state.xPosition + "px",
top: this.state.yPosition - 70 + "px",
- backgroundColor: labelBackgroundColor,
+ backgroundColor: this.labelBackgroundColor,
}}
>
{Math.round(this.props.pendulumLength)} m
@@ -639,7 +635,7 @@ export default class Weight extends React.Component
{
zIndex: -1,
left: this.xMax / 2 + "px",
top: 30 + "px",
- backgroundColor: labelBackgroundColor,
+ backgroundColor: this.labelBackgroundColor,
}}
>
{Math.round(this.props.pendulumAngle * 100) / 100}°
@@ -676,8 +672,8 @@ export default class Weight extends React.Component {
{
left:
this.state.xPosition +
this.props.radius +
- getNewAccelerationX(this.state.updatedForces) * 5 +
+ this.getNewAccelerationX(this.props.updatedForces) * 5 +
25 +
"px",
top:
this.state.yPosition +
this.props.radius +
- getNewAccelerationY(this.state.updatedForces) * 5 +
+ this.getNewAccelerationY(this.props.updatedForces) * 5 +
25 +
"px",
zIndex: -1,
@@ -707,8 +703,8 @@ export default class Weight extends React.Component {
{Math.round(
100 *
Math.sqrt(
- Math.pow(getNewAccelerationX(this.state.updatedForces) * 3, 2) +
- Math.pow(getNewAccelerationY(this.state.updatedForces) * 3, 2)
+ Math.pow(this.getNewAccelerationX(this.props.updatedForces) * 3, 2) +
+ Math.pow(this.getNewAccelerationY(this.props.updatedForces) * 3, 2)
)
) / 100}{" "}
m/s2
@@ -817,12 +813,12 @@ export default class Weight extends React.Component {
pointerEvents: "none",
position: "absolute",
zIndex: -1,
- left: xMin,
- top: yMin,
+ left: this.xMin,
+ top: this.yMin,
}}
>
@@ -857,12 +853,12 @@ export default class Weight extends React.Component {
top: labelTop + "px",
// zIndex: -1,
lineHeight: 0.5,
- backgroundColor: labelBackgroundColor,
+ backgroundColor: this.labelBackgroundColor,
}}
>
{force.description && {force.description}
}
{!force.description && Force
}
- {showForceMagnitudes && (
+ {this.props.showForceMagnitudes && (
{Math.round(100 * force.magnitude) / 100} N
)}
--
cgit v1.2.3-70-g09d2
From e73ee7676183bb91687130ba9147e74a5f55420c Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Fri, 3 Feb 2023 00:09:08 -0500
Subject: convert to class
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 99 +++---
src/client/views/nodes/PhysicsSimulationWall.tsx | 4 +-
src/client/views/nodes/PhysicsSimulationWeight.tsx | 346 ++++++++++-----------
3 files changed, 222 insertions(+), 227 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index bd218f63b..0536d0679 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -1,7 +1,7 @@
import React = require('react');
import "./PhysicsSimulationBox.scss";
import Weight, { IForce } from "./PhysicsSimulationWeight";
-import Wall from "./PhysicsSimulationWall"
+import Wall, { IWallProps } from "./PhysicsSimulationWall"
import Wedge from "./PhysicsSimulationWedge"
import { props, any } from 'bluebird';
import { render } from 'react-dom';
@@ -153,7 +153,7 @@ export default class App extends React.Component<{}, IState> {
let angle = 50;
let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
- let xPos = xMax / 2 - x - 50;
+ let xPos = this.xMax / 2 - x - 50;
let yPos = y - 50 - 5;
this.addPendulum();
this.setState({startPosX: xPos})
@@ -461,52 +461,50 @@ export default class App extends React.Component<{}, IState> {
);
})} */}
- {/* {weight && (
+ {/* {this.state.weight && (
{this.setState({sketching: val})}}
+ setDisplayXAcceleration={(val: number) => {this.setState({accelerationXDisplay: val})}}
+ setDisplayXPosition={(val: number) => {this.setState({positionXDisplay: val})}}
+ setDisplayXVelocity={(val: number) => {this.setState({velocityXDisplay: val})}}
+ setDisplayYAcceleration={(val: number) => {this.setState({accelerationYDisplay: val})}}
+ setDisplayYPosition={(val: number) => {this.setState({positionYDisplay: val})}}
+ setDisplayYVelocity={(val: number) => {this.setState({velocityYDisplay: val})}}
+ setPaused={(val: boolean) => {this.setState({simulationPaused: val})}}
+ setPendulumAngle={(val: number) => {this.setState({pendulumAngle: val})}}
+ setPendulumLength={(val: number) => {this.setState({pendulumLength: val})}}
+ setStartPendulumAngle={(val: number) => {this.setState({startPendulumAngle: val})}}
+ setUpdatedForces={(val: IForce[]) => {this.setState({updatedForces: val})}}
+ showAcceleration={this.state.showAcceleration}
+ showForces={this.state.showForces}
+ showVelocity={this.state.showVelocity}
+ startForces={this.state.startForces}
+ startPosX={this.state.startPosX}
+ startPosY={this.state.startPosY}
timestepSize={0.002}
- updateDisplay={displayChange}
- updatedForces={updatedForces}
- walls={wallPositions}
- wedge={wedge}
- wedgeHeight={wedgeHeight}
- wedgeWidth={wedgeWidth}
- coefficientOfKineticFriction={Number(
- coefficientOfKineticFriction
- )}
+ updateDisplay={this.state.displayChange}
+ updatedForces={this.state.updatedForces}
+ walls={this.state.wallPositions}
+ wedge={this.state.wedge}
+ wedgeHeight={this.state.wedgeHeight}
+ wedgeWidth={this.state.wedgeWidth}
+ coefficientOfKineticFriction={this.state.coefficientOfKineticFriction}
/>
)} */}
{this.state.wedge && (
@@ -520,13 +518,14 @@ export default class App extends React.Component<{}, IState> {
{this.state.wallPositions.map((element, index) => {
return (
-
+
+
+
);
})}
diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx
index a31704d2f..2608e4772 100644
--- a/src/client/views/nodes/PhysicsSimulationWall.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWall.tsx
@@ -12,10 +12,10 @@ export interface IWallProps {
angleInDegrees: number;
}
-export default class App extends React.Component {
+export default class App extends React.Component {
constructor(props: any) {
- super(props)
+ super(props)
}
wallStyle = {
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index fb040c850..669aab67a 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -197,6 +197,77 @@ export default class Weight extends React.Component {
this.setState({yVelocity: this.props.startVelY ?? 0})
this.setDisplayValues();
}
+ if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) {
+ // Change pendulum angle based on input field
+ 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.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.setPendulumAngle(this.props.adjustPendulumAngle.angle);
+ this.props.setPendulumLength(this.props.adjustPendulumAngle.length);
+ }
+ // Update x start position
+ if (this.props.startPosX != prevProps.startPosX) {
+ this.setState({updatedStartPosX: this.props.startPosX})
+ this.setState({xPosition: this.props.startPosX})
+ this.setXPosDisplay(this.props.startPosX);
+ }
+ // Update y start position
+ if (this.props.startPosY != prevProps.startPosY) {
+ this.setState({updatedStartPosY: this.props.startPosY})
+ this.setState({yPosition: this.props.startPosY})
+ this.setYPosDisplay(this.props.startPosY);
+ }
+ if (this.state.xVelocity != prevState.xVelocity) {
+ if (this.props.wedge && this.state.xVelocity != 0 && !this.state.kineticFriction) {
+ this.setState({kineticFriction: true});
+ //switch from static to kinetic friction
+ const normalForce: IForce = {
+ description: "Normal Force",
+ magnitude:
+ this.forceOfGravity.magnitude *
+ Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ directionInDegrees:
+ 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
+ };
+ let frictionForce: IForce = {
+ description: "Kinetic Friction Force",
+ magnitude:
+ this.props.coefficientOfKineticFriction *
+ this.forceOfGravity.magnitude *
+ Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ directionInDegrees:
+ 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
+ };
+ // reduce magnitude of friction force if necessary such that block cannot slide up plane
+ let yForce = -this.forceOfGravity.magnitude;
+ 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) +
+ this.forceOfGravity.magnitude) /
+ Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
+ }
+ if (this.props.coefficientOfKineticFriction != 0) {
+ this.props.setUpdatedForces([this.forceOfGravity, normalForce, frictionForce]);
+ } else {
+ this.props.setUpdatedForces([this.forceOfGravity, normalForce]);
+ }
+ }
+ }
}
resetEverything = () => {
@@ -209,23 +280,6 @@ export default class Weight extends React.Component {
this.setDisplayValues();
};
- // // Change pendulum angle based on input field
- // useEffect(() => {
- // let length = adjustPendulumAngle.length;
- // const x =
- // length * Math.cos(((90 - adjustPendulumAngle.angle) * Math.PI) / 180);
- // const y =
- // length * Math.sin(((90 - adjustPendulumAngle.angle) * Math.PI) / 180);
- // const xPos = xMax / 2 - x - radius;
- // const yPos = y - radius - 5;
- // setXPosition(xPos);
- // setYPosition(yPos);
- // setUpdatedStartPosX(xPos);
- // setUpdatedStartPosY(yPos);
- // setPendulumAngle(adjustPendulumAngle.angle);
- // setPendulumLength(adjustPendulumAngle.length);
- // }, [adjustPendulumAngle]);
-
getNewAccelerationX = (forceList: IForce[]) => {
let newXAcc = 0;
forceList.forEach((force) => {
@@ -294,41 +348,41 @@ export default class Weight extends React.Component {
return vel + acc * this.props.timestepSize;
};
- // const checkForCollisionsWithWall = () => {
- // let collision = false;
- // const minX = this.state.xPosition;
- // const maxX = this.state.xPosition + 2 * this.props.radius;
- // const containerWidth = window.innerWidth;
- // if (this.state.xVelocity != 0) {
- // this.props.walls.forEach((wall) => {
- // if (wall.angleInDegrees == 90) {
- // const wallX = (wall.xPos / 100) * window.innerWidth;
- // if (wall.xPos < 0.35) {
- // if (minX <= wallX) {
- // if (elasticCollisions) {
- // setXVelocity(-xVelocity);
- // } else {
- // setXVelocity(0);
- // setXPosition(wallX + 5);
- // }
- // collision = true;
- // }
- // } else {
- // if (maxX >= wallX) {
- // if (elasticCollisions) {
- // setXVelocity(-xVelocity);
- // } else {
- // setXVelocity(0);
- // setXPosition(wallX - 2 * radius + 5);
- // }
- // collision = true;
- // }
- // }
- // }
- // });
- // }
- // return collision;
- // };
+ checkForCollisionsWithWall = () => {
+ let collision = false;
+ const minX = this.state.xPosition;
+ const maxX = this.state.xPosition + 2 * this.props.radius;
+ const containerWidth = window.innerWidth;
+ if (this.state.xVelocity != 0) {
+ this.props.walls.forEach((wall) => {
+ if (wall.angleInDegrees == 90) {
+ const wallX = (wall.xPos / 100) * window.innerWidth;
+ if (wall.xPos < 0.35) {
+ if (minX <= wallX) {
+ if (this.props.elasticCollisions) {
+ this.setState({xVelocity: -this.state.xVelocity});
+ } else {
+ this.setState({xVelocity: 0});
+ this.setState({xPosition: wallX+5});
+ }
+ collision = true;
+ }
+ } else {
+ if (maxX >= wallX) {
+ if (this.props.elasticCollisions) {
+ this.setState({xVelocity: -this.state.xVelocity});
+ } else {
+ this.setState({xVelocity: 0});
+ this.setState({xPosition: wallX - 2 * this.props.radius + 5});
+ }
+ collision = true;
+ }
+ }
+ }
+ });
+ }
+ return collision;
+ };
checkForCollisionsWithGround = () => {
let collision = false;
@@ -363,115 +417,71 @@ export default class Weight extends React.Component {
return collision;
};
- // useEffect(() => {
- // if (wedge && xVelocity != 0 && mode != "Review" && !kineticFriction) {
- // setKineticFriction(true);
- // //switch from static to kinetic friction
- // const normalForce: IForce = {
- // description: "Normal Force",
- // magnitude:
- // forceOfGravity.magnitude *
- // Math.cos(Math.atan(wedgeHeight / wedgeWidth)),
- // directionInDegrees:
- // 180 - 90 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI,
- // };
- // let frictionForce: IForce = {
- // description: "Kinetic Friction Force",
- // magnitude:
- // coefficientOfKineticFriction *
- // forceOfGravity.magnitude *
- // Math.cos(Math.atan(wedgeHeight / wedgeWidth)),
- // directionInDegrees:
- // 180 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI,
- // };
- // // reduce magnitude of friction force if necessary such that block cannot slide up plane
- // let yForce = -forceOfGravity.magnitude;
- // 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) +
- // forceOfGravity.magnitude) /
- // Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
- // }
- // if (coefficientOfKineticFriction != 0) {
- // this.props.setUpdatedForces([forceOfGravity, normalForce, frictionForce]);
- // } else {
- // this.props.setUpdatedForces([forceOfGravity, normalForce]);
- // }
- // }
- // }, [xVelocity]);
-
- // const update = () => {
- // // RK4 update
- // let xPos = xPosition;
- // let yPos = yPosition;
- // let xVel = xVelocity;
- // let yVel = yVelocity;
- // for (let i = 0; i < 60; i++) {
- // let forces1 = this.getNewForces(xPos, yPos, xVel, yVel);
- // const xAcc1 = this.getNewAccelerationX(forces1);
- // const yAcc1 = this.getNewAccelerationY(forces1);
- // const xVel1 = this.getNewVelocity(xVel, xAcc1);
- // const yVel1 = this.getNewVelocity(yVel, yAcc1);
-
- // let xVel2 = getNewVelocity(xVel, xAcc1 / 2);
- // let yVel2 = getNewVelocity(yVel, yAcc1 / 2);
- // let xPos2 = getNewPosition(xPos, xVel1 / 2);
- // let yPos2 = getNewPosition(yPos, yVel1 / 2);
- // const forces2 = this.getNewForces(xPos2, yPos2, xVel2, yVel2);
- // const xAcc2 = this.getNewAccelerationX(forces2);
- // const yAcc2 = this.getNewAccelerationY(forces2);
- // xVel2 = this.getNewVelocity(xVel2, xAcc2);
- // yVel2 = this.getNewVelocity(yVel2, yAcc2);
- // xPos2 = this.getNewPosition(xPos2, xVel2);
- // yPos2 = this.getNewPosition(yPos2, yVel2);
-
- // let xVel3 = this.getNewVelocity(xVel, xAcc2 / 2);
- // let yVel3 = this.getNewVelocity(yVel, yAcc2 / 2);
- // let xPos3 = this.getNewPosition(xPos, xVel2 / 2);
- // let yPos3 = this.getNewPosition(yPos, yVel2 / 2);
- // const forces3 = this.getNewForces(xPos3, yPos3, xVel3, yVel3);
- // const xAcc3 = this.getNewAccelerationX(forces3);
- // const yAcc3 = this.getNewAccelerationY(forces3);
- // xVel3 = this.getNewVelocity(xVel3, xAcc3);
- // yVel3 = this.getNewVelocity(yVel3, yAcc3);
- // xPos3 = this.getNewPosition(xPos3, xVel3);
- // yPos3 = this.getNewPosition(yPos3, yVel3);
-
- // let xVel4 = this.getNewVelocity(xVel, xAcc3);
- // let yVel4 = this.getNewVelocity(yVel, yAcc3);
- // let xPos4 = this.getNewPosition(xPos, xVel3);
- // let yPos4 = this.getNewPosition(yPos, yVel3);
- // const forces4 = this.getNewForces(xPos4, yPos4, xVel4, yVel4);
- // const xAcc4 = this.getNewAccelerationX(forces4);
- // const yAcc4 = this.getNewAccelerationY(forces4);
- // xVel4 = this.getNewVelocity(xVel4, xAcc4);
- // yVel4 = this.getNewVelocity(yVel4, yAcc4);
- // xPos4 = this.getNewPosition(xPos4, xVel4);
- // yPos4 = this.getNewPosition(yPos4, yVel4);
-
- // xVel +=
- // timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0);
- // yVel +=
- // timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0);
- // xPos +=
- // timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0);
- // yPos +=
- // timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0);
- // }
-
- // setXVelocity(xVel);
- // setYVelocity(yVel);
- // setXPosition(xPos);
- // setYPosition(yPos);
- // this.props.setUpdatedForces(getNewForces(xPos, yPos, xVel, yVel));
- // };
+ update = () => {
+ // RK4 update
+ let xPos = this.state.xPosition;
+ let yPos = this.state.yPosition;
+ let xVel = this.state.xVelocity;
+ let yVel = this.state.yVelocity;
+ for (let i = 0; i < 60; i++) {
+ let forces1 = this.getNewForces(xPos, yPos, xVel, yVel);
+ const xAcc1 = this.getNewAccelerationX(forces1);
+ const yAcc1 = this.getNewAccelerationY(forces1);
+ const xVel1 = this.getNewVelocity(xVel, xAcc1);
+ const yVel1 = this.getNewVelocity(yVel, yAcc1);
+
+ let xVel2 = this.getNewVelocity(xVel, xAcc1 / 2);
+ let yVel2 = this.getNewVelocity(yVel, yAcc1 / 2);
+ let xPos2 = this.getNewPosition(xPos, xVel1 / 2);
+ let yPos2 = this.getNewPosition(yPos, yVel1 / 2);
+ const forces2 = this.getNewForces(xPos2, yPos2, xVel2, yVel2);
+ const xAcc2 = this.getNewAccelerationX(forces2);
+ const yAcc2 = this.getNewAccelerationY(forces2);
+ xVel2 = this.getNewVelocity(xVel2, xAcc2);
+ yVel2 = this.getNewVelocity(yVel2, yAcc2);
+ xPos2 = this.getNewPosition(xPos2, xVel2);
+ yPos2 = this.getNewPosition(yPos2, yVel2);
+
+ let xVel3 = this.getNewVelocity(xVel, xAcc2 / 2);
+ let yVel3 = this.getNewVelocity(yVel, yAcc2 / 2);
+ let xPos3 = this.getNewPosition(xPos, xVel2 / 2);
+ let yPos3 = this.getNewPosition(yPos, yVel2 / 2);
+ const forces3 = this.getNewForces(xPos3, yPos3, xVel3, yVel3);
+ const xAcc3 = this.getNewAccelerationX(forces3);
+ const yAcc3 = this.getNewAccelerationY(forces3);
+ xVel3 = this.getNewVelocity(xVel3, xAcc3);
+ yVel3 = this.getNewVelocity(yVel3, yAcc3);
+ xPos3 = this.getNewPosition(xPos3, xVel3);
+ yPos3 = this.getNewPosition(yPos3, yVel3);
+
+ let xVel4 = this.getNewVelocity(xVel, xAcc3);
+ let yVel4 = this.getNewVelocity(yVel, yAcc3);
+ let xPos4 = this.getNewPosition(xPos, xVel3);
+ let yPos4 = this.getNewPosition(yPos, yVel3);
+ const forces4 = this.getNewForces(xPos4, yPos4, xVel4, yVel4);
+ const xAcc4 = this.getNewAccelerationX(forces4);
+ const yAcc4 = this.getNewAccelerationY(forces4);
+ xVel4 = this.getNewVelocity(xVel4, xAcc4);
+ yVel4 = this.getNewVelocity(yVel4, yAcc4);
+ xPos4 = this.getNewPosition(xPos4, xVel4);
+ yPos4 = this.getNewPosition(yPos4, yVel4);
+
+ xVel +=
+ this.props.timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0);
+ yVel +=
+ this.props.timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0);
+ xPos +=
+ this.props.timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0);
+ yPos +=
+ this.props.timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0);
+ }
+
+ this.setState({xVelocity: xVel});
+ this.setState({yVelocity: yVel});
+ this.setState({xPosition: xPos});
+ this.setState({yPosition: yPos});
+ this.props.setUpdatedForces(this.getNewForces(xPos, yPos, xVel, yVel));
+ };
weightStyle = {
backgroundColor: this.props.color,
@@ -491,20 +501,6 @@ export default class Weight extends React.Component {
labelBackgroundColor = `rgba(255,255,255,0.5)`;
- // // Update x start position
- // useEffect(() => {
- // setUpdatedStartPosX(startPosX);
- // setXPosition(startPosX);
- // setXPosDisplay(startPosX);
- // }, [startPosX]);
-
- // // Update y start position
- // useEffect(() => {
- // setUpdatedStartPosY(startPosY);
- // setYPosition(startPosY);
- // setYPosDisplay(startPosY);
- // }, [startPosY]);
-
render () {
return (
--
cgit v1.2.3-70-g09d2
From 728db020856e3ff5c11e7eabbb4fe48f10a9a490 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Mon, 6 Feb 2023 19:41:25 -0500
Subject: code compiles and runs
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 10 ++++------
src/client/views/nodes/PhysicsSimulationWall.tsx | 3 +--
src/client/views/nodes/PhysicsSimulationWedge.tsx | 15 +++++++--------
src/client/views/nodes/PhysicsSimulationWeight.tsx | 22 ++++++++++------------
4 files changed, 22 insertions(+), 28 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index 0536d0679..1dfa04a31 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -3,8 +3,6 @@ import "./PhysicsSimulationBox.scss";
import Weight, { IForce } from "./PhysicsSimulationWeight";
import Wall, { IWallProps } from "./PhysicsSimulationWall"
import Wedge from "./PhysicsSimulationWedge"
-import { props, any } from 'bluebird';
-import { render } from 'react-dom';
interface PhysicsVectorTemplate {
top: number;
@@ -70,8 +68,8 @@ export default class App extends React.Component<{}, IState> {
};
xMin = 0;
yMin = 0;
- xMax = window.innerWidth * 0.7;
- yMax = window.innerHeight * 0.8;
+ xMax = 300;
+ yMax = 300;
color = `rgba(0,0,0,0.5)`;
radius = 50
@@ -461,7 +459,7 @@ export default class App extends React.Component<{}, IState> {
);
})} */}
- {/* {this.state.weight && (
+ {this.state.weight && (
{
wedgeWidth={this.state.wedgeWidth}
coefficientOfKineticFriction={this.state.coefficientOfKineticFriction}
/>
- )} */}
+ )}
{this.state.wedge && (
{
updateCoordinates() {
const coordinatePair1 =
- Math.round(this.state.left) + "," + Math.round(window.innerHeight * 0.8) + " ";
+ Math.round(this.state.left) + "," + Math.round(300 * 0.8) + " ";
const coordinatePair2 =
Math.round(this.state.left + this.props.startWidth) +
"," +
- Math.round(window.innerHeight * 0.8) +
+ Math.round(300 * 0.8) +
" ";
const coordinatePair3 =
Math.round(this.state.left) +
"," +
- Math.round(window.innerHeight * 0.8 - this.props.startHeight);
+ Math.round(300 * 0.8 - this.props.startHeight);
const coord = coordinatePair1 + coordinatePair2 + coordinatePair3;
this.setState({coordinates: coord});
}
@@ -59,8 +58,8 @@ export default class Wedge extends React.Component {
@@ -71,7 +70,7 @@ export default class Wedge extends React.Component
{
position: "absolute",
zIndex: 500,
left: Math.round(this.state.left + this.props.startWidth - 80) + "px",
- top: Math.round(window.innerHeight * 0.8 - 40) + "px",
+ top: Math.round(300 * 0.8 - 40) + "px",
}}
>
{Math.round(((this.state.angleInRadians * 180) / Math.PI) * 100) / 100}°
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index 669aab67a..9ce740ae9 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -1,6 +1,4 @@
-import React from "react";
-import { useEffect, useState } from "react";
-import { render } from "react-dom";
+import React = require('react');
import { IWallProps } from "./PhysicsSimulationWall";
import Wedge from "./PhysicsSimulationWedge";
@@ -94,9 +92,9 @@ export default class Weight extends React.Component {
magnitude: this.props.mass * 9.81,
directionInDegrees: 270,
};
- xMax = window.innerWidth * 0.7;
+ xMax = 300;
xMin = 0;
- yMax = window.innerHeight * 0.8;
+ yMax = 300;
yMin = 0;
// Helper function to go between display and real values
@@ -352,11 +350,11 @@ export default class Weight extends React.Component {
let collision = false;
const minX = this.state.xPosition;
const maxX = this.state.xPosition + 2 * this.props.radius;
- const containerWidth = window.innerWidth;
+ const containerWidth = 300;
if (this.state.xVelocity != 0) {
this.props.walls.forEach((wall) => {
if (wall.angleInDegrees == 90) {
- const wallX = (wall.xPos / 100) * window.innerWidth;
+ const wallX = (wall.xPos / 100) * 300;
if (wall.xPos < 0.35) {
if (minX <= wallX) {
if (this.props.elasticCollisions) {
@@ -390,7 +388,7 @@ export default class Weight extends React.Component {
if (this.state.yVelocity > 0) {
this.props.walls.forEach((wall) => {
if (wall.angleInDegrees == 0) {
- const groundY = (wall.yPos / 100) * window.innerHeight;
+ const groundY = (wall.yPos / 100) * 300;
if (maxY >= groundY) {
if (this.props.elasticCollisions) {
this.setState({yVelocity: -this.state.yVelocity})
@@ -602,7 +600,7 @@ export default class Weight extends React.Component {
zIndex: -2,
}}
>
-
+
{
top: 0,
}}
>
-
+
{
top: 0,
}}
>
-
+
{
>
Date: Mon, 6 Feb 2023 20:11:42 -0500
Subject: debugging and UI
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 5 ++-
src/client/views/nodes/PhysicsSimulationBox.scss | 35 +++------------
src/client/views/nodes/PhysicsSimulationWall.tsx | 4 +-
src/client/views/nodes/PhysicsSimulationWeight.tsx | 51 ++++++++++++++--------
4 files changed, 45 insertions(+), 50 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index 1dfa04a31..608a38f1a 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -96,7 +96,7 @@ export default class App extends React.Component<{}, IState> {
showForceMagnitudes: false,
showForces: false,
showVelocity: false,
- simulationPaused: false,
+ simulationPaused: true,
simulationReset: false,
simulationType: "Inclined Plane",
sketching: false,
@@ -307,6 +307,9 @@ export default class App extends React.Component<{}, IState> {
componentDidMount() {
+ // Add weight
+ this.addWeight()
+
// Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
document.addEventListener("keydown", (e) => {
if (e.shiftKey) {
diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss
index 1db758540..cfe2ee6ca 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.scss
+++ b/src/client/views/nodes/PhysicsSimulationBox.scss
@@ -4,33 +4,20 @@
}
.mechanicsSimulationContainer {
- height: 100vh;
- width: 100vw;
+ background-color: white;
+ height: 100%;
+ width: 100%;
display: flex;
- .mechanicsSimulationContentContainer {
- width: 70%;
-
- .mechanicsSimulationButtons {
- display: flex;
- justify-content: space-between;
- }
- }
-
.mechanicsSimulationEquationContainer {
- width: 30%;
+ position: fixed;
+ left: 70%;
padding: 1em;
- display: flex;
- flex-direction: column;
.mechanicsSimulationControls {
display: flex;
justify-content: space-between;
}
-
- .slider {
- margin-top: 0.5em;
- }
}
}
@@ -56,18 +43,6 @@ button {
z-index: 5000;
}
-.wordProblemBox {
- border-style: solid;
- border-color: black;
- border-width: 1px;
- margin-top: 10px;
- padding: 10px;
-}
-
-.answer-inactive {
- pointer-events: none;
-}
-
.angleLabel {
font-weight: bold;
font-size: 20px;
diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx
index e1f753179..d502c066a 100644
--- a/src/client/views/nodes/PhysicsSimulationWall.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWall.tsx
@@ -18,8 +18,8 @@ export default class App extends React.Component {
}
wallStyle = {
- width: this.props.angleInDegrees == 0 ? this.props.length + "%" : 0.5 + "vw",
- height: this.props.angleInDegrees == 0 ? 0.5 + "vw" : this.props.length + "%",
+ width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "5px",
+ height: this.props.angleInDegrees == 0 ? "5px" : this.props.length + "%",
position: "absolute" as "absolute",
left: this.props.xPos + "%",
top: this.props.yPos + "%",
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index 9ce740ae9..07ab84bd8 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -97,6 +97,23 @@ export default class Weight extends React.Component {
yMax = 300;
yMin = 0;
+ // Var
+ weightStyle = {
+ backgroundColor: this.props.color,
+ borderStyle: "solid",
+ borderColor: "black",
+ position: "absolute" as "absolute",
+ left: this.props.startPosX + "px",
+ top: this.props.startPosY + "px",
+ width: 2 * this.props.radius + "px",
+ height: 2 * this.props.radius + "px",
+ borderRadius: 50 + "%",
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center",
+ touchAction: "none",
+ };
+
// Helper function to go between display and real values
getDisplayYPos = (yPos: number) => {
return this.yMax - yPos - 2 * this.props.radius + 5;
@@ -138,8 +155,8 @@ export default class Weight extends React.Component {
);
};
- // When display values updated by user, update real values
componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void {
+ // When display values updated by user, update real values
if (this.props.updateDisplay != prevProps.updateDisplay) {
if (this.props.updateDisplay.xDisplay != this.state.xPosition) {
let x = this.props.updateDisplay.xDisplay;
@@ -187,6 +204,22 @@ export default class Weight extends React.Component {
this.setDisplayValues();
}
}
+ this.weightStyle = {
+ backgroundColor: this.props.color,
+ borderStyle: "solid",
+ borderColor: this.state.dragging ? "lightblue" : "black",
+ position: "absolute" as "absolute",
+ left: this.state.xPosition + "px",
+ top: this.state.yPosition + "px",
+ width: 2 * this.props.radius + "px",
+ height: 2 * this.props.radius + "px",
+ borderRadius: 50 + "%",
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center",
+ touchAction: "none",
+ };
+
if (this.props.reset != prevProps.reset) {
this.resetEverything();
}
@@ -481,22 +514,6 @@ export default class Weight extends React.Component {
this.props.setUpdatedForces(this.getNewForces(xPos, yPos, xVel, yVel));
};
- weightStyle = {
- backgroundColor: this.props.color,
- borderStyle: "solid",
- borderColor: this.state.dragging ? "lightblue" : "black",
- position: "absolute" as "absolute",
- left: this.state.xPosition + "px",
- top: this.state.yPosition + "px",
- width: 2 * this.props.radius + "px",
- height: 2 * this.props.radius + "px",
- borderRadius: 50 + "%",
- display: "flex",
- justifyContent: "center",
- alignItems: "center",
- touchAction: "none",
- };
-
labelBackgroundColor = `rgba(255,255,255,0.5)`;
render () {
--
cgit v1.2.3-70-g09d2
From 983ffa5e10abd89448e8b3f9be65894c7b775d84 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Tue, 7 Feb 2023 12:21:00 -0500
Subject: wall show
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 6 +++---
src/client/views/nodes/PhysicsSimulationWall.tsx | 5 ++---
src/client/views/nodes/PhysicsSimulationWeight.tsx | 7 +++++--
3 files changed, 10 insertions(+), 8 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index 608a38f1a..a2490cce8 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -298,9 +298,9 @@ export default class App extends React.Component<{}, IState> {
addWalls = () => {
if (this.state.wallPositions.length == 0) {
let walls = [];
- walls.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 });
- walls.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 });
- walls.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 });
+ walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 });
+ walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 });
+ walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 });
this.setState({wallPositions: walls})
}
};
diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx
index d502c066a..f6396d6a7 100644
--- a/src/client/views/nodes/PhysicsSimulationWall.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWall.tsx
@@ -18,13 +18,12 @@ export default class App extends React.Component {
}
wallStyle = {
- width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "5px",
- height: this.props.angleInDegrees == 0 ? "5px" : this.props.length + "%",
+ width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "3%",
+ height: this.props.angleInDegrees == 0 ? "3%" : this.props.length + "%",
position: "absolute" as "absolute",
left: this.props.xPos + "%",
top: this.props.yPos + "%",
backgroundColor: "#6c7b8b",
- zIndex: -1000,
margin: 0,
padding: 0,
};
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index 07ab84bd8..92d65cf3d 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -93,8 +93,8 @@ export default class Weight extends React.Component {
directionInDegrees: 270,
};
xMax = 300;
- xMin = 0;
yMax = 300;
+ xMin = 0;
yMin = 0;
// Var
@@ -397,6 +397,7 @@ export default class Weight extends React.Component {
this.setState({xPosition: wallX+5});
}
collision = true;
+ console.log('collision with wall')
}
} else {
if (maxX >= wallX) {
@@ -407,6 +408,7 @@ export default class Weight extends React.Component {
this.setState({xPosition: wallX - 2 * this.props.radius + 5});
}
collision = true;
+ console.log('collision with wall')
}
}
}
@@ -421,8 +423,9 @@ export default class Weight extends React.Component {
if (this.state.yVelocity > 0) {
this.props.walls.forEach((wall) => {
if (wall.angleInDegrees == 0) {
- const groundY = (wall.yPos / 100) * 300;
+ const groundY = (wall.yPos / 100) * this.yMax;
if (maxY >= groundY) {
+ console.log('collision with ground ', wall, maxY)
if (this.props.elasticCollisions) {
this.setState({yVelocity: -this.state.yVelocity})
} else {
--
cgit v1.2.3-70-g09d2
From 2387225f18bd63f70569df7039af445064738836 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Tue, 7 Feb 2023 12:58:32 -0500
Subject: free weight and wedge work
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 55 +++++++-----------
src/client/views/nodes/PhysicsSimulationWall.tsx | 2 +-
src/client/views/nodes/PhysicsSimulationWedge.tsx | 21 ++++---
src/client/views/nodes/PhysicsSimulationWeight.tsx | 66 +++++++++++-----------
4 files changed, 68 insertions(+), 76 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index a2490cce8..f31d92db2 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -71,8 +71,7 @@ export default class App extends React.Component<{}, IState> {
xMax = 300;
yMax = 300;
color = `rgba(0,0,0,0.5)`;
- radius = 50
-
+ radius = 0.1*this.yMax
constructor(props: any) {
super(props)
@@ -112,8 +111,8 @@ export default class App extends React.Component<{}, IState> {
wallPositions: [],
wedge: false,
wedgeAngle: 26,
- wedgeHeight: Math.tan((26 * Math.PI) / 180) * 400,
- wedgeWidth: 400,
+ wedgeHeight: Math.tan((26 * Math.PI) / 180) * this.xMax*0.6,
+ wedgeWidth: this.xMax*0.6,
weight: false,
}
}
@@ -219,45 +218,27 @@ export default class App extends React.Component<{}, IState> {
let width = 0;
let height = 0;
if (angle < 50) {
- width = 400;
- height = Math.tan((angle * Math.PI) / 180) * 400;
+ width = this.xMax*0.6;
+ height = Math.tan((angle * Math.PI) / 180) * width;
this.setState({wedgeWidth: width})
this.setState({wedgeHeight: height})
} else if (angle < 70) {
- width = 200;
- height = Math.tan((angle * Math.PI) / 180) * 200;
+ width = this.xMax*0.3;
+ height = Math.tan((angle * Math.PI) / 180) * width;
this.setState({wedgeWidth: width})
this.setState({wedgeHeight: height})
} else {
- width = 100;
- height = Math.tan((angle * Math.PI) / 180) * 100;
+ width = this.xMax*0.15;
+ height = Math.tan((angle * Math.PI) / 180) * width;
this.setState({wedgeWidth: width})
this.setState({wedgeHeight: height})
}
// update weight position based on updated wedge width/height
- let yPos = (width - 50) * Math.tan((angle * Math.PI) / 180);
- if (angle < 40) {
- yPos += Math.sqrt(angle);
- } else if (angle < 58) {
- yPos += angle / 2;
- } else if (angle < 68) {
- yPos += angle;
- } else if (angle < 70) {
- yPos += angle * 1.3;
- } else if (angle < 75) {
- yPos += angle * 1.5;
- } else if (angle < 78) {
- yPos += angle * 2;
- } else if (angle < 79) {
- yPos += angle * 2.25;
- } else if (angle < 80) {
- yPos += angle * 2.6;
- } else {
- yPos += angle * 3;
- }
+ let xPos = (this.xMax * 0.2)-this.radius;
+ let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius;
- this.setState({startPosX: Math.round((this.xMax * 0.5 - 200) * 10) / 10});
+ this.setState({startPosX: xPos});
this.setState({startPosY: this.getDisplayYPos(yPos)});
this.updateForcesWithFriction(
Number(this.state.coefficientOfStaticFriction),
@@ -308,7 +289,7 @@ export default class App extends React.Component<{}, IState> {
componentDidMount() {
// Add weight
- this.addWeight()
+ this.addWedge()
// Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
document.addEventListener("keydown", (e) => {
@@ -477,7 +458,7 @@ export default class App extends React.Component<{}, IState> {
pendulum={this.state.pendulum}
pendulumAngle={this.state.pendulumAngle}
pendulumLength={this.state.pendulumLength}
- radius={50}
+ radius={this.radius}
reset={this.state.simulationReset}
showForceMagnitudes={this.state.showForceMagnitudes}
setSketching={(val: boolean) => {this.setState({sketching: val})}}
@@ -506,13 +487,19 @@ export default class App extends React.Component<{}, IState> {
wedgeHeight={this.state.wedgeHeight}
wedgeWidth={this.state.wedgeWidth}
coefficientOfKineticFriction={this.state.coefficientOfKineticFriction}
+ xMax={this.xMax}
+ yMax={this.yMax}
+ xMin={this.xMin}
+ yMin={this.yMin}
/>
)}
{this.state.wedge && (
)}
diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx
index f6396d6a7..9283e8d46 100644
--- a/src/client/views/nodes/PhysicsSimulationWall.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWall.tsx
@@ -18,7 +18,7 @@ export default class App extends React.Component
{
}
wallStyle = {
- width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "3%",
+ width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "3%",
height: this.props.angleInDegrees == 0 ? "3%" : this.props.length + "%",
position: "absolute" as "absolute",
left: this.props.xPos + "%",
diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx
index b3988221c..43a4d69de 100644
--- a/src/client/views/nodes/PhysicsSimulationWedge.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWedge.tsx
@@ -5,6 +5,8 @@ export interface IWedgeProps {
startHeight: number;
startWidth: number;
startLeft: number;
+ xMax: number;
+ yMax: number;
}
interface IState {
@@ -28,18 +30,19 @@ export default class Wedge extends React.Component {
updateCoordinates() {
const coordinatePair1 =
- Math.round(this.state.left) + "," + Math.round(300 * 0.8) + " ";
+ Math.round(this.state.left) + "," + Math.round(this.props.yMax) + " ";
const coordinatePair2 =
Math.round(this.state.left + this.props.startWidth) +
"," +
- Math.round(300 * 0.8) +
+ Math.round(this.props.yMax) +
" ";
const coordinatePair3 =
Math.round(this.state.left) +
"," +
- Math.round(300 * 0.8 - this.props.startHeight);
+ Math.round(this.props.yMax - this.props.startHeight);
const coord = coordinatePair1 + coordinatePair2 + coordinatePair3;
this.setState({coordinates: coord});
+ console.log("coordinates: ", coord)
}
componentDidMount() {
@@ -47,7 +50,9 @@ export default class Wedge extends React.Component {
}
componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void {
- this.updateCoordinates();
+ if (prevState.coordinates != this.state.coordinates) {
+ this.updateCoordinates();
+ }
if (prevProps.startHeight != this.props.startHeight || prevProps.startWidth != this.props.startWidth) {
this.setState({angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth)});
}
@@ -56,10 +61,10 @@ export default class Wedge extends React.Component {
render() {
return (
-
+
@@ -70,7 +75,7 @@ export default class Wedge extends React.Component
{
position: "absolute",
zIndex: 500,
left: Math.round(this.state.left + this.props.startWidth - 80) + "px",
- top: Math.round(300 * 0.8 - 40) + "px",
+ top: Math.round(this.props.yMax - 40) + "px",
}}
>
{Math.round(((this.state.angleInRadians * 180) / Math.PI) * 100) / 100}°
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index 92d65cf3d..63f8c965f 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -52,6 +52,10 @@ export interface IWeightProps {
coefficientOfKineticFriction: number;
wedgeWidth: number;
wedgeHeight: number;
+ xMax: number;
+ yMax: number;
+ xMin: number;
+ yMin: number;
}
interface IState {
@@ -92,10 +96,6 @@ export default class Weight extends React.Component {
magnitude: this.props.mass * 9.81,
directionInDegrees: 270,
};
- xMax = 300;
- yMax = 300;
- xMin = 0;
- yMin = 0;
// Var
weightStyle = {
@@ -116,10 +116,10 @@ export default class Weight extends React.Component {
// Helper function to go between display and real values
getDisplayYPos = (yPos: number) => {
- return this.yMax - yPos - 2 * this.props.radius + 5;
+ return this.props.yMax - yPos - 2 * this.props.radius + 5;
};
getYPosFromDisplay = (yDisplay: number) => {
- return this.yMax - yDisplay - 2 * this.props.radius + 5;
+ return this.props.yMax - yDisplay - 2 * this.props.radius + 5;
};
// Set display values based on real values
@@ -161,7 +161,7 @@ export default class Weight extends React.Component {
if (this.props.updateDisplay.xDisplay != this.state.xPosition) {
let x = this.props.updateDisplay.xDisplay;
x = Math.max(0, x);
- x = Math.min(x, this.xMax - 2 * this.props.radius);
+ x = Math.min(x, this.props.xMax - 2 * this.props.radius);
this.setState({updatedStartPosX: x})
this.setState({xPosition: x})
this.props.setDisplayXPosition(x);
@@ -170,7 +170,7 @@ export default class Weight extends React.Component {
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.yMax - 2 * this.props.radius);
+ y = Math.min(y, this.props.yMax - 2 * this.props.radius);
this.props.setDisplayYPosition(y);
let coordinatePosition = this.getYPosFromDisplay(y);
this.setState({updatedStartPosY: coordinatePosition})
@@ -235,7 +235,7 @@ export default class Weight extends React.Component {
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.xMax / 2 - x - this.props.radius;
+ 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})
@@ -343,7 +343,7 @@ export default class Weight extends React.Component {
if (!this.props.pendulum) {
return this.props.updatedForces;
}
- const x = this.xMax / 2 - xPos - this.props.radius;
+ 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) {
@@ -423,7 +423,7 @@ export default class Weight extends React.Component {
if (this.state.yVelocity > 0) {
this.props.walls.forEach((wall) => {
if (wall.angleInDegrees == 0) {
- const groundY = (wall.yPos / 100) * this.yMax;
+ const groundY = (wall.yPos / 100) * this.props.yMax;
if (maxY >= groundY) {
console.log('collision with ground ', wall, maxY)
if (this.props.elasticCollisions) {
@@ -537,13 +537,13 @@ export default class Weight extends React.Component {
e.preventDefault();
if (this.state.dragging) {
let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
- if (newY > this.yMax - 2 * this.props.radius) {
- newY = this.yMax - 2 * this.props.radius;
+ if (newY > this.props.yMax - 2 * this.props.radius) {
+ newY = this.props.yMax - 2 * this.props.radius;
}
let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
- if (newX > this.xMax - 2 * this.props.radius) {
- newX = this.xMax - 2 * this.props.radius;
+ if (newX > this.props.xMax - 2 * this.props.radius) {
+ newX = this.props.xMax - 2 * this.props.radius;
} else if (newX < 0) {
newX = 0;
}
@@ -551,7 +551,7 @@ export default class Weight extends React.Component {
this.setState({yPosition: newY})
this.setState({updatedStartPosX: newX})
this.setState({updatedStartPosY: newY})
- this.props.setDisplayYPosition(Math.round((this.yMax - 2 * this.props.radius - newY + 5) * 100) / 100)
+ this.props.setDisplayYPosition(Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100)
this.setState({clickPositionX: e.clientX})
this.setState({clickPositionY: e.clientY})
this.setDisplayValues();
@@ -565,18 +565,18 @@ export default class Weight extends React.Component {
}
this.setState({dragging: false});
let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
- if (newY > this.yMax - 2 * this.props.radius) {
- newY = this.yMax - 2 * this.props.radius;
+ if (newY > this.props.yMax - 2 * this.props.radius) {
+ newY = this.props.yMax - 2 * this.props.radius;
}
let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
- if (newX > this.xMax - 2 * this.props.radius) {
- newX = this.xMax - 2 * this.props.radius;
+ if (newX > this.props.xMax - 2 * this.props.radius) {
+ newX = this.props.xMax - 2 * this.props.radius;
} else if (newX < 0) {
newX = 0;
}
if (this.props.pendulum) {
- const x = this.xMax / 2 - newX - this.props.radius;
+ const x = this.props.xMax / 2 - newX - this.props.radius;
const y = newY + this.props.radius + 5;
let angle = (Math.atan(y / x) * 180) / Math.PI;
if (angle < 0) {
@@ -620,11 +620,11 @@ export default class Weight extends React.Component {
zIndex: -2,
}}
>
-
+
{
style={{
position: "absolute",
zIndex: -1,
- left: this.xMax / 2 + "px",
+ left: this.props.xMax / 2 + "px",
top: 30 + "px",
backgroundColor: this.labelBackgroundColor,
}}
@@ -669,7 +669,7 @@ export default class Weight extends React.Component {
top: 0,
}}
>
-
+
{
top: 0,
}}
>
-
+
{
} else {
labelTop -= 40;
}
- labelTop = Math.min(labelTop, this.yMax + 50);
- labelTop = Math.max(labelTop, this.yMin);
- labelLeft = Math.min(labelLeft, this.xMax - 60);
- labelLeft = Math.max(labelLeft, this.xMin);
+ 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 (
@@ -827,12 +827,12 @@ export default class Weight extends React.Component
{
pointerEvents: "none",
position: "absolute",
zIndex: -1,
- left: this.xMin,
- top: this.yMin,
+ left: this.props.xMin,
+ top: this.props.yMin,
}}
>
--
cgit v1.2.3-70-g09d2
From d757d90c4c5a5609c3c8bca874414e8a5171556c Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Tue, 7 Feb 2023 17:10:23 -0500
Subject: pendulum works
---
src/client/util/CurrentUserUtils.ts | 2 +-
src/client/views/nodes/PhysicsSimulationApp.tsx | 19 +++++++++----------
src/client/views/nodes/PhysicsSimulationWedge.tsx | 1 -
src/client/views/nodes/PhysicsSimulationWeight.tsx | 19 +++++--------------
4 files changed, 15 insertions(+), 26 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 23e9a2bea..c8b36ff3a 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -287,7 +287,7 @@ export class CurrentUserUtils {
{ toolTip: "Tap or drag to create a note board", title: "Notes", icon: "folder", dragFactory: doc.emptyNoteboard as Doc, },
{ toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab), scripts: { onClick: 'openOnRight(copyDragFactory(this.clickFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
{ toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, },
- { toolTip: "Tap or drag to create a physics simulation", title: "Simulation", icon: "calculator", dragFactory: doc.emptySimulation as Doc, },
+ { toolTip: "Tap or drag to create a physics simulation", title: "Simulation", icon: "atom", dragFactory: doc.emptySimulation as Doc, },
{ toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, },
{ toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, },
{ toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, scripts: { onClick: 'openInOverlay(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index f31d92db2..6a3ab28a0 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -146,16 +146,15 @@ export default class App extends React.Component<{}, IState> {
this.setState({weight: true})
this.setState({wedge: false})
this.setState({pendulum: true})
- let length = 300;
- let angle = 50;
+ let length = this.xMax*0.7;
+ let angle = 40;
let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
- let xPos = this.xMax / 2 - x - 50;
- let yPos = y - 50 - 5;
- this.addPendulum();
+ let xPos = this.xMax / 2 - x - this.radius;
+ let yPos = y - this.radius;
this.setState({startPosX: xPos})
this.setState({startPosY: yPos})
- let mag = 9.81 * Math.cos((50 * Math.PI) / 180);
+ let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
let forceOfTension: IForce = {
description: "Tension",
magnitude: mag,
@@ -163,9 +162,9 @@ export default class App extends React.Component<{}, IState> {
};
this.setState({updatedForces: [this.forceOfGravity, forceOfTension]})
this.setState({startForces: [this.forceOfGravity, forceOfTension]})
- this.setState({pendulumAngle: 50})
- this.setState({pendulumLength: 300})
- this.setState({adjustPendulumAngle: {angle: 50, length: 300}})
+ this.setState({pendulumAngle: 40})
+ this.setState({pendulumLength: 100})
+ this.setState({adjustPendulumAngle: {angle: 40, length: 100}})
this.removeWalls();
};
@@ -289,7 +288,7 @@ export default class App extends React.Component<{}, IState> {
componentDidMount() {
// Add weight
- this.addWedge()
+ this.addPendulum()
// Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
document.addEventListener("keydown", (e) => {
diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx
index 43a4d69de..c5a186f18 100644
--- a/src/client/views/nodes/PhysicsSimulationWedge.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWedge.tsx
@@ -42,7 +42,6 @@ export default class Wedge extends React.Component {
Math.round(this.props.yMax - this.props.startHeight);
const coord = coordinatePair1 + coordinatePair2 + coordinatePair3;
this.setState({coordinates: coord});
- console.log("coordinates: ", coord)
}
componentDidMount() {
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index 63f8c965f..dfd463bbe 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -1,6 +1,5 @@
import React = require('react');
import { IWallProps } from "./PhysicsSimulationWall";
-import Wedge from "./PhysicsSimulationWedge";
export interface IForce {
description: string;
@@ -107,6 +106,7 @@ export default class Weight extends React.Component {
top: this.props.startPosY + "px",
width: 2 * this.props.radius + "px",
height: 2 * this.props.radius + "px",
+ zIndex: 5,
borderRadius: 50 + "%",
display: "flex",
justifyContent: "center",
@@ -215,6 +215,7 @@ export default class Weight extends React.Component {
height: 2 * this.props.radius + "px",
borderRadius: 50 + "%",
display: "flex",
+ zIndex: 5,
justifyContent: "center",
alignItems: "center",
touchAction: "none",
@@ -397,7 +398,6 @@ export default class Weight extends React.Component {
this.setState({xPosition: wallX+5});
}
collision = true;
- console.log('collision with wall')
}
} else {
if (maxX >= wallX) {
@@ -408,7 +408,6 @@ export default class Weight extends React.Component {
this.setState({xPosition: wallX - 2 * this.props.radius + 5});
}
collision = true;
- console.log('collision with wall')
}
}
}
@@ -425,7 +424,6 @@ export default class Weight extends React.Component {
if (wall.angleInDegrees == 0) {
const groundY = (wall.yPos / 100) * this.props.yMax;
if (maxY >= groundY) {
- console.log('collision with ground ', wall, maxY)
if (this.props.elasticCollisions) {
this.setState({yVelocity: -this.state.yVelocity})
} else {
@@ -521,7 +519,7 @@ export default class Weight extends React.Component {
render () {
return (
-
+
{
@@ -617,7 +615,6 @@ export default class Weight extends React.Component
{
position: "absolute",
left: 0,
top: 0,
- zIndex: -2,
}}
>
@@ -632,7 +629,7 @@ export default class Weight extends React.Component {
{!this.state.dragging && (
-
{
}}
>
{Math.round(this.props.pendulumLength)} m
-
+ */}
{
style={{
pointerEvents: "none",
position: "absolute",
- zIndex: -1,
left: 0,
top: 0,
}}
@@ -709,7 +704,6 @@ export default class Weight extends React.Component {
this.getNewAccelerationY(this.props.updatedForces) * 5 +
25 +
"px",
- zIndex: -1,
lineHeight: 0.5,
}}
>
@@ -733,7 +727,6 @@ export default class Weight extends React.Component {
style={{
pointerEvents: "none",
position: "absolute",
- zIndex: -1,
left: 0,
top: 0,
}}
@@ -768,7 +761,6 @@ export default class Weight extends React.Component {
position: "absolute",
left: this.state.xPosition + this.props.radius + this.state.xVelocity * 3 + 25 + "px",
top: this.state.yPosition + this.props.radius + this.state.yVelocity * 3 + "px",
- zIndex: -1,
lineHeight: 0.5,
}}
>
@@ -826,7 +818,6 @@ export default class Weight extends React.Component {
style={{
pointerEvents: "none",
position: "absolute",
- zIndex: -1,
left: this.props.xMin,
top: this.props.yMin,
}}
--
cgit v1.2.3-70-g09d2
From 456d91f480ed96ac963c9f17164eb23e76fb4320 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Thu, 9 Feb 2023 10:29:04 -0500
Subject: switch between sim types
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
index 6a3ab28a0..acca65b08 100644
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ b/src/client/views/nodes/PhysicsSimulationApp.tsx
@@ -147,7 +147,7 @@ export default class App extends React.Component<{}, IState> {
this.setState({wedge: false})
this.setState({pendulum: true})
let length = this.xMax*0.7;
- let angle = 40;
+ let angle = 35;
let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
let xPos = this.xMax / 2 - x - this.radius;
@@ -162,9 +162,9 @@ export default class App extends React.Component<{}, IState> {
};
this.setState({updatedForces: [this.forceOfGravity, forceOfTension]})
this.setState({startForces: [this.forceOfGravity, forceOfTension]})
- this.setState({pendulumAngle: 40})
- this.setState({pendulumLength: 100})
- this.setState({adjustPendulumAngle: {angle: 40, length: 100}})
+ this.setState({pendulumAngle: angle})
+ this.setState({pendulumLength: length})
+ this.setState({adjustPendulumAngle: {angle: angle, length: length}})
this.removeWalls();
};
@@ -536,6 +536,17 @@ export default class App extends React.Component<{}, IState> {
this.setState({simulationReset: !this.state.simulationReset});
}} >RESET
)}
+
--
cgit v1.2.3-70-g09d2
From cb19032c67d810d3683e101896e20df7eecec77c Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Sun, 12 Feb 2023 15:34:16 -0500
Subject: start making everything persistent
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 573 +++++++++++++++++++++++-
1 file changed, 556 insertions(+), 17 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 4a68ba5aa..3ea4fba9f 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -3,33 +3,572 @@ import { FieldView, FieldViewProps } from './FieldView';
import React = require('react');
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { observer } from 'mobx-react';
-import App from './PhysicsSimulationApp';
+import "./PhysicsSimulationBox.scss";
+import Weight from "./PhysicsSimulationWeight";
+import Wall from "./PhysicsSimulationWall"
+import Wedge from "./PhysicsSimulationWedge"
export interface IForce {
- description: string;
- magnitude: number;
- directionInDegrees: number;
+ description: string;
+ magnitude: number;
+ directionInDegrees: number;
}
export interface IWallProps {
- length: number;
- xPos: number;
- yPos: number;
- angleInDegrees: number;
+ length: number;
+ xPos: number;
+ yPos: number;
+ angleInDegrees: number;
+}
+
+interface PhysicsVectorTemplate {
+ top: number;
+ left: number;
+ width: number;
+ height: number;
+ x1: number;
+ y1: number;
+ x2: number;
+ y2: number;
+ weightX: number;
+ weightY: number;
+}
+
+interface IState {
+ accelerationXDisplay: number,
+ accelerationYDisplay: number,
+ adjustPendulumAngle: {angle: number, length: number},
+ coefficientOfKineticFriction: number,
+ coefficientOfStaticFriction: number,
+ currentForceSketch: PhysicsVectorTemplate | null,
+ deleteMode: boolean,
+ displayChange: {xDisplay: number, yDisplay: number},
+ elasticCollisions: boolean,
+ forceSketches: PhysicsVectorTemplate[],
+ pendulum: boolean,
+ pendulumAngle: number,
+ pendulumLength: number,
+ positionXDisplay: number,
+ positionYDisplay: number,
+ showAcceleration: boolean,
+ showForceMagnitudes: boolean,
+ showForces: boolean,
+ showVelocity: boolean,
+ simulationPaused: boolean,
+ simulationReset: boolean,
+ simulationType: "Inclined Plane",
+ sketching: boolean,
+ startForces: IForce[],
+ startPendulumAngle: number,
+ startPosX: number,
+ startPosY: number,
+ stepNumber: number,
+ timer: number,
+ updatedForces: IForce[],
+ velocityXDisplay: number,
+ velocityYDisplay: number,
+ wallPositions: IWallProps[],
+ wedge: boolean,
+ wedgeAngle: number,
+ wedgeHeight: number,
+ wedgeWidth: number,
+ weight: boolean,
}
@observer
export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
() {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }
+
+ // Constants
+ gravityMagnitude = 9.81;
+ forceOfGravity: IForce = {
+ description: "Gravity",
+ magnitude: this.gravityMagnitude,
+ directionInDegrees: 270,
+ };
+ xMin = 0;
+ yMin = 0;
+ xMax = 300;
+ yMax = 300;
+ color = `rgba(0,0,0,0.5)`;
+ radius = 0.1*this.yMax
+
+ constructor(props: any) {
+ super(props);
+ this.dataDoc.accelerationXDisplay = 0;
+ this.dataDoc.accelerationYDisplay = 0;
+ this.dataDoc.adjustPendulumAngle = {angle: 0, length: 0};
+ this.dataDoc.coefficientOfKineticFriction = 0;
+ this.dataDoc.coefficientOfStaticFriction = 0;
+ this.dataDoc.currentForceSketch = [];
+ this.dataDoc.deleteMode = false;
+ this.dataDoc.displayChange = {xDisplay: 0, yDisplay: 0};
+ this.dataDoc.elasticCollisions = false;
+ this.dataDoc.forceSketches = [];
+ this.dataDoc.pendulum = false;
+ this.dataDoc.pendulumAngle = 0;
+ this.dataDoc.pendulumLength = 300;
+ this.dataDoc.positionXDisplay = 0;
+ this.dataDoc.positionYDisplay = 0;
+ this.dataDoc.showAcceleration = false;
+ this.dataDoc.showForceMagnitudes = false;
+ this.dataDoc.showForces = false;
+ this.dataDoc.showVelocity = false;
+ this.dataDoc.simulationPaused = true;
+ this.dataDoc.simulationReset = false;
+ this.dataDoc.simulationType = "Inclined Plane";
+ this.dataDoc.sketching = false;
+ this.dataDoc.startForces = [this.forceOfGravity];
+ this.dataDoc.startPendulumAngle = 0;
+ this.dataDoc.startPosX = 0;
+ this.dataDoc.startPosY = 0;
+ this.dataDoc.stepNumber = 0;
+ this.dataDoc.timer = 0;
+ this.dataDoc.updatedForces = [this.forceOfGravity];
+ this.dataDoc.velocityXDisplay = 0;
+ this.dataDoc.velocityYDisplay = 0;
+ this.dataDoc.wallPositions = [];
+ this.dataDoc.wedge = false;
+ this.dataDoc.wedgeAngle = 26;
+ this.dataDoc.wedgeHeight = Math.tan((26 * Math.PI) / 180) * this.xMax*0.6;
+ this.dataDoc.wedgeWidth = this.xMax*0.6;
+ this.dataDoc.weight = false;
+ }
+
+ // Add one weight to the simulation
+ addWeight () {
+ this.dataDoc.weight = true;
+ this.dataDoc.wedge = false;
+ this.dataDoc.pendulum = false;
+ this.dataDoc.startPosY = this.yMin+this.radius;
+ this.dataDoc.startPosX = (this.xMax+this.xMin-this.radius)/2;
+ this.dataDoc.updatedForces = [this.forceOfGravity];
+ this.dataDoc.startForces = [this.forceOfGravity];
+ this.addWalls();
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset;
+ };
+
+ // Add a wedge with a One Weight to the simulation
+ addWedge () {
+ this.dataDoc.weight = true;
+ this.dataDoc.wedge = true;
+ this.dataDoc.pendulum = false;
+ this.changeWedgeBasedOnNewAngle(26);
+ this.addWalls();
+ this.dataDoc.startForces = [this.forceOfGravity];
+ this.updateForcesWithFriction(this.dataDoc.coefficientOfStaticFriction);
+ };
+
+ // Add a simple pendulum to the simulation
+ addPendulum = () => {
+ this.dataDoc.weight = true;
+ this.dataDoc.wedge = false;
+ this.dataDoc.pendulum = true;
+ let length = this.xMax*0.7;
+ let angle = 35;
+ let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
+ let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
+ let xPos = this.xMax / 2 - x - this.radius;
+ let yPos = y - this.radius;
+ this.dataDoc.startPosX = xPos;
+ this.dataDoc.startPosY = yPos;
+ let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
+ let forceOfTension: IForce = {
+ description: "Tension",
+ magnitude: mag,
+ directionInDegrees: 90 - angle,
+ };
+ this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension];
+ this.dataDoc.startForces = [this.forceOfGravity, forceOfTension];
+ this.dataDoc.pendulumAngle = angle;
+ this.dataDoc.pendulumLength = length;
+ this.dataDoc.adjustPendulumAngle = {angle: angle, length: length};
+ this.removeWalls();
+ };
+
+ // Update forces when coefficient of static friction changes in freeform mode
+ updateForcesWithFriction (
+ coefficient: number,
+ width: number = this.dataDoc.wedgeWidth,
+ height: number = this.dataDoc.wedgeHeight
+ ) {
+ let normalForce = {
+ description: "Normal Force",
+ magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)),
+ directionInDegrees:
+ 180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
+ };
+ let frictionForce: IForce = {
+ description: "Static Friction Force",
+ magnitude:
+ coefficient *
+ this.forceOfGravity.magnitude *
+ Math.cos(Math.atan(height / width)),
+ directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
+ };
+ // reduce magnitude of friction force if necessary such that block cannot slide up plane
+ let yForce = -this.forceOfGravity.magnitude;
+ 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) +
+ this.forceOfGravity.magnitude) /
+ Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
+ }
+ if (coefficient != 0) {
+ this.dataDoc.startForces = [this.forceOfGravity, normalForce, frictionForce];
+ this.dataDoc.updatedForces = [this.forceOfGravity, normalForce, frictionForce];
+ } else {
+ this.dataDoc.startForces = [this.forceOfGravity, normalForce];
+ this.dataDoc.updatedForces = [this.forceOfGravity, normalForce];
+ }
+ };
+
+ // Change wedge height and width and weight position to match new wedge angle
+ changeWedgeBasedOnNewAngle = (angle: number) => {
+ let width = 0;
+ let height = 0;
+ if (angle < 50) {
+ width = this.xMax*0.6;
+ height = Math.tan((angle * Math.PI) / 180) * width;
+ this.dataDoc.wedgeWidth = width;
+ this.dataDoc.wedgeHeight = height;
+ } else if (angle < 70) {
+ width = this.xMax*0.3;
+ height = Math.tan((angle * Math.PI) / 180) * width;
+ this.dataDoc.wedgeWidth = width;
+ this.dataDoc.wedgeHeight = height;
+ } else {
+ width = this.xMax*0.15;
+ height = Math.tan((angle * Math.PI) / 180) * width;
+ this.dataDoc.wedgeWidth = width;
+ this.dataDoc.wedgeHeight = height;
+ }
+
+ // update weight position based on updated wedge width/height
+ let xPos = (this.xMax * 0.2)-this.radius;
+ let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius;
+
+ this.dataDoc.startPosX = xPos;
+ this.dataDoc.startPosY = this.getDisplayYPos(yPos);
+ this.updateForcesWithFriction(
+ Number(this.dataDoc.coefficientOfStaticFriction),
+ width,
+ height
+ );
+ };
+
+ // Helper function to go between display and real values
+ getDisplayYPos = (yPos: number) => {
+ return this.yMax - yPos - 2 * 50 + 5;
+ };
+
+ // In review mode, edit force arrow sketch on mouse movement
+ editForce = (element: PhysicsVectorTemplate) => {
+ if (!this.dataDoc.sketching) {
+ let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element);
+ this.dataDoc.forceSketches = sketches;
+ this.dataDoc.currentForceSketch = element;
+ this.dataDoc.sketching = true;
+ }
+ };
+
+ // In review mode, used to delete force arrow sketch on SHIFT+click
+ deleteForce = (element: PhysicsVectorTemplate) => {
+ if (!this.dataDoc.sketching) {
+ let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element);
+ this.dataDoc.forceSketches = sketches;
+ }
+ };
+
+ // Remove floor and walls from simulation
+ removeWalls = () => {
+ this.dataDoc.wallPositions = []
+ };
+
+ // Add floor and walls to simulation
+ addWalls = () => {
+ if (this.dataDoc.wallPositions.length == 0) {
+ let walls = [];
+ walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 });
+ walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 });
+ walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 });
+ this.dataDoc.wallPositions = walls
+ }
+ };
+
+
+ componentDidMount() {
+ // Add weight
+ this.addPendulum()
+
+ // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
+ document.addEventListener("keydown", (e) => {
+ if (e.shiftKey) {
+ this.dataDoc.deleteMode = true;
+ }
+ });
+ document.addEventListener("keyup", (e) => {
+ if (e.shiftKey) {
+ this.dataDoc.deleteMode = false;
+ }
+ });
- constructor(props: any) {
- super(props);
- }
+ // Timer for animating the simulation
+ setInterval(() => {
+ this.dataDoc.timer = this.dataDoc.timer+1;
+ }, 60);
+ }
render () {
return (
-
- );
- }
+
+
+
{
+ // if (sketching) {
+ // x1 = positionXDisplay + 50;
+ // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50;
+ // x2 = e.clientX;
+ // y2 = e.clientY;
+ // height = Math.abs(y1 - y2) + 120;
+ // width = Math.abs(x1 - x2) + 120;
+ // top = Math.min(y1, y2) - 60;
+ // left = Math.min(x1, x2) - 60;
+ // x1Updated = x1 - left;
+ // x2Updated = x2 - left;
+ // y1Updated = y1 - top;
+ // y2Updated = y2 - top;
+ // setCurrentForceSketch({
+ // top: top,
+ // left: left,
+ // width: width,
+ // height: height,
+ // x1: x1Updated,
+ // y1: y1Updated,
+ // x2: x2Updated,
+ // y2: y2Updated,
+ // weightX: positionXDisplay,
+ // weightY: positionYDisplay,
+ // });
+ // }
+ }}
+ onPointerDown={(e) => {
+ // if (sketching && currentForceSketch) {
+ // setSketching(false);
+ // sketches = forceSketches;
+ // sketches.push(currentForceSketch);
+ // setForceSketches(sketches);
+ // setCurrentForceSketch(null);
+ // }
+ }}
+ >
+
+
+ {/* {showForces && currentForceSketch && simulationPaused && (
+
+ )} */}
+ {/* {showForces &&
+ forceSketches.length > 0 &&
+ simulationPaused &&
+ forceSketches.map((element: PhysicsVectorTemplate, index) => {
+ return (
+
+
+
+
+
+
+
+ {
+ if (deleteMode) {
+ deleteForce(element);
+ } else {
+ editForce(element);
+ }
+ }}
+ />
+
+
+ );
+ })} */}
+ {this.dataDoc.weight && (
+
{this.dataDoc.sketching = val}}
+ setDisplayXAcceleration={(val: number) => {this.dataDoc.accelerationXDisplay = val}}
+ setDisplayXPosition={(val: number) => {this.dataDoc.positionXDisplay = val}}
+ setDisplayXVelocity={(val: number) => {this.dataDoc.velocityXDisplay = val}}
+ setDisplayYAcceleration={(val: number) => {this.dataDoc.accelerationYDisplay = val}}
+ setDisplayYPosition={(val: number) => {this.dataDoc.positionYDisplay = val}}
+ setDisplayYVelocity={(val: number) => {this.dataDoc.velocityYDisplay = val}}
+ setPaused={(val: boolean) => {this.dataDoc.simulationPaused = val}}
+ setPendulumAngle={(val: number) => {this.dataDoc.pendulumAngle = val}}
+ setPendulumLength={(val: number) => {this.dataDoc.pendulumLength = val}}
+ setStartPendulumAngle={(val: number) => {this.dataDoc.startPendulumAngle = val}}
+ setUpdatedForces={(val: IForce[]) => {this.dataDoc.updatedForces = val}}
+ showAcceleration={this.dataDoc.showAcceleration}
+ showForces={this.dataDoc.showForces}
+ showVelocity={this.dataDoc.showVelocity}
+ startForces={this.dataDoc.startForces}
+ startPosX={this.dataDoc.startPosX}
+ startPosY={this.dataDoc.startPosY}
+ timestepSize={0.002}
+ updateDisplay={this.dataDoc.displayChange}
+ updatedForces={this.dataDoc.updatedForces}
+ walls={this.dataDoc.wallPositions}
+ wedge={this.dataDoc.wedge}
+ wedgeHeight={this.dataDoc.wedgeHeight}
+ wedgeWidth={this.dataDoc.wedgeWidth}
+ coefficientOfKineticFriction={this.dataDoc.coefficientOfKineticFriction}
+ xMax={this.xMax}
+ yMax={this.yMax}
+ xMin={this.xMin}
+ yMin={this.yMin}
+ />
+ )}
+ {this.dataDoc.wedge && (
+
+ )}
+
+
+ {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
+ return (
+
+
+
+ );
+ })}
+
+
+
+
+
+
+ {this.dataDoc.simulationPaused && (
+
+ )}
+ {!this.dataDoc.simulationPaused && (
+
+ )}
+ {this.dataDoc.simulationPaused && (
+
+ )}
+
+
+
+
+
+
+ );
+ }
}
\ No newline at end of file
--
cgit v1.2.3-70-g09d2
From ac98c1e9b6a2370569113e64514dd1240a2adf7e Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Mon, 13 Feb 2023 16:55:24 -0500
Subject: keep converting to persistent
---
src/client/views/nodes/PhysicsSimulationApp.tsx | 557 ---------------------
src/client/views/nodes/PhysicsSimulationBox.tsx | 194 +------
src/client/views/nodes/PhysicsSimulationWeight.tsx | 129 ++---
3 files changed, 55 insertions(+), 825 deletions(-)
delete mode 100644 src/client/views/nodes/PhysicsSimulationApp.tsx
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx
deleted file mode 100644
index acca65b08..000000000
--- a/src/client/views/nodes/PhysicsSimulationApp.tsx
+++ /dev/null
@@ -1,557 +0,0 @@
-import React = require('react');
-import "./PhysicsSimulationBox.scss";
-import Weight, { IForce } from "./PhysicsSimulationWeight";
-import Wall, { IWallProps } from "./PhysicsSimulationWall"
-import Wedge from "./PhysicsSimulationWedge"
-
-interface PhysicsVectorTemplate {
- top: number;
- left: number;
- width: number;
- height: number;
- x1: number;
- y1: number;
- x2: number;
- y2: number;
- weightX: number;
- weightY: number;
-}
-
-interface IState {
- accelerationXDisplay: number,
- accelerationYDisplay: number,
- adjustPendulumAngle: {angle: number, length: number},
- coefficientOfKineticFriction: number,
- coefficientOfStaticFriction: number,
- currentForceSketch: PhysicsVectorTemplate | null,
- deleteMode: boolean,
- displayChange: {xDisplay: number, yDisplay: number},
- elasticCollisions: boolean,
- forceSketches: PhysicsVectorTemplate[],
- pendulum: boolean,
- pendulumAngle: number,
- pendulumLength: number,
- positionXDisplay: number,
- positionYDisplay: number,
- showAcceleration: boolean,
- showForceMagnitudes: boolean,
- showForces: boolean,
- showVelocity: boolean,
- simulationPaused: boolean,
- simulationReset: boolean,
- simulationType: "Inclined Plane",
- sketching: boolean,
- startForces: IForce[],
- startPendulumAngle: number,
- startPosX: number,
- startPosY: number,
- stepNumber: number,
- timer: number,
- updatedForces: IForce[],
- velocityXDisplay: number,
- velocityYDisplay: number,
- wallPositions: IWallProps[],
- wedge: boolean,
- wedgeAngle: number,
- wedgeHeight: number,
- wedgeWidth: number,
- weight: boolean,
-}
-export default class App extends React.Component<{}, IState> {
-
- // Constants
- gravityMagnitude = 9.81;
- forceOfGravity: IForce = {
- description: "Gravity",
- magnitude: this.gravityMagnitude,
- directionInDegrees: 270,
- };
- xMin = 0;
- yMin = 0;
- xMax = 300;
- yMax = 300;
- color = `rgba(0,0,0,0.5)`;
- radius = 0.1*this.yMax
-
- constructor(props: any) {
- super(props)
- this.state = {
- accelerationXDisplay: 0,
- accelerationYDisplay: 0,
- adjustPendulumAngle: {angle: 0, length: 0},
- coefficientOfKineticFriction: 0,
- coefficientOfStaticFriction: 0,
- currentForceSketch: null,
- deleteMode: false,
- displayChange: {xDisplay: 0, yDisplay: 0},
- elasticCollisions: false,
- forceSketches: [],
- pendulum: false,
- pendulumAngle: 0,
- pendulumLength: 300,
- positionXDisplay: 0,
- positionYDisplay: 0,
- showAcceleration: false,
- showForceMagnitudes: false,
- showForces: false,
- showVelocity: false,
- simulationPaused: true,
- simulationReset: false,
- simulationType: "Inclined Plane",
- sketching: false,
- startForces: [this.forceOfGravity],
- startPendulumAngle: 0,
- startPosX: 0,
- startPosY: 0,
- stepNumber: 0,
- timer: 0,
- updatedForces: [this.forceOfGravity],
- velocityXDisplay: 0,
- velocityYDisplay: 0,
- wallPositions: [],
- wedge: false,
- wedgeAngle: 26,
- wedgeHeight: Math.tan((26 * Math.PI) / 180) * this.xMax*0.6,
- wedgeWidth: this.xMax*0.6,
- weight: false,
- }
- }
-
- // Add one weight to the simulation
- addWeight () {
- this.setState({weight: true})
- this.setState({wedge: false})
- this.setState({pendulum: false})
- this.setState({startPosY: this.yMin+this.radius})
- this.setState({startPosX: (this.xMax+this.xMin-this.radius)/2})
- this.setState({updatedForces: [this.forceOfGravity]})
- this.setState({startForces: [this.forceOfGravity]})
- this.addWalls();
- this.setState({simulationReset: !this.state.simulationReset})
- };
-
- // Add a wedge with a One Weight to the simulation
- addWedge () {
- this.setState({weight: true})
- this.setState({wedge: true})
- this.setState({pendulum: false})
- this.changeWedgeBasedOnNewAngle(26);
- this.addWalls();
- this.setState({startForces: [this.forceOfGravity]})
- this.updateForcesWithFriction(this.state.coefficientOfStaticFriction);
- };
-
- // Add a simple pendulum to the simulation
- addPendulum = () => {
- this.setState({weight: true})
- this.setState({wedge: false})
- this.setState({pendulum: true})
- let length = this.xMax*0.7;
- let angle = 35;
- let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
- let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
- let xPos = this.xMax / 2 - x - this.radius;
- let yPos = y - this.radius;
- this.setState({startPosX: xPos})
- this.setState({startPosY: yPos})
- let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
- let forceOfTension: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: 90 - angle,
- };
- this.setState({updatedForces: [this.forceOfGravity, forceOfTension]})
- this.setState({startForces: [this.forceOfGravity, forceOfTension]})
- this.setState({pendulumAngle: angle})
- this.setState({pendulumLength: length})
- this.setState({adjustPendulumAngle: {angle: angle, length: length}})
- this.removeWalls();
- };
-
- // Update forces when coefficient of static friction changes in freeform mode
- updateForcesWithFriction (
- coefficient: number,
- width: number = this.state.wedgeWidth,
- height: number = this.state.wedgeHeight
- ) {
- let normalForce = {
- description: "Normal Force",
- magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)),
- directionInDegrees:
- 180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
- };
- let frictionForce: IForce = {
- description: "Static Friction Force",
- magnitude:
- coefficient *
- this.forceOfGravity.magnitude *
- Math.cos(Math.atan(height / width)),
- directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
- };
- // reduce magnitude of friction force if necessary such that block cannot slide up plane
- let yForce = -this.forceOfGravity.magnitude;
- 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) +
- this.forceOfGravity.magnitude) /
- Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
- }
- if (coefficient != 0) {
- this.setState({startForces: [this.forceOfGravity, normalForce, frictionForce]})
- this.setState({updatedForces: [this.forceOfGravity, normalForce, frictionForce]});
- } else {
- this.setState({startForces: [this.forceOfGravity, normalForce]})
- this.setState({updatedForces: [this.forceOfGravity, normalForce]});
- }
- };
-
- // Change wedge height and width and weight position to match new wedge angle
- changeWedgeBasedOnNewAngle = (angle: number) => {
- let width = 0;
- let height = 0;
- if (angle < 50) {
- width = this.xMax*0.6;
- height = Math.tan((angle * Math.PI) / 180) * width;
- this.setState({wedgeWidth: width})
- this.setState({wedgeHeight: height})
- } else if (angle < 70) {
- width = this.xMax*0.3;
- height = Math.tan((angle * Math.PI) / 180) * width;
- this.setState({wedgeWidth: width})
- this.setState({wedgeHeight: height})
- } else {
- width = this.xMax*0.15;
- height = Math.tan((angle * Math.PI) / 180) * width;
- this.setState({wedgeWidth: width})
- this.setState({wedgeHeight: height})
- }
-
- // update weight position based on updated wedge width/height
- let xPos = (this.xMax * 0.2)-this.radius;
- let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius;
-
- this.setState({startPosX: xPos});
- this.setState({startPosY: this.getDisplayYPos(yPos)});
- this.updateForcesWithFriction(
- Number(this.state.coefficientOfStaticFriction),
- width,
- height
- );
- };
-
- // Helper function to go between display and real values
- getDisplayYPos = (yPos: number) => {
- return this.yMax - yPos - 2 * 50 + 5;
- };
-
- // In review mode, edit force arrow sketch on mouse movement
- editForce = (element: PhysicsVectorTemplate) => {
- if (!this.state.sketching) {
- let sketches = this.state.forceSketches.filter((sketch) => sketch != element);
- this.setState({forceSketches: sketches})
- this.setState({currentForceSketch: element})
- this.setState({sketching: true})
- }
- };
-
- // In review mode, used to delete force arrow sketch on SHIFT+click
- deleteForce = (element: PhysicsVectorTemplate) => {
- if (!this.state.sketching) {
- let sketches = this.state.forceSketches.filter((sketch) => sketch != element);
- this.setState({forceSketches: sketches})
- }
- };
-
- // Remove floor and walls from simulation
- removeWalls = () => {
- this.setState({wallPositions: []})
- };
-
- // Add floor and walls to simulation
- addWalls = () => {
- if (this.state.wallPositions.length == 0) {
- let walls = [];
- walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 });
- walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 });
- walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 });
- this.setState({wallPositions: walls})
- }
- };
-
-
- componentDidMount() {
- // Add weight
- this.addPendulum()
-
- // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
- document.addEventListener("keydown", (e) => {
- if (e.shiftKey) {
- this.setState({deleteMode: true})
- }
- });
- document.addEventListener("keyup", (e) => {
- if (e.shiftKey) {
- this.setState({deleteMode: false})
- }
- });
-
- // Timer for animating the simulation
- setInterval(() => {
- this.setState({timer: this.state.timer+1})
- }, 60);
- }
-
- render () {
- return (
-
-
-
{
- // if (sketching) {
- // x1 = positionXDisplay + 50;
- // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50;
- // x2 = e.clientX;
- // y2 = e.clientY;
- // height = Math.abs(y1 - y2) + 120;
- // width = Math.abs(x1 - x2) + 120;
- // top = Math.min(y1, y2) - 60;
- // left = Math.min(x1, x2) - 60;
- // x1Updated = x1 - left;
- // x2Updated = x2 - left;
- // y1Updated = y1 - top;
- // y2Updated = y2 - top;
- // setCurrentForceSketch({
- // top: top,
- // left: left,
- // width: width,
- // height: height,
- // x1: x1Updated,
- // y1: y1Updated,
- // x2: x2Updated,
- // y2: y2Updated,
- // weightX: positionXDisplay,
- // weightY: positionYDisplay,
- // });
- // }
- }}
- onPointerDown={(e) => {
- // if (sketching && currentForceSketch) {
- // setSketching(false);
- // sketches = forceSketches;
- // sketches.push(currentForceSketch);
- // setForceSketches(sketches);
- // setCurrentForceSketch(null);
- // }
- }}
- >
-
-
- {/* {showForces && currentForceSketch && simulationPaused && (
-
- )} */}
- {/* {showForces &&
- forceSketches.length > 0 &&
- simulationPaused &&
- forceSketches.map((element: PhysicsVectorTemplate, index) => {
- return (
-
-
-
-
-
-
-
- {
- if (deleteMode) {
- deleteForce(element);
- } else {
- editForce(element);
- }
- }}
- />
-
-
- );
- })} */}
- {this.state.weight && (
-
{this.setState({sketching: val})}}
- setDisplayXAcceleration={(val: number) => {this.setState({accelerationXDisplay: val})}}
- setDisplayXPosition={(val: number) => {this.setState({positionXDisplay: val})}}
- setDisplayXVelocity={(val: number) => {this.setState({velocityXDisplay: val})}}
- setDisplayYAcceleration={(val: number) => {this.setState({accelerationYDisplay: val})}}
- setDisplayYPosition={(val: number) => {this.setState({positionYDisplay: val})}}
- setDisplayYVelocity={(val: number) => {this.setState({velocityYDisplay: val})}}
- setPaused={(val: boolean) => {this.setState({simulationPaused: val})}}
- setPendulumAngle={(val: number) => {this.setState({pendulumAngle: val})}}
- setPendulumLength={(val: number) => {this.setState({pendulumLength: val})}}
- setStartPendulumAngle={(val: number) => {this.setState({startPendulumAngle: val})}}
- setUpdatedForces={(val: IForce[]) => {this.setState({updatedForces: val})}}
- showAcceleration={this.state.showAcceleration}
- showForces={this.state.showForces}
- showVelocity={this.state.showVelocity}
- startForces={this.state.startForces}
- startPosX={this.state.startPosX}
- startPosY={this.state.startPosY}
- timestepSize={0.002}
- updateDisplay={this.state.displayChange}
- updatedForces={this.state.updatedForces}
- walls={this.state.wallPositions}
- wedge={this.state.wedge}
- wedgeHeight={this.state.wedgeHeight}
- wedgeWidth={this.state.wedgeWidth}
- coefficientOfKineticFriction={this.state.coefficientOfKineticFriction}
- xMax={this.xMax}
- yMax={this.yMax}
- xMin={this.xMin}
- yMin={this.yMin}
- />
- )}
- {this.state.wedge && (
-
- )}
-
-
- {this.state.wallPositions.map((element, index) => {
- return (
-
-
-
- );
- })}
-
-
-
-
-
-
- {this.state.simulationPaused && (
-
- )}
- {!this.state.simulationPaused && (
-
- )}
- {this.state.simulationPaused && (
-
- )}
-
-
-
-
-
-
- );
- }
-}
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 3ea4fba9f..9d91adefb 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -33,46 +33,6 @@ interface PhysicsVectorTemplate {
weightY: number;
}
-interface IState {
- accelerationXDisplay: number,
- accelerationYDisplay: number,
- adjustPendulumAngle: {angle: number, length: number},
- coefficientOfKineticFriction: number,
- coefficientOfStaticFriction: number,
- currentForceSketch: PhysicsVectorTemplate | null,
- deleteMode: boolean,
- displayChange: {xDisplay: number, yDisplay: number},
- elasticCollisions: boolean,
- forceSketches: PhysicsVectorTemplate[],
- pendulum: boolean,
- pendulumAngle: number,
- pendulumLength: number,
- positionXDisplay: number,
- positionYDisplay: number,
- showAcceleration: boolean,
- showForceMagnitudes: boolean,
- showForces: boolean,
- showVelocity: boolean,
- simulationPaused: boolean,
- simulationReset: boolean,
- simulationType: "Inclined Plane",
- sketching: boolean,
- startForces: IForce[],
- startPendulumAngle: number,
- startPosX: number,
- startPosY: number,
- stepNumber: number,
- timer: number,
- updatedForces: IForce[],
- velocityXDisplay: number,
- velocityYDisplay: number,
- wallPositions: IWallProps[],
- wedge: boolean,
- wedgeAngle: number,
- wedgeHeight: number,
- wedgeWidth: number,
- weight: boolean,
-}
@observer
export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() {
@@ -96,7 +56,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
-
{
- // if (sketching) {
- // x1 = positionXDisplay + 50;
- // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50;
- // x2 = e.clientX;
- // y2 = e.clientY;
- // height = Math.abs(y1 - y2) + 120;
- // width = Math.abs(x1 - x2) + 120;
- // top = Math.min(y1, y2) - 60;
- // left = Math.min(x1, x2) - 60;
- // x1Updated = x1 - left;
- // x2Updated = x2 - left;
- // y1Updated = y1 - top;
- // y2Updated = y2 - top;
- // setCurrentForceSketch({
- // top: top,
- // left: left,
- // width: width,
- // height: height,
- // x1: x1Updated,
- // y1: y1Updated,
- // x2: x2Updated,
- // y2: y2Updated,
- // weightX: positionXDisplay,
- // weightY: positionYDisplay,
- // });
- // }
- }}
- onPointerDown={(e) => {
- // if (sketching && currentForceSketch) {
- // setSketching(false);
- // sketches = forceSketches;
- // sketches.push(currentForceSketch);
- // setForceSketches(sketches);
- // setCurrentForceSketch(null);
- // }
- }}
- >
+
- {/* {showForces && currentForceSketch && simulationPaused && (
-
- )} */}
- {/* {showForces &&
- forceSketches.length > 0 &&
- simulationPaused &&
- forceSketches.map((element: PhysicsVectorTemplate, index) => {
- return (
-
-
-
-
-
-
-
- {
- if (deleteMode) {
- deleteForce(element);
- } else {
- editForce(element);
- }
- }}
- />
-
-
- );
- })} */}
{this.dataDoc.weight && (
{this.dataDoc.sketching = val}}
- setDisplayXAcceleration={(val: number) => {this.dataDoc.accelerationXDisplay = val}}
- setDisplayXPosition={(val: number) => {this.dataDoc.positionXDisplay = val}}
- setDisplayXVelocity={(val: number) => {this.dataDoc.velocityXDisplay = val}}
- setDisplayYAcceleration={(val: number) => {this.dataDoc.accelerationYDisplay = val}}
- setDisplayYPosition={(val: number) => {this.dataDoc.positionYDisplay = val}}
- setDisplayYVelocity={(val: number) => {this.dataDoc.velocityYDisplay = val}}
- setPaused={(val: boolean) => {this.dataDoc.simulationPaused = val}}
- setPendulumAngle={(val: number) => {this.dataDoc.pendulumAngle = val}}
- setPendulumLength={(val: number) => {this.dataDoc.pendulumLength = val}}
- setStartPendulumAngle={(val: number) => {this.dataDoc.startPendulumAngle = val}}
- setUpdatedForces={(val: IForce[]) => {this.dataDoc.updatedForces = val}}
showAcceleration={this.dataDoc.showAcceleration}
showForces={this.dataDoc.showForces}
showVelocity={this.dataDoc.showVelocity}
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index dfd463bbe..fcfb149c9 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -1,4 +1,5 @@
import React = require('react');
+import { Doc } from '../../../fields/Doc';
import { IWallProps } from "./PhysicsSimulationWall";
export interface IForce {
@@ -7,35 +8,17 @@ export interface IForce {
directionInDegrees: number;
}
export interface IWeightProps {
- adjustPendulumAngle: { angle: number; length: number };
+ dataDoc: Doc;
color: string;
- displayXPosition: number;
- displayYPosition: number;
- displayXVelocity: number;
- displayYVelocity: number;
- elasticCollisions: boolean;
startForces: IForce[];
- incrementTime: number;
mass: number;
- paused: boolean;
pendulum: boolean;
pendulumLength: number;
wedge: boolean;
radius: number;
reset: boolean;
- setDisplayXAcceleration: (val: number) => any;
- setDisplayXPosition: (val: number) => any;
- setDisplayXVelocity: (val: number) => any;
- setDisplayYAcceleration: (val: number) => any;
- setDisplayYPosition: (val: number) => any;
- setDisplayYVelocity: (val: number) => any;
- setPaused: (bool: boolean) => any;
- setPendulumAngle: (val: number) => any;
- setPendulumLength: (val: number) => any;
- setStartPendulumAngle: (val: number) => any;
showAcceleration: boolean;
pendulumAngle: number;
- setSketching: (val: boolean) => any;
showForces: boolean;
showForceMagnitudes: boolean;
showVelocity: boolean;
@@ -46,7 +29,6 @@ export interface IWeightProps {
timestepSize: number;
updateDisplay: { xDisplay: number; yDisplay: number };
updatedForces: IForce[];
- setUpdatedForces: (val: IForce[]) => any;
walls: IWallProps[];
coefficientOfKineticFriction: number;
wedgeWidth: number;
@@ -125,16 +107,16 @@ export default class Weight extends React.Component {
// Set display values based on real values
setYPosDisplay = (yPos: number) => {
const displayPos = this.getDisplayYPos(yPos);
- this.props.setDisplayYPosition(Math.round(displayPos * 100) / 100)
+ this.props.dataDoc['positionYDisplay'] = Math.round(displayPos * 100) / 100
};
setXPosDisplay = (xPos: number) => {
- this.props.setDisplayXPosition(Math.round(xPos * 100) / 100);
+ this.props.dataDoc['positionXDisplay'] = Math.round(xPos * 100) / 100;
};
setYVelDisplay = (yVel: number) => {
- this.props.setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100);
+ this.props.dataDoc['velocityYDisplay'] = (-1 * Math.round(yVel * 100)) / 100;
};
setXVelDisplay = (xVel: number) => {
- this.props.setDisplayXVelocity(Math.round(xVel * 100) / 100);
+ this.props.dataDoc['velocityXDisplay'] = Math.round(xVel * 100) / 100;
};
setDisplayValues = (
@@ -147,12 +129,12 @@ export default class Weight extends React.Component {
this.setXPosDisplay(xPos);
this.setYVelDisplay(yVel);
this.setXVelDisplay(xVel);
- this.props.setDisplayYAcceleration(
+ this.props.dataDoc['accelerationYDisplay'] =
(-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100
- );
- this.props.setDisplayXAcceleration(
+ ;
+ this.props.dataDoc['accelerationXDisplay'] =
Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100
- );
+ ;
};
componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void {
@@ -164,34 +146,34 @@ export default class Weight extends React.Component {
x = Math.min(x, this.props.xMax - 2 * this.props.radius);
this.setState({updatedStartPosX: x})
this.setState({xPosition: x})
- this.props.setDisplayXPosition(x);
+ this.props.dataDoc['positionXDisplay'] = x;
}
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);
- this.props.setDisplayYPosition(y);
+ this.props.dataDoc['positionYDisplay'] = y;
let coordinatePosition = this.getYPosFromDisplay(y);
this.setState({updatedStartPosY: coordinatePosition})
this.setState({yPosition: coordinatePosition})
}
- if (this.props.displayXVelocity != this.state.xVelocity) {
- let x = this.props.displayXVelocity;
+ if (this.props.dataDoc['velocityXDisplay'] != this.state.xVelocity) {
+ let x = this.props.dataDoc['velocityXDisplay'];
this.setState({xVelocity: x})
- this.props.setDisplayXVelocity(x);
+ this.props.dataDoc['velocityXDisplay'] = x;
}
- if (this.props.displayYVelocity != this.state.yVelocity) {
- let y = this.props.displayYVelocity;
+ if (this.props.dataDoc['velocityYDisplay'] != this.state.yVelocity) {
+ let y = this.props.dataDoc['velocityYDisplay'];
this.setState({yVelocity: -y})
- this.props.setDisplayXVelocity(y);
+ this.props.dataDoc['velocityYDisplay']
}
}
// Update sim
- if (this.props.incrementTime != prevProps.incrementTime) {
- if (!this.props.paused) {
+ if (this.props.dataDoc['incrementTime'] != prevProps.dataDoc['incrementTime']) {
+ if (!this.props.dataDoc['simulationPaused']) {
let collisions = false;
if (!this.props.pendulum) {
const collisionsWithGround = this.checkForCollisionsWithGround();
@@ -229,21 +211,19 @@ export default class Weight extends React.Component {
this.setState({yVelocity: this.props.startVelY ?? 0})
this.setDisplayValues();
}
- if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) {
+ if (this.props.dataDoc['adjustPendulumAngle'] != prevProps.dataDoc['adjustPendulumAngle']) {
// Change pendulum angle based on input field
- let length = this.props.adjustPendulumAngle.length;
+ let length = this.props.dataDoc['pendulumLength'] ?? 0;
const x =
- length * Math.cos(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180);
+ length * Math.cos(((90 - this.props.dataDoc['pendulumAngle']) * Math.PI) / 180);
const y =
- length * Math.sin(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180);
+ length * Math.sin(((90 - this.props.dataDoc['pendulumAngle']) * 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.setPendulumAngle(this.props.adjustPendulumAngle.angle);
- this.props.setPendulumLength(this.props.adjustPendulumAngle.length);
}
// Update x start position
if (this.props.startPosX != prevProps.startPosX) {
@@ -314,24 +294,28 @@ export default class Weight extends React.Component {
getNewAccelerationX = (forceList: IForce[]) => {
let newXAcc = 0;
- forceList.forEach((force) => {
- newXAcc +=
- (force.magnitude *
- Math.cos((force.directionInDegrees * Math.PI) / 180)) /
- this.props.mass;
- });
+ if (forceList) {
+ forceList.forEach((force) => {
+ newXAcc +=
+ (force.magnitude *
+ Math.cos((force.directionInDegrees * Math.PI) / 180)) /
+ this.props.mass;
+ });
+ }
return newXAcc;
};
getNewAccelerationY = (forceList: IForce[]) => {
let newYAcc = 0;
- forceList.forEach((force) => {
- newYAcc +=
- (-1 *
- (force.magnitude *
- Math.sin((force.directionInDegrees * Math.PI) / 180))) /
- this.props.mass;
- });
+ if (forceList) {
+ forceList.forEach((force) => {
+ newYAcc +=
+ (-1 *
+ (force.magnitude *
+ Math.sin((force.directionInDegrees * Math.PI) / 180))) /
+ this.props.mass;
+ });
+ }
return newYAcc;
};
@@ -356,8 +340,8 @@ export default class Weight extends React.Component {
}
const pendulumLength = Math.sqrt(x * x + y * y);
- this.props.setPendulumAngle(oppositeAngle);
- this.props.setPendulumLength(Math.sqrt(x * x + y * y));
+ this.props.dataDoc['pendulumAngle'] = oppositeAngle;
+ this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y);
const mag =
this.props.mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) +
@@ -391,7 +375,7 @@ export default class Weight extends React.Component {
const wallX = (wall.xPos / 100) * 300;
if (wall.xPos < 0.35) {
if (minX <= wallX) {
- if (this.props.elasticCollisions) {
+ if (this.props.dataDoc['elasticCollisions']) {
this.setState({xVelocity: -this.state.xVelocity});
} else {
this.setState({xVelocity: 0});
@@ -401,7 +385,7 @@ export default class Weight extends React.Component {
}
} else {
if (maxX >= wallX) {
- if (this.props.elasticCollisions) {
+ if (this.props.dataDoc['elasticCollisions']) {
this.setState({xVelocity: -this.state.xVelocity});
} else {
this.setState({xVelocity: 0});
@@ -424,7 +408,7 @@ export default class Weight extends React.Component {
if (wall.angleInDegrees == 0) {
const groundY = (wall.yPos / 100) * this.props.yMax;
if (maxY >= groundY) {
- if (this.props.elasticCollisions) {
+ if (this.props.dataDoc['elasticCollisions']) {
this.setState({yVelocity: -this.state.yVelocity})
} else {
this.setState({yVelocity: 0})
@@ -525,7 +509,7 @@ export default class Weight extends React.Component {
onPointerDown={(e) => {
if (this.draggable) {
e.preventDefault();
- this.props.setPaused(true);
+ this.props.dataDoc['simulationPaused'] = true;
this.setState({dragging: true});
this.setState({clickPositionX: e.clientX})
this.setState({clickPositionY: e.clientY})
@@ -549,7 +533,7 @@ export default class Weight extends React.Component {
this.setState({yPosition: newY})
this.setState({updatedStartPosX: newX})
this.setState({updatedStartPosY: newY})
- this.props.setDisplayYPosition(Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100)
+ this.props.dataDoc['positionYDisplay'] = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100;
this.setState({clickPositionX: e.clientX})
this.setState({clickPositionY: e.clientY})
this.setDisplayValues();
@@ -586,8 +570,8 @@ export default class Weight extends React.Component {
}
const pendulumLength = Math.sqrt(x * x + y * y);
- this.props.setPendulumAngle(oppositeAngle);
- this.props.setPendulumLength(Math.sqrt(x * x + y * y));
+ this.props.dataDoc['pendulumAngle'] = oppositeAngle;
+ this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y);
const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180);
const forceOfTension: IForce = {
description: "Tension",
@@ -629,17 +613,6 @@ export default class Weight extends React.Component {
{!this.state.dragging && (
- {/*
- {Math.round(this.props.pendulumLength)} m
-
*/}
{
backgroundColor: this.labelBackgroundColor,
}}
>
- {Math.round(this.props.pendulumAngle * 100) / 100}°
+ {Math.round(this.props.dataDoc['pendulumAngle'] * 100) / 100}°
)}
--
cgit v1.2.3-70-g09d2
From 8cf1aed33306d633466ac78d3156e629b9dfe5e9 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Wed, 15 Feb 2023 20:51:59 -0500
Subject: simulation compiles and runs
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 56 +++-----
src/client/views/nodes/PhysicsSimulationWeight.tsx | 142 ++++++++++-----------
2 files changed, 91 insertions(+), 107 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 9d91adefb..13b4fe0b2 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -61,7 +61,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {
- if (e.shiftKey) {
- this.dataDoc.deleteMode = true;
- }
- });
- document.addEventListener("keyup", (e) => {
- if (e.shiftKey) {
- this.dataDoc.deleteMode = false;
- }
- });
+ // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click
+ document.addEventListener("keydown", (e) => {
+ if (e.shiftKey) {
+ this.dataDoc.deleteMode = true;
+ }
+ });
+ document.addEventListener("keyup", (e) => {
+ if (e.shiftKey) {
+ this.dataDoc.deleteMode = false;
+ }
+ });
- // Timer for animating the simulation
- setInterval(() => {
- this.dataDoc.timer = this.dataDoc.timer+1;
- }, 60);
+ // // Timer for animating the simulation
+ // setInterval(() => {
+ // this.dataDoc.timer = this.dataDoc.timer+1;
+ // }, 60);
}
render () {
@@ -297,26 +297,8 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
{this.dataDoc.simulationPaused && (
)}
{!this.dataDoc.simulationPaused && (
)}
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index fcfb149c9..e7bd86915 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -10,27 +10,13 @@ export interface IForce {
export interface IWeightProps {
dataDoc: Doc;
color: string;
- startForces: IForce[];
mass: number;
- pendulum: boolean;
- pendulumLength: number;
wedge: boolean;
radius: number;
- reset: boolean;
- showAcceleration: boolean;
- pendulumAngle: number;
- showForces: boolean;
- showForceMagnitudes: boolean;
- showVelocity: boolean;
- startPosX: number;
- startPosY: number;
startVelX?: number;
startVelY?: number;
timestepSize: number;
- updateDisplay: { xDisplay: number; yDisplay: number };
- updatedForces: IForce[];
walls: IWallProps[];
- coefficientOfKineticFriction: number;
wedgeWidth: number;
wedgeHeight: number;
xMax: number;
@@ -46,6 +32,7 @@ interface IState {
kineticFriction: boolean,
updatedStartPosX: number,
updatedStartPosY: number,
+ timer: number;
xPosition: number,
yPosition: number,
xVelocity: number,
@@ -60,17 +47,18 @@ export default class Weight extends React.Component {
clickPositionY: 0,
dragging: false,
kineticFriction: false,
- updatedStartPosX: this.props.startPosX,
- updatedStartPosY: this.props.startPosY,
- xPosition: this.props.startPosX,
- yPosition: this.props.startPosY,
+ timer: 0,
+ updatedStartPosX: this.props.dataDoc['startPosX'],
+ updatedStartPosY: this.props.dataDoc['startPosY'],
+ xPosition: this.props.dataDoc['startPosX'],
+ yPosition: this.props.dataDoc['startPosY'],
xVelocity: this.props.startVelX ? this.props.startVelX: 0,
yVelocity: this.props.startVelY ? this.props.startVelY: 0,
}
}
// Constants
- draggable = !this.props.wedge;
+ draggable = !this.props.dataDoc['wedge'] ;
epsilon = 0.0001;
forceOfGravity: IForce = {
description: "Gravity",
@@ -84,8 +72,8 @@ export default class Weight extends React.Component {
borderStyle: "solid",
borderColor: "black",
position: "absolute" as "absolute",
- left: this.props.startPosX + "px",
- top: this.props.startPosY + "px",
+ left: this.props.dataDoc['startPosX'] + "px",
+ top: this.props.dataDoc['startPosY'] + "px",
width: 2 * this.props.radius + "px",
height: 2 * this.props.radius + "px",
zIndex: 5,
@@ -130,18 +118,25 @@ export default class Weight extends React.Component {
this.setYVelDisplay(yVel);
this.setXVelDisplay(xVel);
this.props.dataDoc['accelerationYDisplay'] =
- (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100
+ (-1 * Math.round(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 100)) / 100
;
this.props.dataDoc['accelerationXDisplay'] =
- Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100
+ Math.round(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 100) / 100
;
};
+ componentDidMount() {
+ // Timer for animating the simulation
+ setInterval(() => {
+ this.setState({timer: this.state.timer + 1});
+ }, 60);
+ }
+
componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void {
// When display values updated by user, update real values
- if (this.props.updateDisplay != prevProps.updateDisplay) {
- if (this.props.updateDisplay.xDisplay != this.state.xPosition) {
- let x = this.props.updateDisplay.xDisplay;
+ if (this.props.dataDoc['updateDisplay'] != prevProps.dataDoc['updateDisplay']) {
+ if (this.props.dataDoc['positionXDisplay'] != this.state.xPosition) {
+ let x = this.props.dataDoc['positionXDisplay'];
x = Math.max(0, x);
x = Math.min(x, this.props.xMax - 2 * this.props.radius);
this.setState({updatedStartPosX: x})
@@ -149,8 +144,8 @@ export default class Weight extends React.Component {
this.props.dataDoc['positionXDisplay'] = x;
}
- if (this.props.updateDisplay.yDisplay != this.getDisplayYPos(this.state.yPosition)) {
- let y = this.props.updateDisplay.yDisplay;
+ if (this.props.dataDoc['positionYDisplay'] != this.getDisplayYPos(this.state.yPosition)) {
+ let y = this.props.dataDoc['positionYDisplay'];
y = Math.max(0, y);
y = Math.min(y, this.props.yMax - 2 * this.props.radius);
this.props.dataDoc['positionYDisplay'] = y;
@@ -172,10 +167,11 @@ export default class Weight extends React.Component {
}
}
// Update sim
- if (this.props.dataDoc['incrementTime'] != prevProps.dataDoc['incrementTime']) {
+ if (this.state.timer != prevState.timer) {
if (!this.props.dataDoc['simulationPaused']) {
+ console.log('update')
let collisions = false;
- if (!this.props.pendulum) {
+ if (!this.props.dataDoc['pendulum']) {
const collisionsWithGround = this.checkForCollisionsWithGround();
const collisionsWithWalls = this.checkForCollisionsWithWall();
collisions = collisionsWithGround || collisionsWithWalls;
@@ -203,10 +199,10 @@ export default class Weight extends React.Component {
touchAction: "none",
};
- if (this.props.reset != prevProps.reset) {
+ if (this.props.dataDoc['simulationReset'] != prevProps.dataDoc['simulationReset']) {
this.resetEverything();
}
- if (this.props.startForces != prevProps.startForces) {
+ if (this.props.dataDoc['startForces'] != prevProps.dataDoc['startForces']) {
this.setState({xVelocity: this.props.startVelX ?? 0})
this.setState({yVelocity: this.props.startVelY ?? 0})
this.setDisplayValues();
@@ -226,37 +222,37 @@ export default class Weight extends React.Component {
this.setState({updatedStartPosY: yPos})
}
// Update x start position
- if (this.props.startPosX != prevProps.startPosX) {
- this.setState({updatedStartPosX: this.props.startPosX})
- this.setState({xPosition: this.props.startPosX})
- this.setXPosDisplay(this.props.startPosX);
+ if (this.props.dataDoc['startPosX'] != prevProps.dataDoc['startPosX']) {
+ this.setState({updatedStartPosX: this.props.dataDoc['startPosX']})
+ this.setState({xPosition: this.props.dataDoc['startPosX']})
+ this.setXPosDisplay(this.props.dataDoc['startPosX']);
}
// Update y start position
- if (this.props.startPosY != prevProps.startPosY) {
- this.setState({updatedStartPosY: this.props.startPosY})
- this.setState({yPosition: this.props.startPosY})
- this.setYPosDisplay(this.props.startPosY);
+ if (this.props.dataDoc['startPosY'] != prevProps.dataDoc['startPosY']) {
+ this.setState({updatedStartPosY: this.props.dataDoc['startPosY']})
+ this.setState({yPosition: this.props.dataDoc['startPosY']})
+ this.setYPosDisplay(this.props.dataDoc['startPosY']);
}
if (this.state.xVelocity != prevState.xVelocity) {
- if (this.props.wedge && this.state.xVelocity != 0 && !this.state.kineticFriction) {
+ if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) {
this.setState({kineticFriction: true});
//switch from static to kinetic friction
const normalForce: IForce = {
description: "Normal Force",
magnitude:
this.forceOfGravity.magnitude *
- Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )),
directionInDegrees:
- 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
+ 180 - 90 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI,
};
let frictionForce: IForce = {
description: "Kinetic Friction Force",
magnitude:
- this.props.coefficientOfKineticFriction *
+ this.props.dataDoc['coefficientOfKineticFriction'] *
this.forceOfGravity.magnitude *
- Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)),
+ Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )),
directionInDegrees:
- 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI,
+ 180 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI,
};
// reduce magnitude of friction force if necessary such that block cannot slide up plane
let yForce = -this.forceOfGravity.magnitude;
@@ -273,10 +269,10 @@ export default class Weight extends React.Component {
this.forceOfGravity.magnitude) /
Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
}
- if (this.props.coefficientOfKineticFriction != 0) {
- this.props.setUpdatedForces([this.forceOfGravity, normalForce, frictionForce]);
+ if (this.props.dataDoc['coefficientOfKineticFriction'] != 0) {
+ this.props.dataDoc['updatedForces'] = [this.forceOfGravity, normalForce, frictionForce];
} else {
- this.props.setUpdatedForces([this.forceOfGravity, normalForce]);
+ this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, normalForce]);
}
}
}
@@ -288,7 +284,7 @@ export default class Weight extends React.Component {
this.setState({yPosition: this.state.updatedStartPosY})
this.setState({xVelocity: this.props.startVelX ?? 0})
this.setState({yVelocity: this.props.startVelY ?? 0})
- this.props.setUpdatedForces(this.props.startForces)
+ this.props.dataDoc['updatedForces'] = (this.props.dataDoc['startForces'])
this.setDisplayValues();
};
@@ -325,8 +321,8 @@ export default class Weight extends React.Component {
xVel: number,
yVel: number
) => {
- if (!this.props.pendulum) {
- return this.props.updatedForces;
+ if (!this.props.dataDoc['pendulum']) {
+ return this.props.dataDoc['updatedForces'];
}
const x = this.props.xMax / 2 - xPos - this.props.radius;
const y = yPos + this.props.radius + 5;
@@ -370,7 +366,7 @@ export default class Weight extends React.Component {
const maxX = this.state.xPosition + 2 * this.props.radius;
const containerWidth = 300;
if (this.state.xVelocity != 0) {
- this.props.walls.forEach((wall) => {
+ this.props.dataDoc['wallPositions'].forEach((wall) => {
if (wall.angleInDegrees == 90) {
const wallX = (wall.xPos / 100) * 300;
if (wall.xPos < 0.35) {
@@ -404,7 +400,7 @@ export default class Weight extends React.Component {
let collision = false;
const maxY = this.state.yPosition + 2 * this.props.radius;
if (this.state.yVelocity > 0) {
- this.props.walls.forEach((wall) => {
+ this.props.dataDoc['wallPositions'] .forEach((wall) => {
if (wall.angleInDegrees == 0) {
const groundY = (wall.yPos / 100) * this.props.yMax;
if (maxY >= groundY) {
@@ -423,7 +419,7 @@ export default class Weight extends React.Component {
magnitude: 9.81 * this.props.mass,
directionInDegrees: wall.angleInDegrees + 90,
};
- this.props.setUpdatedForces([forceOfGravity, normalForce]);
+ this.props.dataDoc['updatedForces'] = ([forceOfGravity, normalForce]);
}
collision = true;
}
@@ -496,9 +492,13 @@ export default class Weight extends React.Component {
this.setState({yVelocity: yVel});
this.setState({xPosition: xPos});
this.setState({yPosition: yPos});
- this.props.setUpdatedForces(this.getNewForces(xPos, yPos, xVel, yVel));
+ this.props.dataDoc['updatedForces'] = (this.getNewForces(xPos, yPos, xVel, yVel));
};
+
+
+
+
labelBackgroundColor = `rgba(255,255,255,0.5)`;
render () {
@@ -542,7 +542,7 @@ export default class Weight extends React.Component {
onPointerUp={(e) => {
if (this.state.dragging) {
e.preventDefault();
- if (!this.props.pendulum) {
+ if (!this.props.dataDoc['pendulum']) {
this.resetEverything();
}
this.setState({dragging: false});
@@ -557,7 +557,7 @@ export default class Weight extends React.Component {
} else if (newX < 0) {
newX = 0;
}
- if (this.props.pendulum) {
+ if (this.props.dataDoc['pendulum']) {
const x = this.props.xMax / 2 - newX - this.props.radius;
const y = newY + this.props.radius + 5;
let angle = (Math.atan(y / x) * 180) / Math.PI;
@@ -582,7 +582,7 @@ export default class Weight extends React.Component {
this.setState({xVelocity: this.props.startVelX ?? 0})
this.setState({yVelocity: this.props.startVelY ?? 0})
this.setDisplayValues();
- this.props.setUpdatedForces([this.forceOfGravity, forceOfTension]);
+ this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, forceOfTension]);
}
}
}}
@@ -591,7 +591,7 @@ export default class Weight extends React.Component {
{this.props.mass} kg
- {this.props.pendulum && (
+ {this.props.dataDoc['pendulum'] && (
{
)}
)}
- {!this.state.dragging && this.props.showAcceleration && (
+ {!this.state.dragging && this.props.dataDoc['showAcceleration'] && (
{
{
left:
this.state.xPosition +
this.props.radius +
- this.getNewAccelerationX(this.props.updatedForces) * 5 +
+ this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 5 +
25 +
"px",
top:
this.state.yPosition +
this.props.radius +
- this.getNewAccelerationY(this.props.updatedForces) * 5 +
+ this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 5 +
25 +
"px",
lineHeight: 0.5,
@@ -684,8 +684,8 @@ export default class Weight extends React.Component {
{Math.round(
100 *
Math.sqrt(
- Math.pow(this.getNewAccelerationX(this.props.updatedForces) * 3, 2) +
- Math.pow(this.getNewAccelerationY(this.props.updatedForces) * 3, 2)
+ Math.pow(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 3, 2) +
+ Math.pow(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 3, 2)
)
) / 100}{" "}
m/s2
@@ -694,7 +694,7 @@ export default class Weight extends React.Component {
)}
- {!this.state.dragging && this.props.showVelocity && (
+ {!this.state.dragging && this.props.dataDoc['showVelocity'] && (
{
)}
{!this.state.dragging &&
- this.props.showForces &&
- this.props.updatedForces.map((force, index) => {
+ this.props.dataDoc['showForces'] &&
+ this.props.dataDoc['updatedForces'].map((force, index) => {
if (force.magnitude < this.epsilon) {
return;
}
@@ -836,7 +836,7 @@ export default class Weight extends React.Component
{
>
{force.description && {force.description}
}
{!force.description && Force
}
- {this.props.showForceMagnitudes && (
+ {this.props.dataDoc['showForceMagnitudes'] && (
{Math.round(100 * force.magnitude) / 100} N
)}
--
cgit v1.2.3-70-g09d2
From 15c5985f0f52a4ceed3532c95106a7e9c493b080 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Thu, 16 Feb 2023 13:38:53 -0500
Subject: debugging persistence
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 67 +++++++++++++++++--------
1 file changed, 45 insertions(+), 22 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 13b4fe0b2..25777ce18 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -99,30 +99,52 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
{
this.dataDoc.weight = true;
this.dataDoc.wedge = false;
this.dataDoc.pendulum = true;
+ this.removeWalls();
+ let angle = this.dataDoc.pendulumAngle;
+ let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
+ let forceOfTension: IForce = {
+ description: "Tension",
+ magnitude: mag,
+ directionInDegrees: 90 - angle,
+ };
+ this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension];
+ this.dataDoc.startForces = [this.forceOfGravity, forceOfTension];
+ };
+
+ // Set pendulum defaults
+ setToPendulumDefault () {
let length = this.xMax*0.7;
let angle = 35;
let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
@@ -132,18 +154,10 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {
@@ -279,10 +299,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {
- // this.dataDoc.timer = this.dataDoc.timer+1;
- // }, 60);
+ this.dataDoc['simulationPaused'] = true;
}
render () {
@@ -351,17 +368,23 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentRESET
)}
- )}
--
cgit v1.2.3-70-g09d2
From 8428ad5be1d49c8985a59b442823ceaa33005aa6 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Fri, 17 Feb 2023 23:29:10 -0500
Subject: debugging datadoc not working
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 25777ce18..f9baac431 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -278,12 +278,19 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
{this.dataDoc.simulationPaused && (
{
- console.log('start sim')
this.dataDoc.simulationPaused = false}
} >START
)}
{!this.dataDoc.simulationPaused && (
{
- console.log('pause sim')
this.dataDoc.simulationPaused = true}
} >PAUSE
)}
@@ -372,17 +377,17 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentTYPE)}
--
cgit v1.2.3-70-g09d2
From b206cc3e0f992d72010d8420a0e78b38a9840d2f Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Fri, 17 Feb 2023 23:49:56 -0500
Subject: sim type persists
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 112 +++++++++++-------------
1 file changed, 53 insertions(+), 59 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index f9baac431..a78d899e0 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -54,44 +54,32 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {
- if (this.dataDoc.wallPositions.length == 0) {
- let walls = [];
- walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 });
- walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 });
- walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 });
- this.dataDoc.wallPositions = walls
- }
+ let walls = [];
+ walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 });
+ walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 });
+ walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 });
+ this.dataDoc.wallPositions = walls
};
@@ -289,7 +275,8 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
- {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
- return (
-
-
-
- );
- })}
+ {/* {this.dataDoc.wallPositions && (
+ {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
+ return (
+
+
+
+ );
+ })}
+ )} */}
--
cgit v1.2.3-70-g09d2
From 5a7019a97eb22b79fa15770badbfb265cb668208 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Sat, 18 Feb 2023 10:12:57 -0500
Subject: weight pos changes on type change
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 190 +++++++++++----------
src/client/views/nodes/PhysicsSimulationWeight.tsx | 95 ++++++-----
2 files changed, 152 insertions(+), 133 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index a78d899e0..e7d5e48f0 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -51,6 +51,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
-
-
-
-
- {this.dataDoc.weight && (
-
- )}
- {this.dataDoc.wedge && (
-
- )}
+ componentDidUpdate() {
+ this.xMax = this.layoutDoc._width;
+ this.yMax = this.layoutDoc._height;
+ this.radius = 0.1*this.yMax
+ }
+
+ render () {
+ return (
+
+
+
+
+
+ {this.dataDoc.weight && (
+
+ )}
+ {this.dataDoc.wedge && (
+
+ )}
+
+
+ {/* {this.dataDoc.wallPositions && (
+ {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
+ return (
+
+
+
+ );
+ })}
+ )} */}
+
+
+
+
- {/* {this.dataDoc.wallPositions && (
- {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
- return (
-
-
-
- );
- })}
- )} */}
+ {this.dataDoc.simulationPaused && (
+
{
+ this.dataDoc.simulationPaused = false}
+ } >START
+ )}
+ {!this.dataDoc.simulationPaused && (
+
{
+ this.dataDoc.simulationPaused = true}
+ } >PAUSE
+ )}
+ {this.dataDoc.simulationPaused && (
+
{
+ this.dataDoc.simulationReset = !this.dataDoc.simulationReset}
+ } >RESET
+ )}
+ {this.dataDoc.simulationPaused && (
{
+ if (!this.dataDoc.pendulum && !this.dataDoc.wedge) {
+ this.addWedge()
+ this.setToWedgeDefault()
+ this.dataDoc.simulationType = "Inclined Plane"
+ }
+ else if (!this.dataDoc.pendulum && this.dataDoc.wedge) {
+ this.setToPendulumDefault()
+ this.addPendulum()
+ this.dataDoc.simulationType = "Pendulum"
+ }
+ else {
+ this.setToWeightDefault()
+ this.addWeight()
+ this.dataDoc.simulationType = "Free Weight"
+ }
+ }} >TYPE)}
+
-
-
-
- {this.dataDoc.simulationPaused && (
- {
- this.dataDoc.simulationPaused = false}
- } >START
- )}
- {!this.dataDoc.simulationPaused && (
- {
- this.dataDoc.simulationPaused = true}
- } >PAUSE
- )}
- {this.dataDoc.simulationPaused && (
- {
- this.dataDoc.simulationReset = !this.dataDoc.simulationReset}
- } >RESET
- )}
- {this.dataDoc.simulationPaused && ( {
- if (!this.dataDoc.pendulum && !this.dataDoc.wedge) {
- this.addWedge()
- this.setToWedgeDefault()
- this.dataDoc.simulationType = "Inclined Plane"
- }
- else if (!this.dataDoc.pendulum && this.dataDoc.wedge) {
- this.setToPendulumDefault()
- this.addPendulum()
- this.dataDoc.simulationType = "Pendulum"
- }
- else {
- this.addWeight()
- this.setToWeightDefault()
- this.dataDoc.simulationType = "Free Weight"
- }
- }} >TYPE)}
-
-
-
-
- );
- }
-}
\ No newline at end of file
+ );
+ }
+ }
\ No newline at end of file
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index e7bd86915..fc75fa5aa 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -8,20 +8,25 @@ export interface IForce {
directionInDegrees: number;
}
export interface IWeightProps {
- dataDoc: Doc;
+ adjustPendulumAngle: boolean;
color: string;
+ dataDoc: Doc;
mass: number;
- wedge: boolean;
radius: number;
+ simulationReset: boolean;
+ startPosX: number;
+ startPosY: number;
startVelX?: number;
startVelY?: number;
timestepSize: number;
+ updateDisplay: boolean,
walls: IWallProps[];
- wedgeWidth: number;
+ wedge: boolean;
wedgeHeight: number;
+ wedgeWidth: number;
xMax: number;
- yMax: number;
xMin: number;
+ yMax: number;
yMin: number;
}
@@ -37,6 +42,7 @@ interface IState {
yPosition: number,
xVelocity: number,
yVelocity: number,
+ update: boolean,
}
export default class Weight extends React.Component
{
@@ -133,8 +139,9 @@ export default class Weight extends React.Component {
}
componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void {
+
// When display values updated by user, update real values
- if (this.props.dataDoc['updateDisplay'] != prevProps.dataDoc['updateDisplay']) {
+ if (this.props.updateDisplay != prevProps.updateDisplay) {
if (this.props.dataDoc['positionXDisplay'] != this.state.xPosition) {
let x = this.props.dataDoc['positionXDisplay'];
x = Math.max(0, x);
@@ -167,47 +174,29 @@ export default class Weight extends React.Component {
}
}
// Update sim
- if (this.state.timer != prevState.timer) {
- if (!this.props.dataDoc['simulationPaused']) {
- console.log('update')
- let collisions = false;
- if (!this.props.dataDoc['pendulum']) {
- const collisionsWithGround = this.checkForCollisionsWithGround();
- const collisionsWithWalls = this.checkForCollisionsWithWall();
- collisions = collisionsWithGround || collisionsWithWalls;
- }
- if (!collisions) {
- this.update();
- }
- this.setDisplayValues();
+ if (!this.props.dataDoc['simulationPaused']) {
+ if (this.state.timer != prevState.timer) {
+ console.log('update sim')
+ console.log('update')
+ let collisions = false;
+ if (!this.props.dataDoc['pendulum']) {
+ const collisionsWithGround = this.checkForCollisionsWithGround();
+ const collisionsWithWalls = this.checkForCollisionsWithWall();
+ collisions = collisionsWithGround || collisionsWithWalls;
+ }
+ if (!collisions) {
+ this.update();
+ }
+ this.setDisplayValues();
}
}
- this.weightStyle = {
- backgroundColor: this.props.color,
- borderStyle: "solid",
- borderColor: this.state.dragging ? "lightblue" : "black",
- position: "absolute" as "absolute",
- left: this.state.xPosition + "px",
- top: this.state.yPosition + "px",
- width: 2 * this.props.radius + "px",
- height: 2 * this.props.radius + "px",
- borderRadius: 50 + "%",
- display: "flex",
- zIndex: 5,
- justifyContent: "center",
- alignItems: "center",
- touchAction: "none",
- };
- if (this.props.dataDoc['simulationReset'] != prevProps.dataDoc['simulationReset']) {
+ if (this.props.simulationReset != prevProps.simulationReset) {
+ console.log('reset sim')
this.resetEverything();
}
- if (this.props.dataDoc['startForces'] != prevProps.dataDoc['startForces']) {
- this.setState({xVelocity: this.props.startVelX ?? 0})
- this.setState({yVelocity: this.props.startVelY ?? 0})
- this.setDisplayValues();
- }
- if (this.props.dataDoc['adjustPendulumAngle'] != prevProps.dataDoc['adjustPendulumAngle']) {
+ if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) {
+ console.log('update angle')
// Change pendulum angle based on input field
let length = this.props.dataDoc['pendulumLength'] ?? 0;
const x =
@@ -222,18 +211,21 @@ export default class Weight extends React.Component {
this.setState({updatedStartPosY: yPos})
}
// Update x start position
- if (this.props.dataDoc['startPosX'] != prevProps.dataDoc['startPosX']) {
+ if (this.props.startPosX != prevProps.startPosX) {
+ console.log('update start x pos')
this.setState({updatedStartPosX: this.props.dataDoc['startPosX']})
this.setState({xPosition: this.props.dataDoc['startPosX']})
this.setXPosDisplay(this.props.dataDoc['startPosX']);
}
// Update y start position
- if (this.props.dataDoc['startPosY'] != prevProps.dataDoc['startPosY']) {
+ if (this.props.startPosY != prevProps.startPosY) {
+ console.log('update start y pos')
this.setState({updatedStartPosY: this.props.dataDoc['startPosY']})
this.setState({yPosition: this.props.dataDoc['startPosY']})
this.setYPosDisplay(this.props.dataDoc['startPosY']);
}
if (this.state.xVelocity != prevState.xVelocity) {
+ console.log('check for kinetic friction')
if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) {
this.setState({kineticFriction: true});
//switch from static to kinetic friction
@@ -276,6 +268,23 @@ export default class Weight extends React.Component {
}
}
}
+
+ this.weightStyle = {
+ backgroundColor: this.props.color,
+ borderStyle: "solid",
+ borderColor: this.state.dragging ? "lightblue" : "black",
+ position: "absolute" as "absolute",
+ left: this.state.xPosition + "px",
+ top: this.state.yPosition + "px",
+ width: 2 * this.props.radius + "px",
+ height: 2 * this.props.radius + "px",
+ borderRadius: 50 + "%",
+ display: "flex",
+ zIndex: 5,
+ justifyContent: "center",
+ alignItems: "center",
+ touchAction: "none",
+ };
}
resetEverything = () => {
--
cgit v1.2.3-70-g09d2
From a9b9c26764cae849af16078796578db53a180be4 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Sat, 18 Feb 2023 10:20:58 -0500
Subject: debugging
---
src/client/views/nodes/PhysicsSimulationWeight.tsx | 75 +++++++++++-----------
1 file changed, 37 insertions(+), 38 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index fc75fa5aa..f7755dc5c 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -35,14 +35,14 @@ interface IState {
clickPositionY: number,
dragging: boolean,
kineticFriction: boolean,
+ timer: number;
+ update: boolean,
updatedStartPosX: number,
updatedStartPosY: number,
- timer: number;
xPosition: number,
- yPosition: number,
xVelocity: number,
+ yPosition: number,
yVelocity: number,
- update: boolean,
}
export default class Weight extends React.Component {
@@ -57,8 +57,8 @@ export default class Weight extends React.Component {
updatedStartPosX: this.props.dataDoc['startPosX'],
updatedStartPosY: this.props.dataDoc['startPosY'],
xPosition: this.props.dataDoc['startPosX'],
- yPosition: this.props.dataDoc['startPosY'],
xVelocity: this.props.startVelX ? this.props.startVelX: 0,
+ yPosition: this.props.dataDoc['startPosY'],
yVelocity: this.props.startVelY ? this.props.startVelY: 0,
}
}
@@ -74,20 +74,20 @@ export default class Weight extends React.Component {
// Var
weightStyle = {
+ alignItems: "center",
backgroundColor: this.props.color,
- borderStyle: "solid",
borderColor: "black",
- position: "absolute" as "absolute",
- left: this.props.dataDoc['startPosX'] + "px",
- top: this.props.dataDoc['startPosY'] + "px",
- width: 2 * this.props.radius + "px",
- height: 2 * this.props.radius + "px",
- zIndex: 5,
borderRadius: 50 + "%",
+ borderStyle: "solid",
display: "flex",
+ height: 2 * this.props.radius + "px",
justifyContent: "center",
- alignItems: "center",
+ left: this.props.dataDoc['startPosX'] + "px",
+ position: "absolute" as "absolute",
+ top: this.props.dataDoc['startPosY'] + "px",
touchAction: "none",
+ width: 2 * this.props.radius + "px",
+ zIndex: 5,
};
// Helper function to go between display and real values
@@ -174,20 +174,18 @@ export default class Weight extends React.Component {
}
}
// Update sim
- if (!this.props.dataDoc['simulationPaused']) {
- if (this.state.timer != prevState.timer) {
- console.log('update sim')
- console.log('update')
- let collisions = false;
- if (!this.props.dataDoc['pendulum']) {
- const collisionsWithGround = this.checkForCollisionsWithGround();
- const collisionsWithWalls = this.checkForCollisionsWithWall();
- collisions = collisionsWithGround || collisionsWithWalls;
- }
- if (!collisions) {
- this.update();
- }
- this.setDisplayValues();
+ if (this.state.timer != prevState.timer) {
+ if (!this.props.dataDoc['simulationPaused']) {
+ let collisions = false;
+ if (!this.props.dataDoc['pendulum']) {
+ const collisionsWithGround = this.checkForCollisionsWithGround();
+ const collisionsWithWalls = this.checkForCollisionsWithWall();
+ collisions = collisionsWithGround || collisionsWithWalls;
+ }
+ if (!collisions) {
+ this.update();
+ }
+ this.setDisplayValues();
}
}
@@ -270,20 +268,20 @@ export default class Weight extends React.Component {
}
this.weightStyle = {
+ alignItems: "center",
backgroundColor: this.props.color,
- borderStyle: "solid",
borderColor: this.state.dragging ? "lightblue" : "black",
- position: "absolute" as "absolute",
- left: this.state.xPosition + "px",
- top: this.state.yPosition + "px",
- width: 2 * this.props.radius + "px",
- height: 2 * this.props.radius + "px",
borderRadius: 50 + "%",
+ borderStyle: "solid",
display: "flex",
- zIndex: 5,
+ height: 2 * this.props.radius + "px",
justifyContent: "center",
- alignItems: "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,
};
}
@@ -375,6 +373,7 @@ export default class Weight extends React.Component {
const maxX = this.state.xPosition + 2 * this.props.radius;
const containerWidth = 300;
if (this.state.xVelocity != 0) {
+ if (this.props.dataDoc.wallPositions) {
this.props.dataDoc['wallPositions'].forEach((wall) => {
if (wall.angleInDegrees == 90) {
const wallX = (wall.xPos / 100) * 300;
@@ -401,6 +400,7 @@ export default class Weight extends React.Component {
}
}
});
+ }
}
return collision;
};
@@ -409,7 +409,8 @@ export default class Weight extends React.Component {
let collision = false;
const maxY = this.state.yPosition + 2 * this.props.radius;
if (this.state.yVelocity > 0) {
- this.props.dataDoc['wallPositions'] .forEach((wall) => {
+ if (this.props.dataDoc.wallPositions) {
+ this.props.dataDoc['wallPositions'].forEach((wall) => {
if (wall.angleInDegrees == 0) {
const groundY = (wall.yPos / 100) * this.props.yMax;
if (maxY >= groundY) {
@@ -434,6 +435,7 @@ export default class Weight extends React.Component {
}
}
});
+ }
}
return collision;
};
@@ -505,9 +507,6 @@ export default class Weight extends React.Component {
};
-
-
-
labelBackgroundColor = `rgba(255,255,255,0.5)`;
render () {
--
cgit v1.2.3-70-g09d2
From 1bffa19d7b2c085a2f647a0269acdc05630d5146 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Sat, 18 Feb 2023 15:00:46 -0500
Subject: debugging
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 67 +++++++++--------
src/client/views/nodes/PhysicsSimulationWeight.tsx | 87 +++++++++++-----------
2 files changed, 78 insertions(+), 76 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index e7d5e48f0..0f2bc43a0 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -7,6 +7,7 @@ import "./PhysicsSimulationBox.scss";
import Weight from "./PhysicsSimulationWeight";
import Wall from "./PhysicsSimulationWall"
import Wedge from "./PhysicsSimulationWedge"
+import { isUndefined } from "lodash";
export interface IForce {
description: string;
@@ -55,32 +56,6 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {
@@ -292,12 +298,6 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentTYPE)}
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index f7755dc5c..e77cfa96a 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -190,7 +190,6 @@ export default class Weight extends React.Component
{
}
if (this.props.simulationReset != prevProps.simulationReset) {
- console.log('reset sim')
this.resetEverything();
}
if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) {
@@ -210,59 +209,58 @@ export default class Weight extends React.Component {
}
// Update x start position
if (this.props.startPosX != prevProps.startPosX) {
- console.log('update start x pos')
this.setState({updatedStartPosX: this.props.dataDoc['startPosX']})
this.setState({xPosition: this.props.dataDoc['startPosX']})
this.setXPosDisplay(this.props.dataDoc['startPosX']);
}
// Update y start position
if (this.props.startPosY != prevProps.startPosY) {
- console.log('update start y pos')
this.setState({updatedStartPosY: this.props.dataDoc['startPosY']})
this.setState({yPosition: this.props.dataDoc['startPosY']})
this.setYPosDisplay(this.props.dataDoc['startPosY']);
}
- if (this.state.xVelocity != prevState.xVelocity) {
- console.log('check for kinetic friction')
- if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) {
- this.setState({kineticFriction: true});
- //switch from static to kinetic friction
- const normalForce: IForce = {
- description: "Normal Force",
- magnitude:
- this.forceOfGravity.magnitude *
- Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )),
- directionInDegrees:
- 180 - 90 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI,
- };
- let frictionForce: IForce = {
- description: "Kinetic Friction Force",
- magnitude:
- this.props.dataDoc['coefficientOfKineticFriction'] *
- this.forceOfGravity.magnitude *
- Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )),
- directionInDegrees:
- 180 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI,
- };
- // reduce magnitude of friction force if necessary such that block cannot slide up plane
- let yForce = -this.forceOfGravity.magnitude;
- 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) +
- this.forceOfGravity.magnitude) /
+ if (!this.props.dataDoc['simulationPaused']) {
+ if (this.state.xVelocity != prevState.xVelocity) {
+ if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) {
+ this.setState({kineticFriction: true});
+ //switch from static to kinetic friction
+ const normalForce: IForce = {
+ description: "Normal Force",
+ magnitude:
+ this.forceOfGravity.magnitude *
+ Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )),
+ directionInDegrees:
+ 180 - 90 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI,
+ };
+ let frictionForce: IForce = {
+ description: "Kinetic Friction Force",
+ magnitude:
+ this.props.dataDoc['coefficientOfKineticFriction'] *
+ this.forceOfGravity.magnitude *
+ Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )),
+ directionInDegrees:
+ 180 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI,
+ };
+ // reduce magnitude of friction force if necessary such that block cannot slide up plane
+ let yForce = -this.forceOfGravity.magnitude;
+ yForce +=
+ normalForce.magnitude *
+ Math.sin((normalForce.directionInDegrees * Math.PI) / 180);
+ yForce +=
+ frictionForce.magnitude *
Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
- }
- if (this.props.dataDoc['coefficientOfKineticFriction'] != 0) {
- this.props.dataDoc['updatedForces'] = [this.forceOfGravity, normalForce, frictionForce];
- } else {
- this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, normalForce]);
+ if (yForce > 0) {
+ frictionForce.magnitude =
+ (-normalForce.magnitude *
+ Math.sin((normalForce.directionInDegrees * Math.PI) / 180) +
+ this.forceOfGravity.magnitude) /
+ Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
+ }
+ if (this.props.dataDoc['coefficientOfKineticFriction'] != 0) {
+ this.props.dataDoc['updatedForces'] = [this.forceOfGravity, normalForce, frictionForce];
+ } else {
+ this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, normalForce]);
+ }
}
}
}
@@ -503,6 +501,9 @@ export default class Weight extends React.Component {
this.setState({yVelocity: yVel});
this.setState({xPosition: xPos});
this.setState({yPosition: yPos});
+
+ console.log("start forces" this.props.dataDoc['startForces'])
+ console.log("updated forces" this.props.dataDoc['updatedForces'])
this.props.dataDoc['updatedForces'] = (this.getNewForces(xPos, yPos, xVel, yVel));
};
--
cgit v1.2.3-70-g09d2
From 57be7b707694fcc3a2a7a6da6c8cd7782e4eb088 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Sat, 18 Feb 2023 19:17:12 -0500
Subject: debugging pendulum
---
src/client/views/nodes/PhysicsSimulationWeight.tsx | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index e77cfa96a..7c26334bf 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -31,6 +31,7 @@ export interface IWeightProps {
}
interface IState {
+ angleLabel: number,
clickPositionX: number,
clickPositionY: number,
dragging: boolean,
@@ -54,6 +55,7 @@ export default class Weight extends React.Component {
dragging: false,
kineticFriction: false,
timer: 0,
+ angleLabel: 0,
updatedStartPosX: this.props.dataDoc['startPosX'],
updatedStartPosY: this.props.dataDoc['startPosY'],
xPosition: this.props.dataDoc['startPosX'],
@@ -206,6 +208,7 @@ export default class Weight extends React.Component {
this.setState({yPosition: yPos})
this.setState({updatedStartPosX: xPos})
this.setState({updatedStartPosY: yPos})
+ this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle'] * 100) / 100})
}
// Update x start position
if (this.props.startPosX != prevProps.startPosX) {
@@ -353,6 +356,7 @@ export default class Weight extends React.Component {
magnitude: mag,
directionInDegrees: angle,
};
+ this.setState({angleLabel: Math.round(oppositeAngle * 100) / 100})
return [this.forceOfGravity, forceOfTension];
};
@@ -502,8 +506,6 @@ export default class Weight extends React.Component {
this.setState({xPosition: xPos});
this.setState({yPosition: yPos});
- console.log("start forces" this.props.dataDoc['startForces'])
- console.log("updated forces" this.props.dataDoc['updatedForces'])
this.props.dataDoc['updatedForces'] = (this.getNewForces(xPos, yPos, xVel, yVel));
};
@@ -630,7 +632,7 @@ export default class Weight extends React.Component {
backgroundColor: this.labelBackgroundColor,
}}
>
- {Math.round(this.props.dataDoc['pendulumAngle'] * 100) / 100}°
+ {this.state.angleLabel}°
)}
--
cgit v1.2.3-70-g09d2
From b8762e80e3fd6b1c78b62f6bd50acb2029a68f58 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Mon, 20 Feb 2023 13:46:55 -0500
Subject: start sim settings menu
---
src/client/views/nodes/PhysicsSimulationBox.scss | 16 +++++
src/client/views/nodes/PhysicsSimulationBox.tsx | 73 +++++++++++++++++++---
src/client/views/nodes/PhysicsSimulationWeight.tsx | 1 -
3 files changed, 80 insertions(+), 10 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss
index cfe2ee6ca..9efe835a3 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.scss
+++ b/src/client/views/nodes/PhysicsSimulationBox.scss
@@ -49,3 +49,19 @@ button {
user-select: none;
pointer-events: none;
}
+
+.mechanicsSimulationSettingsMenu {
+ width: 100%;
+ height: 100%;
+ font-size: 12px;
+ background-color: purple;
+ border-radius: 2px;
+ border-color: black;
+ border-style: solid;
+ z-index: 20000;
+}
+
+.mechanicsSimulationSettingsMenuRow {
+ display: flex;
+ z-index: 20000;
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 0f2bc43a0..b7f4ed0fb 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -7,8 +7,8 @@ import "./PhysicsSimulationBox.scss";
import Weight from "./PhysicsSimulationWeight";
import Wall from "./PhysicsSimulationWall"
import Wedge from "./PhysicsSimulationWedge"
-import { isUndefined } from "lodash";
-
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { CheckBox } from "../search/CheckBox";
export interface IForce {
description: string;
magnitude: number;
@@ -53,6 +53,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
)}
-
- {/* {this.dataDoc.wallPositions && (
- {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
+ {/*
+ {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
return (
);
})}
- )} */}
-
+
*/}
+
+ {this.menuIsOpen && (
+
+
{this.menuIsOpen = false}}>
+
+
+
Simulation Settings
+ {this.dataDoc.simulationType == "Free Weight" &&
+
+
Elastic collisions
+
{this.dataDoc.elasticCollisions = val}} originalStatus={this.dataDoc.elasticCollisions} />
+
+ }
+ {/* {this.dataDoc.simulationType == "Inclined Plane" &&
+
+
Inclined plane angle
+
input field!
+
+ }
+ {this.dataDoc.simulationType == "Pendulum" &&
+
+
Pendulum angle
+
input field!
+
+ }
+
+
Show forces
+
+ this.dataDoc.showForces = !this.dataDoc.showForces
+ }
+ />
+
+
+
Show acceleration
+
+ this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration
+ }
+ />
+
+
+
Show velocity
+
+ this.dataDoc.showVelocity = !this.dataDoc.showVelocity
+ }
+ />
+ */}
+
+ )}
+
@@ -395,6 +449,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentTYPE)}
+ {this.menuIsOpen=true; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}>MENU
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index 7c26334bf..b9fa14df0 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -840,7 +840,6 @@ export default class Weight extends React.Component {
position: "absolute",
left: labelLeft + "px",
top: labelTop + "px",
- // zIndex: -1,
lineHeight: 0.5,
backgroundColor: this.labelBackgroundColor,
}}
--
cgit v1.2.3-70-g09d2
From 0fd4eb6a8bf80861345633aabe6d482c24cb4d70 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Tue, 21 Feb 2023 12:07:39 -0500
Subject: settings menu
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 45 ++++++++--------------
src/client/views/nodes/PhysicsSimulationWeight.tsx | 4 +-
2 files changed, 17 insertions(+), 32 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index b7f4ed0fb..f0e009deb 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -361,14 +361,14 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
{this.menuIsOpen && (
-
{this.menuIsOpen = false}}>
-
+
{this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}} style={{zIndex: 20000}}>
+
-
Simulation Settings
+
Simulation Settings
{this.dataDoc.simulationType == "Free Weight" &&
-
Elastic collisions
-
{this.dataDoc.elasticCollisions = val}} originalStatus={this.dataDoc.elasticCollisions} />
+ Elastic collisions
+ {this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
}
{/* {this.dataDoc.simulationType == "Inclined Plane" &&
@@ -376,40 +376,25 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
Inclined plane angle
input field!
- }
- {this.dataDoc.simulationType == "Pendulum" &&
+ } */}
+ {/* {this.dataDoc.simulationType == "Pendulum" &&
Pendulum angle
input field!
- }
+ } */}
-
Show forces
-
- this.dataDoc.showForces = !this.dataDoc.showForces
- }
- />
+ Show forces
+ {this.dataDoc.showForces = !this.dataDoc.showForces}}/>
-
Show acceleration
-
- this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration
- }
- />
+ Show acceleration
+ {this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
-
Show velocity
-
- this.dataDoc.showVelocity = !this.dataDoc.showVelocity
- }
- />
- */}
+
Show velocity
+
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
+
)}
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index b9fa14df0..66af645b5 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -769,12 +769,12 @@ export default class Weight extends React.Component {
let arrowEndY: number =
arrowStartY -
Math.abs(force.magnitude) *
- 20 *
+ 10 *
Math.sin((force.directionInDegrees * Math.PI) / 180);
const arrowEndX: number =
arrowStartX +
Math.abs(force.magnitude) *
- 20 *
+ 10 *
Math.cos((force.directionInDegrees * Math.PI) / 180);
let color = "#0d0d0d";
--
cgit v1.2.3-70-g09d2
From 0f03110bab8d4636d33abf7568bf7c6cb14847b4 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Tue, 21 Feb 2023 16:10:23 -0500
Subject: settings menu
---
src/client/views/nodes/PhysicsSimulationBox.scss | 17 +++++++----
src/client/views/nodes/PhysicsSimulationBox.tsx | 36 +++++++++++-------------
2 files changed, 28 insertions(+), 25 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss
index 9efe835a3..7573f1472 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.scss
+++ b/src/client/views/nodes/PhysicsSimulationBox.scss
@@ -40,7 +40,7 @@ tr:nth-child(even) {
}
button {
- z-index: 5000;
+ z-index: 50;
}
.angleLabel {
@@ -54,14 +54,21 @@ button {
width: 100%;
height: 100%;
font-size: 12px;
- background-color: purple;
+ background-color: rgb(224, 224, 224);
border-radius: 2px;
border-color: black;
border-style: solid;
- z-index: 20000;
+ padding: 10px;
+ position: fixed;
+ z-index: 1000;
}
-.mechanicsSimulationSettingsMenuRow {
+.mechanicsSimulationSettingsMenuColumn {
+ display: flex;
+ flex-direction: column;
+ width: 50%;
+}
+
+.mechanicsSimulationSettingsMenuContents {
display: flex;
- z-index: 20000;
}
\ No newline at end of file
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index f0e009deb..7eb9092bf 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -361,16 +361,24 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
{this.menuIsOpen && (
-
{this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}} style={{zIndex: 20000}}>
-
+
{this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}>
+
-
Simulation Settings
- {this.dataDoc.simulationType == "Free Weight" &&
-
-
Elastic collisions
-
{this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
+
Simulation Settings
+
+
+
+
+
+ {this.dataDoc.simulationType == "Free Weight" &&
}
+
+
- }
+
{/* {this.dataDoc.simulationType == "Inclined Plane" &&
Inclined plane angle
@@ -383,18 +391,6 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
input field!
} */}
-
-
Show forces
-
{this.dataDoc.showForces = !this.dataDoc.showForces}}/>
-
-
-
Show acceleration
-
{this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
-
-
-
Show velocity
-
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
-
)}
--
cgit v1.2.3-70-g09d2
From 9a5f2e9d098d0ad2db1be90818b6295390a60501 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Wed, 22 Feb 2023 14:29:44 -0500
Subject: pendulum angle
---
src/client/views/nodes/PhysicsSimulationBox.scss | 8 +--
src/client/views/nodes/PhysicsSimulationBox.tsx | 76 ++++++++++++++++------
src/client/views/nodes/PhysicsSimulationWeight.tsx | 3 +-
3 files changed, 61 insertions(+), 26 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss
index 7573f1472..0f05010b4 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.scss
+++ b/src/client/views/nodes/PhysicsSimulationBox.scss
@@ -63,12 +63,10 @@ button {
z-index: 1000;
}
-.mechanicsSimulationSettingsMenuColumn {
+.mechanicsSimulationSettingsMenuRow {
display: flex;
- flex-direction: column;
- width: 50%;
}
-.mechanicsSimulationSettingsMenuContents {
- display: flex;
+.mechanicsSimulationSettingsMenuRowDescription {
+ width: 50%;
}
\ No newline at end of file
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 7eb9092bf..1a64ec795 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -119,6 +119,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
{this.dataDoc.weight && (
Simulation Settings
-
-
-
-
-
- {this.dataDoc.simulationType == "Free Weight" &&
}
-
-
+
+
+
{this.dataDoc.showForces = !this.dataDoc.showForces}}/>
+
+
+
+
{this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
+
+
+
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
+
+
+ {this.dataDoc.simulationType == "Free Weight" &&
+
+
{this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
+
}
+ {this.dataDoc.simulationType == "Pendulum" &&
+
+
+ {
+ let angle = e.target.value;
+ if (angle > 35) {
+ angle = 35
+ }
+ if (angle < 0) {
+ angle = 0
+ }
+ let length = this.xMax*0.7;
+ let x = length * Math.cos(((90 - angle) * Math.PI) / 180);
+ let y = length * Math.sin(((90 - angle) * Math.PI) / 180);
+ let xPos = this.xMax / 2 - x - this.radius;
+ let yPos = y - this.radius;
+ this.dataDoc.startPosX = xPos;
+ this.dataDoc.startPosY = yPos;
+ let mag = 9.81 * Math.cos((angle * Math.PI) / 180);
+ this.dataDoc.pendulumAngle = angle;
+ this.dataDoc.pendulumLength = length;
+ this.dataDoc.startPendulumAngle = angle;
+ this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle;
+ }}
+ />
+
+
}
{/* {this.dataDoc.simulationType == "Inclined Plane" &&
Inclined plane angle
input field!
} */}
- {/* {this.dataDoc.simulationType == "Pendulum" &&
-
-
Pendulum angle
-
input field!
-
- } */}
)}
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index 66af645b5..9aa5a6aab 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -293,6 +293,7 @@ export default class Weight extends React.Component {
this.setState({xVelocity: this.props.startVelX ?? 0})
this.setState({yVelocity: this.props.startVelY ?? 0})
this.props.dataDoc['updatedForces'] = (this.props.dataDoc['startForces'])
+ this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle']* 100) / 100})
this.setDisplayValues();
};
@@ -356,7 +357,7 @@ export default class Weight extends React.Component {
magnitude: mag,
directionInDegrees: angle,
};
- this.setState({angleLabel: Math.round(oppositeAngle * 100) / 100})
+ this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle']* 100) / 100})
return [this.forceOfGravity, forceOfTension];
};
--
cgit v1.2.3-70-g09d2
From 4c0336f3d7380595f9a5e074ec8c0e31f061a709 Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Wed, 22 Feb 2023 14:38:26 -0500
Subject: wedge angle
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 31 ++++++++++++++++++-------
1 file changed, 23 insertions(+), 8 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 1a64ec795..2db49de3c 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -194,8 +194,6 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentShow velocity
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
-
+
{this.dataDoc.simulationType == "Free Weight" &&
}
- {/* {this.dataDoc.simulationType == "Inclined Plane" &&
-
-
Inclined plane angle
-
input field!
+ {this.dataDoc.simulationType == "Inclined Plane" &&
+
+
+ {
+ let angle = e.target.value ?? 0
+ if (angle > 70) {
+ angle = 70
+ }
+ if (angle < 0) {
+ angle = 0
+ }
+ this.dataDoc.wedgeAngle = angle
+ this.changeWedgeBasedOnNewAngle(angle)
+ }}
+ />
- } */}
+
}
)}
--
cgit v1.2.3-70-g09d2
From dffb5bdfdcffc7e1f85888b7222468bfb95a05ac Mon Sep 17 00:00:00 2001
From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com>
Date: Wed, 22 Feb 2023 22:37:37 -0500
Subject: improvements
---
src/client/views/nodes/PhysicsSimulationBox.tsx | 12 +-
src/client/views/nodes/PhysicsSimulationWedge.tsx | 4 +-
src/client/views/nodes/PhysicsSimulationWeight.tsx | 160 ++++++++++-----------
3 files changed, 88 insertions(+), 88 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx
index 2db49de3c..d0e854263 100644
--- a/src/client/views/nodes/PhysicsSimulationBox.tsx
+++ b/src/client/views/nodes/PhysicsSimulationBox.tsx
@@ -271,8 +271,8 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
)}
- {/*
- {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
+
+ {(this.dataDoc.wallPositions ?? []).map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => {
return (
);
})}
-
*/}
+
@@ -468,11 +468,13 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
{
}
componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void {
- if (prevState.coordinates != this.state.coordinates) {
- this.updateCoordinates();
- }
if (prevProps.startHeight != this.props.startHeight || prevProps.startWidth != this.props.startWidth) {
this.setState({angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth)});
+ this.updateCoordinates();
}
}
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx
index 9aa5a6aab..39b3249e8 100644
--- a/src/client/views/nodes/PhysicsSimulationWeight.tsx
+++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx
@@ -518,86 +518,86 @@ export default class Weight extends React.Component {
{
- if (this.draggable) {
- e.preventDefault();
- this.props.dataDoc['simulationPaused'] = true;
- this.setState({dragging: true});
- this.setState({clickPositionX: e.clientX})
- this.setState({clickPositionY: e.clientY})
- }
- }}
- onPointerMove={(e) => {
- e.preventDefault();
- if (this.state.dragging) {
- let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
- if (newY > this.props.yMax - 2 * this.props.radius) {
- newY = this.props.yMax - 2 * this.props.radius;
- }
-
- let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
- if (newX > this.props.xMax - 2 * this.props.radius) {
- newX = this.props.xMax - 2 * this.props.radius;
- } else if (newX < 0) {
- newX = 0;
- }
- this.setState({xPosition: newX})
- this.setState({yPosition: newY})
- this.setState({updatedStartPosX: newX})
- this.setState({updatedStartPosY: newY})
- this.props.dataDoc['positionYDisplay'] = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100;
- this.setState({clickPositionX: e.clientX})
- this.setState({clickPositionY: e.clientY})
- this.setDisplayValues();
- }
- }}
- onPointerUp={(e) => {
- if (this.state.dragging) {
- e.preventDefault();
- if (!this.props.dataDoc['pendulum']) {
- 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) {
- newY = this.props.yMax - 2 * this.props.radius;
- }
-
- let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
- if (newX > this.props.xMax - 2 * this.props.radius) {
- newX = this.props.xMax - 2 * this.props.radius;
- } else if (newX < 0) {
- newX = 0;
- }
- if (this.props.dataDoc['pendulum']) {
- const x = this.props.xMax / 2 - newX - this.props.radius;
- const y = newY + 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;
- this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y);
- const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180);
- const forceOfTension: IForce = {
- description: "Tension",
- magnitude: mag,
- directionInDegrees: angle,
- };
- this.setState({kineticFriction: false})
- this.setState({xVelocity: this.props.startVelX ?? 0})
- this.setState({yVelocity: this.props.startVelY ?? 0})
- this.setDisplayValues();
- this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, forceOfTension]);
- }
- }
- }}
+ // onPointerDown={(e) => {
+ // if (this.draggable) {
+ // e.preventDefault();
+ // this.props.dataDoc['simulationPaused'] = true;
+ // this.setState({dragging: true});
+ // this.setState({clickPositionX: e.clientX})
+ // this.setState({clickPositionY: e.clientY})
+ // }
+ // }}
+ // onPointerMove={(e) => {
+ // e.preventDefault();
+ // if (this.state.dragging) {
+ // let newY = this.state.yPosition + e.clientY - this.state.clickPositionY;
+ // if (newY > this.props.yMax - 2 * this.props.radius) {
+ // newY = this.props.yMax - 2 * this.props.radius;
+ // }
+
+ // let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
+ // if (newX > this.props.xMax - 2 * this.props.radius) {
+ // newX = this.props.xMax - 2 * this.props.radius;
+ // } else if (newX < 0) {
+ // newX = 0;
+ // }
+ // this.setState({xPosition: newX})
+ // this.setState({yPosition: newY})
+ // this.setState({updatedStartPosX: newX})
+ // this.setState({updatedStartPosY: newY})
+ // this.props.dataDoc['positionYDisplay'] = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100;
+ // this.setState({clickPositionX: e.clientX})
+ // this.setState({clickPositionY: e.clientY})
+ // this.setDisplayValues();
+ // }
+ // }}
+ // onPointerUp={(e) => {
+ // if (this.state.dragging) {
+ // e.preventDefault();
+ // if (!this.props.dataDoc['pendulum']) {
+ // 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) {
+ // newY = this.props.yMax - 2 * this.props.radius;
+ // }
+
+ // let newX = this.state.xPosition + e.clientX - this.state.clickPositionX;
+ // if (newX > this.props.xMax - 2 * this.props.radius) {
+ // newX = this.props.xMax - 2 * this.props.radius;
+ // } else if (newX < 0) {
+ // newX = 0;
+ // }
+ // if (this.props.dataDoc['pendulum']) {
+ // const x = this.props.xMax / 2 - newX - this.props.radius;
+ // const y = newY + 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;
+ // this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y);
+ // const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180);
+ // const forceOfTension: IForce = {
+ // description: "Tension",
+ // magnitude: mag,
+ // directionInDegrees: angle,
+ // };
+ // this.setState({kineticFriction: false})
+ // this.setState({xVelocity: this.props.startVelX ?? 0})
+ // this.setState({yVelocity: this.props.startVelY ?? 0})
+ // this.setDisplayValues();
+ // this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, forceOfTension]);
+ // }
+ // }
+ // }}
>
{this.props.mass} kg
--
cgit v1.2.3-70-g09d2