diff options
author | bobzel <zzzman@gmail.com> | 2023-05-23 14:57:38 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-05-23 14:57:38 -0400 |
commit | 2c7c450f646dff3ec771f10f0fe323ae761670aa (patch) | |
tree | a5a81e04e5d4f6e6b84b9d3d33a8a1ced2d01316 | |
parent | 18e458603d1c672b412c18237be73f6581d58137 (diff) |
more phys cleanup
-rw-r--r-- | src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx | 660 | ||||
-rw-r--r-- | src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx | 137 |
2 files changed, 385 insertions, 412 deletions
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index 35e9c189f..fa47a218b 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -86,6 +86,78 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP @computed get gravity() { return NumCast(this.dataDoc.simulation_gravity, -9.81); } + @computed get simulationType() { + return StrCast(this.dataDoc.simulation_type, 'Inclined Plane'); + } + @computed get simulationMode() { + return StrCast(this.dataDoc.simulation_mode, 'Freeform'); + } + // Used for spring simulation + @computed get springConstant() { + return NumCast(this.dataDoc.spring_constant, 0.5); + } + @computed get springLengthRest() { + return NumCast(this.dataDoc.spring_lengthRest, 200); + } + @computed get springLengthStart() { + return NumCast(this.dataDoc.spring_lengthStart, 200); + } + + @computed get pendulumAngle() { + return NumCast(this.dataDoc.pendulum_angle); + } + @computed get pendulumAngleStart() { + return NumCast(this.dataDoc.pendulum_angleStart); + } + @computed get pendulumLength() { + return NumCast(this.dataDoc.pendulum_length); + } + @computed get pendulumLengthStart() { + return NumCast(this.dataDoc.pendulum_lengthStart); + } + + // Used for wedge simulation + @computed get wedgeAngle() { + return NumCast(this.dataDoc.wedge_angle, 26); + } + @computed get wedgeHeight() { + return NumCast(this.dataDoc.wedge_height, Math.tan((26 * Math.PI) / 180) * this.xMax * 0.5); + } + @computed get wedgeWidth() { + return NumCast(this.dataDoc.wedge_width, this.xMax * 0.5); + } + @computed get mass1() { + return NumCast(this.dataDoc.mass1, 1); + } + @computed get mass2() { + return NumCast(this.dataDoc.mass2, 1); + } + + @computed get mass1PosXStart() { + return NumCast(this.dataDoc.mass1_positionXstart, Math.round((this.xMax * 0.5 - 200) * 10) / 10); + } + @computed get mass1PosYStart() { + return NumCast(this.dataDoc.mass1_positionYstart, this.getDisplayYPos((400 - 0.08 * this.layoutDoc[HeightSym]()) * Math.tan((26 * Math.PI) / 180) + Math.sqrt(26))); + } + @computed get mass1VelXStart() { + return NumCast(this.dataDoc.mass1_velocityXstart); + } + @computed get mass1VelYStart() { + return NumCast(this.dataDoc.mass1_velocityYstart); + } + + @computed get mass2PosXStart() { + return NumCast(this.dataDoc.mass2_positionXstart); + } + @computed get mass2PosYStart() { + return NumCast(this.dataDoc.mass2_positionYstart, this.getDisplayYPos((400 - 0.08 * this.layoutDoc[HeightSym]()) * Math.tan((26 * Math.PI) / 180) + Math.sqrt(26))); + } + @computed get mass2VelXStart() { + return NumCast(this.dataDoc.mass2_velocityXstart); + } + @computed get mass2VelYStart() { + return NumCast(this.dataDoc.mass2_velocityYstart); + } // Constants xMin = 0; @@ -102,15 +174,8 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.layoutDoc._height = 800; this.xMax = this.layoutDoc._width * 0.6; this.yMax = this.layoutDoc._height * 0.9; - this.dataDoc.simulation_gravity = NumCast(this.dataDoc.simulation_gravity, -9.81); - this.dataDoc.mass1 = NumCast(this.dataDoc.mass1, 1); - this.dataDoc.simulation_mode = 'Freeform'; this.dataDoc.simulation_showComponentForces = this.dataDoc.simulation_showComponentForces ?? false; this.dataDoc.simulation_speed = NumCast(this.dataDoc.simulation_speed, 2); - this.dataDoc.simulation_type = StrCast(this.dataDoc.simulation_type, 'Inclined Plane'); - this.dataDoc.mass1_positionXstart = this.dataDoc.mass1_positionXstart ?? Math.round((this.xMax * 0.5 - 200) * 10) / 10; - this.dataDoc.mass1_positionYstart = this.dataDoc.mass1_positionYstart ?? this.getDisplayYPos((400 - 0.08 * this.layoutDoc._height) * Math.tan((26 * Math.PI) / 180) + Math.sqrt(26)); - // Used for review mode // this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? null; // this.dataDoc.deleteMode = this.dataDoc.deleteMode ?? false; @@ -123,24 +188,8 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP // Used for tutorial mode this.dataDoc.tutorial = this.dataDoc.tutorial ?? tutorials.inclinePlane; - // Used for spring simulation - this.dataDoc.spring_constant = NumCast(this.dataDoc.spring_constant, 0.5); - this.dataDoc.spring_lengthRest = NumCast(this.dataDoc.spring_lengthRest, 200); - this.dataDoc.spring_lengthStart = NumCast(this.dataDoc.spring_lengthStart, 200); - - // Used for pendulum simulation - this.dataDoc.pendulum_length = NumCast(this.dataDoc.pendulum_length, 300); - - // Used for wedge simulation - this.dataDoc.wedge_angle = NumCast(this.dataDoc.wedge_angle, 26); - this.dataDoc.wedge_height = NumCast(this.dataDoc.wedge_height, Math.tan((26 * Math.PI) / 180) * this.xMax * 0.5); - this.dataDoc.wedge_width = NumCast(this.dataDoc.wedge_width, this.xMax * 0.5); - - // Used for pulley simulation - this.dataDoc.mass2 = NumCast(this.dataDoc.mass2, 1); - // Setup simulation - this.setupSimulation(StrCast(this.dataDoc.simulation_type), StrCast(this.dataDoc.simulation_mode)); + this.setupSimulation(); // Create walls let walls = []; @@ -157,11 +206,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.layoutDoc._height = Math.max(this.layoutDoc[HeightSym](), 600); this.xMax = this.layoutDoc._width * 0.6; this.yMax = this.layoutDoc._height * 0.9; - this.setupSimulation(StrCast(this.dataDoc.simulation_type), StrCast(this.dataDoc.simulation_mode)); + this.setupSimulation(); } } - setupSimulation = (simulationType: string, mode: string) => { + setupSimulation = () => { + const simulationType = this.simulationType; + const mode = this.simulationMode; this.dataDoc.simulation_paused = true; if (simulationType != 'Circular Motion') { this.dataDoc.mass1_velocityXstart = 0; @@ -180,7 +231,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_forcesUpdated = JSON.stringify([ { description: 'Gravity', - magnitude: Math.abs(this.gravity) * NumCast(this.dataDoc.mass1), + magnitude: Math.abs(this.gravity) * this.mass1, directionInDegrees: 270, component: false, }, @@ -188,18 +239,19 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_forcesStart = JSON.stringify([ { description: 'Gravity', - magnitude: Math.abs(this.gravity) * NumCast(this.dataDoc.mass1), + magnitude: Math.abs(this.gravity) * this.mass1, directionInDegrees: 270, component: false, }, ]); this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset; + ``; } else if (simulationType == 'Inclined Plane') { this.changeWedgeBasedOnNewAngle(26); this.dataDoc.mass1_forcesStart = JSON.stringify([ { description: 'Gravity', - magnitude: Math.abs(this.gravity) * NumCast(this.dataDoc.mass1), + magnitude: Math.abs(this.gravity) * this.mass1, directionInDegrees: 270, component: false, }, @@ -248,7 +300,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.simulation_showComponentForces = false; this.dataDoc.tutorial_stepNumber = 0; this.dataDoc.simulation_showAcceleration = false; - if (this.dataDoc.simulation_type != 'Circular Motion') { + if (this.simulationType != 'Circular Motion') { this.dataDoc.mass1_velocityX = 0; this.dataDoc.mass1_velocityY = 0; this.dataDoc.simulation_showVelocity = false; @@ -258,14 +310,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.simulation_showVelocity = true; } - if (this.dataDoc.simulation_type == 'One Weight') { + if (this.simulationType == 'One Weight') { this.dataDoc.simulation_showForces = true; this.dataDoc.mass1_positionYstart = this.yMax - 100; this.dataDoc.mass1_positionXstart = (this.xMax + this.xMin) / 2 - 0.08 * this.layoutDoc[HeightSym](); this.dataDoc.tutorial = tutorials.freeWeight; this.dataDoc.mass1_forcesStart = JSON.stringify(tutorials.freeWeight.steps[0].forces); this.dataDoc.simulation_showForceMagnitudes = tutorials.freeWeight.steps[0].showMagnitude; - } else if (this.dataDoc.simulation_type == 'Spring') { + } else if (this.simulationType == 'Spring') { this.dataDoc.simulation_showForces = true; this.setupSpring(); this.dataDoc.mass1_positionYstart = this.yMin + 200 + 19.62; @@ -273,43 +325,31 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.tutorial = tutorials.spring; this.dataDoc.mass1_forcesStart = JSON.stringify(tutorials.spring.steps[0].forces); this.dataDoc.simulation_showForceMagnitudes = tutorials.spring.steps[0].showMagnitude; - } else if (this.dataDoc.simulation_type == 'Pendulum') { - this.dataDoc.simulation_showForces = true; - const length = 300; - const angle = 30; - const x = length * Math.cos(((90 - angle) * Math.PI) / 180); - const y = length * Math.sin(((90 - angle) * Math.PI) / 180); - const xPos = this.xMax / 2 - x - 0.08 * this.layoutDoc[HeightSym](); - const yPos = y - 0.08 * this.layoutDoc[HeightSym]() - 5; - this.dataDoc.mass1_positionXstart = xPos; - this.dataDoc.mass1_positionYstart = yPos; + } else if (this.simulationType == 'Pendulum') { + this.setupPendulum(); this.dataDoc.tutorial = tutorials.pendulum; this.dataDoc.mass1_forcesStart = JSON.stringify(tutorials.pendulum.steps[0].forces); this.dataDoc.simulation_showForceMagnitudes = tutorials.pendulum.steps[0].showMagnitude; - this.dataDoc.pendulum_angle = 30; - this.dataDoc.pendulum_length = 300; - this.dataDoc.pendulum_angle_adjust = 30; - this.dataDoc.pendulum_length_adjust = 300; - } else if (this.dataDoc.simulation_type == 'Inclined Plane') { + } else if (this.simulationType == 'Inclined Plane') { this.dataDoc.simulation_showForces = true; this.dataDoc.wedge_angle = 26; this.changeWedgeBasedOnNewAngle(26); this.dataDoc.tutorial = tutorials.inclinePlane; this.dataDoc.mass1_forcesStart = JSON.stringify(tutorials.inclinePlane.steps[0].forces); this.dataDoc.simulation_showForceMagnitudes = tutorials.inclinePlane.steps[0].showMagnitude; - } else if (this.dataDoc.simulation_type == 'Circular Motion') { + } else if (this.simulationType == 'Circular Motion') { this.dataDoc.simulation_showForces = true; this.setupCircular(40); this.dataDoc.tutorial = tutorials.circular; this.dataDoc.mass1_forcesStart = JSON.stringify(tutorials.circular.steps[0].forces); this.dataDoc.simulation_showForceMagnitudes = tutorials.circular.steps[0].showMagnitude; - } else if (this.dataDoc.simulation_type == 'Pulley') { + } else if (this.simulationType == 'Pulley') { this.dataDoc.simulation_showForces = true; this.setupPulley(); this.dataDoc.tutorial = tutorials.pulley; this.dataDoc.mass1_forcesStart = JSON.stringify(tutorials.pulley.steps[0].forces); this.dataDoc.simulation_showForceMagnitudes = tutorials.pulley.steps[0].showMagnitude; - } else if (this.dataDoc.simulation_type == 'Suspension') { + } else if (this.simulationType == 'Suspension') { this.dataDoc.simulation_showForces = true; this.setupSuspension(); this.dataDoc.tutorial = tutorials.suspension; @@ -329,25 +369,25 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP }; // Update forces when coefficient of static friction changes in freeform mode - updateForcesWithFriction = (coefficient: number, width: number = NumCast(this.dataDoc.wedge_width), height: number = NumCast(this.dataDoc.wedge_height)) => { + updateForcesWithFriction = (coefficient: number, width = this.wedgeWidth, height = this.wedgeHeight) => { const normalForce: IForce = { description: 'Normal Force', - magnitude: Math.abs(this.gravity) * Math.cos(Math.atan(height / width)) * NumCast(this.dataDoc.mass1), + magnitude: Math.abs(this.gravity) * Math.cos(Math.atan(height / width)) * this.mass1, directionInDegrees: 180 - 90 - (Math.atan(height / width) * 180) / Math.PI, component: false, }; let frictionForce: IForce = { description: 'Static Friction Force', - magnitude: coefficient * Math.abs(this.gravity) * Math.cos(Math.atan(height / width)) * NumCast(this.dataDoc.mass1), + magnitude: coefficient * Math.abs(this.gravity) * Math.cos(Math.atan(height / width)) * this.mass1, directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI, component: false, }; // reduce magnitude or friction force if necessary such that block cannot slide up plane - let yForce = -Math.abs(this.gravity) * NumCast(this.dataDoc.mass1); + let yForce = -Math.abs(this.gravity) * this.mass1; yForce += normalForce.magnitude * Math.sin((normalForce.directionInDegrees * Math.PI) / 180); yForce += frictionForce.magnitude * Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); if (yForce > 0) { - frictionForce.magnitude = (-normalForce.magnitude * Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + Math.abs(this.gravity) * NumCast(this.dataDoc.mass1)) / Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + frictionForce.magnitude = (-normalForce.magnitude * Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + Math.abs(this.gravity) * this.mass1) / Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); } const frictionForceComponent: IForce = { description: 'Static Friction Force', @@ -363,19 +403,19 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP }; const gravityParallel: IForce = { description: 'Gravity Parallel Component', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity) * Math.sin(Math.PI / 2 - Math.atan(height / width)), + magnitude: this.mass1 * Math.abs(this.gravity) * Math.sin(Math.PI / 2 - Math.atan(height / width)), directionInDegrees: 180 - 90 - (Math.atan(height / width) * 180) / Math.PI + 180, component: true, }; const gravityPerpendicular: IForce = { description: 'Gravity Perpendicular Component', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity) * Math.cos(Math.PI / 2 - Math.atan(height / width)), + magnitude: this.mass1 * Math.abs(this.gravity) * Math.cos(Math.PI / 2 - Math.atan(height / width)), directionInDegrees: 360 - (Math.atan(height / width) * 180) / Math.PI, component: true, }; const gravityForce: IForce = { description: 'Gravity', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity), + magnitude: this.mass1 * Math.abs(this.gravity), directionInDegrees: 270, component: false, }; @@ -421,14 +461,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_positionXstart = this.xMax * 0.25; this.dataDoc.mass1_positionYstart = yPos; - if (this.dataDoc.simulation_mode == 'Freeform') { + if (this.simulationMode == 'Freeform') { this.updateForcesWithFriction(NumCast(this.dataDoc.coefficientOfStaticFriction), this.xMax * 0.5, Math.tan((angle * Math.PI) / 180) * this.xMax * 0.5); } }; // In review mode, update forces when coefficient of static friction changed updateReviewForcesBasedOnCoefficient = (coefficient: number) => { - let theta: number = NumCast(this.dataDoc.wedge_angle); + let theta = this.wedgeAngle; let index = this.dataDoc.selectedQuestion.variablesForQuestionSetup.indexOf('theta - max 45'); if (index >= 0) { theta = NumListCast(this.dataDoc.questionVariables)[index]; @@ -472,7 +512,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP getAnswersToQuestion = (question: QuestionTemplate, questionVars: number[]) => { const solutions: number[] = []; - let theta: number = NumCast(this.dataDoc.wedge_angle); + let theta = this.wedgeAngle; let index = question.variablesForQuestionSetup.indexOf('theta - max 45'); if (index >= 0) { theta = questionVars[index]; @@ -549,7 +589,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP error = true; } } else if (this.dataDoc.selectedQuestion.answerParts[i] == 'wedge angle') { - if (Math.abs(NumCast(this.dataDoc.wedge_angle) - this.dataDoc.selectedSolutions[i]) > epsilon) { + if (Math.abs(this.wedgeAngle - this.dataDoc.selectedSolutions[i]) > epsilon) { error = true; } } @@ -596,7 +636,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP const vars: number[] = []; let question: QuestionTemplate = questions.inclinePlane[0]; - if (this.dataDoc.simulation_type == 'Inclined Plane') { + if (this.simulationType === 'Inclined Plane') { if (this.dataDoc.questionNumber === questions.inclinePlane.length - 1) { this.dataDoc.questionNumber = 0; } else { @@ -652,7 +692,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_positionXstart = xPos; const tensionForce: IForce = { description: 'Centripetal Force', - magnitude: (this.dataDoc.mass1_velocityXstart ** 2 * NumCast(this.dataDoc.mass1)) / this.circularMotionRadius, + magnitude: (this.dataDoc.mass1_velocityXstart ** 2 * this.mass1) / this.circularMotionRadius, directionInDegrees: 90, component: false, }; @@ -671,7 +711,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP const yPos = y - 0.08 * this.layoutDoc[HeightSym]() - 5; this.dataDoc.mass1_positionXstart = xPos; this.dataDoc.mass1_positionYstart = yPos; - const mag = NumCast(this.dataDoc.mass1) * Math.abs(this.gravity) * Math.sin((60 * Math.PI) / 180); + const mag = this.mass1 * Math.abs(this.gravity) * Math.sin((60 * Math.PI) / 180); const forceOfTension: IForce = { description: 'Tension', magnitude: mag, @@ -687,13 +727,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP }; const gravityParallel: IForce = { description: 'Gravity Parallel Component', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity) * Math.sin(((90 - angle) * Math.PI) / 180), + magnitude: this.mass1 * Math.abs(this.gravity) * Math.sin(((90 - angle) * Math.PI) / 180), directionInDegrees: -angle - 90, component: true, }; const gravityPerpendicular: IForce = { description: 'Gravity Perpendicular Component', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity) * Math.cos(((90 - angle) * Math.PI) / 180), + magnitude: this.mass1 * Math.abs(this.gravity) * Math.cos(((90 - angle) * Math.PI) / 180), directionInDegrees: -angle, component: true, }; @@ -702,7 +742,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_forcesUpdated = JSON.stringify([ { description: 'Gravity', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity), + magnitude: this.mass1 * Math.abs(this.gravity), directionInDegrees: 270, component: false, }, @@ -711,17 +751,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_forcesStart = JSON.stringify([ { description: 'Gravity', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity), + magnitude: this.mass1 * Math.abs(this.gravity), directionInDegrees: 270, component: false, }, forceOfTension, ]); - this.dataDoc.pendulum_angleStart = 30; - this.dataDoc.pendulum_angle = 30; - this.dataDoc.pendulum_length = 300; - this.dataDoc.pendulum_angle_adjust = 30; - this.dataDoc.pendulum_length_adjust = 300; + this.dataDoc.pendulum_angle = this.dataDoc.pendulum_angleStart = 30; + this.dataDoc.pendulum_length = this.dataDoc.pendulum_lengthStart = 300; }; // Default setup for spring simulation @@ -729,7 +766,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.simulation_showComponentForces = false; const gravityForce: IForce = { description: 'Gravity', - magnitude: Math.abs(this.gravity) * NumCast(this.dataDoc.mass1), + magnitude: Math.abs(this.gravity) * this.mass1, directionInDegrees: 270, component: false, }; @@ -751,7 +788,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_positionXstart = xPos; this.dataDoc.mass1_positionY = this.getDisplayYPos(yPos); this.dataDoc.mass1_positionX = xPos; - let tensionMag = (NumCast(this.dataDoc.mass1) * Math.abs(this.gravity)) / (2 * Math.sin(Math.PI / 4)); + let tensionMag = (this.mass1 * Math.abs(this.gravity)) / (2 * Math.sin(Math.PI / 4)); const tensionForce1: IForce = { description: 'Tension', magnitude: tensionMag, @@ -766,7 +803,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP }; const grav: IForce = { description: 'Gravity', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity), + magnitude: this.mass1 * Math.abs(this.gravity), directionInDegrees: 270, component: false, }; @@ -782,29 +819,29 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_positionXstart = (this.xMin + this.xMax) / 2 - 2 * (0.08 * this.layoutDoc[HeightSym]()) - 5; this.dataDoc.mass1_positionY = this.getDisplayYPos((this.yMax + this.yMin) / 2); this.dataDoc.mass1_positionX = (this.xMin + this.xMax) / 2 - 2 * (0.08 * this.layoutDoc[HeightSym]()) - 5; - let a = (-1 * ((NumCast(this.dataDoc.mass1) - NumCast(this.dataDoc.mass2)) * Math.abs(this.gravity))) / (NumCast(this.dataDoc.mass1) + NumCast(this.dataDoc.mass2)); + let a = (-1 * ((this.mass1 - this.mass2) * Math.abs(this.gravity))) / (this.mass1 + this.mass2); const gravityForce1: IForce = { description: 'Gravity', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity), + magnitude: this.mass1 * Math.abs(this.gravity), directionInDegrees: 270, component: false, }; const tensionForce1: IForce = { description: 'Tension', - magnitude: NumCast(this.dataDoc.mass1) * a + NumCast(this.dataDoc.mass1) * Math.abs(this.gravity), + magnitude: this.mass1 * a + this.mass1 * Math.abs(this.gravity), directionInDegrees: 90, component: false, }; a *= -1; const gravityForce2: IForce = { description: 'Gravity', - magnitude: NumCast(this.dataDoc.mass2) * Math.abs(this.gravity), + magnitude: this.mass2 * Math.abs(this.gravity), directionInDegrees: 270, component: false, }; const tensionForce2: IForce = { description: 'Tension', - magnitude: NumCast(this.dataDoc.mass2) * a + NumCast(this.dataDoc.mass2) * Math.abs(this.gravity), + magnitude: this.mass2 * a + this.mass2 * Math.abs(this.gravity), directionInDegrees: 90, component: false, }; @@ -849,6 +886,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_forcesUpdated = JSON.stringify([forceOfGravityReview, normalForceReview, staticFrictionForceReview]); }; + pause = () => (this.dataDoc.paused = true); componentForces1 = () => PhysicsSimulationBox.parseJSON(StrCast(this.dataDoc.mass1_componentForces)); setComponentForces1 = (forces: IForce[]) => (this.dataDoc.mass1_componentForces = JSON.stringify(forces)); componentForces2 = () => PhysicsSimulationBox.parseJSON(StrCast(this.dataDoc.mass2_componentForces)); @@ -859,8 +897,76 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP setForcesUpdated1 = (forces: IForce[]) => (this.dataDoc.mass1_forcesUpdated = JSON.stringify(forces)); forcesUpdated2 = () => PhysicsSimulationBox.parseJSON(StrCast(this.dataDoc.mass2_forcesUpdated)); setForcesUpdated2 = (forces: IForce[]) => (this.dataDoc.mass2_forcesUpdated = JSON.stringify(forces)); - + setPosition1 = (xPos: number | undefined, yPos: number | undefined) => { + yPos !== undefined && (this.dataDoc.mass1_positionY = Math.round(yPos * 100) / 100); + xPos !== undefined && (this.dataDoc.mass1_positionX = Math.round(xPos * 100) / 100); + }; + setPosition2 = (xPos: number | undefined, yPos: number | undefined) => { + yPos !== undefined && (this.dataDoc.mass2_positionY = Math.round(yPos * 100) / 100); + xPos !== undefined && (this.dataDoc.mass2_positionX = Math.round(xPos * 100) / 100); + }; + setVelocity1 = (xVel: number | undefined, yVel: number | undefined) => { + yVel !== undefined && (this.dataDoc.mass1_velocityY = (-1 * Math.round(yVel * 100)) / 100); + xVel !== undefined && (this.dataDoc.mass1_velocityX = Math.round(xVel * 100) / 100); + }; + setVelocity2 = (xVel: number | undefined, yVel: number | undefined) => { + yVel !== undefined && (this.dataDoc.mass2_velocityY = (-1 * Math.round(yVel * 100)) / 100); + xVel !== undefined && (this.dataDoc.mass2_velocityX = Math.round(xVel * 100) / 100); + }; + setAcceleration1 = (xAccel: number, yAccel: number) => { + this.dataDoc.mass1_accelerationY = yAccel; + this.dataDoc.mass1_accelerationX = xAccel; + }; + setAcceleration2 = (xAccel: number, yAccel: number) => { + this.dataDoc.mass2_accelerationY = yAccel; + this.dataDoc.mass2_accelerationX = xAccel; + }; + setPendulumAngle = (angle: number | undefined, length: number | undefined) => { + angle !== undefined && (this.dataDoc.pendulum_angle = angle); + length !== undefined && (this.dataDoc.pendulum_length = length); + }; + setSpringLength = (length: number) => { + this.dataDoc.spring_lengthStart = length; + }; render() { + const commonWeightProps = { + pause: this.pause, + paused: BoolCast(this.dataDoc.simulation_paused), + panelWidth: this.layoutDoc[WidthSym], + panelHeight: this.layoutDoc[HeightSym], + xMax: this.xMax, + xMin: this.xMin, + yMax: this.yMax, + yMin: this.yMin, + wallPositions: this.wallPositions, + gravity: this.gravity, + timestepSize: 0.05, + showComponentForces: BoolCast(this.dataDoc.simulation_showComponentForces), + coefficientOfKineticFriction: NumCast(this.dataDoc.coefficientOfKineticFriction), + elasticCollisions: BoolCast(this.dataDoc.elasticCollisions), + simulationMode: this.simulationMode, + noMovement: BoolCast(this.dataDoc.noMovement), + circularMotionRadius: this.circularMotionRadius, + wedgeHeight: this.wedgeHeight, + wedgeWidth: this.wedgeWidth, + springConstant: this.springConstant, + springStartLength: this.springLengthStart, + springRestLength: this.springLengthRest, + setSpringLength: this.setSpringLength, + setPendulumAngle: this.setPendulumAngle, + pendulumAngle: this.pendulumAngle, + pendulumLength: this.pendulumLength, + startPendulumAngle: this.pendulumAngleStart, + startPendulumLength: this.pendulumLengthStart, + radius: 0.08 * this.layoutDoc[HeightSym](), + reset: BoolCast(this.dataDoc.simulation_reset), + simulationSpeed: NumCast(this.dataDoc.simulation_speed), + showAcceleration: BoolCast(this.dataDoc.simulation_showAcceleration), + showForceMagnitudes: BoolCast(this.dataDoc.simulation_showForceMagnitudes), + showForces: BoolCast(this.dataDoc.simulation_showForces), + showVelocity: BoolCast(this.dataDoc.simulation_showVelocity), + simulationType: this.simulationType, + }; return ( <div className="physicsSimApp"> <div className="mechanicsSimulationContainer"> @@ -881,153 +987,81 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </div> <div className="mechanicsSimulationElements"> <Weight - dataDoc={this.dataDoc} - layoutDoc={this.layoutDoc} - wallPositions={this.wallPositions} - adjustPendulumAngle={NumCast(this.dataDoc.pendulum_angle_adjust)} - adjustPendulumLength={NumCast(this.dataDoc.pendulum_length_adjust)} - gravity={this.gravity} - circularMotionRadius={this.circularMotionRadius} + {...commonWeightProps} + color="red" componentForces={this.componentForces1} setComponentForces={this.setComponentForces1} - showComponentForces={BoolCast(this.dataDoc.simulation_showComponentForces)} - color={'red'} - coefficientOfKineticFriction={NumCast(this.dataDoc.coefficientOfKineticFriction)} displayXVelocity={NumCast(this.dataDoc.mass1_velocityX)} displayYVelocity={NumCast(this.dataDoc.mass1_velocityY)} - elasticCollisions={BoolCast(this.dataDoc.elasticCollisions)} - mass={NumCast(this.dataDoc.mass1)} - simulationMode={StrCast(this.dataDoc.simulation_mode)} - noMovement={BoolCast(this.dataDoc.noMovement)} - paused={BoolCast(this.dataDoc.simulation_paused)} - pendulumAngle={NumCast(this.dataDoc.pendulum_angle)} - pendulumLength={NumCast(this.dataDoc.pendulum_length)} - radius={0.08 * this.layoutDoc[HeightSym]()} - reset={BoolCast(this.dataDoc.simulation_reset)} - simulationSpeed={NumCast(this.dataDoc.simulation_speed)} - startPendulumAngle={NumCast(this.dataDoc.pendulum_angleStart)} - showAcceleration={BoolCast(this.dataDoc.simulation_showAcceleration)} - showForceMagnitudes={BoolCast(this.dataDoc.simulation_showForceMagnitudes)} - showForces={BoolCast(this.dataDoc.simulation_showForces)} - showVelocity={BoolCast(this.dataDoc.simulation_showVelocity)} - simulationType={StrCast(this.dataDoc.simulation_type)} - springConstant={NumCast(this.dataDoc.spring_constant)} - springStartLength={NumCast(this.dataDoc.spring_lengthStart)} - springRestLength={NumCast(this.dataDoc.spring_lengthRest)} + mass={this.mass1} startForces={this.startForces1} - startPosX={NumCast(this.dataDoc.mass1_positionXstart)} - startPosY={NumCast(this.dataDoc.mass1_positionYstart)} - startVelX={NumCast(this.dataDoc.mass1_velocityXstart)} - startVelY={NumCast(this.dataDoc.mass1_velocityYstart)} - timestepSize={0.05} + startPosX={this.mass1PosXStart} + startPosY={this.mass1PosYStart} + startVelX={this.mass1VelXStart} + startVelY={this.mass1VelYStart} updateMassPosX={NumCast(this.dataDoc.mass1_xChange)} updateMassPosY={NumCast(this.dataDoc.mass1_yChange)} forcesUpdated={this.forcesUpdated1} setForcesUpdated={this.setForcesUpdated1} - wedgeHeight={NumCast(this.dataDoc.wedge_height)} - wedgeWidth={NumCast(this.dataDoc.wedge_width)} - xMax={this.xMax} - xMin={this.xMin} - yMax={this.yMax} - yMin={this.yMin} + setPosition={this.setPosition1} + setVelocity={this.setVelocity1} + setAcceleration={this.setAcceleration1} /> - {this.dataDoc.simulation_type == 'Pulley' && ( + {this.simulationType == 'Pulley' && ( <Weight - dataDoc={this.dataDoc} - layoutDoc={this.layoutDoc} - wallPositions={this.wallPositions} - adjustPendulumAngle={NumCast(this.dataDoc.pendulum_angle_adjust)} - adjustPendulumLength={NumCast(this.dataDoc.pendulum_length_adjust)} - circularMotionRadius={this.circularMotionRadius} - gravity={this.gravity} + {...commonWeightProps} + color="green" componentForces={this.componentForces2} setComponentForces={this.setComponentForces2} - showComponentForces={BoolCast(this.dataDoc.simulation_showComponentForces)} - color={'blue'} - coefficientOfKineticFriction={NumCast(this.dataDoc.coefficientOfKineticFriction)} - displayXVelocity={NumCast(this.dataDoc.mass1_velocityX)} - displayYVelocity={NumCast(this.dataDoc.mass1_velocityY)} - elasticCollisions={BoolCast(this.dataDoc.elasticCollisions)} - mass={NumCast(this.dataDoc.mass2)} - simulationMode={StrCast(this.dataDoc.simulation_mode)} - noMovement={BoolCast(this.dataDoc.noMovement)} - paused={BoolCast(this.dataDoc.simulation_paused)} - pendulumAngle={NumCast(this.dataDoc.pendulum_angle)} - pendulumLength={NumCast(this.dataDoc.pendulum_length)} - radius={0.08 * this.layoutDoc[HeightSym]()} - reset={BoolCast(this.dataDoc.simulation_reset)} - simulationSpeed={NumCast(this.dataDoc.simulation_speed)} - startPendulumAngle={NumCast(this.dataDoc.pendulum_angleStart)} - showAcceleration={BoolCast(this.dataDoc.simulation_showAcceleration)} - showForceMagnitudes={BoolCast(this.dataDoc.simulation_showForceMagnitudes)} - showForces={BoolCast(this.dataDoc.simulation_showForces)} - showVelocity={BoolCast(this.dataDoc.simulation_showVelocity)} - simulationType={this.dataDoc.simulation_type} - springConstant={NumCast(this.dataDoc.spring_constant)} - springStartLength={NumCast(this.dataDoc.spring_lengthStart)} - springRestLength={NumCast(this.dataDoc.spring_lengthRest)} + displayXVelocity={NumCast(this.dataDoc.mass2_velocityX)} + displayYVelocity={NumCast(this.dataDoc.mass2_velocityY)} + mass={this.mass2} startForces={this.startForces2} - startPosX={NumCast(this.dataDoc.mass2_positionXstart)} - startPosY={NumCast(this.dataDoc.mass2_positionYstart)} - startVelX={NumCast(this.dataDoc.mass2_velocityXstart)} - startVelY={NumCast(this.dataDoc.mass2_velocityYstart)} - timestepSize={0.05} + startPosX={this.mass2PosXStart} + startPosY={this.mass2PosYStart} + startVelX={this.mass2VelXStart} + startVelY={this.mass2VelYStart} updateMassPosX={NumCast(this.dataDoc.mass2_xChange)} updateMassPosY={NumCast(this.dataDoc.mass2_yChange)} forcesUpdated={this.forcesUpdated2} setForcesUpdated={this.setForcesUpdated2} - wedgeHeight={NumCast(this.dataDoc.wedge_height)} - wedgeWidth={NumCast(this.dataDoc.wedge_width)} - xMax={this.xMax} - xMin={this.xMin} - yMax={this.yMax} - yMin={this.yMin} + setPosition={this.setPosition2} + setVelocity={this.setVelocity2} + setAcceleration={this.setAcceleration2} /> )} </div> <div> - {(this.dataDoc.simulation_type == 'One Weight' || this.dataDoc.simulation_type == 'Inclined Plane') && - this.wallPositions && - this.wallPositions.map((element, index) => { - return <Wall key={index} length={element.length} xPos={element.xPos} yPos={element.yPos} angleInDegrees={element.angleInDegrees} />; - })} + {(this.simulationType == 'One Weight' || this.simulationType == 'Inclined Plane') && + this.wallPositions?.map((element, index) => <Wall key={index} length={element.length} xPos={element.xPos} yPos={element.yPos} angleInDegrees={element.angleInDegrees} />)} </div> </div> </div> <div className="mechanicsSimulationEquationContainer"> <div className="mechanicsSimulationControls"> <Stack direction="row" spacing={1}> - {this.dataDoc.simulation_paused && this.dataDoc.simulation_mode != 'Tutorial' && ( - <IconButton - onClick={() => { - this.dataDoc.simulation_paused = false; - }}> + {this.dataDoc.simulation_paused && this.simulationMode != 'Tutorial' && ( + <IconButton onClick={() => (this.dataDoc.simulation_paused = false)}> <PlayArrowIcon /> </IconButton> )} - {!this.dataDoc.simulation_paused && this.dataDoc.simulation_mode != 'Tutorial' && ( - <IconButton - onClick={() => { - this.dataDoc.simulation_paused = true; - }}> + {!this.dataDoc.simulation_paused && this.simulationMode != 'Tutorial' && ( + <IconButton onClick={() => (this.dataDoc.simulation_paused = true)}> <PauseIcon /> </IconButton> )} - {this.dataDoc.simulation_paused && this.dataDoc.simulation_mode != 'Tutorial' && ( - <IconButton - onClick={() => { - this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset; - }}> + {this.dataDoc.simulation_paused && this.simulationMode != 'Tutorial' && ( + <IconButton onClick={() => (this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset)}> <ReplayIcon /> </IconButton> )} </Stack> <div className="dropdownMenu"> <select - value={StrCast(this.dataDoc.simulation_type)} + value={StrCast(this.simulationType)} onChange={event => { this.dataDoc.simulation_type = event.target.value; - this.setupSimulation(event.target.value, StrCast(this.dataDoc.simulation_mode)); + this.setupSimulation(); }} style={{ height: '2em', width: '100%', fontSize: '16px' }}> <option value="One Weight">Projectile</option> @@ -1041,10 +1075,10 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </div> <div className="dropdownMenu"> <select - value={StrCast(this.dataDoc.simulation_mode)} + value={this.simulationMode} onChange={event => { this.dataDoc.simulation_mode = event.target.value; - this.setupSimulation(StrCast(this.dataDoc.simulation_type), event.target.value); + this.setupSimulation(); }} style={{ height: '2em', width: '100%', fontSize: '16px' }}> <option value="Tutorial">Tutorial Mode</option> @@ -1053,21 +1087,19 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </select> </div> </div> - {this.dataDoc.simulation_mode == 'Review' && this.dataDoc.simulation_type != 'Inclined Plane' && ( + {this.simulationMode == 'Review' && this.simulationType != 'Inclined Plane' && ( <div className="wordProblemBox"> <p> - <>{this.dataDoc.simulation_type} review problems in progress!</> + <>{this.simulationType} review problems in progress!</> </p> <hr /> </div> )} - {this.dataDoc.simulation_mode == 'Review' && this.dataDoc.simulation_type == 'Inclined Plane' && ( + {this.simulationMode == 'Review' && this.simulationType == 'Inclined Plane' && ( <div> {!this.dataDoc.hintDialogueOpen && ( <IconButton - onClick={() => { - this.dataDoc.hintDialogueOpen = true; - }} + onClick={() => (this.dataDoc.hintDialogueOpen = true)} sx={{ position: 'fixed', left: this.xMax - 50 + 'px', @@ -1079,30 +1111,23 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP <Dialog maxWidth={'sm'} fullWidth={true} open={BoolCast(this.dataDoc.hintDialogueOpen)} onClose={() => (this.dataDoc.hintDialogueOpen = false)}> <DialogTitle>Hints</DialogTitle> <DialogContent> - {this.dataDoc.selectedQuestion.hints?.map((hint: any, index: number) => { - return ( - <div key={index}> - <DialogContentText> - <details> - <summary> - <b> - Hint {index + 1}: {hint.description} - </b> - </summary> - {hint.content} - </details> - </DialogContentText> - </div> - ); - })} + {this.dataDoc.selectedQuestion.hints?.map((hint: any, index: number) => ( + <div key={index}> + <DialogContentText> + <details> + <summary> + <b> + Hint {index + 1}: {hint.description} + </b> + </summary> + {hint.content} + </details> + </DialogContentText> + </div> + ))} </DialogContent> <DialogActions> - <Button - onClick={() => { - this.dataDoc.hintDialogueOpen = false; - }}> - Close - </Button> + <Button onClick={() => (this.dataDoc.hintDialogueOpen = false)}>Close</Button> </DialogActions> </Dialog> <div className="wordProblemBox"> @@ -1232,7 +1257,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP step={1} unit={'°'} upperBound={49} - value={NumCast(this.dataDoc.wedge_angle, 26)} + value={this.wedgeAngle} effect={(val: number) => { this.changeWedgeBasedOnNewAngle(val); this.updateReviewForcesBasedOnAngle(val); @@ -1246,7 +1271,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </div> </div> )} - {this.dataDoc.simulation_mode == 'Tutorial' && ( + {this.simulationMode == 'Tutorial' && ( <div className="wordProblemBox"> <div className="question"> <h2>Problem</h2> @@ -1292,8 +1317,8 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </IconButton> </div> <div> - {(this.dataDoc.simulation_type == 'One Weight' || this.dataDoc.simulation_type == 'Inclined Plane' || this.dataDoc.simulation_type == 'Pendulum') && <p>Resources</p>} - {this.dataDoc.simulation_type == 'One Weight' && ( + {(this.simulationType == 'One Weight' || this.simulationType == 'Inclined Plane' || this.simulationType == 'Pendulum') && <p>Resources</p>} + {this.simulationType == 'One Weight' && ( <ul> <li> <a @@ -1321,7 +1346,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </li> </ul> )} - {this.dataDoc.simulation_type == 'Inclined Plane' && ( + {this.simulationType == 'Inclined Plane' && ( <ul> <li> <a @@ -1349,7 +1374,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </li> </ul> )} - {this.dataDoc.simulation_type == 'Pendulum' && ( + {this.simulationType == 'Pendulum' && ( <ul> <li> <a @@ -1368,7 +1393,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </div> </div> )} - {this.dataDoc.simulation_mode == 'Review' && this.dataDoc.simulation_type == 'Inclined Plane' && ( + {this.simulationMode == 'Review' && this.simulationType == 'Inclined Plane' && ( <div style={{ display: 'flex', @@ -1406,11 +1431,11 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </div> </div> )} - {this.dataDoc.simulation_mode == 'Freeform' && ( + {this.simulationMode == 'Freeform' && ( <div className="vars"> <FormControl component="fieldset"> <FormGroup> - {this.dataDoc.simulation_type == 'One Weight' && ( + {this.simulationType == 'One Weight' && ( <FormControlLabel control={<Checkbox checked={BoolCast(this.dataDoc.elasticCollisions)} onChange={() => (this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions)} />} label="Make collisions elastic" @@ -1422,7 +1447,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP label="Show force vectors" labelPlacement="start" /> - {(this.dataDoc.simulation_type == 'Inclined Plane' || this.dataDoc.simulation_type == 'Pendulum') && ( + {(this.simulationType == 'Inclined Plane' || this.simulationType == 'Pendulum') && ( <FormControlLabel control={<Checkbox checked={BoolCast(this.dataDoc.simulation_showForces)} onChange={() => (this.dataDoc.simulation_showComponentForces = !this.dataDoc.simulation_showComponentForces)} />} label="Show component force vectors" @@ -1440,7 +1465,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP labelPlacement="start" /> <InputField label={<Box>Speed</Box>} lowerBound={1} dataDoc={this.dataDoc} prop="simulation_speed" step={1} unit={'x'} upperBound={10} value={NumCast(this.dataDoc.simulation_speed, 2)} labelWidth={'5em'} /> - {this.dataDoc.simulation_paused && this.dataDoc.simulation_type != 'Circular Motion' && ( + {this.dataDoc.simulation_paused && this.simulationType != 'Circular Motion' && ( <InputField label={<Box>Gravity</Box>} lowerBound={-30} @@ -1450,13 +1475,11 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP unit={'m/s2'} upperBound={0} value={NumCast(this.dataDoc.simulation_gravity, -9.81)} - effect={(val: number) => { - this.setupSimulation(StrCast(this.dataDoc.simulation_type), StrCast(this.dataDoc.simulation_mode)); - }} + effect={(val: number) => this.setupSimulation()} labelWidth={'5em'} /> )} - {this.dataDoc.simulation_paused && this.dataDoc.simulation_type != 'Pulley' && ( + {this.dataDoc.simulation_paused && this.simulationType != 'Pulley' && ( <InputField label={<Box>Mass</Box>} lowerBound={1} @@ -1465,14 +1488,12 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP step={0.1} unit={'kg'} upperBound={5} - value={NumCast(this.dataDoc.mass1) ?? 1} - effect={(val: number) => { - this.setupSimulation(StrCast(this.dataDoc.simulation_type), StrCast(this.dataDoc.simulation_mode)); - }} + value={this.mass1 ?? 1} + effect={(val: number) => this.setupSimulation()} labelWidth={'5em'} /> )} - {this.dataDoc.simulation_paused && this.dataDoc.simulation_type == 'Pulley' && ( + {this.dataDoc.simulation_paused && this.simulationType == 'Pulley' && ( <InputField label={<Box>Red mass</Box>} lowerBound={1} @@ -1481,14 +1502,12 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP step={0.1} unit={'kg'} upperBound={5} - value={NumCast(this.dataDoc.mass1) ?? 1} - effect={(val: number) => { - this.setupSimulation(StrCast(this.dataDoc.simulation_type), StrCast(this.dataDoc.simulation_mode)); - }} + value={this.mass1 ?? 1} + effect={(val: number) => this.setupSimulation()} labelWidth={'5em'} /> )} - {this.dataDoc.simulation_paused && this.dataDoc.simulation_type == 'Pulley' && ( + {this.dataDoc.simulation_paused && this.simulationType == 'Pulley' && ( <InputField label={<Box>Blue mass</Box>} lowerBound={1} @@ -1497,14 +1516,12 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP step={0.1} unit={'kg'} upperBound={5} - value={NumCast(this.dataDoc.mass2) ?? 1} - effect={(val: number) => { - this.setupSimulation(StrCast(this.dataDoc.simulation_type), StrCast(this.dataDoc.simulation_mode)); - }} + value={this.mass2 ?? 1} + effect={(val: number) => this.setupSimulation()} labelWidth={'5em'} /> )} - {this.dataDoc.simulation_paused && this.dataDoc.simulation_type == 'Circular Motion' && ( + {this.dataDoc.simulation_paused && this.simulationType == 'Circular Motion' && ( <InputField label={<Box>Rod length</Box>} lowerBound={100} @@ -1514,15 +1531,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP unit={'m'} upperBound={250} value={this.circularMotionRadius} - effect={(val: number) => { - this.setupSimulation(StrCast(this.dataDoc.simulation_type), StrCast(this.dataDoc.simulation_mode)); - }} + effect={(val: number) => this.setupSimulation()} labelWidth={'5em'} /> )} </FormGroup> </FormControl> - {this.dataDoc.simulation_type == 'Spring' && this.dataDoc.simulation_paused && ( + {this.simulationType == 'Spring' && this.dataDoc.simulation_paused && ( <div> <InputField label={<Typography color="inherit">Spring stiffness</Typography>} @@ -1532,10 +1547,8 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP step={1} unit={'N/m'} upperBound={500} - value={NumCast(this.dataDoc.spring_constant) ?? 0.5} - effect={(val: number) => { - this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset; - }} + value={this.springConstant} + effect={(val: number) => (this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset)} radianEquivalent={false} mode={'Freeform'} labelWidth={'7em'} @@ -1546,37 +1559,35 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP dataDoc={this.dataDoc} prop="spring_lengthRest" step={100} - unit={''} + unit="" upperBound={500} - value={NumCast(this.dataDoc.spring_lengthRest) ?? 200} - effect={(val: number) => { - this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset; - }} + value={this.springLengthRest} + effect={(val: number) => (this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset)} radianEquivalent={false} - mode={'Freeform'} + mode="Freeform" labelWidth={'7em'} /> <InputField label={<Typography color="inherit">Starting displacement</Typography>} - lowerBound={-(NumCast(this.dataDoc.spring_lengthRest) - 10)} + lowerBound={-(this.springLengthRest - 10)} dataDoc={this.dataDoc} prop="" step={10} - unit={''} - upperBound={NumCast(this.dataDoc.spring_lengthRest)} - value={NumCast(this.dataDoc.spring_lengthStart) - NumCast(this.dataDoc.spring_lengthRest)} + unit="" + upperBound={this.springLengthRest} + value={this.springLengthStart - this.springLengthRest} effect={(val: number) => { - this.dataDoc.mass1_positionYstart = NumCast(this.dataDoc.spring_lengthRest) + val; - this.dataDoc.spring_lengthStart = NumCast(this.dataDoc.spring_lengthRest) + val; + this.dataDoc.mass1_positionYstart = this.springLengthRest + val; + this.dataDoc.spring_lengthStart = this.springLengthRest + val; this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset; }} radianEquivalent={false} - mode={'Freeform'} + mode="Freeform" labelWidth={'7em'} /> </div> )} - {this.dataDoc.simulation_type == 'Inclined Plane' && this.dataDoc.simulation_paused && ( + {this.simulationType == 'Inclined Plane' && this.dataDoc.simulation_paused && ( <div> <InputField label={<Box>θ</Box>} @@ -1586,7 +1597,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP step={1} unit={'°'} upperBound={49} - value={NumCast(this.dataDoc.wedge_angle, 26)} + value={this.wedgeAngle} effect={(val: number) => { this.changeWedgeBasedOnNewAngle(val); this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset; @@ -1639,10 +1650,10 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP /> </div> )} - {this.dataDoc.simulation_type == 'Inclined Plane' && !this.dataDoc.simulation_paused && ( + {this.simulationType == 'Inclined Plane' && !this.dataDoc.simulation_paused && ( <Typography> <> - θ: {Math.round(NumCast(this.dataDoc.wedge_angle) * 100) / 100}° ≈ {Math.round(((NumCast(this.dataDoc.wedge_angle) * Math.PI) / 180) * 100) / 100} rad + θ: {Math.round(this.wedgeAngle * 100) / 100}° ≈ {Math.round(((this.wedgeAngle * Math.PI) / 180) * 100) / 100} rad <br /> μ <sub>s</sub>: {this.dataDoc.coefficientOfStaticFriction} <br /> @@ -1650,12 +1661,12 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </> </Typography> )} - {this.dataDoc.simulation_type == 'Pendulum' && !this.dataDoc.simulation_paused && ( + {this.simulationType == 'Pendulum' && !this.dataDoc.simulation_paused && ( <Typography> - θ: {Math.round(NumCast(this.dataDoc.pendulum_angle) * 100) / 100}° ≈ {Math.round(((NumCast(this.dataDoc.pendulum_angle) * Math.PI) / 180) * 100) / 100} rad + θ: {Math.round(this.pendulumAngle * 100) / 100}° ≈ {Math.round(((this.pendulumAngle * Math.PI) / 180) * 100) / 100} rad </Typography> )} - {this.dataDoc.simulation_type == 'Pendulum' && this.dataDoc.simulation_paused && ( + {this.simulationType == 'Pendulum' && this.dataDoc.simulation_paused && ( <div> <InputField label={<Box>Angle</Box>} @@ -1668,8 +1679,9 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP value={NumCast(this.dataDoc.pendulum_angle, 30)} effect={value => { this.dataDoc.pendulum_angleStart = value; - if (this.dataDoc.simulation_type == 'Pendulum') { - const mag = NumCast(this.dataDoc.mass1) * Math.abs(this.gravity) * Math.cos((value * Math.PI) / 180); + this.dataDoc.pendulum_lengthStart = this.dataDoc.pendulum_length; + if (this.simulationType == 'Pendulum') { + const mag = this.mass1 * Math.abs(this.gravity) * Math.cos((value * Math.PI) / 180); const forceOfTension: IForce = { description: 'Tension', @@ -1697,7 +1709,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP component: true, }; - const length = NumCast(this.dataDoc.pendulum_length); + const length = this.pendulumLength; const x = length * Math.cos(((90 - value) * Math.PI) / 180); const y = length * Math.sin(((90 - value) * Math.PI) / 180); const xPos = this.xMax / 2 - x - NumCast(this.dataDoc.radius); @@ -1708,7 +1720,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_forcesStart = JSON.stringify([ { description: 'Gravity', - magnitude: Math.abs(this.gravity) * NumCast(this.dataDoc.mass1), + magnitude: Math.abs(this.gravity) * this.mass1, directionInDegrees: 270, component: false, }, @@ -1717,21 +1729,19 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.mass1_forcesUpdated = JSON.stringify([ { description: 'Gravity', - magnitude: Math.abs(this.gravity) * NumCast(this.dataDoc.mass1), + magnitude: Math.abs(this.gravity) * this.mass1, directionInDegrees: 270, component: false, }, forceOfTension, ]); this.dataDoc.mass1_componentForces = JSON.stringify([tensionComponent, gravityParallel, gravityPerpendicular]); - this.dataDoc.pendulum_angle_adjust = value; - this.dataDoc.pendulum_length_adjust = this.dataDoc.pendulum_length; this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset; } }} radianEquivalent={true} - mode={'Freeform'} - labelWidth={'5em'} + mode="Freeform" + labelWidth="5em" /> <InputField label={<Box>Rod length</Box>} @@ -1739,30 +1749,30 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP dataDoc={this.dataDoc} prop="pendulum_length" step={1} - unit={'m'} + unit="m" upperBound={400} - value={Math.round(NumCast(this.dataDoc.pendulum_length))} + value={Math.round(this.pendulumLength)} effect={value => { - if (this.dataDoc.simulation_type == 'Pendulum') { - this.dataDoc.pendulum_angle_adjust = NumCast(this.dataDoc.pendulum_angle); - this.dataDoc.pendulum_length_adjust = value; + if (this.simulationType == 'Pendulum') { + this.dataDoc.pendulum_angleStart = this.pendulumAngle; + this.dataDoc.pendulum_lengthStart = value; this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset; } }} radianEquivalent={false} - mode={'Freeform'} - labelWidth={'5em'} + mode="Freeform" + labelWidth="5em" /> </div> )} </div> )} <div className="mechanicsSimulationEquation"> - {this.dataDoc.simulation_mode == 'Freeform' && ( + {this.simulationMode == 'Freeform' && ( <table> <tbody> <tr> - <td>{this.dataDoc.simulation_type == 'Pulley' ? 'Red Weight' : ''}</td> + <td>{this.simulationType == 'Pulley' ? 'Red Weight' : ''}</td> <td>X</td> <td>Y</td> </tr> @@ -1777,27 +1787,27 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP > <Box>Position</Box> </td> - {(!this.dataDoc.simulation_paused || this.dataDoc.simulation_type == 'Inclined Plane' || this.dataDoc.simulation_type == 'Circular Motion' || this.dataDoc.simulation_type == 'Pulley') && ( + {(!this.dataDoc.simulation_paused || this.simulationType == 'Inclined Plane' || this.simulationType == 'Circular Motion' || this.simulationType == 'Pulley') && ( <td style={{ cursor: 'default' }}> <>{this.dataDoc.mass1_positionX} m</> </td> )}{' '} - {this.dataDoc.simulation_paused && this.dataDoc.simulation_type != 'Inclined Plane' && this.dataDoc.simulation_type != 'Circular Motion' && this.dataDoc.simulation_type != 'Pulley' && ( + {this.dataDoc.simulation_paused && this.simulationType != 'Inclined Plane' && this.simulationType != 'Circular Motion' && this.simulationType != 'Pulley' && ( <td style={{ cursor: 'default', }}> <InputField - lowerBound={this.dataDoc.simulation_type == 'Projectile' ? 1 : (this.xMax + this.xMin) / 4 - this.radius - 15} + lowerBound={this.simulationType == 'Projectile' ? 1 : (this.xMax + this.xMin) / 4 - this.radius - 15} dataDoc={this.dataDoc} prop="mass1_positionX" step={1} unit={'m'} - upperBound={this.dataDoc.simulation_type == 'Projectile' ? this.xMax - 110 : (3 * (this.xMax + this.xMin)) / 4 - this.radius / 2 - 15} + upperBound={this.simulationType == 'Projectile' ? this.xMax - 110 : (3 * (this.xMax + this.xMin)) / 4 - this.radius / 2 - 15} value={NumCast(this.dataDoc.mass1_positionX)} effect={value => { this.dataDoc.mass1_xChange = value; - if (this.dataDoc.simulation_type == 'Suspension') { + if (this.simulationType == 'Suspension') { let x1rod = (this.xMax + this.xMin) / 2 - this.radius - this.yMin - 200; let x2rod = (this.xMax + this.xMin) / 2 + this.yMin + 200 + this.radius; let deltaX1 = value + this.radius - x1rod; @@ -1805,7 +1815,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP let deltaY = this.getYPosFromDisplay(NumCast(this.dataDoc.mass1_positionY)) + this.radius; let dir1T = Math.PI - Math.atan(deltaY / deltaX1); let dir2T = Math.atan(deltaY / deltaX2); - let tensionMag2 = (NumCast(this.dataDoc.mass1) * Math.abs(this.gravity)) / ((-Math.cos(dir2T) / Math.cos(dir1T)) * Math.sin(dir1T) + Math.sin(dir2T)); + let tensionMag2 = (this.mass1 * Math.abs(this.gravity)) / ((-Math.cos(dir2T) / Math.cos(dir1T)) * Math.sin(dir1T) + Math.sin(dir2T)); let tensionMag1 = (-tensionMag2 * Math.cos(dir2T)) / Math.cos(dir1T); dir1T = (dir1T * 180) / Math.PI; dir2T = (dir2T * 180) / Math.PI; @@ -1823,7 +1833,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP }; const grav: IForce = { description: 'Gravity', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity), + magnitude: this.mass1 * Math.abs(this.gravity), directionInDegrees: 270, component: false, }; @@ -1831,14 +1841,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP } }} small={true} - mode={'Freeform'} + mode="Freeform" /> </td> )}{' '} - {(!this.dataDoc.simulation_paused || this.dataDoc.simulation_type == 'Inclined Plane' || this.dataDoc.simulation_type == 'Circular Motion' || this.dataDoc.simulation_type == 'Pulley') && ( + {(!this.dataDoc.simulation_paused || this.simulationType == 'Inclined Plane' || this.simulationType == 'Circular Motion' || this.simulationType == 'Pulley') && ( <td style={{ cursor: 'default' }}>{`${NumCast(this.dataDoc.mass1_positionY)} m`}</td> )}{' '} - {this.dataDoc.simulation_paused && this.dataDoc.simulation_type != 'Inclined Plane' && this.dataDoc.simulation_type != 'Circular Motion' && this.dataDoc.simulation_type != 'Pulley' && ( + {this.dataDoc.simulation_paused && this.simulationType != 'Inclined Plane' && this.simulationType != 'Circular Motion' && this.simulationType != 'Pulley' && ( <td style={{ cursor: 'default', @@ -1848,12 +1858,12 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP dataDoc={this.dataDoc} prop="mass1_positionY" step={1} - unit={'m'} + unit="m" upperBound={this.yMax - 110} value={NumCast(this.dataDoc.mass1_positionY)} effect={value => { this.dataDoc.mass1_yChange = value; - if (this.dataDoc.simulation_type == 'Suspension') { + if (this.simulationType == 'Suspension') { let x1rod = (this.xMax + this.xMin) / 2 - this.radius - this.yMin - 200; let x2rod = (this.xMax + this.xMin) / 2 + this.yMin + 200 + this.radius; let deltaX1 = NumCast(this.dataDoc.mass1_positionX) + this.radius - x1rod; @@ -1861,7 +1871,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP let deltaY = this.getYPosFromDisplay(value) + this.radius; let dir1T = Math.PI - Math.atan(deltaY / deltaX1); let dir2T = Math.atan(deltaY / deltaX2); - let tensionMag2 = (NumCast(this.dataDoc.mass1) * Math.abs(this.gravity)) / ((-Math.cos(dir2T) / Math.cos(dir1T)) * Math.sin(dir1T) + Math.sin(dir2T)); + let tensionMag2 = (this.mass1 * Math.abs(this.gravity)) / ((-Math.cos(dir2T) / Math.cos(dir1T)) * Math.sin(dir1T) + Math.sin(dir2T)); let tensionMag1 = (-tensionMag2 * Math.cos(dir2T)) / Math.cos(dir1T); dir1T = (dir1T * 180) / Math.PI; dir2T = (dir2T * 180) / Math.PI; @@ -1879,7 +1889,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP }; const grav: IForce = { description: 'Gravity', - magnitude: NumCast(this.dataDoc.mass1) * Math.abs(this.gravity), + magnitude: this.mass1 * Math.abs(this.gravity), directionInDegrees: 270, component: false, }; @@ -1887,7 +1897,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP } }} small={true} - mode={'Freeform'} + mode="Freeform" /> </td> )}{' '} @@ -1903,10 +1913,10 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP > <Box>Velocity</Box> </td> - {(!this.dataDoc.simulation_paused || (this.dataDoc.simulation_type != 'One Weight' && this.dataDoc.simulation_type != 'Circular Motion')) && ( + {(!this.dataDoc.simulation_paused || (this.simulationType != 'One Weight' && this.simulationType != 'Circular Motion')) && ( <td style={{ cursor: 'default' }}>{`${NumCast(this.dataDoc.mass1_velocityX)} m/s`}</td> )}{' '} - {this.dataDoc.simulation_paused && (this.dataDoc.simulation_type == 'One Weight' || this.dataDoc.simulation_type == 'Circular Motion') && ( + {this.dataDoc.simulation_paused && (this.simulationType == 'One Weight' || this.simulationType == 'Circular Motion') && ( <td style={{ cursor: 'default', @@ -1924,16 +1934,16 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP this.dataDoc.simulation_reset = !this.dataDoc.simulation_reset; }} small={true} - mode={'Freeform'} + mode="Freeform" /> </td> )}{' '} - {(!this.dataDoc.simulation_paused || this.dataDoc.simulation_type != 'One Weight') && ( + {(!this.dataDoc.simulation_paused || this.simulationType != 'One Weight') && ( <td style={{ cursor: 'default' }}> <>{this.dataDoc.mass1_velocityY} m/s</> </td> )}{' '} - {this.dataDoc.simulation_paused && this.dataDoc.simulation_type == 'One Weight' && ( + {this.dataDoc.simulation_paused && this.simulationType == 'One Weight' && ( <td style={{ cursor: 'default', @@ -1943,14 +1953,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP dataDoc={this.dataDoc} prop="mass1_velocityY" step={1} - unit={'m/s'} + unit="m/s" upperBound={50} value={NumCast(this.dataDoc.mass1_velocityY)} effect={value => { this.dataDoc.mass1_velocityYstart = -value; }} small={true} - mode={'Freeform'} + mode="Freeform" /> </td> )}{' '} @@ -1981,13 +1991,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP <td> <Box>Momentum</Box> </td> - <td>{Math.round(NumCast(this.dataDoc.mass1_velocityX) * NumCast(this.dataDoc.mass1) * 10) / 10} kg*m/s</td> - <td>{Math.round(NumCast(this.dataDoc.mass1_velocityY) * NumCast(this.dataDoc.mass1) * 10) / 10} kg*m/s</td> + <td>{Math.round(NumCast(this.dataDoc.mass1_velocityX) * this.mass1 * 10) / 10} kg*m/s</td> + <td>{Math.round(NumCast(this.dataDoc.mass1_velocityY) * this.mass1 * 10) / 10} kg*m/s</td> </tr> </tbody> </table> )} - {this.dataDoc.simulation_mode == 'Freeform' && this.dataDoc.simulation_type == 'Pulley' && ( + {this.simulationMode == 'Freeform' && this.simulationType == 'Pulley' && ( <table> <tbody> <tr> @@ -2028,14 +2038,14 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP <td> <Box>Momentum</Box> </td> - <td>{Math.round(NumCast(this.dataDoc.mass2_velocityX) * NumCast(this.dataDoc.mass1) * 10) / 10} kg*m/s</td> - <td>{Math.round(NumCast(this.dataDoc.mass2_velocityY) * NumCast(this.dataDoc.mass1) * 10) / 10} kg*m/s</td> + <td>{Math.round(NumCast(this.dataDoc.mass2_velocityX) * this.mass1 * 10) / 10} kg*m/s</td> + <td>{Math.round(NumCast(this.dataDoc.mass2_velocityY) * this.mass1 * 10) / 10} kg*m/s</td> </tr> </tbody> </table> )} </div> - {this.dataDoc.simulation_type != 'Pendulum' && this.dataDoc.simulation_type != 'Spring' && ( + {this.simulationType != 'Pendulum' && this.simulationType != 'Spring' && ( <div> <p>Kinematic Equations</p> <ul> @@ -2052,7 +2062,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </ul> </div> )} - {this.dataDoc.simulation_type == 'Spring' && ( + {this.simulationType == 'Spring' && ( <div> <p>Harmonic Motion Equations: Spring</p> <ul> @@ -2081,7 +2091,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP </ul> </div> )} - {this.dataDoc.simulation_type == 'Pendulum' && ( + {this.simulationType == 'Pendulum' && ( <div> <p>Harmonic Motion Equations: Pendulum</p> <ul> @@ -2116,7 +2126,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewP top: this.yMax - 120 + 40 + 'px', left: this.xMin + 90 - 80 + 'px', }}> - {this.dataDoc.simulation_type == 'Circular Motion' ? 'Z' : 'Y'} + {this.simulationType == 'Circular Motion' ? 'Z' : 'Y'} </p> <p style={{ diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx index 025c757c9..ac28ee4a0 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx @@ -1,6 +1,5 @@ import { computed, trace } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, HeightSym, WidthSym } from '../../../../fields/Doc'; import './PhysicsSimulationBox.scss'; import React = require('react'); @@ -17,10 +16,9 @@ interface IForce { component: boolean; } export interface IWeightProps { - dataDoc: Doc; - layoutDoc: Doc; - adjustPendulumAngle: number; - adjustPendulumLength: number; + pause: () => void; + panelWidth: () => number; + panelHeight: () => number; circularMotionRadius: number; coefficientOfKineticFriction: number; color: string; @@ -50,6 +48,7 @@ export interface IWeightProps { springStartLength: number; startForces: () => IForce[]; startPendulumAngle: number; + startPendulumLength: number; startPosX: number; startPosY: number; startVelX: number; @@ -59,6 +58,11 @@ export interface IWeightProps { updateMassPosY: number; forcesUpdated: () => IForce[]; setForcesUpdated: (x: IForce[]) => {}; + setPosition: (x: number | undefined, y: number | undefined) => void; + setVelocity: (x: number | undefined, y: number | undefined) => void; + setAcceleration: (x: number, y: number) => void; + setPendulumAngle: (ang: number | undefined, length: number | undefined) => void; + setSpringLength: (length: number) => void; wallPositions: IWallProps[]; wedgeHeight: number; wedgeWidth: number; @@ -147,43 +151,15 @@ export default class Weight extends React.Component<IWeightProps, IState> { // Helper function to go between display and real values getDisplayYPos = (yPos: number) => this.props.yMax - yPos - 2 * this.props.radius + 5; - // Set display values based on real values - setPosition = (xPos: number | undefined, yPos: number | undefined) => { - if (this.props.color == 'red') { - yPos !== undefined && (this.props.dataDoc.mass1_positionY = Math.round(this.getDisplayYPos(yPos) * 100) / 100); - xPos !== undefined && (this.props.dataDoc.mass1_positionX = Math.round(xPos * 100) / 100); - } else { - yPos !== undefined && (this.props.dataDoc.mass2_positionY = Math.round(this.getDisplayYPos(yPos) * 100) / 100); - xPos !== undefined && (this.props.dataDoc.mass2_positionX = Math.round(xPos * 100) / 100); - } - }; - setVelocity = (xVel: number | undefined, yVel: number | undefined) => { - if (this.props.color == 'red') { - yVel !== undefined && (this.props.dataDoc.mass1_velocityY = (-1 * Math.round(yVel * 100)) / 100); - xVel !== undefined && (this.props.dataDoc.mass1_velocityX = Math.round(xVel * 100) / 100); - } else { - yVel !== undefined && (this.props.dataDoc.mass2_velocityY = (-1 * Math.round(yVel * 100)) / 100); - xVel !== undefined && (this.props.dataDoc.mass2_velocityX = Math.round(xVel * 100) / 100); - } - }; - setAcceleration = (xAccel: number, yAccel: number) => { - if (this.props.color == 'red') { - this.props.dataDoc.mass1_accelerationY = yAccel; - this.props.dataDoc.mass1_accelerationX = xAccel; - } else { - this.props.dataDoc.mass2_accelerationY = yAccel; - this.props.dataDoc.mass2_accelerationX = xAccel; - } - - this.setState({ xAccel }); - this.setState({ yAccel }); - }; - // Update display values when simulation updates setDisplayValues = (xPos: number = this.state.xPosition, yPos: number = this.state.yPosition, xVel: number = this.state.xVelocity, yVel: number = this.state.yVelocity) => { - this.setPosition(xPos, yPos); - this.setVelocity(xVel, yVel); - this.setAcceleration(Math.round(this.getNewAccelerationX(this.props.forcesUpdated()) * 100) / 100, (-1 * Math.round(this.getNewAccelerationY(this.props.forcesUpdated()) * 100)) / 100); + this.props.setPosition(xPos, this.getDisplayYPos(yPos)); + this.props.setVelocity(xVel, yVel); + const xAccel = Math.round(this.getNewAccelerationX(this.props.forcesUpdated()) * 100) / 100; + const yAccel = (-1 * Math.round(this.getNewAccelerationY(this.props.forcesUpdated()) * 100)) / 100; + this.props.setAcceleration(xAccel, yAccel); + this.setState({ xAccel }); + this.setState({ yAccel }); }; componentDidUpdate(prevProps: Readonly<IWeightProps>, prevState: Readonly<IState>, snapshot?: any): void { @@ -194,18 +170,17 @@ export default class Weight extends React.Component<IWeightProps, IState> { } // Change pendulum angle from input field - if (prevProps.adjustPendulumAngle != this.props.adjustPendulumAngle || prevProps.adjustPendulumLength !== this.props.adjustPendulumLength) { - let length = this.props.adjustPendulumLength; - const x = length * Math.cos(((90 - this.props.adjustPendulumAngle) * Math.PI) / 180); - const y = length * Math.sin(((90 - this.props.adjustPendulumAngle) * Math.PI) / 180); + if (prevProps.startPendulumAngle != this.props.startPendulumAngle || prevProps.startPendulumLength !== this.props.startPendulumLength) { + let length = this.props.startPendulumLength; + const x = length * Math.cos(((90 - this.props.startPendulumAngle) * Math.PI) / 180); + const y = length * Math.sin(((90 - this.props.startPendulumAngle) * Math.PI) / 180); const xPos = this.props.xMax / 2 - x - this.props.radius; const yPos = y - this.props.radius - 5; this.setState({ xPosition: xPos }); this.setState({ yPosition: yPos }); this.setState({ updatedStartPosX: xPos }); this.setState({ updatedStartPosY: yPos }); - this.props.dataDoc.pendulum_angle = this.props.adjustPendulumAngle; - this.props.dataDoc.pendulum_length = this.props.adjustPendulumLength; + this.props.setPendulumAngle(this.props.startPendulumAngle, this.props.startPendulumLength); } // When display values updated by user, update real value @@ -215,7 +190,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { x = Math.min(x, this.props.xMax - 2 * this.props.radius); this.setState({ updatedStartPosX: x }); this.setState({ xPosition: x }); - this.setPosition(x, undefined); + this.props.setPosition(x, undefined); } if (prevProps.updateMassPosY != this.props.updateMassPosY) { let y = this.props.updateMassPosY; @@ -224,18 +199,18 @@ export default class Weight extends React.Component<IWeightProps, IState> { let coordinatePosition = this.getDisplayYPos(y); this.setState({ updatedStartPosY: coordinatePosition }); this.setState({ yPosition: coordinatePosition }); - this.setPosition(undefined, y); + this.props.setPosition(undefined, this.getDisplayYPos(y)); if (this.props.displayXVelocity != this.state.xVelocity) { let x = this.props.displayXVelocity; this.setState({ xVelocity: x }); - this.setVelocity(x, undefined); + this.props.setVelocity(x, undefined); } if (this.props.displayYVelocity != -this.state.yVelocity) { let y = this.props.displayYVelocity; this.setState({ yVelocity: -y }); - this.setVelocity(undefined, y); + this.props.setVelocity(undefined, y); } } @@ -360,7 +335,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { if (this.props.paused && !isNaN(this.props.startPosX)) { this.setState({ xPosition: this.props.startPosX }); this.setState({ updatedStartPosX: this.props.startPosX }); - this.setPosition(this.props.startPosX, undefined); + this.props.setPosition(this.props.startPosX, undefined); } } @@ -369,7 +344,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { if (this.props.paused && !isNaN(this.props.startPosY)) { this.setState({ yPosition: this.props.startPosY }); this.setState({ updatedStartPosY: this.props.startPosY ?? 0 }); - this.setPosition(undefined, this.props.startPosY ?? 0); + this.props.setPosition(undefined, this.getDisplayYPos(this.props.startPosY)); } } @@ -410,23 +385,11 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.setState({ yPosition: this.state.updatedStartPosY }); this.setState({ xVelocity: this.props.startVelX }); this.setState({ yVelocity: this.props.startVelY }); - this.props.dataDoc.pendulum_angle = this.props.startPendulumAngle; + this.props.setPendulumAngle(this.props.startPendulumAngle, undefined); this.props.setForcesUpdated(this.props.startForces()); - if (this.props.color == 'red') { - this.props.dataDoc.mass1_positionX = this.state.updatedStartPosX; - this.props.dataDoc.mass1_positionY = this.state.updatedStartPosY; - this.props.dataDoc.mass1_velocityX = this.props.startVelX; - this.props.dataDoc.mass1_velocityY = this.props.startVelY; - this.props.dataDoc.mass1_accelerationX = 0; - this.props.dataDoc.mass1_accelerationY = 0; - } else { - this.props.dataDoc.mass2_positionX = this.state.updatedStartPosX; - this.props.dataDoc.mass2_positionY = this.state.updatedStartPosY; - this.props.dataDoc.mass2_velocityX = this.props.startVelX; - this.props.dataDoc.mass2_velocityY = this.props.startVelY; - this.props.dataDoc.mass2_accelerationX = 0; - this.props.dataDoc.mass2_accelerationY = 0; - } + this.props.setPosition(this.state.updatedStartPosX, this.state.updatedStartPosY); + this.props.setVelocity(this.props.startVelX, this.props.startVelY); + this.props.setAcceleration(0, 0); this.setState({ angleLabel: Math.round(this.props.pendulumAngle * 100) / 100 }); }; @@ -514,7 +477,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { } const pendulumLength = Math.sqrt(x * x + y * y); - this.props.dataDoc.pendulum_angle = oppositeAngle; + this.props.setPendulumAngle(oppositeAngle, undefined); const mag = this.props.mass * Math.abs(this.props.gravity) * Math.cos((oppositeAngle * Math.PI) / 180) + (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength; @@ -544,7 +507,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { if (this.state.xVelocity != 0) { this.state.walls.forEach(wall => { if (wall.angleInDegrees == 90) { - const wallX = (wall.xPos / 100) * this.props.layoutDoc[WidthSym](); + const wallX = (wall.xPos / 100) * this.props.panelWidth(); if (wall.xPos < 0.35) { if (minX <= wallX) { this.setState({ xPosition: wallX + 0.01 }); @@ -580,7 +543,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { if (this.state.yVelocity > 0) { this.state.walls.forEach(wall => { if (wall.angleInDegrees == 0 && wall.yPos > 0.4) { - const groundY = (wall.yPos / 100) * this.props.layoutDoc[HeightSym](); + const groundY = (wall.yPos / 100) * this.props.panelHeight(); if (maxY > groundY) { this.setState({ yPosition: groundY - 2 * this.props.radius - 0.01 }); if (this.props.elasticCollisions) { @@ -626,7 +589,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { if (this.state.yVelocity < 0) { this.state.walls.forEach(wall => { if (wall.angleInDegrees == 0 && wall.yPos < 0.4) { - const groundY = (wall.yPos / 100) * this.props.layoutDoc[HeightSym](); + const groundY = (wall.yPos / 100) * this.props.panelHeight(); if (minY < groundY) { this.setState({ yPosition: groundY + 0.01 }); if (this.props.elasticCollisions) { @@ -800,7 +763,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { className="weightContainer" onPointerDown={e => { if (this.draggable) { - this.props.dataDoc.paused = true; + this.props.pause(); this.setState({ dragging: true }); this.setState({ clickPositionX: e.clientX }); this.setState({ clickPositionY: e.clientY }); @@ -830,10 +793,10 @@ export default class Weight extends React.Component<IWeightProps, IState> { } this.setState({ yPosition: newY }); - this.props.dataDoc.mass1_positionY = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100; + this.props.setPosition(undefined, Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100); if (this.props.simulationType != 'Pulley') { this.setState({ xPosition: newX }); - this.props.dataDoc.mass1_positionX = newX; + this.props.setPosition(newX, undefined); } if (this.props.simulationType != 'Suspension') { if (this.props.simulationType != 'Pulley') { @@ -866,7 +829,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { newX = 10; } if (this.props.simulationType == 'Spring') { - this.props.dataDoc.spring_lengthStart = newY; + this.props.setSpringLength(newY); } if (this.props.simulationType == 'Suspension') { let x1rod = (this.props.xMax + this.props.xMin) / 2 - this.props.radius - this.props.yMin - 200; @@ -915,7 +878,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: 0, top: 0, }}> - <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax + 'px'} height={this.props.panelHeight() + 'px'}> {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(val => { const count = 10; let xPos1; @@ -946,7 +909,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: 0, top: 0, }}> - <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax + 'px'} height={this.props.panelHeight() + 'px'}> <line x1={this.state.xPosition + this.props.radius} y1={this.state.yPosition + this.props.radius} x2={this.state.xPosition + this.props.radius} y2={this.props.yMin} stroke={'#deb887'} strokeWidth="10" /> </svg> </div> @@ -960,7 +923,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: 0, top: 0, }}> - <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax + 'px'} height={this.props.panelHeight() + 'px'}> <circle cx={(this.props.xMax + this.props.xMin) / 2} cy={this.props.radius} r={this.props.radius * 1.5} fill={'#808080'} /> </svg> </div> @@ -974,7 +937,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: 0, top: 0, }}> - <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax + 'px'} height={this.props.panelHeight() + 'px'}> <line x1={this.state.xPosition + this.props.radius} y1={this.state.yPosition + this.props.radius} @@ -1004,7 +967,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: 0, top: 0, }}> - <svg width={this.props.layoutDoc._width + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.panelWidth() + 'px'} height={this.props.panelHeight() + 'px'}> <line x1={this.state.xPosition + this.props.radius} y1={this.state.yPosition + this.props.radius} @@ -1039,7 +1002,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: 0, top: 0, }}> - <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax + 'px'} height={this.props.panelHeight() + 'px'}> <line x1={this.state.xPosition + this.props.radius} y1={this.state.yPosition + this.props.radius} @@ -1060,7 +1023,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: 0, top: 0, }}> - <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax + 'px'} height={this.props.panelHeight() + 'px'}> <line x1={this.state.xPosition + this.props.radius} y1={this.state.yPosition + this.props.radius} x2={this.props.xMax / 2} y2={-5} stroke={'#deb887'} strokeWidth="10" /> </svg> {!this.state.dragging && ( @@ -1115,7 +1078,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: 0, top: 0, }}> - <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax + 'px'} height={this.props.panelHeight() + 'px'}> <defs> <marker id="accArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth"> <path d="M0,0 L0,6 L9,3 z" fill="green" /> @@ -1156,7 +1119,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: 0, top: 0, }}> - <svg width={this.props.xMax + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax + 'px'} height={this.props.panelHeight() + 'px'}> <defs> <marker id="velArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth"> <path d="M0,0 L0,6 L9,3 z" fill="blue" /> @@ -1224,7 +1187,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: this.props.xMin, top: this.props.yMin, }}> - <svg width={this.props.xMax - this.props.xMin + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax - this.props.xMin + 'px'} height={this.props.panelHeight() + 'px'}> <defs> <marker id="forceArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth"> <path d="M0,0 L0,6 L9,3 z" fill={color} /> @@ -1289,7 +1252,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: this.props.xMin, top: this.props.yMin, }}> - <svg width={this.props.xMax - this.props.xMin + 'px'} height={this.props.layoutDoc._height + 'px'}> + <svg width={this.props.xMax - this.props.xMin + 'px'} height={this.props.panelHeight() + 'px'}> <defs> <marker id="forceArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth"> <path d="M0,0 L0,6 L9,3 z" fill={color} /> |