use serde::{Deserialize, Serialize};
pub trait PhysicalObject {
fn compute_force(&self, position: [f32; 3]) -> [f32; 3];
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Sphere {
pub center: [f32; 3],
pub radius: f32,
pub stiffness: f32, pub magnetism: f32, pub damping: f32, }
impl PhysicalObject for Sphere {
fn compute_force(&self, position: [f32; 3]) -> [f32; 3] {
let dx = position[0] - self.center[0];
let dy = position[1] - self.center[1];
let dz = position[2] - self.center[2];
let distance = (dx * dx + dy * dy + dz * dz).sqrt();
if distance < self.radius {
let norm_dx = dx / distance;
let norm_dy = dy / distance;
let norm_dz = dz / distance;
let penetration = self.radius - distance;
[
self.stiffness * penetration * norm_dx,
self.stiffness * penetration * norm_dy,
self.stiffness * penetration * norm_dz,
]
} else if distance > 0.0 {
let norm_dx = (self.center[0] - position[0]) / distance;
let norm_dy = (self.center[1] - position[1]) / distance;
let norm_dz = (self.center[2] - position[2]) / distance;
[
self.magnetism * norm_dx,
self.magnetism * norm_dy,
self.magnetism * norm_dz,
]
} else {
[0.0, 0.0, 0.0]
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Cube {
pub center: [f32; 3],
pub size: f32, pub stiffness: f32, pub magnetism: f32, pub damping: f32, }
impl PhysicalObject for Cube {
fn compute_force(&self, position: [f32; 3]) -> [f32; 3] {
let half = self.size / 2.0;
let mut force = [0.0_f32, 0.0, 0.0];
for i in 0..3 {
let diff = position[i] - self.center[i];
if diff.abs() < half {
force[i] = -self.stiffness * diff;
} else {
force[i] = if diff > 0.0 {
self.magnetism
} else {
-self.magnetism
};
}
}
force
}
}
pub fn compute_total_force(position: [f32; 3], objects: &[Box<dyn PhysicalObject>]) -> [f32; 3] {
let mut total = [0.0_f32, 0.0, 0.0];
for obj in objects {
let f = obj.compute_force(position);
total[0] += f[0];
total[1] += f[1];
total[2] += f[2];
}
total
}