import "./PhysicsSimulationBox.scss"; import { FieldView, FieldViewProps } from './FieldView'; import React = require('react'); import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { observer } from 'mobx-react'; import "./PhysicsSimulationBox.scss"; import Weight from "./PhysicsSimulationWeight"; import Wall from "./PhysicsSimulationWall" import Wedge from "./PhysicsSimulationWedge" export interface IForce { description: string; magnitude: number; directionInDegrees: number; } export interface IWallProps { length: number; xPos: number; yPos: number; angleInDegrees: number; } interface PhysicsVectorTemplate { top: number; left: number; width: number; height: number; x1: number; y1: number; x2: number; y2: number; weightX: number; weightY: number; } @observer export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); } // Constants gravityMagnitude = 9.81; forceOfGravity: IForce = { description: "Gravity", magnitude: this.gravityMagnitude, directionInDegrees: 270, }; xMin = 0; yMin = 0; xMax = 300; yMax = 300; color = `rgba(0,0,0,0.5)`; radius = 0.1*this.yMax constructor(props: any) { super(props); // this.dataDoc.coefficientOfKineticFriction = 0; // this.dataDoc.coefficientOfStaticFriction = 0; // this.dataDoc.currentForceSketch = []; // this.dataDoc.updateDisplay = false; // this.dataDoc.elasticCollisions = false; // this.dataDoc.forceSketches = []; // this.dataDoc.pendulumAngle = 0; // this.dataDoc.pendulumLength = 300; // this.dataDoc.positionXDisplay = 0; // this.dataDoc.positionYDisplay = 0; // this.dataDoc.showAcceleration = false; // this.dataDoc.showForceMagnitudes = false; // this.dataDoc.showForces = false; // this.dataDoc.showVelocity = false; // this.dataDoc.startForces = [this.forceOfGravity]; // this.dataDoc.startPendulumAngle = 0; // this.dataDoc.startPosX = 0; // this.dataDoc.startPosY = 0; // this.dataDoc.stepNumber = 0; // this.dataDoc.updatedForces = [this.forceOfGravity]; // this.dataDoc.velocityXDisplay = 0; // this.dataDoc.velocityYDisplay = 0; // this.dataDoc.wallPositions = []; // this.dataDoc.wedgeAngle = 26; // this.dataDoc.wedgeHeight = Math.tan((26 * Math.PI) / 180) * this.xMax*0.6; // this.dataDoc.wedgeWidth = this.xMax*0.6; } // Add one weight to the simulation addWeight () { this.dataDoc.weight = true; this.dataDoc.wedge = false; this.dataDoc.pendulum = false; this.addWalls(); this.dataDoc.simulationReset = !this.dataDoc.simulationReset; }; // Set weight defaults setToWeightDefault () { this.dataDoc.startPosY = this.yMin+this.radius; this.dataDoc.startPosX = (this.xMax+this.xMin-this.radius)/2; this.dataDoc.updatedForces = [this.forceOfGravity]; this.dataDoc.startForces = [this.forceOfGravity]; } // Add a wedge with a One Weight to the simulation addWedge () { this.dataDoc.weight = true; this.dataDoc.wedge = true; this.dataDoc.pendulum = false; this.addWalls(); }; // Set wedge defaults setToWedgeDefault () { this.changeWedgeBasedOnNewAngle(26); this.updateForcesWithFriction(this.dataDoc.coefficientOfStaticFriction); this.dataDoc.startForces = [this.forceOfGravity]; } // Add a simple pendulum to the simulation addPendulum = () => { this.dataDoc.weight = true; this.dataDoc.wedge = false; this.dataDoc.pendulum = true; this.removeWalls(); let angle = this.dataDoc.pendulumAngle; let mag = 9.81 * Math.cos((angle * Math.PI) / 180); let forceOfTension: IForce = { description: "Tension", magnitude: mag, directionInDegrees: 90 - angle, }; this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension]; this.dataDoc.startForces = [this.forceOfGravity, forceOfTension]; }; // Set pendulum defaults setToPendulumDefault () { let length = this.xMax*0.7; let angle = 35; let x = length * Math.cos(((90 - angle) * Math.PI) / 180); let y = length * Math.sin(((90 - angle) * Math.PI) / 180); let xPos = this.xMax / 2 - x - this.radius; let yPos = y - this.radius; this.dataDoc.startPosX = xPos; this.dataDoc.startPosY = yPos; let mag = 9.81 * Math.cos((angle * Math.PI) / 180); this.dataDoc.pendulumAngle = angle; this.dataDoc.pendulumLength = length; this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle; } // Update forces when coefficient of static friction changes in freeform mode updateForcesWithFriction ( coefficient: number, width: number = this.dataDoc.wedgeWidth, height: number = this.dataDoc.wedgeHeight ) { let normalForce = { description: "Normal Force", magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)), directionInDegrees: 180 - 90 - (Math.atan(height / width) * 180) / Math.PI, }; let frictionForce: IForce = { description: "Static Friction Force", magnitude: coefficient * this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)), directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI, }; // reduce magnitude of friction force if necessary such that block cannot slide up plane let yForce = -this.forceOfGravity.magnitude; yForce += normalForce.magnitude * Math.sin((normalForce.directionInDegrees * Math.PI) / 180); yForce += frictionForce.magnitude * Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); if (yForce > 0) { frictionForce.magnitude = (-normalForce.magnitude * Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + this.forceOfGravity.magnitude) / Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); } if (coefficient != 0) { this.dataDoc.startForces = [this.forceOfGravity, normalForce, frictionForce]; this.dataDoc.updatedForces = [this.forceOfGravity, normalForce, frictionForce]; } else { this.dataDoc.startForces = [this.forceOfGravity, normalForce]; this.dataDoc.updatedForces = [this.forceOfGravity, normalForce]; } }; // Change wedge height and width and weight position to match new wedge angle changeWedgeBasedOnNewAngle = (angle: number) => { let width = 0; let height = 0; if (angle < 50) { width = this.xMax*0.6; height = Math.tan((angle * Math.PI) / 180) * width; this.dataDoc.wedgeWidth = width; this.dataDoc.wedgeHeight = height; } else if (angle < 70) { width = this.xMax*0.3; height = Math.tan((angle * Math.PI) / 180) * width; this.dataDoc.wedgeWidth = width; this.dataDoc.wedgeHeight = height; } else { width = this.xMax*0.15; height = Math.tan((angle * Math.PI) / 180) * width; this.dataDoc.wedgeWidth = width; this.dataDoc.wedgeHeight = height; } // update weight position based on updated wedge width/height let xPos = (this.xMax * 0.2)-this.radius; let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius; this.dataDoc.startPosX = xPos; this.dataDoc.startPosY = this.getDisplayYPos(yPos); this.updateForcesWithFriction( Number(this.dataDoc.coefficientOfStaticFriction), width, height ); }; // Helper function to go between display and real values getDisplayYPos = (yPos: number) => { return this.yMax - yPos - 2 * 50 + 5; }; // In review mode, edit force arrow sketch on mouse movement editForce = (element: PhysicsVectorTemplate) => { if (!this.dataDoc.sketching) { let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); this.dataDoc.forceSketches = sketches; this.dataDoc.currentForceSketch = element; this.dataDoc.sketching = true; } }; // In review mode, used to delete force arrow sketch on SHIFT+click deleteForce = (element: PhysicsVectorTemplate) => { if (!this.dataDoc.sketching) { let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); this.dataDoc.forceSketches = sketches; } }; // Remove floor and walls from simulation removeWalls = () => { this.dataDoc.wallPositions = [] }; // Add floor and walls to simulation addWalls = () => { let walls = []; walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 }); walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }); walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 }); this.dataDoc.wallPositions = walls }; componentDidMount() { this.xMax = this.layoutDoc._width; this.yMax = this.layoutDoc._height; this.radius = 0.1*this.yMax // Add weight if (this.dataDoc.simulationType == "Inclined Plane") { console.log('add wedge on mount') this.addWedge() } else if (this.dataDoc.simulationType == "Pendulum") { console.log('add pendulum on mount') this.addPendulum() } else { this.dataDoc.simulationType = "Free Weight" console.log('add weight on mount') this.addWeight() } // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click document.addEventListener("keydown", (e) => { if (e.shiftKey) { this.dataDoc.deleteMode = true; } }); document.addEventListener("keyup", (e) => { if (e.shiftKey) { this.dataDoc.deleteMode = false; } }); this.dataDoc.simulationPaused = true; this.dataDoc.simulationReset = false; this.dataDoc.accelerationXDisplay = 0; this.dataDoc.accelerationYDisplay = 0; this.dataDoc.adjustPendulumAngle = true; this.dataDoc.timer = 0; } render () { return (
{this.dataDoc.weight && ( )} {this.dataDoc.wedge && ( )}
{/* {this.dataDoc.wallPositions && ( {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { return (
); })} )} */}
{this.dataDoc.simulationPaused && ( )} {!this.dataDoc.simulationPaused && ( )} {this.dataDoc.simulationPaused && ( )} {this.dataDoc.simulationPaused && ( )}
); } }