diff options
Diffstat (limited to 'src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx')
-rw-r--r-- | src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx | 257 |
1 files changed, 125 insertions, 132 deletions
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx index ab23c42c0..f43994346 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx @@ -179,13 +179,59 @@ export default class Weight extends React.Component<IWeightProps, IState> { }; componentDidUpdate(prevProps: Readonly<IWeightProps>, prevState: Readonly<IState>, snapshot?: any): void { - } - - - - + // Change pendulum angle from input field + if (prevProps.adjustPendulumAngle != this.props.adjustPendulumAngle) { + let length = this.props.adjustPendulumAngle.length; + const x = + length * Math.cos(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180); + const y = + length * Math.sin(((90 - this.props.adjustPendulumAngle.angle) * 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['pendulumAngle'] = this.props.adjustPendulumAngle.angle + this.props.dataDoc['pendulumLength'] = this.props.adjustPendulumAngle.length + } + // When display values updated by user, update real values + if (prevProps.updateDisplay != this.props.updateDisplay) { + if (this.props.updateDisplay.xDisplay != this.state.xPosition) { + let x = this.props.updateDisplay.xDisplay; + x = Math.max(0, x); + x = Math.min(x, this.props.xMax - 2 * this.props.radius); + this.setState({updatedStartPosX: x}) + this.setState({xPosition: x}) + this.props.dataDoc['positionXDisplay'] = x + } + + if (this.props.updateDisplay.yDisplay != this.getDisplayYPos(this.state.yPosition)) { + let y = this.props.updateDisplay.yDisplay; + y = Math.max(0, y); + y = Math.min(y, this.props.yMax - 2 * this.props.radius); + let coordinatePosition = this.getYPosFromDisplay(y); + this.setState({updatedStartPosY: coordinatePosition}) + this.setState({yPosition: coordinatePosition}) + this.props.dataDoc['positionYDisplay'] = y + } + + if (this.props.displayXVelocity != this.state.xVelocity) { + let x = this.props.displayXVelocity; + this.setState({xVelocity: x}) + this.props.dataDoc['velocityXDisplay'] = x + } + + if (this.props.displayYVelocity != -this.state.yVelocity) { + let y = this.props.displayYVelocity; + this.setState({yVelocity: -y}) + this.props.dataDoc['velocityYDisplay'] = y + } + } + // TODO move all use effect code here + } // Reset simulation on reset button click resetEverything = () => { @@ -205,9 +251,6 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle']* 100) / 100}) }; - - - // Compute x acceleration from forces, F=ma getNewAccelerationX = (forceList: IForce[]) => { let newXAcc = 0; @@ -275,7 +318,6 @@ export default class Weight extends React.Component<IWeightProps, IState> { component: false, }; } - return [ { description: "Gravity", @@ -309,7 +351,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { this.props.dataDoc['pendulumAngle'] = oppositeAngle; const mag = - this.props.mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) + + this.props.mass * Math.abs(this.props.gravity) * Math.cos((oppositeAngle * Math.PI) / 180) + (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength; const forceOfTension: IForce = { @@ -437,7 +479,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { }; // Called at each RK4 step - const evaluate = ( + evaluate = ( currentXPos: number, currentYPos: number, currentXVel: number, @@ -454,16 +496,16 @@ export default class Weight extends React.Component<IWeightProps, IState> { const newYVel = currentYVel + deltaYVel * dt; const newDeltaXPos = newXVel; const newDeltaYPos = newYVel; - let forces = updatedForces; + let forces = this.props.dataDoc['updatedForces']; if (this.props.dataDoc['simulationType'] == "Pendulum") { - forces = getNewPendulumForces(newXPos, newYPos, newXVel, newYVel); + forces = this.getNewPendulumForces(newXPos, newYPos, newXVel, newYVel); } else if (this.props.dataDoc['simulationType'] == "Spring") { - forces = getNewSpringForces(newYPos); + forces = this.getNewSpringForces(newYPos); } else if (this.props.dataDoc['simulationType'] == "Circular Motion") { - forces = getNewCircularMotionForces(newXPos, newYPos); + forces = this.getNewCircularMotionForces(newXPos, newYPos); } - const newDeltaXVel = getNewAccelerationX(forces); - const newDeltaYVel = getNewAccelerationY(forces); + const newDeltaXVel = this.getNewAccelerationX(forces); + const newDeltaYVel = this.getNewAccelerationY(forces); return { xPos: newXPos, yPos: newYPos, @@ -477,26 +519,26 @@ export default class Weight extends React.Component<IWeightProps, IState> { }; // Update position, velocity using RK4 method - const update = () => { - let startXVel = xVelocity; - let startYVel = yVelocity; - let xPos = xPosition; - let yPos = yPosition; - let xVel = xVelocity; - let yVel = yVelocity; - let forces = updatedForces; + update = () => { + let startXVel = this.state.xVelocity; + let startYVel = this.state.yVelocity; + let xPos = this.state.xPosition; + let yPos = this.state.yPosition; + let xVel = this.state.xVelocity; + let yVel = this.state.yVelocity; + let forces = this.props.dataDoc['updatedForces']; if (this.props.dataDoc['simulationType'] == "Pendulum") { - forces = getNewPendulumForces(xPos, yPos, xVel, yVel); + forces = this.getNewPendulumForces(xPos, yPos, xVel, yVel); } else if (this.props.dataDoc['simulationType'] == "Spring") { - forces = getNewSpringForces(yPos); + forces = this.getNewSpringForces(yPos); } else if (this.props.dataDoc['simulationType'] == "Circular Motion") { - forces = getNewCircularMotionForces(xPos, yPos); + forces = this.getNewCircularMotionForces(xPos, yPos); } - const xAcc = getNewAccelerationX(forces); - const yAcc = getNewAccelerationY(forces); - for (let i = 0; i < simulationSpeed; i++) { - const k1 = evaluate(xPos, yPos, xVel, yVel, xVel, yVel, xAcc, yAcc, 0); - const k2 = evaluate( + const xAcc = this.getNewAccelerationX(forces); + const yAcc = this.getNewAccelerationY(forces); + for (let i = 0; i < this.props.simulationSpeed; i++) { + const k1 = this.evaluate(xPos, yPos, xVel, yVel, xVel, yVel, xAcc, yAcc, 0); + const k2 = this.evaluate( xPos, yPos, xVel, @@ -505,9 +547,9 @@ export default class Weight extends React.Component<IWeightProps, IState> { k1.deltaYPos, k1.deltaXVel, k1.deltaYVel, - timestepSize * 0.5 + this.props.timestepSize * 0.5 ); - const k3 = evaluate( + const k3 = this.evaluate( xPos, yPos, xVel, @@ -516,9 +558,9 @@ export default class Weight extends React.Component<IWeightProps, IState> { k2.deltaYPos, k2.deltaXVel, k2.deltaYVel, - timestepSize * 0.5 + this.props.timestepSize * 0.5 ); - const k4 = evaluate( + const k4 = this.evaluate( xPos, yPos, xVel, @@ -527,75 +569,75 @@ export default class Weight extends React.Component<IWeightProps, IState> { k3.deltaYPos, k3.deltaXVel, k3.deltaYVel, - timestepSize + this.props.timestepSize ); xVel += - ((timestepSize * 1.0) / 6.0) * + ((this.props.timestepSize * 1.0) / 6.0) * (k1.deltaXVel + 2 * (k2.deltaXVel + k3.deltaXVel) + k4.deltaXVel); yVel += - ((timestepSize * 1.0) / 6.0) * + ((this.props.timestepSize * 1.0) / 6.0) * (k1.deltaYVel + 2 * (k2.deltaYVel + k3.deltaYVel) + k4.deltaYVel); xPos += - ((timestepSize * 1.0) / 6.0) * + ((this.props.timestepSize * 1.0) / 6.0) * (k1.deltaXPos + 2 * (k2.deltaXPos + k3.deltaXPos) + k4.deltaXPos); yPos += - ((timestepSize * 1.0) / 6.0) * + ((this.props.timestepSize * 1.0) / 6.0) * (k1.deltaYPos + 2 * (k2.deltaYPos + k3.deltaYPos) + k4.deltaYPos); } // make sure harmonic motion maintained and errors don't propagate if (this.props.dataDoc['simulationType'] == "Spring") { - if (startYVel < 0 && yVel > 0 && yPos < springRestLength) { + if (startYVel < 0 && yVel > 0 && yPos < this.props.springRestLength) { let equilibriumPos = - springRestLength + (mass * Math.abs(gravity)) / springConstant; - let amplitude = Math.abs(equilibriumPos - springStartLength); + this.props.springRestLength + (this.props.mass * Math.abs(this.props.gravity)) / this.props.springConstant; + let amplitude = Math.abs(equilibriumPos - this.props.springStartLength); yPos = equilibriumPos - amplitude; - } else if (startYVel > 0 && yVel < 0 && yPos > springRestLength) { + } else if (startYVel > 0 && yVel < 0 && yPos > this.props.springRestLength) { let equilibriumPos = - springRestLength + (mass * Math.abs(gravity)) / springConstant; - let amplitude = Math.abs(equilibriumPos - springStartLength); + this.props.springRestLength + (this.props.mass * Math.abs(this.props.gravity)) / this.props.springConstant; + let amplitude = Math.abs(equilibriumPos - this.props.springStartLength); yPos = equilibriumPos + amplitude; } } if (this.props.dataDoc['simulationType'] == "Pendulum") { - let startX = updatedStartPosX; + let startX = this.state.updatedStartPosX; if (startXVel <= 0 && xVel > 0) { - xPos = updatedStartPosX; - if (updatedStartPosX > xMax / 2) { - xPos = xMax / 2 + (xMax / 2 - startX) - 2 * radius; + xPos = this.state.updatedStartPosX; + if (this.state.updatedStartPosX > this.props.xMax / 2) { + xPos = this.props.xMax / 2 + (this.props.xMax / 2 - startX) - 2 * this.props.radius; } - yPos = startPosY; + yPos = this.props.startPosY; } else if (startXVel >= 0 && xVel < 0) { - xPos = updatedStartPosX; - if (updatedStartPosX < xMax / 2) { - xPos = xMax / 2 + (xMax / 2 - startX) - 2 * radius; + xPos = this.state.updatedStartPosX; + if (this.state.updatedStartPosX < this.props.xMax / 2) { + xPos = this.props.xMax / 2 + (this.props.xMax / 2 - startX) - 2 * this.props.radius; } - yPos = startPosY; + yPos = this.props.startPosY; } } if (this.props.dataDoc['simulationType'] == "One Weight") { - if (yPos < maxPosYConservation) { - yPos = maxPosYConservation; + if (yPos < this.state.maxPosYConservation) { + yPos = this.state.maxPosYConservation; } } - setXVelocity(xVel); - setYVelocity(yVel); - setXPosition(xPos); - setYPosition(yPos); - let forcesn = updatedForces; + this.setState({xVelocity: xVel}); + this.setState({yVelocity: yVel}); + this.setState({xPosition: xPos}); + this.setState({yPosition: yPos}); + let forcesn = this.props.dataDoc['updatedForces'] if (this.props.dataDoc['simulationType'] == "Pendulum") { - forcesn = getNewPendulumForces(xPos, yPos, xVel, yVel); + forcesn = this.getNewPendulumForces(xPos, yPos, xVel, yVel); } else if (this.props.dataDoc['simulationType'] == "Spring") { - forcesn = getNewSpringForces(yPos); + forcesn = this.getNewSpringForces(yPos); } else if (this.props.dataDoc['simulationType'] == "Circular Motion") { - forcesn = getNewCircularMotionForces(xPos, yPos); + forcesn = this.getNewCircularMotionForces(xPos, yPos); } - setUpdatedForces(forcesn); + this.props.dataDoc['updatedForces'] = (forcesn); // set component forces if they change if (this.props.dataDoc['simulationType'] == "Pendulum") { - let x = xMax / 2 - xPos - radius; - let y = yPos + radius + 5; + let x = this.props.xMax / 2 - xPos - this.props.radius; + let y = yPos + this.props.radius + 5; let angle = (Math.atan(y / x) * 180) / Math.PI; if (angle < 0) { angle += 180; @@ -608,8 +650,8 @@ export default class Weight extends React.Component<IWeightProps, IState> { const pendulumLength = Math.sqrt(x * x + y * y); const mag = - mass * Math.abs(gravity) * Math.cos((oppositeAngle * Math.PI) / 180) + - (mass * (xVel * xVel + yVel * yVel)) / pendulumLength; + this.props.mass * Math.abs(this.props.gravity) * Math.cos((oppositeAngle * Math.PI) / 180) + + (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength; const tensionComponent: IForce = { description: "Tension", @@ -619,23 +661,23 @@ export default class Weight extends React.Component<IWeightProps, IState> { }; const gravityParallel: IForce = { description: "Gravity Parallel Component", - magnitude: Math.abs(gravity) * Math.cos(((90 - angle) * Math.PI) / 180), + magnitude: Math.abs(this.props.gravity) * Math.cos(((90 - angle) * Math.PI) / 180), directionInDegrees: 270 - (90 - angle), component: true, }; const gravityPerpendicular: IForce = { description: "Gravity Perpendicular Component", - magnitude: Math.abs(gravity) * Math.sin(((90 - angle) * Math.PI) / 180), + magnitude: Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180), directionInDegrees: -(90 - angle), component: true, }; - if (Math.abs(gravity) * Math.sin(((90 - angle) * Math.PI) / 180) < 0) { + if (Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180) < 0) { gravityPerpendicular.magnitude = Math.abs( - Math.abs(gravity) * Math.sin(((90 - angle) * Math.PI) / 180) + Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180) ); gravityPerpendicular.directionInDegrees = 180 - (90 - angle); } - setComponentForces([ + this.props.dataDoc['componentForces'] = ([ tensionComponent, gravityParallel, gravityPerpendicular, @@ -643,57 +685,8 @@ export default class Weight extends React.Component<IWeightProps, IState> { } }; - // Change pendulum angle based on input field - useEffect(() => { - let length = adjustPendulumAngle.length; - const x = - length * Math.cos(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); - const y = - length * Math.sin(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); - const xPos = xMax / 2 - x - radius; - const yPos = y - radius - 5; - setXPosition(xPos); - setYPosition(yPos); - setUpdatedStartPosX(xPos); - setUpdatedStartPosY(yPos); - setPendulumAngle(adjustPendulumAngle.angle); - setPendulumLength(adjustPendulumAngle.length); - }, [adjustPendulumAngle]); - - // When display values updated by user, update real values - useEffect(() => { - if (updateDisplay.xDisplay != xPosition) { - let x = updateDisplay.xDisplay; - x = Math.max(0, x); - x = Math.min(x, xMax - 2 * radius); - setUpdatedStartPosX(x); - setXPosition(x); - setDisplayXPosition(x); - } - - if (updateDisplay.yDisplay != getDisplayYPos(yPosition)) { - let y = updateDisplay.yDisplay; - y = Math.max(0, y); - y = Math.min(y, yMax - 2 * radius); - setDisplayYPosition(y); - let coordinatePosition = getYPosFromDisplay(y); - setUpdatedStartPosY(coordinatePosition); - setYPosition(coordinatePosition); - } - - if (displayXVelocity != xVelocity) { - let x = displayXVelocity; - setXVelocity(x); - setDisplayXVelocity(x); - } - - if (displayYVelocity != -yVelocity) { - let y = displayYVelocity; - setYVelocity(-y); - setDisplayYVelocity(y); - } - }, [updateDisplay]); + // TODO // Prevent bug when switching between sims useEffect(() => { setXVelocity(startVelX); @@ -843,16 +836,16 @@ export default class Weight extends React.Component<IWeightProps, IState> { component: false, }; if (coefficientOfKineticFriction != 0) { - setUpdatedForces([gravityForce, normalForce, frictionForce]); - setComponentForces([ + this.props.dataDoc['updatedForces'] = ([gravityForce, normalForce, frictionForce]); + this.props.dataDoc['componentForces'] = ([ frictionForceComponent, normalForceComponent, gravityParallel, gravityPerpendicular, ]); } else { - setUpdatedForces([gravityForce, normalForce]); - setComponentForces([ + this.props.dataDoc['updatedForces'] = ([gravityForce, normalForce]); + this.props.dataDoc['componentForces'] = ([ normalForceComponent, gravityParallel, gravityPerpendicular, @@ -1020,7 +1013,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { directionInDegrees: 270, component: false, }; - setUpdatedForces([tensionForce1, tensionForce2, grav]); + this.props.dataDoc['updatedForces'] = ([tensionForce1, tensionForce2, grav]); } } }} |