Skip to main content

Dynamics

The DynamicsExtensions class provides extension methods for particle dynamics โ€” forces, momentum, energy, work, power, and collisions.

๐Ÿ‹๏ธ Newton's Lawsโ€‹

Compute acceleration from force, force from mass and acceleration, net force, and weight:

Fโƒ—=maโƒ—,aโƒ—=Fโƒ—m,Wโƒ—=mgโƒ—\vec{F} = m\vec{a}, \quad \vec{a} = \frac{\vec{F}}{m}, \quad \vec{W} = m\vec{g}

// Newton's 2nd law: a = F/m
var force = new Vector(10, 0, 0);
Vector acceleration = force.Acceleration(mass: 5); // (2, 0, 0)

// F = ma
Vector F = 10.0.Force(new Vector(0, 0, -9.8)); // (0, 0, -98)

// Sum of forces
Vector net = f1.NetForce(f2, f3);

// Weight (default direction: -Z)
Vector W = 80.0.Weight(); // (0, 0, -784.5)

๐Ÿ’ฅ Momentum & Impulseโ€‹

Compute linear momentum and impulse:

pโƒ—=mvโƒ—,Jโƒ—=Fโƒ—โ€‰ฮ”t=mโ€‰ฮ”vโƒ—\vec{p} = m\vec{v}, \quad \vec{J} = \vec{F}\,\Delta t = m\,\Delta\vec{v}

Vector p = 5.0.Momentum(new Vector(3, 4, 0));         // (15, 20, 0)
Vector J = force.Impulse(duration: 0.5); // Fยทฮ”t
Vector J2 = mass.ImpulseFromVelocityChange(vBefore, vAfter); // mยทฮ”v
Vector vNew = impulse.ApplyImpulse(mass: 5, v0); // v + J/m

โšก Energyโ€‹

Compute kinetic energy, potential energy, and mechanical energy:

KE=12mv2,PE=mgh,U=โˆ’Gm1m2r,E=KE+PEKE = \tfrac{1}{2}mv^2, \quad PE = mgh, \quad U = -\frac{Gm_1 m_2}{r}, \quad E = KE + PE

double ke = 4.0.KineticEnergy(new Vector(3, 4, 0));   // ยฝmvยฒ = 50 J
double pe = 10.0.PotentialEnergy(height: 5); // mgh
double U = m1.GravitationalPotentialEnergy(m2, r); // -Gmโ‚mโ‚‚/r
double E = mass.MechanicalEnergy(velocity, height); // KE + PE
double v = mass.SpeedFromKineticEnergy(ke); // โˆš(2ยทKE/m)

๐Ÿ”ง Work & Powerโ€‹

Compute work done by a force and instantaneous or average power:

W=Fโƒ—โ‹…dโƒ—,W=Fdcosโกฮธ,P=Fโƒ—โ‹…vโƒ—,Pห‰=Wฮ”t,ฮ”KE=12m(v22โˆ’v12)W = \vec{F} \cdot \vec{d}, \quad W = Fd\cos\theta, \quad P = \vec{F} \cdot \vec{v}, \quad \bar{P} = \frac{W}{\Delta t}, \quad \Delta KE = \tfrac{1}{2}m(v_2^2 - v_1^2)

double W = force.Work(displacement);                   // Fยทd (dot product)
double W2 = 10.0.Work(5, angleRadians: Math.PI / 3); // Fยทdยทcos(ฮธ) = 25 J
double P = force.Power(velocity); // Fยทv (instantaneous)
double P2 = 100.0.AveragePower(duration: 5); // W/ฮ”t = 20 W
double ฮ”KE = mass.WorkEnergyTheorem(vBefore, vAfter); // ยฝm(vโ‚‚ยฒ - vโ‚ยฒ)

๐Ÿ’ซ Elastic & Inelastic Collisionsโ€‹

Compute outcomes of 1D and 3D collisions:

m1v1+m2v2=m1v1โ€ฒ+m2v2โ€ฒ,e=v2โ€ฒโˆ’v1โ€ฒv1โˆ’v2m_1 v_1 + m_2 v_2 = m_1 v_1' + m_2 v_2', \quad e = \frac{v_2' - v_1'}{v_1 - v_2}

// 1D elastic collision โ€” both momentum and energy conserved
var (v1f, v2f) = m1.ElasticCollision(v1, m2, v2);

// Perfectly inelastic (sticky) collision
double vf = m1.InelasticCollisionVelocity(v1, m2, v2);
Vector vf3d = m1.InelasticCollisionVelocity(v1Vec, m2, v2Vec); // 3D version
double loss = m1.InelasticCollisionEnergyLoss(v1, m2, v2);

// Coefficient of restitution: e = 1 (elastic), e = 0 (perfectly inelastic)
double e = v1Before.CoefficientOfRestitution(v2Before, v1After, v2After);

๐Ÿงฑ Rigid Bodyโ€‹

Create rigid bodies from standard shapes with automatic inertia tensors:

var sphere  = RigidBody.CreateSolidSphere(mass: 10, radius: 2);
var box = RigidBody.CreateSolidBox(mass: 12, width: 2, height: 3, depth: 4);
var cyl = RigidBody.CreateSolidCylinder(mass: 6, radius: 1, height: 4);
var hollow = RigidBody.CreateHollowSphere(mass: 5, radius: 3);
var tube = RigidBody.CreateHollowCylinder(mass: 8, innerRadius: 1, outerRadius: 2, height: 3);
var rod = RigidBody.CreateThinRod(mass: 4, length: 5);
var wall = RigidBody.CreateStatic(new Vector(0, 0, 0)); // immovable

Apply forces, torques, and query state:

var body = RigidBody.CreateSolidSphere(10, 1);
body.Position = new Vector(0, 5, 0);
body.Velocity = new Vector(3, 0, 0);

body.ApplyForce(new Vector(0, 0, -98)); // gravity
body.ApplyForceAtPoint( // generates torque too
new Vector(10, 0, 0), worldPoint: new Vector(0, 1, 0));
body.ApplyTorque(new Vector(0, 0, 5));

Vector a = body.LinearAcceleration; // F/m
Vector alpha = body.AngularAcceleration; // Iโปยนฯ„
Vector p = body.LinearMomentum; // mv
Vector L = body.AngularMomentum; // Iฯ‰
double KE = body.KineticEnergy; // ยฝmvยฒ + ยฝฯ‰แต€Iฯ‰

body.ClearForces(); // reset accumulators after integration step

โฑ๏ธ RigidBody Integrationโ€‹

Three time-stepping methods advance a RigidBody by one dt. Each delegates to the corresponding ODE solver in DifferentialEquationExtensions, packing body state into VectorN internally.

// Semi-implicit (symplectic) Euler โ€” stable for games, first-order
// Apply forces before calling; accumulators are cleared afterwards
var body = RigidBody.CreateSolidSphere(10, 1);
body.Position = new Vector(0, 0, 100);
body.ApplyForce(new Vector(0, 0, -9.80665 * body.Mass));
body.IntegrateSemiImplicitEuler(dt: 0.001);

// Velocity Verlet โ€” O(dtยฒ) accuracy, excellent energy conservation
// Forces are evaluated by forceFunc (no need to pre-apply)
Func<RigidBody, (Vector force, Vector torque)> gravity = b =>
(new Vector(0, 0, -9.80665 * b.Mass), new Vector(0, 0, 0));
body.IntegrateVelocityVerlet(gravity, dt: 0.01);

// Explicit Euler โ€” simplest, least stable
body.ApplyForce(new Vector(0, 0, -9.80665 * body.Mass));
body.IntegrateEuler(dt: 0.001);

๐Ÿงฒ Common Force Modelsโ€‹

Ready-made force functions for building simulations โ€” combine them in a forceFunc for the integrators.

// Spring (Hooke's law): F = -kยท(|ฮ”r| - Lโ‚€)ยทrฬ‚
var spring = 50.0.SpringForce(restLength: 2.0, position, anchor);

// Viscous damping: F = -cยทv
var damping = 0.5.DampingForce(velocity);

// Aerodynamic drag: F = -ยฝยทCdยทฯยทAยท|v|ยทv
var drag = 0.47.DragForce(fluidDensity: 1.225, crossSectionArea: 0.01, velocity);

// Friction (kinetic โ€” moving object)
var kinetic = 0.3.FrictionForce(normalForceMagnitude: 98, velocity);

// Friction (static โ€” stationary object, opposes applied force up to ฮผN)
var friction = 0.5.FrictionForce(normalForceMagnitude: 100, velocity: new Vector(0, 0, 0),
appliedTangentialForce: new Vector(20, 0, 0)); // returns (-20, 0, 0)

// Compose forces in a Verlet simulation
Func<RigidBody, (Vector, Vector)> forces = b =>
{
var F = 50.0.SpringForce(2.0, b.Position, new Vector(0, 0, 0))
+ 0.5.DampingForce(b.Velocity);
return (F, new Vector(0, 0, 0));
};
body.IntegrateVelocityVerlet(forces, dt: 0.01);

๐ŸŒ€ Moment of Inertia (Scalar)โ€‹

Isolidย sphere=25mr2,Ihollowย sphere=23mr2,Isolidย cyl=12mr2,Irod,ย center=mL212,Irod,ย end=mL23I_{\text{solid sphere}} = \tfrac{2}{5}mr^2, \quad I_{\text{hollow sphere}} = \tfrac{2}{3}mr^2, \quad I_{\text{solid cyl}} = \tfrac{1}{2}mr^2, \quad I_{\text{rod, center}} = \tfrac{mL^2}{12}, \quad I_{\text{rod, end}} = \tfrac{mL^2}{3}

double I  = 10.0.MomentOfInertiaSolidSphere(radius: 2);       // 2/5ยทmrยฒ
double I2 = 10.0.MomentOfInertiaHollowSphere(radius: 2); // 2/3ยทmrยฒ
double I3 = 8.0.MomentOfInertiaSolidCylinder(radius: 3); // ยฝmrยฒ
double I4 = 6.0.MomentOfInertiaThinRod(length: 4); // mLยฒ/12
double I5 = 6.0.MomentOfInertiaThinRodEnd(length: 4); // mLยฒ/3
double I6 = 12.0.MomentOfInertiaSolidBox(sideA: 3, sideB: 4); // m/12ยท(aยฒ+bยฒ)

// Parallel axis theorem: I_new = I_cm + mยทdยฒ
double Inew = I.ParallelAxis(mass: 10, distance: 3);

๐Ÿงฎ Inertia Tensor (3ร—3 Matrix)โ€‹

Inew=Icm+m(d2Eโˆ’dโƒ—โŠ—dโƒ—)\mathbf{I}_{\text{new}} = \mathbf{I}_{\text{cm}} + m\bigl(d^2\mathbf{E} - \vec{d}\otimes\vec{d}\bigr)

Matrix I  = 10.0.InertiaTensorSolidSphere(radius: 2);
Matrix Ib = 12.0.InertiaTensorSolidBox(width: 2, height: 3, depth: 4);
Matrix Ic = 6.0.InertiaTensorSolidCylinder(radius: 1, height: 4);

// Parallel axis theorem for 3ร—3 tensor: I_new = I_cm + mยท(dยฒE - dโŠ—d)
Matrix Inew = I.ParallelAxis(mass: 10, offset: new Vector(3, 0, 0));

๐Ÿ”„ Torque & Rotational Dynamicsโ€‹

ฯ„โƒ—=rโƒ—ร—Fโƒ—,ฯ„=Frsinโกฮธ,Lโƒ—=Iฯ‰โƒ—,ฮฑโƒ—=Iโˆ’1ฯ„โƒ—,KErot=12ฯ‰โƒ—โ€‰โฃโŠคIฯ‰โƒ—\vec{\tau} = \vec{r} \times \vec{F}, \quad \tau = Fr\sin\theta, \quad \vec{L} = \mathbf{I}\vec{\omega}, \quad \vec{\alpha} = \mathbf{I}^{-1}\vec{\tau}, \quad KE_{\text{rot}} = \tfrac{1}{2}\vec{\omega}^{\!\top}\mathbf{I}\vec{\omega}

// Vector: ฯ„ = r ร— F
Vector tau = momentArm.Torque(force);

// Scalar: ฯ„ = Fยทrยทsin(ฮธ)
double tau2 = 20.0.Torque(momentArm: 3, angleRadians: Math.PI / 6);

// Angular momentum: L = Iฯ‰
Vector L = inertiaTensor.AngularMomentum(omega);
double Ls = momentOfInertia.AngularMomentum(omega);

// Angular acceleration: ฮฑ = Iโปยนฯ„
Vector alpha = inverseInertiaTensor.AngularAcceleration(torque);

// Rotational kinetic energy: KE = ยฝฯ‰แต€Iฯ‰
double KE = inertiaTensor.RotationalKineticEnergy(omega);
double KEs = momentOfInertia.RotationalKineticEnergy(omega);