Source code for dymion.dynamics.forces

from __future__ import annotations
from ..core.vector import Vector
from .body import Body
import math

# --- Constants ---
G_EARTH = 9.80665 # Standard gravity in m/s^2
G_UNIVERSAL = 6.67430e-11 # m^3 kg^-1 s^-2

# --- Force Generators ---

[docs] def gravity(body: Body, g: float = G_EARTH) -> Vector: """ Calculates the weight force acting on a body: F = m * g By default, it uses Earth's gravity pointing downwards (-Y) """ return Vector(0, -body.mass * g, 0)
[docs] def friction(body: Body, mu: float, normal_force: float) -> Vector: """ Calculates the kinetic friction force: F_f = mu * N The force always opposes the direction of velocity """ if body.velocity.magnitude == 0: return Vector(0, 0, 0) # Direction is opposite to velocity direction = body.velocity.normalize() * -1.0 magnitude = mu * normal_force return direction * magnitude
[docs] def spring_force(k: float, displacement: Vector) -> Vector: """ Hooke's Law: F = -k * x 'k' is the spring constant, 'displacement' is the vector from equilibrium. """ return displacement * -k
[docs] def air_resistance(body: Body, rho: float, drag_coefficient: float, area: float) -> Vector: """ Drag Equation: F_d = 1/2 * rho * v^2 * C_d * A Rho is air density, C_d is drag coefficient, A is cross-sectional area. """ speed = body.velocity.magnitude if speed == 0: return Vector(0, 0, 0) direction = body.velocity.normalize() * -1.0 magnitude = 0.5 * rho * (speed**2) * drag_coefficient * area return direction * magnitude
[docs] def buoyancy_force(fluid_density: float, submerged_volume: float, g: float = G_EARTH) -> Vector: """ Archimedes' Principle: F_b = rho * V * g Points upwards (+Y). """ magnitude = fluid_density * submerged_volume * g return Vector(0, magnitude, 0)
[docs] def universal_gravitation(body1: Body, body2: Body) -> Vector: """ Calculates the gravitational force between two bodies: F = G * (m1 * m2) / r^2 The force is returned as a vector acting on body1. """ # Vector from body1 to body2 r_vector = body2.position - body1.position distance = r_vector.magnitude if distance == 0: return Vector(0, 0, 0) # Magnitude of the force force_mag = G_UNIVERSAL * (body1.mass * body2.mass) / (distance**2) # Direction: Unit vector from body1 to body2 direction = r_vector.normalize() return direction * force_mag
[docs] def escape_velocity(mass_of_planet: float, radius: float) -> float: """ Calculates the minimum speed needed to escape a planet's gravity. v = sqrt(2 * G * M / r) """ return math.sqrt((2 * G_UNIVERSAL * mass_of_planet) / radius)
[docs] def centripetal_force(body: Body, omega: float, radius: float) -> Vector: """ Calculates the centripetal force required to keep a body in a circular path. F_c = m * omega^2 * r """ # Assuming rotation is in the X-Y plane around the origin if body.position.magnitude == 0: return Vector(0, 0, 0) # Direction is towards the origin direction = body.position.normalize() * -1.0 magnitude = body.mass * (omega**2) * radius return direction * magnitude
[docs] def centrifugal_force(body: Body, omega: float, radius: float) -> Vector: """ Calculates the centrifugal (fictitious) force experienced in a rotating frame. F_f = m * omega^2 * r The force vector points away from the center of rotation (along r). """ return centripetal_force(body, omega, radius) * -1.0