diff options
author | bobzel <zzzman@gmail.com> | 2023-05-24 15:04:13 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-05-24 15:04:13 -0400 |
commit | 4c96bbd25d84964811838d005ff4e40487e1ec41 (patch) | |
tree | 01e7b2e33cd1e8010b9e545130c166303e11354f /src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx | |
parent | f0dad2a437ac339e2d6126bdadfd7a110d9ff999 (diff) |
more phys code streamlining
Diffstat (limited to 'src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx')
-rw-r--r-- | src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx | 251 |
1 files changed, 59 insertions, 192 deletions
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx index d062cc8c5..98b0e3f04 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx @@ -14,7 +14,6 @@ interface IForce { description: string; magnitude: number; directionInDegrees: number; - component: boolean; } export interface IWeightProps { pause: () => void; @@ -250,13 +249,11 @@ export default class Weight extends React.Component<IWeightProps, IState> { description: 'Normal Force', magnitude: this.props.mass * Math.abs(this.props.gravity) * Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), directionInDegrees: 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, - component: false, }; const frictionForce: IForce = { description: 'Kinetic Friction Force', magnitude: this.props.mass * this.props.coefficientOfKineticFriction * Math.abs(this.props.gravity) * Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), directionInDegrees: 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, - component: false, }; // reduce magnitude of friction force if necessary such that block cannot slide up plane // prettier-ignore @@ -271,31 +268,26 @@ export default class Weight extends React.Component<IWeightProps, IState> { description: 'Kinetic Friction Force', magnitude: this.props.mass * this.props.coefficientOfKineticFriction * Math.abs(this.props.gravity) * Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), directionInDegrees: 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, - component: true, }; const normalForceComponent: IForce = { description: 'Normal Force', magnitude: this.props.mass * Math.abs(this.props.gravity) * Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), directionInDegrees: 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, - component: true, }; const gravityParallel: IForce = { description: 'Gravity Parallel Component', magnitude: this.props.mass * Math.abs(this.props.gravity) * Math.sin(Math.PI / 2 - Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), directionInDegrees: 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI + 180, - component: true, }; const gravityPerpendicular: IForce = { description: 'Gravity Perpendicular Component', magnitude: this.props.mass * Math.abs(this.props.gravity) * Math.cos(Math.PI / 2 - Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), directionInDegrees: 360 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, - component: true, }; const gravityForce: IForce = { description: 'Gravity', magnitude: this.props.mass * Math.abs(this.props.gravity), directionInDegrees: 270, - component: false, }; const kineticFriction = this.props.coefficientOfKineticFriction != 0; this.props.setForcesUpdated([gravityForce, normalForce, ...(kineticFriction ? [frictionForce] : [])]); @@ -394,7 +386,6 @@ export default class Weight extends React.Component<IWeightProps, IState> { description: 'Centripetal Force', magnitude: (this.props.startVelX ** 2 * this.props.mass) / this.props.circularMotionRadius, directionInDegrees: (Math.atan2(deltaY, deltaX) * 180) / Math.PI, - component: false, }, ]; }; @@ -408,13 +399,11 @@ export default class Weight extends React.Component<IWeightProps, IState> { description: 'Gravity', magnitude: Math.abs(this.props.gravity) * this.props.mass, directionInDegrees: 270, - component: false, }, { description: 'Spring Force', magnitude: this.props.springConstant * (yPos - this.props.springRestLength) * (yPosPlus ? 1 : yPosMinus ? -1 : 0), directionInDegrees: yPosPlus ? 90 : 270, - component: false, }, ]; }; @@ -442,13 +431,11 @@ export default class Weight extends React.Component<IWeightProps, IState> { description: 'Gravity', magnitude: Math.abs(this.props.gravity) * this.props.mass, directionInDegrees: 270, - component: false, }, { description: 'Tension', magnitude: mag, directionInDegrees: angle, - component: false, }, ]; }; @@ -488,7 +475,6 @@ export default class Weight extends React.Component<IWeightProps, IState> { description: 'Gravity', magnitude: Math.abs(this.props.gravity) * this.props.mass, directionInDegrees: 270, - component: false, }; if (maxY > groundY) { this.setState({ yPosition: groundY - 2 * this.props.radius - 0.01 }); @@ -500,11 +486,10 @@ export default class Weight extends React.Component<IWeightProps, IState> { description: 'Normal force', magnitude: gravity.magnitude, directionInDegrees: -gravity.directionInDegrees, - component: false, }; this.props.setForcesUpdated([gravity, normalForce]); if (this.props.simulationType === 'Inclined Plane') { - this.props.setComponentForces([gravity, { ...normalForce, component: true }]); + this.props.setComponentForces([gravity, normalForce]); } } collision = true; @@ -641,19 +626,16 @@ export default class Weight extends React.Component<IWeightProps, IState> { description: 'Tension', magnitude: mag, directionInDegrees: angle, - component: true, }; const gravityParallel: IForce = { description: 'Gravity Parallel Component', 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(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180), directionInDegrees: -(90 - angle), - component: true, }; if (Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180) < 0) { gravityPerpendicular.magnitude = Math.abs(Math.abs(this.props.gravity) * Math.sin(((90 - angle) * Math.PI) / 180)); @@ -663,6 +645,57 @@ export default class Weight extends React.Component<IWeightProps, IState> { } }; + renderForce = (force: IForce, index: number, asComponent: boolean) => { + if (force.magnitude < this.epsilon) return; + + const angle = (force.directionInDegrees * Math.PI) / 180; + const arrowStartY = this.state.yPosition + this.props.radius - this.props.radius * Math.sin(angle); + const arrowStartX = this.state.xPosition + this.props.radius + this.props.radius * Math.cos(angle); + const arrowEndY = arrowStartY - Math.abs(force.magnitude) * Math.sin(angle) - this.props.radius * Math.sin(angle); + const arrowEndX = arrowStartX + Math.abs(force.magnitude) * Math.cos(angle) + this.props.radius * Math.cos(angle); + + const color = '#0d0d0d'; + + let labelTop = arrowEndY + (force.directionInDegrees >= 0 && force.directionInDegrees < 180 ? 40 : -40); + let labelLeft = arrowEndX + (force.directionInDegrees > 90 && force.directionInDegrees < 270 ? -120 : 30); + + labelTop = Math.max(Math.min(labelTop, this.props.yMax + 50), this.props.yMin); + labelLeft = Math.max(Math.min(labelLeft, this.props.xMax - 60), this.props.xMin); + + return ( + <div key={index} style={{ zIndex: 6, position: 'absolute' }}> + <div + style={{ + pointerEvents: 'none', + position: 'absolute', + left: this.props.xMin, + top: this.props.yMin, + }}> + <svg width={this.props.xMax - this.props.xMin + 'px'} height={this.panelHeight}> + <defs> + <marker id="forceArrow" markerWidth="4" markerHeight="4" refX="0" refY="2" orient="auto" markerUnits="strokeWidth"> + <path d="M0,0 L0,4 L4,2 z" fill={color} /> + </marker> + </defs> + <line strokeDasharray={asComponent ? '10,10' : undefined} x1={arrowStartX} y1={arrowStartY} x2={arrowEndX} y2={arrowEndY} stroke={color} strokeWidth="5" markerEnd="url(#forceArrow)" /> + </svg> + </div> + <div + style={{ + pointerEvents: 'none', + position: 'absolute', + left: labelLeft + 'px', + top: labelTop + 'px', + lineHeight: 1, + backgroundColor: this.labelBackgroundColor, + }}> + <p>{force.description || 'Force'}</p> + {this.props.showForceMagnitudes && <p>{Math.round(100 * force.magnitude) / 100} N</p>} + </div> + </div> + ); + }; + // Render weight, spring, rod(s), vectors render() { return ( @@ -757,19 +790,16 @@ export default class Weight extends React.Component<IWeightProps, IState> { description: 'Tension', magnitude: tensionMag1, directionInDegrees: (dir1T * 180) / Math.PI, - component: false, }; const tensionForce2: IForce = { description: 'Tension', magnitude: tensionMag2, directionInDegrees: (dir2T * 180) / Math.PI, - component: false, }; const grav: IForce = { description: 'Gravity', magnitude: this.props.mass * Math.abs(this.props.gravity), directionInDegrees: 270, - component: false, }; this.props.setForcesUpdated([tensionForce1, tensionForce2, grav]); } @@ -802,14 +832,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { )} {this.props.simulationType == 'Pulley' && ( - <div - className="rod" - style={{ - pointerEvents: 'none', - position: 'absolute', - left: 0, - top: 0, - }}> + <div className="rod"> <svg width={this.panelWidth} height={this.panelHeight}> <line // x1={this.state.xPosition + this.props.radius} @@ -837,14 +860,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { </div> )} {this.props.simulationType == 'Suspension' && ( - <div - className="rod" - style={{ - pointerEvents: 'none', - position: 'absolute', - left: 0, - top: 0, - }}> + <div className="rod"> <svg width={this.panelWidth} height={this.panelHeight}> <line x1={this.state.xPosition + this.props.radius} @@ -867,14 +883,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { ) / 100} ° </p> - <div - className="rod" - style={{ - pointerEvents: 'none', - position: 'absolute', - left: 0, - top: 0, - }}> + <div className="rod"> <svg width={this.props.panelWidth() + 'px'} height={this.panelHeight}> <line x1={this.state.xPosition + this.props.radius} @@ -902,14 +911,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { </div> )} {this.props.simulationType == 'Circular Motion' && ( - <div - className="rod" - style={{ - pointerEvents: 'none', - position: 'absolute', - left: 0, - top: 0, - }}> + <div className="rod"> <svg width={this.panelWidth} height={this.panelHeight}> <line x1={this.state.xPosition + this.props.radius} @@ -923,14 +925,7 @@ export default class Weight extends React.Component<IWeightProps, IState> { </div> )} {this.props.simulationType == 'Pendulum' && ( - <div - className="rod" - style={{ - pointerEvents: 'none', - position: 'absolute', - left: 0, - top: 0, - }}> + <div className="rod"> <svg width={this.panelWidth} height={this.panelHeight}> <line x1={this.state.xPosition + this.props.radius} y1={this.state.yPosition + this.props.radius} x2={this.props.xMax / 2} y2={-5} stroke={'#deb887'} strokeWidth="10" /> </svg> @@ -1056,136 +1051,8 @@ export default class Weight extends React.Component<IWeightProps, IState> { </div> </div> )} - {!this.state.dragging && - this.props.showComponentForces && - this.props.componentForces().map((force, index) => { - if (force.magnitude < this.epsilon) { - return; - } - const arrowStartY = this.state.yPosition + this.props.radius; - const arrowStartX = this.state.xPosition + this.props.radius; - const arrowEndY = arrowStartY - Math.abs(force.magnitude) * 20 * Math.sin((force.directionInDegrees * Math.PI) / 180); - const arrowEndX = arrowStartX + Math.abs(force.magnitude) * 20 * Math.cos((force.directionInDegrees * Math.PI) / 180); - - const color = '#0d0d0d'; - - let labelTop = arrowEndY; - let labelLeft = arrowEndX; - if (force.directionInDegrees > 90 && force.directionInDegrees < 270) { - labelLeft -= 120; - } else { - labelLeft += 30; - } - if (force.directionInDegrees >= 0 && force.directionInDegrees < 180) { - labelTop += 40; - } else { - labelTop -= 40; - } - labelTop = Math.min(labelTop, this.props.yMax + 50); - labelTop = Math.max(labelTop, this.props.yMin); - labelLeft = Math.min(labelLeft, this.props.xMax - 60); - labelLeft = Math.max(labelLeft, this.props.xMin); - - return ( - <div key={index}> - <div - style={{ - pointerEvents: 'none', - position: 'absolute', - left: this.props.xMin, - top: this.props.yMin, - }}> - <svg width={this.props.xMax - this.props.xMin + 'px'} height={this.panelHeight}> - <defs> - <marker id="forceArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth"> - <path d="M0,0 L0,6 L9,3 z" fill={color} /> - </marker> - </defs> - {force.component == true && <line x1={arrowStartX} y1={arrowStartY} x2={arrowEndX} y2={arrowEndY} stroke={color} strokeWidth="5" strokeDasharray="10,10" markerEnd="url(#forceArrow)" />} - {force.component == false && <line x1={arrowStartX} y1={arrowStartY} x2={arrowEndX} y2={arrowEndY} stroke={color} strokeWidth="5" markerEnd="url(#forceArrow)" />} - </svg> - </div> - <div - style={{ - pointerEvents: 'none', - position: 'absolute', - left: labelLeft + 'px', - top: labelTop + 'px', - lineHeight: 1, - backgroundColor: this.labelBackgroundColor, - }}> - {force.description && <p>{force.description}</p>} - {!force.description && <p>Force</p>} - {this.props.showForceMagnitudes && <p>{Math.round(100 * force.magnitude) / 100} N</p>} - </div> - </div> - ); - })} - {!this.state.dragging && - this.props.showForces && - this.props.forcesUpdated().map((force, index) => { - if (force.magnitude < this.epsilon) { - return; - } - const arrowStartY = this.state.yPosition + this.props.radius; - const arrowStartX = this.state.xPosition + this.props.radius; - const arrowEndY = arrowStartY - Math.abs(force.magnitude) * 20 * Math.sin((force.directionInDegrees * Math.PI) / 180); - const arrowEndX = arrowStartX + Math.abs(force.magnitude) * 20 * Math.cos((force.directionInDegrees * Math.PI) / 180); - - const color = '#0d0d0d'; - - let labelTop = arrowEndY; - let labelLeft = arrowEndX; - if (force.directionInDegrees > 90 && force.directionInDegrees < 270) { - labelLeft -= 120; - } else { - labelLeft += 30; - } - if (force.directionInDegrees >= 0 && force.directionInDegrees < 180) { - labelTop += 40; - } else { - labelTop -= 40; - } - labelTop = Math.min(labelTop, this.props.yMax + 50); - labelTop = Math.max(labelTop, this.props.yMin); - labelLeft = Math.min(labelLeft, this.props.xMax - 60); - labelLeft = Math.max(labelLeft, this.props.xMin); - - return ( - <div key={index}> - <div - style={{ - pointerEvents: 'none', - position: 'absolute', - left: this.props.xMin, - top: this.props.yMin, - }}> - <svg width={this.props.xMax - this.props.xMin + 'px'} height={this.panelHeight}> - <defs> - <marker id="forceArrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth"> - <path d="M0,0 L0,6 L9,3 z" fill={color} /> - </marker> - </defs> - {force.component == true && <line x1={arrowStartX} y1={arrowStartY} x2={arrowEndX} y2={arrowEndY} stroke={color} strokeWidth="5" strokeDasharray="10,10" markerEnd="url(#forceArrow)" />} - {force.component == false && <line x1={arrowStartX} y1={arrowStartY} x2={arrowEndX} y2={arrowEndY} stroke={color} strokeWidth="5" markerEnd="url(#forceArrow)" />} - </svg> - </div> - <div - style={{ - pointerEvents: 'none', - position: 'absolute', - left: labelLeft + 'px', - top: labelTop + 'px', - lineHeight: 1, - backgroundColor: this.labelBackgroundColor, - }}> - {force.description && <p>{force.description}</p>} - {!force.description && <p>Force</p>} - {this.props.showForceMagnitudes && <p>{Math.round(100 * force.magnitude) / 100} N</p>} - </div> - </div> - ); - })} + {!this.state.dragging && this.props.showComponentForces && this.props.componentForces().map((force, index) => this.renderForce(force, index, true))} + {!this.state.dragging && this.props.showForces && this.props.forcesUpdated().map((force, index) => this.renderForce(force, index, false))} </div> ); } |