aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/PhysicsSimulationApp.tsx
diff options
context:
space:
mode:
authorbrynnchernosky <56202540+brynnchernosky@users.noreply.github.com>2023-01-30 14:29:43 -0500
committerbrynnchernosky <56202540+brynnchernosky@users.noreply.github.com>2023-01-30 14:29:43 -0500
commit136d946b88ff817c2dd738553ddb2aea0a11f0e7 (patch)
tree7b3dac455b5151dd347a85ff07dfb753fb29c5f6 /src/client/views/nodes/PhysicsSimulationApp.tsx
parentd5ebbf476aeb7ce3f88e2e4c3961ffed4ed8e61a (diff)
remove extraneous code
Diffstat (limited to 'src/client/views/nodes/PhysicsSimulationApp.tsx')
-rw-r--r--src/client/views/nodes/PhysicsSimulationApp.tsx1353
1 files changed, 19 insertions, 1334 deletions
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) => (
- <Tooltip {...props} classes={{ popper: className }} />
- ))(({ 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<number>(0);
const [reviewStaticAngle, setReviewStaticAngle] = useState<number>(0);
const [reviewStaticMagnitude, setReviewStaticMagnitude] = useState<number>(0);
- const [selectedQuestion, setSelectedQuestion] = useState<QuestionTemplate>(
- questions.inclinePlane[0]
- );
- const [selectedTutorial, setSelectedTutorial] = useState<TutorialTemplate>(
- tutorials.inclinePlane
- );
const [questionPartTwo, setQuestionPartTwo] = useState<string>("");
const [selectedSolutions, setSelectedSolutions] = useState<number[]>([]);
const [showAcceleration, setShowAcceleration] = useState<boolean>(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(<div></div>);
- };
-
+
// 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(
- <div key={i + d.getTime()}>
- <InputField
- label={
- <p>
- F<sub>G</sub>
- </p>
- }
- lowerBound={0}
- changeValue={setReviewGravityMagnitude}
- step={0.1}
- unit={"N"}
- upperBound={50}
- value={reviewGravityMagnitude}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
- </div>
- );
- } else if (question.answerParts[i] == "angle of gravity") {
- setReviewGravityAngle(0);
- answerInput.push(
- <div key={i + d.getTime()}>
- <InputField
- label={
- <p>
- &theta;<sub>G</sub>
- </p>
- }
- lowerBound={0}
- changeValue={setReviewGravityAngle}
- step={1}
- unit={"°"}
- upperBound={360}
- value={reviewGravityAngle}
- radianEquivalent={true}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
- </div>
- );
- } else if (question.answerParts[i] == "normal force") {
- setReviewNormalMagnitude(0);
- answerInput.push(
- <div key={i + d.getTime()}>
- <InputField
- label={
- <p>
- F<sub>N</sub>
- </p>
- }
- lowerBound={0}
- changeValue={setReviewNormalMagnitude}
- step={0.1}
- unit={"N"}
- upperBound={50}
- value={reviewNormalMagnitude}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
- </div>
- );
- } else if (question.answerParts[i] == "angle of normal force") {
- setReviewNormalAngle(0);
- answerInput.push(
- <div key={i + d.getTime()}>
- <InputField
- label={
- <p>
- &theta;<sub>N</sub>
- </p>
- }
- lowerBound={0}
- changeValue={setReviewNormalAngle}
- step={1}
- unit={"°"}
- upperBound={360}
- value={reviewNormalAngle}
- radianEquivalent={true}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
- </div>
- );
- } else if (question.answerParts[i] == "force of static friction") {
- setReviewStaticMagnitude(0);
- answerInput.push(
- <div key={i + d.getTime()}>
- <InputField
- label={
- <p>
- F
- <sub>
- F<sub>s</sub>
- </sub>
- </p>
- }
- lowerBound={0}
- changeValue={setReviewStaticMagnitude}
- step={0.1}
- unit={"N"}
- upperBound={50}
- value={reviewStaticMagnitude}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
- </div>
- );
- } else if (question.answerParts[i] == "angle of static friction") {
- setReviewStaticAngle(0);
- answerInput.push(
- <div key={i + d.getTime()}>
- <InputField
- label={
- <p>
- &theta;
- <sub>
- F<sub>s</sub>
- </sub>
- </p>
- }
- lowerBound={0}
- changeValue={setReviewStaticAngle}
- step={1}
- unit={"°"}
- upperBound={360}
- value={reviewStaticAngle}
- radianEquivalent={true}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
- </div>
- );
- } else if (question.answerParts[i] == "coefficient of static friction") {
- updateReviewForcesBasedOnCoefficient(0);
- answerInput.push(
- <div key={i + d.getTime()}>
- <InputField
- label={
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">
- &mu;<sub>s</sub>
- </Typography>
- Coefficient of static friction; between 0 and 1
- </React.Fragment>
- }
- followCursor
- >
- <Box>
- &mu;<sub>s</sub>
- </Box>
- </Tooltip>
- }
- lowerBound={0}
- changeValue={setCoefficientOfStaticFriction}
- step={0.1}
- unit={""}
- upperBound={1}
- value={coefficientOfStaticFriction}
- effect={updateReviewForcesBasedOnCoefficient}
- showIcon={showIcon}
- correctValue={answers[i]}
- />
- </div>
- );
- } else if (question.answerParts[i] == "wedge angle") {
- updateReviewForcesBasedOnAngle(0);
- answerInput.push(
- <div key={i + d.getTime()}>
- <InputField
- label={
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">&theta;</Typography>
- Angle of incline plane from the ground, 0-49
- </React.Fragment>
- }
- followCursor
- >
- <Box>&theta;</Box>
- </Tooltip>
- }
- 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]}
- />
- </div>
- );
- }
- }
-
- setAnswerInputFields(
- <div
- style={{ display: "flex", flexDirection: "column", alignItems: "left" }}
- >
- {answerInput}
- </div>
- );
- };
-
// 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",
}}
>
- <LinearProgress />
+ <p>SIMULATION IN PROGRESS</p>
</div>
)}
<div
@@ -1370,41 +735,23 @@ function App() {
</div>
<div className="mechanicsSimulationEquationContainer">
<div className="mechanicsSimulationControls">
- <Stack direction="row" spacing={1}>
- {simulationPaused && mode != "Tutorial" && (
- <Tooltip title="Start simulation" followCursor>
- <IconButton
- onClick={() => {
- setSimulationPaused(false);
- }}
- >
- <PlayArrowIcon />
- </IconButton>
- </Tooltip>
+ <div>
+ {simulationPaused && (
+ <button onClick={() => {
+ setSimulationPaused(false);
+ }} >START</button>
)}
- {!simulationPaused && mode != "Tutorial" && (
- <Tooltip title="Pause simulation" followCursor>
- <IconButton
- onClick={() => {
- setSimulationPaused(true);
- }}
- >
- <PauseIcon />
- </IconButton>
- </Tooltip>
+ {!simulationPaused && (
+ <button onClick={() => {
+ setSimulationPaused(true);
+ }} >PAUSE</button>
)}
- {simulationPaused && mode != "Tutorial" && (
- <Tooltip title="Reset simulation" followCursor>
- <IconButton
- onClick={() => {
- setSimulationReset(!simulationReset);
- }}
- >
- <ReplayIcon />
- </IconButton>
- </Tooltip>
+ {simulationPaused && (
+ <button onClick={() => {
+ setSimulationReset(!simulationReset);
+ }} >RESET</button>
)}
- </Stack>
+ </div>
<div className="dropdownMenu">
<select
value={mode}
@@ -1419,668 +766,6 @@ function App() {
</select>
</div>
</div>
- {mode == "Review" && (
- <div>
- {!hintDialogueOpen && (
- <IconButton
- onClick={() => {
- setHintDialogueOpen(true);
- }}
- sx={{
- position: "fixed",
- left: xMax - 50 + "px",
- top: yMin + 14 + "px",
- }}
- >
- <QuestionMarkIcon />
- </IconButton>
- )}
- <Dialog
- maxWidth={"sm"}
- fullWidth={true}
- open={hintDialogueOpen}
- onClose={() => setHintDialogueOpen(false)}
- >
- <DialogTitle>Hints</DialogTitle>
- <DialogContent>
- {selectedQuestion.hints.map((hint, index) => {
- return (
- <div key={index}>
- <DialogContentText>
- <details>
- <summary>
- <b>
- Hint {index + 1}: {hint.description}
- </b>
- </summary>
- {hint.content}
- </details>
- </DialogContentText>
- </div>
- );
- })}
- </DialogContent>
- <DialogActions>
- <Button
- onClick={() => {
- setHintDialogueOpen(false);
- }}
- >
- Close
- </Button>
- </DialogActions>
- </Dialog>
- <div className="wordProblemBox">
- <div className="question">
- <p>{questionPartOne}</p>
- <p>{questionPartTwo}</p>
- </div>
- <div className="answer">{answerInputFields}</div>
- </div>
- </div>
- )}
- {mode == "Tutorial" && (
- <div className="wordProblemBox">
- <div className="question">
- <h2>Problem</h2>
- <p>{selectedTutorial.question}</p>
- </div>
- <div
- style={{
- display: "flex",
- justifyContent: "spaceBetween",
- width: "100%",
- }}
- >
- <IconButton
- onClick={() => {
- 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}
- >
- <ArrowLeftIcon />
- </IconButton>
- <div>
- <h3>
- Step {stepNumber + 1}:{" "}
- {selectedTutorial.steps[stepNumber].description}
- </h3>
- <p>{selectedTutorial.steps[stepNumber].content}</p>
- </div>
- <IconButton
- onClick={() => {
- 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}
- >
- <ArrowRightIcon />
- </IconButton>
- </div>
- <div>
- <p>Resources</p>
- {simulationType == "One Weight" && (
- <ul>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/one-dimensional-motion"
- target="_blank"
- rel="noreferrer"
- style={{ color: "blue", textDecoration: "underline" }}
- >
- Khan Academy - One Dimensional Motion
- </a>
- </li>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/two-dimensional-motion"
- target="_blank"
- rel="noreferrer"
- style={{ color: "blue", textDecoration: "underline" }}
- >
- Khan Academy - Two Dimensional Motion
- </a>
- </li>
- </ul>
- )}
- {simulationType == "Inclined Plane" && (
- <ul>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/forces-newtons-laws#normal-contact-force"
- target="_blank"
- rel="noreferrer"
- style={{ color: "blue", textDecoration: "underline" }}
- >
- Khan Academy - Normal Force
- </a>
- </li>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/forces-newtons-laws#inclined-planes-friction"
- target="_blank"
- rel="noreferrer"
- style={{ color: "blue", textDecoration: "underline" }}
- >
- Khan Academy - Inclined Planes
- </a>
- </li>
- </ul>
- )}
- {simulationType == "Pendulum" && (
- <ul>
- <li>
- <a
- href="https://www.khanacademy.org/science/physics/forces-newtons-laws#tension-tutorial"
- target="_blank"
- rel="noreferrer"
- style={{ color: "blue", textDecoration: "underline" }}
- >
- Khan Academy - Tension
- </a>
- </li>
- </ul>
- )}
- </div>
- </div>
- )}
- {mode == "Review" && (
- <div
- style={{
- display: "flex",
- justifyContent: "space-between",
- marginTop: "10px",
- }}
- >
- <p
- style={{
- color: "blue",
- textDecoration: "underline",
- cursor: "pointer",
- }}
- onClick={() => setMode("Tutorial")}
- >
- {" "}
- Go to walkthrough{" "}
- </p>
- <div style={{ display: "flex", flexDirection: "column" }}>
- <Button
- onClick={() => {
- setSimulationReset(!simulationReset);
- checkAnswers();
- generateInputFieldsForQuestion(true);
- }}
- variant="outlined"
- >
- <Typography>Submit</Typography>
- </Button>
- <Button
- onClick={() => generateNewQuestion()}
- variant="outlined"
- >
- <Typography>New question</Typography>
- </Button>
- </div>
- </div>
- )}
-
- {mode == "Freeform" && (
- <div>
- <FormControl component="fieldset">
- <FormGroup>
- {!wedge && !pendulum && (
- <FormControlLabel
- control={
- <Checkbox
- value={elasticCollisions}
- onChange={() =>
- setElasticCollisions(!elasticCollisions)
- }
- />
- }
- label="Make collisions elastic"
- labelPlacement="start"
- />
- )}
- {!wedge && !pendulum && <Divider />}
- <FormControlLabel
- control={
- <Checkbox
- value={showForces}
- onChange={() => setShowForces(!showForces)}
- defaultChecked
- />
- }
- label="Show force vectors"
- labelPlacement="start"
- />
- <FormControlLabel
- control={
- <Checkbox
- value={showAcceleration}
- onChange={() => setShowAcceleration(!showAcceleration)}
- />
- }
- label="Show acceleration vector"
- labelPlacement="start"
- />
- <FormControlLabel
- control={
- <Checkbox
- value={showVelocity}
- onChange={() => setShowVelocity(!showVelocity)}
- />
- }
- label="Show velocity vector"
- labelPlacement="start"
- />
- </FormGroup>
- </FormControl>
- {wedge && simulationPaused && (
- <div>
- <InputField
- label={
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">&theta;</Typography>
- Angle of incline plane from the ground, 0-49
- </React.Fragment>
- }
- followCursor
- >
- <Box>&theta;</Box>
- </Tooltip>
- }
- lowerBound={0}
- changeValue={setWedgeAngle}
- step={1}
- unit={"°"}
- upperBound={49}
- value={wedgeAngle}
- effect={changeWedgeBasedOnNewAngle}
- radianEquivalent={true}
- mode={"Freeform"}
- />
- <InputField
- label={
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">
- &mu;<sub>s</sub>
- </Typography>
- Coefficient of static friction, between 0 and 1
- </React.Fragment>
- }
- followCursor
- >
- <Box>
- &mu;<sub>s</sub>
- </Box>
- </Tooltip>
- }
- lowerBound={0}
- changeValue={setCoefficientOfStaticFriction}
- step={0.1}
- unit={""}
- upperBound={1}
- value={coefficientOfStaticFriction}
- effect={updateForcesWithFriction}
- mode={"Freeform"}
- />
- <InputField
- label={
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">
- &mu;<sub>k</sub>
- </Typography>
- Coefficient of kinetic friction, between 0 and
- coefficient of static friction
- </React.Fragment>
- }
- followCursor
- >
- <Box>
- &mu;<sub>k</sub>
- </Box>
- </Tooltip>
- }
- lowerBound={0}
- changeValue={setCoefficientOfKineticFriction}
- step={0.1}
- unit={""}
- upperBound={Number(coefficientOfStaticFriction)}
- value={coefficientOfKineticFriction}
- mode={"Freeform"}
- />
- </div>
- )}
- {wedge && !simulationPaused && (
- <Typography>
- &theta;: {Math.round(Number(wedgeAngle) * 100) / 100}° ≈{" "}
- {Math.round(((Number(wedgeAngle) * Math.PI) / 180) * 100) /
- 100}{" "}
- rad
- <br />
- &mu; <sub>s</sub>: {coefficientOfStaticFriction}
- <br />
- &mu; <sub>k</sub>: {coefficientOfKineticFriction}
- </Typography>
- )}
- {pendulum && !simulationPaused && (
- <Typography>
- &theta;: {Math.round(pendulumAngle * 100) / 100}° ≈{" "}
- {Math.round(((pendulumAngle * Math.PI) / 180) * 100) / 100}{" "}
- rad
- </Typography>
- )}
- {pendulum && simulationPaused && (
- <div>
- <InputField
- label={
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">&theta;</Typography>
- Pendulum angle offest from equilibrium
- </React.Fragment>
- }
- followCursor
- >
- <Box>&theta;</Box>
- </Tooltip>
- }
- 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"}
- />
- <InputField
- label={
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">Length</Typography>
- Pendulum rod length
- </React.Fragment>
- }
- followCursor
- >
- <Box>Length</Box>
- </Tooltip>
- }
- 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"}
- />
- </div>
- )}
- </div>
- )}
- <div className="mechanicsSimulationEquation">
- {mode == "Freeform" && twoWeights && <p>Red Weight</p>}
- {mode == "Freeform" && weight && (
- <table>
- <tbody>
- <tr>
- <td>&nbsp;</td>
- <td>X</td>
- <td>Y</td>
- </tr>
- <tr>
- <td
- style={{ cursor: "help" }}
- onClick={() => {
- window.open(
- "https://www.khanacademy.org/science/physics/two-dimensional-motion"
- );
- }}
- >
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">Position</Typography>
- Equation: x<sub>1</sub>
- =x
- <sub>0</sub>
- +v
- <sub>0</sub>
- t+0.5at
- <sup>2</sup>
- <br />
- Units: m
- </React.Fragment>
- }
- followCursor
- >
- <Box>Position</Box>
- </Tooltip>
- </td>
- <td>
- {(!simulationPaused || wedge) && (
- <p style={{ cursor: "default" }}>
- {positionXDisplay} m
- </p>
- )}{" "}
- {simulationPaused && !wedge && (
- <InputField
- lowerBound={0}
- changeValue={setPositionXDisplay}
- step={1}
- unit={"m"}
- upperBound={xMax}
- value={positionXDisplay}
- effect={(value) => {
- setDisplayChange({
- xDisplay: value,
- yDisplay: positionYDisplay,
- });
- }}
- small={true}
- mode={"Freeform"}
- />
- )}{" "}
- </td>
- <td>
- {(!simulationPaused || wedge) && (
- <p style={{ cursor: "default" }}>
- {positionYDisplay} m
- </p>
- )}{" "}
- {simulationPaused && !wedge && (
- <InputField
- lowerBound={0}
- changeValue={setPositionYDisplay}
- step={1}
- unit={"m"}
- upperBound={yMax}
- value={positionYDisplay}
- effect={(value) => {
- setDisplayChange({
- xDisplay: positionXDisplay,
- yDisplay: value,
- });
- }}
- small={true}
- mode={"Freeform"}
- />
- )}{" "}
- </td>
- </tr>
- <tr>
- <td
- style={{ cursor: "help" }}
- onClick={() => {
- window.open(
- "https://www.khanacademy.org/science/physics/two-dimensional-motion"
- );
- }}
- >
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">Velocity</Typography>
- Equation: v<sub>1</sub>
- =v
- <sub>0</sub>
- +at
- <br />
- Units: m/s
- </React.Fragment>
- }
- followCursor
- >
- <Box>Velocity</Box>
- </Tooltip>
- </td>
- <td>
- {(!simulationPaused || pendulum || wedge) && (
- <p style={{ cursor: "default" }}>
- {velocityXDisplay} m/s
- </p>
- )}{" "}
- {simulationPaused && !pendulum && !wedge && (
- <InputField
- lowerBound={-50}
- changeValue={setVelocityXDisplay}
- step={1}
- unit={"m/s"}
- upperBound={50}
- value={velocityXDisplay}
- effect={(value) =>
- setDisplayChange({
- xDisplay: positionXDisplay,
- yDisplay: positionYDisplay,
- })
- }
- small={true}
- mode={"Freeform"}
- />
- )}{" "}
- </td>
- <td>
- {(!simulationPaused || pendulum || wedge) && (
- <p style={{ cursor: "default" }}>
- {velocityYDisplay} m/s
- </p>
- )}{" "}
- {simulationPaused && !pendulum && !wedge && (
- <InputField
- lowerBound={-50}
- changeValue={setVelocityYDisplay}
- step={1}
- unit={"m/s"}
- upperBound={50}
- value={velocityYDisplay}
- effect={(value) =>
- setDisplayChange({
- xDisplay: positionXDisplay,
- yDisplay: positionYDisplay,
- })
- }
- small={true}
- mode={"Freeform"}
- />
- )}{" "}
- </td>
- </tr>
- <tr>
- <td
- style={{ cursor: "help" }}
- onClick={() => {
- window.open(
- "https://www.khanacademy.org/science/physics/two-dimensional-motion"
- );
- }}
- >
- <Tooltip
- title={
- <React.Fragment>
- <Typography color="inherit">
- Acceleration
- </Typography>
- Equation: a=F/m
- <br />
- Units: m/s
- <sup>2</sup>
- </React.Fragment>
- }
- followCursor
- >
- <Box>Acceleration</Box>
- </Tooltip>
- </td>
- <td style={{ cursor: "default" }}>
- {accelerationXDisplay} m/s<sup>2</sup>
- </td>
- <td style={{ cursor: "default" }}>
- {accelerationYDisplay} m/s<sup>2</sup>
- </td>
- </tr>
- </tbody>
- </table>
- )}
- </div>
{/* {mode == "Freeform" &&
simulationElements.length > 0 &&
simulationElements[0].pendulum && (
@@ -2146,7 +831,7 @@ function App() {
)}*/}
</div>
</div>
- <CoordinateSystem top={window.innerHeight - 120} right={xMin + 90} />
+ {/* <CoordinateSystem top={window.innerHeight - 120} right={xMin + 90} /> */}
</div>
);
}