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" import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CheckBox } from "../search/CheckBox"; 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 update = true menuIsOpen = false constructor(props: any) { super(props); } // Add one weight to the simulation addWeight () { this.dataDoc.weight = true; this.dataDoc.wedge = false; this.dataDoc.pendulum = false; this.addWalls(); }; // 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); } // 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); console.log('update start pos x') console.log('update start pos y') this.updateForcesWithFriction( Number(this.dataDoc.coefficientOfStaticFriction), width, height ); this.dataDoc['updateDisplay'] = !this.dataDoc['updateDisplay'] }; // 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.layoutDoc._height; // Add weight if (this.dataDoc.simulationType == "Inclined Plane") { this.addWedge() } else if (this.dataDoc.simulationType == "Pendulum") { this.addPendulum() } else { this.dataDoc.simulationType = "Free Weight" this.addWeight() } this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0; this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0; this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0; this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0; this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? []; this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false; this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? []; this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 26; this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300; this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0; this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0; this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false; this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? false; this.dataDoc.showForces = this.dataDoc.showForces ?? false; this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false; this.dataDoc.startForces = this.dataDoc.startForces ?? [this.forceOfGravity]; this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0; this.dataDoc.startPosX = this.dataDoc.startPosX ?? 0; this.dataDoc.startPosY = this.dataDoc.startPosY ?? 0; this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0; this.dataDoc.updateDisplay = this.dataDoc.updateDisplay ?? false; this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [this.forceOfGravity]; this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0; this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0; this.dataDoc.wallPositions = this.dataDoc.wallPositions ?? []; this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26; this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * this.xMax*0.6; this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? this.xMax*0.6; this.dataDoc.adjustPendulumAngle = true; this.dataDoc.simulationPaused = true; this.dataDoc.simulationReset = false; // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click document.addEventListener("keydown", (e) => { if (e.shiftKey) { this.dataDoc.deleteMode = true; } }); document.addEventListener("keyup", (e) => { if (e.shiftKey) { this.dataDoc.deleteMode = false; } }); } componentDidUpdate() { this.xMax = this.layoutDoc._width; this.yMax = this.layoutDoc._height; this.radius = 0.1*this.layoutDoc._height; } render () { return (
{this.dataDoc.weight && ( )} {this.dataDoc.wedge && ( )}
{/*
{this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { return (
); })}
*/}
{this.menuIsOpen && (
{this.menuIsOpen = false}}>

Simulation Settings

{this.dataDoc.simulationType == "Free Weight" &&

Elastic collisions

{this.dataDoc.elasticCollisions = val}} originalStatus={this.dataDoc.elasticCollisions} />
} {/* {this.dataDoc.simulationType == "Inclined Plane" &&

Inclined plane angle

input field!

} {this.dataDoc.simulationType == "Pendulum" &&

Pendulum angle

input field!

}

Show forces

this.dataDoc.showForces = !this.dataDoc.showForces } />

Show acceleration

this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration } />

Show velocity

this.dataDoc.showVelocity = !this.dataDoc.showVelocity } />
*/}
)}
{this.dataDoc.simulationPaused && ( )} {!this.dataDoc.simulationPaused && ( )} {this.dataDoc.simulationPaused && ( )} {this.dataDoc.simulationPaused && ( )}
); } }