use crate::particle::Particle;
use crate::vek2d::Vec2d;
use crate::FP;
use std::ptr;
pub trait ForceGenerator {
fn update_force(&mut self);
fn contains_ptr(&self, ptr: usize) -> bool;
}
pub struct Gravity {
particle: ptr::NonNull<Particle>,
gravity: FP,
}
impl Gravity {
pub fn new(particle: ptr::NonNull<Particle>, gravity: FP) -> Gravity {
Gravity { particle, gravity }
}
}
impl ForceGenerator for Gravity {
fn update_force(&mut self) {
let particle = unsafe { self.particle.as_mut() };
let force = Vec2d::new(0.0, self.gravity * particle.mass());
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle.as_ptr() as usize == ptr
}
}
pub struct Drag {
particle: ptr::NonNull<Particle>,
k1: FP,
k2: FP,
}
impl Drag {
pub fn new(particle: ptr::NonNull<Particle>, k1: FP, k2: FP) -> Drag {
Drag { particle, k1, k2 }
}
}
impl ForceGenerator for Drag {
fn update_force(&mut self) {
let particle = unsafe { self.particle.as_mut() };
let mut force = particle.velocity();
let mut drag_coeff = force.magnitude();
drag_coeff = self.k1 * drag_coeff + self.k2 * drag_coeff * drag_coeff;
force = force.normalise();
force *= -drag_coeff;
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle.as_ptr() as usize == ptr
}
}
pub struct AnchoredSpring {
particle: ptr::NonNull<Particle>,
anchor: Vec2d<FP>,
spring_const: FP,
rest_len: FP,
}
impl AnchoredSpring {
pub fn new(
particle: ptr::NonNull<Particle>,
anchor: Vec2d<FP>,
spring_const: FP,
rest_len: FP,
) -> AnchoredSpring {
AnchoredSpring {
particle,
anchor,
spring_const,
rest_len,
}
}
}
impl ForceGenerator for AnchoredSpring {
fn update_force(&mut self) {
let particle = unsafe { self.particle.as_mut() };
let mut force = particle.position();
force -= self.anchor;
let mut magnitude = force.magnitude();
magnitude = (self.rest_len - magnitude) * self.spring_const;
force = force.normalise();
force *= magnitude;
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle.as_ptr() as usize == ptr
}
}
pub struct AnchoredBungee {
particle: ptr::NonNull<Particle>,
anchor: ptr::NonNull<Particle>,
spring_const: FP,
rest_len: FP,
}
impl AnchoredBungee {
pub fn new(
particle: ptr::NonNull<Particle>,
anchor: ptr::NonNull<Particle>,
spring_const: FP,
rest_len: FP,
) -> AnchoredBungee {
AnchoredBungee {
particle,
anchor,
spring_const,
rest_len,
}
}
}
impl ForceGenerator for AnchoredBungee {
fn update_force(&mut self) {
let pos = unsafe { self.anchor.as_ref().position() };
let particle = unsafe { self.particle.as_mut() };
let mut force = particle.position();
force -= pos;
let mut magnitude = force.magnitude();
if magnitude <= self.rest_len {
return;
}
magnitude -= self.rest_len;
magnitude *= self.spring_const;
force = force.normalise();
force *= -magnitude;
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle.as_ptr() as usize == ptr
|| self.anchor.as_ptr() as usize == ptr
}
}
pub struct Buoyancy {
particle: ptr::NonNull<Particle>,
max_depth: FP,
volume: FP,
water_height: FP,
liquid_density: FP,
}
impl Buoyancy {
pub fn new(
particle: ptr::NonNull<Particle>,
max_depth: FP,
volume: FP,
water_height: FP,
liquid_density: FP,
) -> Buoyancy {
Buoyancy {
particle,
max_depth,
volume,
water_height,
liquid_density,
}
}
}
impl ForceGenerator for Buoyancy {
fn update_force(&mut self) {
let particle = unsafe { self.particle.as_mut() };
let depth = particle.position().y();
if depth >= self.water_height + self.max_depth {
return;
}
let mut force = Vec2d::default();
if depth < self.water_height - self.max_depth {
force.set_y(self.liquid_density * self.volume);
particle.add_force(force);
return;
}
force.set_y(
self.liquid_density
* self.volume
* (depth - self.max_depth - self.water_height)
/ 2.0
* self.max_depth,
);
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle.as_ptr() as usize == ptr
}
}