aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-05-24 15:04:13 -0400
committerbobzel <zzzman@gmail.com>2023-05-24 15:04:13 -0400
commit4c96bbd25d84964811838d005ff4e40487e1ec41 (patch)
tree01e7b2e33cd1e8010b9e545130c166303e11354f /src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx
parentf0dad2a437ac339e2d6126bdadfd7a110d9ff999 (diff)
more phys code streamlining
Diffstat (limited to 'src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx')
-rw-r--r--src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx251
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>
);
}