import React = require('react'); import "./PhysicsSimulationBox.scss"; import { IForce, Weight } from "./PhysicsSimulationWeight"; import {Wall, IWallProps } from "./PhysicsSimulationWall" import {Wedge} from "./PhysicsSimulationWedge" import { props, any } from 'bluebird'; import { render } from 'react-dom'; interface PhysicsVectorTemplate { top: number; left: number; width: number; height: number; x1: number; y1: number; x2: number; y2: number; weightX: number; weightY: number; } interface IState { accelerationXDisplay: number, accelerationYDisplay: number, adjustPendulumAngle: {angle: number, length: number}, coefficientOfKineticFriction: number, coefficientOfStaticFriction: number, currentForceSketch: PhysicsVectorTemplate | null, deleteMode: boolean, displayChange: {xDisplay: number, yDisplay: number}, elasticCollisions: boolean, forceSketches: PhysicsVectorTemplate[], pendulum: boolean, pendulumAngle: number, pendulumLength: number, positionXDisplay: number, positionYDisplay: number, showAcceleration: boolean, showForceMagnitudes: boolean, showForces: boolean, showVelocity: boolean, simulationPaused: boolean, simulationReset: boolean, simulationType: "Inclined Plane", sketching: boolean, startForces: IForce[], startPendulumAngle: number, startPosX: number, startPosY: number, stepNumber: number, timer: number, updatedForces: IForce[], velocityXDisplay: number, velocityYDisplay: number, wallPositions: IWallProps[], wedge: boolean, wedgeAngle: number, wedgeHeight: number, wedgeWidth: number, weight: boolean, } export default class App extends React.Component<{}, IState> { // Constants gravityMagnitude = 9.81; forceOfGravity: IForce = { description: "Gravity", magnitude: this.gravityMagnitude, directionInDegrees: 270, }; xMin = 0; yMin = 0; xMax = window.innerWidth * 0.7; yMax = window.innerHeight * 0.8; color = `rgba(0,0,0,0.5)`; radius = 50 constructor(props: any) { super(props) this.state = { accelerationXDisplay: 0, accelerationYDisplay: 0, adjustPendulumAngle: {angle: 0, length: 0}, coefficientOfKineticFriction: 0, coefficientOfStaticFriction: 0, currentForceSketch: null, deleteMode: false, displayChange: {xDisplay: 0, yDisplay: 0}, elasticCollisions: false, forceSketches: [], pendulum: false, pendulumAngle: 0, pendulumLength: 300, positionXDisplay: 0, positionYDisplay: 0, showAcceleration: false, showForceMagnitudes: false, showForces: false, showVelocity: false, simulationPaused: false, simulationReset: false, simulationType: "Inclined Plane", sketching: false, startForces: [this.forceOfGravity], startPendulumAngle: 0, startPosX: 0, startPosY: 0, stepNumber: 0, timer: 0, updatedForces: [this.forceOfGravity], velocityXDisplay: 0, velocityYDisplay: 0, wallPositions: [], wedge: false, wedgeAngle: 26, wedgeHeight: Math.tan((26 * Math.PI) / 180) * 400, wedgeWidth: 400, weight: false, } } // Add one weight to the simulation addWeight () { this.setState({weight: true}) this.setState({wedge: false}) this.setState({pendulum: false}) this.setState({startPosY: this.yMin+this.radius}) this.setState({startPosX: (this.xMax+this.xMin-this.radius)/2}) this.setState({updatedForces: [this.forceOfGravity]}) this.setState({startForces: [this.forceOfGravity]}) this.addWalls(); this.setState({simulationReset: !this.state.simulationReset}) }; // Add a wedge with a One Weight to the simulation addWedge () { this.setState({weight: true}) this.setState({wedge: true}) this.setState({pendulum: false}) this.changeWedgeBasedOnNewAngle(26); this.addWalls(); this.setState({startForces: [this.forceOfGravity]}) this.updateForcesWithFriction(this.state.coefficientOfStaticFriction); }; // Add a simple pendulum to the simulation addPendulum = () => { this.setState({weight: true}) this.setState({wedge: false}) this.setState({pendulum: true}) let length = 300; let angle = 50; let x = length * Math.cos(((90 - angle) * Math.PI) / 180); let y = length * Math.sin(((90 - angle) * Math.PI) / 180); let xPos = xMax / 2 - x - 50; let yPos = y - 50 - 5; this.addPendulum(); this.setState({startPosX: xPos}) this.setState({startPosY: yPos}) let mag = 9.81 * Math.cos((50 * Math.PI) / 180); let forceOfTension: IForce = { description: "Tension", magnitude: mag, directionInDegrees: 90 - angle, }; this.setState({updatedForces: [this.forceOfGravity, forceOfTension]}) this.setState({startForces: [this.forceOfGravity, forceOfTension]}) this.setState({pendulumAngle: 50}) this.setState({pendulumLength: 300}) this.setState({adjustPendulumAngle: {angle: 50, length: 300}}) this.removeWalls(); }; // Update forces when coefficient of static friction changes in freeform mode updateForcesWithFriction ( coefficient: number, width: number = this.state.wedgeWidth, height: number = this.state.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.setState({startForces: [this.forceOfGravity, normalForce, frictionForce]}) this.setState({updatedForces: [this.forceOfGravity, normalForce, frictionForce]}); } else { this.setState({startForces: [this.forceOfGravity, normalForce]}) this.setState({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 = 400; height = Math.tan((angle * Math.PI) / 180) * 400; this.setState({wedgeWidth: width}) this.setState({wedgeHeight: height}) } else if (angle < 70) { width = 200; height = Math.tan((angle * Math.PI) / 180) * 200; this.setState({wedgeWidth: width}) this.setState({wedgeHeight: height}) } else { width = 100; height = Math.tan((angle * Math.PI) / 180) * 100; this.setState({wedgeWidth: width}) this.setState({wedgeHeight: height}) } // update weight position based on updated wedge width/height let yPos = (width - 50) * Math.tan((angle * Math.PI) / 180); if (angle < 40) { yPos += Math.sqrt(angle); } else if (angle < 58) { yPos += angle / 2; } else if (angle < 68) { yPos += angle; } else if (angle < 70) { yPos += angle * 1.3; } else if (angle < 75) { yPos += angle * 1.5; } else if (angle < 78) { yPos += angle * 2; } else if (angle < 79) { yPos += angle * 2.25; } else if (angle < 80) { yPos += angle * 2.6; } else { yPos += angle * 3; } this.setState({startPosX: Math.round((this.xMax * 0.5 - 200) * 10) / 10}); this.setState({startPosY: this.getDisplayYPos(yPos)}); this.updateForcesWithFriction( Number(this.state.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.state.sketching) { let sketches = this.state.forceSketches.filter((sketch) => sketch != element); this.setState({forceSketches: sketches}) this.setState({currentForceSketch: element}) this.setState({sketching: true}) } }; // In review mode, used to delete force arrow sketch on SHIFT+click deleteForce = (element: PhysicsVectorTemplate) => { if (!this.state.sketching) { let sketches = this.state.forceSketches.filter((sketch) => sketch != element); this.setState({forceSketches: sketches}) } }; // Remove floor and walls from simulation removeWalls = () => { this.setState({wallPositions: []}) }; // Add floor and walls to simulation addWalls = () => { if (this.state.wallPositions.length == 0) { let walls = []; walls.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 }); walls.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 }); walls.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 }); this.setState({wallPositions: walls}) } }; componentDidMount() { // 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.setState({deleteMode: true}) } }); document.addEventListener("keyup", (e) => { if (e.shiftKey) { this.setState({deleteMode: false}) } }); // Timer for animating the simulation setInterval(() => { this.setState({timer: this.state.timer+1}) }, 60); } render () { return (

Hello world!

//
//
//
{ // // if (sketching) { // // x1 = positionXDisplay + 50; // // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50; // // x2 = e.clientX; // // y2 = e.clientY; // // height = Math.abs(y1 - y2) + 120; // // width = Math.abs(x1 - x2) + 120; // // top = Math.min(y1, y2) - 60; // // left = Math.min(x1, x2) - 60; // // x1Updated = x1 - left; // // x2Updated = x2 - left; // // y1Updated = y1 - top; // // y2Updated = y2 - top; // // setCurrentForceSketch({ // // top: top, // // left: left, // // width: width, // // height: height, // // x1: x1Updated, // // y1: y1Updated, // // x2: x2Updated, // // y2: y2Updated, // // weightX: positionXDisplay, // // weightY: positionYDisplay, // // }); // // } // }} // onPointerDown={(e) => { // // if (sketching && currentForceSketch) { // // setSketching(false); // // sketches = forceSketches; // // sketches.push(currentForceSketch); // // setForceSketches(sketches); // // setCurrentForceSketch(null); // // } // }} // > //
//
// {/* {showForces && currentForceSketch && simulationPaused && ( //
// // // // // // // // //
// )} */} // {/* {showForces && // forceSketches.length > 0 && // simulationPaused && // forceSketches.map((element: PhysicsVectorTemplate, index) => { // return ( //
// // // // // // // { // if (deleteMode) { // deleteForce(element); // } else { // editForce(element); // } // }} // /> // //
// ); // })} */} // {weight && ( // // )} // {wedge && ( // // )} //
//
// {wallPositions.map((element, index) => { // return ( // // ); // })} //
//
//
//
//
//
// {simulationPaused && ( // // )} // {!simulationPaused && ( // // )} // {simulationPaused && ( // // )} //
//
//
//
//
); } }