diff options
author | brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> | 2023-01-30 14:29:43 -0500 |
---|---|---|
committer | brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> | 2023-01-30 14:29:43 -0500 |
commit | 136d946b88ff817c2dd738553ddb2aea0a11f0e7 (patch) | |
tree | 7b3dac455b5151dd347a85ff07dfb753fb29c5f6 /src | |
parent | d5ebbf476aeb7ce3f88e2e4c3961ffed4ed8e61a (diff) |
remove extraneous code
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/nodes/PhysicsSimulationApp.tsx | 1353 | ||||
-rw-r--r-- | src/client/views/nodes/PhysicsSimulationBox.scss | 7 | ||||
-rw-r--r-- | src/client/views/nodes/PhysicsSimulationWall.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/PhysicsSimulationWedge.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/PhysicsSimulationWeight.tsx | 1 |
5 files changed, 27 insertions, 1337 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> - θ<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> - θ<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> - θ - <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"> - μ<sub>s</sub> - </Typography> - Coefficient of static friction; between 0 and 1 - </React.Fragment> - } - followCursor - > - <Box> - μ<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">θ</Typography> - Angle of incline plane from the ground, 0-49 - </React.Fragment> - } - followCursor - > - <Box>θ</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">θ</Typography> - Angle of incline plane from the ground, 0-49 - </React.Fragment> - } - followCursor - > - <Box>θ</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"> - μ<sub>s</sub> - </Typography> - Coefficient of static friction, between 0 and 1 - </React.Fragment> - } - followCursor - > - <Box> - μ<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"> - μ<sub>k</sub> - </Typography> - Coefficient of kinetic friction, between 0 and - coefficient of static friction - </React.Fragment> - } - followCursor - > - <Box> - μ<sub>k</sub> - </Box> - </Tooltip> - } - lowerBound={0} - changeValue={setCoefficientOfKineticFriction} - step={0.1} - unit={""} - upperBound={Number(coefficientOfStaticFriction)} - value={coefficientOfKineticFriction} - mode={"Freeform"} - /> - </div> - )} - {wedge && !simulationPaused && ( - <Typography> - θ: {Math.round(Number(wedgeAngle) * 100) / 100}° ≈{" "} - {Math.round(((Number(wedgeAngle) * Math.PI) / 180) * 100) / - 100}{" "} - rad - <br /> - μ <sub>s</sub>: {coefficientOfStaticFriction} - <br /> - μ <sub>k</sub>: {coefficientOfKineticFriction} - </Typography> - )} - {pendulum && !simulationPaused && ( - <Typography> - θ: {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">θ</Typography> - Pendulum angle offest from equilibrium - </React.Fragment> - } - followCursor - > - <Box>θ</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> </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> ); } 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"; |