diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/nodes/PhysicsSimulationBox.tsx | 56 | ||||
-rw-r--r-- | src/client/views/nodes/PhysicsSimulationWeight.tsx | 142 |
2 files changed, 91 insertions, 107 deletions
diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 9d91adefb..13b4fe0b2 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -61,7 +61,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi this.dataDoc.coefficientOfStaticFriction = 0; this.dataDoc.currentForceSketch = []; this.dataDoc.deleteMode = false; - this.dataDoc.displayChange = {xDisplay: 0, yDisplay: 0}; + this.dataDoc.updateDisplay = false; this.dataDoc.elasticCollisions = false; this.dataDoc.forceSketches = []; this.dataDoc.pendulum = false; @@ -264,25 +264,25 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi componentDidMount() { - // Add weight - this.addPendulum() + // Add weight + this.addPendulum() - // 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; - } - }); + // 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; + } + }); - // Timer for animating the simulation - setInterval(() => { - this.dataDoc.timer = this.dataDoc.timer+1; - }, 60); + // // Timer for animating the simulation + // setInterval(() => { + // this.dataDoc.timer = this.dataDoc.timer+1; + // }, 60); } render () { @@ -297,26 +297,8 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi color={"red"} dataDoc={this.dataDoc} mass={1} - pendulum={this.dataDoc.pendulum} - pendulumAngle={this.dataDoc.pendulumAngle} - pendulumLength={this.dataDoc.pendulumLength} radius={this.radius} - reset={this.dataDoc.simulationReset} - showForceMagnitudes={this.dataDoc.showForceMagnitudes} - showAcceleration={this.dataDoc.showAcceleration} - showForces={this.dataDoc.showForces} - showVelocity={this.dataDoc.showVelocity} - startForces={this.dataDoc.startForces} - startPosX={this.dataDoc.startPosX} - startPosY={this.dataDoc.startPosY} timestepSize={0.002} - updateDisplay={this.dataDoc.displayChange} - updatedForces={this.dataDoc.updatedForces} - walls={this.dataDoc.wallPositions} - wedge={this.dataDoc.wedge} - wedgeHeight={this.dataDoc.wedgeHeight} - wedgeWidth={this.dataDoc.wedgeWidth} - coefficientOfKineticFriction={this.dataDoc.coefficientOfKineticFriction} xMax={this.xMax} yMax={this.yMax} xMin={this.xMin} @@ -354,11 +336,13 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<Fi <div> {this.dataDoc.simulationPaused && ( <button onClick={() => { + console.log('start sim') this.dataDoc.simulationPaused = false} } >START</button> )} {!this.dataDoc.simulationPaused && ( <button onClick={() => { + console.log('pause sim') this.dataDoc.simulationPaused = true} } >PAUSE</button> )} diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index fcfb149c9..e7bd86915 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -10,27 +10,13 @@ export interface IForce { export interface IWeightProps { dataDoc: Doc; color: string; - startForces: IForce[]; mass: number; - pendulum: boolean; - pendulumLength: number; wedge: boolean; radius: number; - reset: boolean; - showAcceleration: boolean; - pendulumAngle: number; - showForces: boolean; - showForceMagnitudes: boolean; - showVelocity: boolean; - startPosX: number; - startPosY: number; startVelX?: number; startVelY?: number; timestepSize: number; - updateDisplay: { xDisplay: number; yDisplay: number }; - updatedForces: IForce[]; walls: IWallProps[]; - coefficientOfKineticFriction: number; wedgeWidth: number; wedgeHeight: number; xMax: number; @@ -46,6 +32,7 @@ interface IState { kineticFriction: boolean, updatedStartPosX: number, updatedStartPosY: number, + timer: number; xPosition: number, yPosition: number, xVelocity: number, @@ -60,17 +47,18 @@ export default class Weight extends React.Component<IWeightProps, IState> { clickPositionY: 0, dragging: false, kineticFriction: false, - updatedStartPosX: this.props.startPosX, - updatedStartPosY: this.props.startPosY, - xPosition: this.props.startPosX, - yPosition: this.props.startPosY, + timer: 0, + updatedStartPosX: this.props.dataDoc['startPosX'], + updatedStartPosY: this.props.dataDoc['startPosY'], + xPosition: this.props.dataDoc['startPosX'], + yPosition: this.props.dataDoc['startPosY'], xVelocity: this.props.startVelX ? this.props.startVelX: 0, yVelocity: this.props.startVelY ? this.props.startVelY: 0, } } // Constants - draggable = !this.props.wedge; + draggable = !this.props.dataDoc['wedge'] ; epsilon = 0.0001; forceOfGravity: IForce = { description: "Gravity", @@ -84,8 +72,8 @@ export default class Weight extends React.Component<IWeightProps, IState> { borderStyle: "solid", borderColor: "black", position: "absolute" as "absolute", - left: this.props.startPosX + "px", - top: this.props.startPosY + "px", + left: this.props.dataDoc['startPosX'] + "px", + top: this.props.dataDoc['startPosY'] + "px", width: 2 * this.props.radius + "px", height: 2 * this.props.radius + "px", zIndex: 5, @@ -130,18 +118,25 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.setYVelDisplay(yVel); this.setXVelDisplay(xVel); this.props.dataDoc['accelerationYDisplay'] = - (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100 + (-1 * Math.round(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 100)) / 100 ; this.props.dataDoc['accelerationXDisplay'] = - Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100 + Math.round(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 100) / 100 ; }; + componentDidMount() { + // Timer for animating the simulation + setInterval(() => { + this.setState({timer: this.state.timer + 1}); + }, 60); + } + componentDidUpdate(prevProps: Readonly<IWeightProps>, prevState: Readonly<IState>, snapshot?: any): void { // When display values updated by user, update real values - if (this.props.updateDisplay != prevProps.updateDisplay) { - if (this.props.updateDisplay.xDisplay != this.state.xPosition) { - let x = this.props.updateDisplay.xDisplay; + if (this.props.dataDoc['updateDisplay'] != prevProps.dataDoc['updateDisplay']) { + if (this.props.dataDoc['positionXDisplay'] != this.state.xPosition) { + let x = this.props.dataDoc['positionXDisplay']; x = Math.max(0, x); x = Math.min(x, this.props.xMax - 2 * this.props.radius); this.setState({updatedStartPosX: x}) @@ -149,8 +144,8 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.props.dataDoc['positionXDisplay'] = x; } - if (this.props.updateDisplay.yDisplay != this.getDisplayYPos(this.state.yPosition)) { - let y = this.props.updateDisplay.yDisplay; + if (this.props.dataDoc['positionYDisplay'] != this.getDisplayYPos(this.state.yPosition)) { + let y = this.props.dataDoc['positionYDisplay']; y = Math.max(0, y); y = Math.min(y, this.props.yMax - 2 * this.props.radius); this.props.dataDoc['positionYDisplay'] = y; @@ -172,10 +167,11 @@ export default class Weight extends React.Component<IWeightProps, IState> { } } // Update sim - if (this.props.dataDoc['incrementTime'] != prevProps.dataDoc['incrementTime']) { + if (this.state.timer != prevState.timer) { if (!this.props.dataDoc['simulationPaused']) { + console.log('update') let collisions = false; - if (!this.props.pendulum) { + if (!this.props.dataDoc['pendulum']) { const collisionsWithGround = this.checkForCollisionsWithGround(); const collisionsWithWalls = this.checkForCollisionsWithWall(); collisions = collisionsWithGround || collisionsWithWalls; @@ -203,10 +199,10 @@ export default class Weight extends React.Component<IWeightProps, IState> { touchAction: "none", }; - if (this.props.reset != prevProps.reset) { + if (this.props.dataDoc['simulationReset'] != prevProps.dataDoc['simulationReset']) { this.resetEverything(); } - if (this.props.startForces != prevProps.startForces) { + if (this.props.dataDoc['startForces'] != prevProps.dataDoc['startForces']) { this.setState({xVelocity: this.props.startVelX ?? 0}) this.setState({yVelocity: this.props.startVelY ?? 0}) this.setDisplayValues(); @@ -226,37 +222,37 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.setState({updatedStartPosY: yPos}) } // Update x start position - if (this.props.startPosX != prevProps.startPosX) { - this.setState({updatedStartPosX: this.props.startPosX}) - this.setState({xPosition: this.props.startPosX}) - this.setXPosDisplay(this.props.startPosX); + if (this.props.dataDoc['startPosX'] != prevProps.dataDoc['startPosX']) { + this.setState({updatedStartPosX: this.props.dataDoc['startPosX']}) + this.setState({xPosition: this.props.dataDoc['startPosX']}) + this.setXPosDisplay(this.props.dataDoc['startPosX']); } // Update y start position - if (this.props.startPosY != prevProps.startPosY) { - this.setState({updatedStartPosY: this.props.startPosY}) - this.setState({yPosition: this.props.startPosY}) - this.setYPosDisplay(this.props.startPosY); + if (this.props.dataDoc['startPosY'] != prevProps.dataDoc['startPosY']) { + this.setState({updatedStartPosY: this.props.dataDoc['startPosY']}) + this.setState({yPosition: this.props.dataDoc['startPosY']}) + this.setYPosDisplay(this.props.dataDoc['startPosY']); } if (this.state.xVelocity != prevState.xVelocity) { - if (this.props.wedge && this.state.xVelocity != 0 && !this.state.kineticFriction) { + if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) { this.setState({kineticFriction: true}); //switch from static to kinetic friction const normalForce: IForce = { description: "Normal Force", magnitude: this.forceOfGravity.magnitude * - Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), + Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), directionInDegrees: - 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, + 180 - 90 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, }; let frictionForce: IForce = { description: "Kinetic Friction Force", magnitude: - this.props.coefficientOfKineticFriction * + this.props.dataDoc['coefficientOfKineticFriction'] * this.forceOfGravity.magnitude * - Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), + Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), directionInDegrees: - 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, + 180 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, }; // reduce magnitude of friction force if necessary such that block cannot slide up plane let yForce = -this.forceOfGravity.magnitude; @@ -273,10 +269,10 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.forceOfGravity.magnitude) / Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); } - if (this.props.coefficientOfKineticFriction != 0) { - this.props.setUpdatedForces([this.forceOfGravity, normalForce, frictionForce]); + if (this.props.dataDoc['coefficientOfKineticFriction'] != 0) { + this.props.dataDoc['updatedForces'] = [this.forceOfGravity, normalForce, frictionForce]; } else { - this.props.setUpdatedForces([this.forceOfGravity, normalForce]); + this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, normalForce]); } } } @@ -288,7 +284,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.setState({yPosition: this.state.updatedStartPosY}) this.setState({xVelocity: this.props.startVelX ?? 0}) this.setState({yVelocity: this.props.startVelY ?? 0}) - this.props.setUpdatedForces(this.props.startForces) + this.props.dataDoc['updatedForces'] = (this.props.dataDoc['startForces']) this.setDisplayValues(); }; @@ -325,8 +321,8 @@ export default class Weight extends React.Component<IWeightProps, IState> { xVel: number, yVel: number ) => { - if (!this.props.pendulum) { - return this.props.updatedForces; + if (!this.props.dataDoc['pendulum']) { + return this.props.dataDoc['updatedForces']; } const x = this.props.xMax / 2 - xPos - this.props.radius; const y = yPos + this.props.radius + 5; @@ -370,7 +366,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { const maxX = this.state.xPosition + 2 * this.props.radius; const containerWidth = 300; if (this.state.xVelocity != 0) { - this.props.walls.forEach((wall) => { + this.props.dataDoc['wallPositions'].forEach((wall) => { if (wall.angleInDegrees == 90) { const wallX = (wall.xPos / 100) * 300; if (wall.xPos < 0.35) { @@ -404,7 +400,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { let collision = false; const maxY = this.state.yPosition + 2 * this.props.radius; if (this.state.yVelocity > 0) { - this.props.walls.forEach((wall) => { + this.props.dataDoc['wallPositions'] .forEach((wall) => { if (wall.angleInDegrees == 0) { const groundY = (wall.yPos / 100) * this.props.yMax; if (maxY >= groundY) { @@ -423,7 +419,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { magnitude: 9.81 * this.props.mass, directionInDegrees: wall.angleInDegrees + 90, }; - this.props.setUpdatedForces([forceOfGravity, normalForce]); + this.props.dataDoc['updatedForces'] = ([forceOfGravity, normalForce]); } collision = true; } @@ -496,9 +492,13 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.setState({yVelocity: yVel}); this.setState({xPosition: xPos}); this.setState({yPosition: yPos}); - this.props.setUpdatedForces(this.getNewForces(xPos, yPos, xVel, yVel)); + this.props.dataDoc['updatedForces'] = (this.getNewForces(xPos, yPos, xVel, yVel)); }; + + + + labelBackgroundColor = `rgba(255,255,255,0.5)`; render () { @@ -542,7 +542,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { onPointerUp={(e) => { if (this.state.dragging) { e.preventDefault(); - if (!this.props.pendulum) { + if (!this.props.dataDoc['pendulum']) { this.resetEverything(); } this.setState({dragging: false}); @@ -557,7 +557,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { } else if (newX < 0) { newX = 0; } - if (this.props.pendulum) { + if (this.props.dataDoc['pendulum']) { const x = this.props.xMax / 2 - newX - this.props.radius; const y = newY + this.props.radius + 5; let angle = (Math.atan(y / x) * 180) / Math.PI; @@ -582,7 +582,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.setState({xVelocity: this.props.startVelX ?? 0}) this.setState({yVelocity: this.props.startVelY ?? 0}) this.setDisplayValues(); - this.props.setUpdatedForces([this.forceOfGravity, forceOfTension]); + this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, forceOfTension]); } } }} @@ -591,7 +591,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { <p className="weightLabel">{this.props.mass} kg</p> </div> </div> - {this.props.pendulum && ( + {this.props.dataDoc['pendulum'] && ( <div className="rod" style={{ @@ -627,7 +627,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { )} </div> )} - {!this.state.dragging && this.props.showAcceleration && ( + {!this.state.dragging && this.props.dataDoc['showAcceleration'] && ( <div> <div style={{ @@ -654,8 +654,8 @@ export default class Weight extends React.Component<IWeightProps, IState> { <line x1={this.state.xPosition + this.props.radius} y1={this.state.yPosition + this.props.radius} - x2={this.state.xPosition + this.props.radius + this.getNewAccelerationX(this.props.updatedForces) * 5} - y2={this.state.yPosition + this.props.radius + this.getNewAccelerationY(this.props.updatedForces) * 5} + x2={this.state.xPosition + this.props.radius + this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 5} + y2={this.state.yPosition + this.props.radius + this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 5} stroke={"green"} strokeWidth="5" markerEnd="url(#accArrow)" @@ -668,13 +668,13 @@ export default class Weight extends React.Component<IWeightProps, IState> { left: this.state.xPosition + this.props.radius + - this.getNewAccelerationX(this.props.updatedForces) * 5 + + this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 5 + 25 + "px", top: this.state.yPosition + this.props.radius + - this.getNewAccelerationY(this.props.updatedForces) * 5 + + this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 5 + 25 + "px", lineHeight: 0.5, @@ -684,8 +684,8 @@ export default class Weight extends React.Component<IWeightProps, IState> { {Math.round( 100 * Math.sqrt( - Math.pow(this.getNewAccelerationX(this.props.updatedForces) * 3, 2) + - Math.pow(this.getNewAccelerationY(this.props.updatedForces) * 3, 2) + Math.pow(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 3, 2) + + Math.pow(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 3, 2) ) ) / 100}{" "} m/s<sup>2</sup> @@ -694,7 +694,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { </div> </div> )} - {!this.state.dragging && this.props.showVelocity && ( + {!this.state.dragging && this.props.dataDoc['showVelocity'] && ( <div> <div style={{ @@ -748,8 +748,8 @@ export default class Weight extends React.Component<IWeightProps, IState> { </div> )} {!this.state.dragging && - this.props.showForces && - this.props.updatedForces.map((force, index) => { + this.props.dataDoc['showForces'] && + this.props.dataDoc['updatedForces'].map((force, index) => { if (force.magnitude < this.epsilon) { return; } @@ -836,7 +836,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { > {force.description && <p>{force.description}</p>} {!force.description && <p>Force</p>} - {this.props.showForceMagnitudes && ( + {this.props.dataDoc['showForceMagnitudes'] && ( <p>{Math.round(100 * force.magnitude) / 100} N</p> )} </div> |