use crate::geometry::Walls;
use grass_scheduler::prelude::*;
use soil_core::Atom;
pub enum WallMotion {
Static,
ConstantVelocity,
Oscillate {
amplitude: f64,
frequency: f64,
},
Servo {
target_force: f64,
max_velocity: f64,
gain: f64,
},
}
pub fn wall_move(mut walls: ResMut<Walls>, atoms: Res<Atom>) {
let dt = atoms.dt;
let time = walls.time;
let nplanes = walls.planes.len();
for idx in 0..nplanes {
if !walls.active[idx] {
continue;
}
let wall = &mut walls.planes[idx];
match wall.motion {
WallMotion::Static => {}
WallMotion::ConstantVelocity => {
wall.point_x += wall.velocity[0] * dt;
wall.point_y += wall.velocity[1] * dt;
wall.point_z += wall.velocity[2] * dt;
}
WallMotion::Oscillate {
amplitude,
frequency,
} => {
let phase = 2.0 * std::f64::consts::PI * frequency * (time + dt);
let disp = amplitude * phase.sin();
wall.point_x = wall.origin[0] + disp * wall.normal_x;
wall.point_y = wall.origin[1] + disp * wall.normal_y;
wall.point_z = wall.origin[2] + disp * wall.normal_z;
let vel_mag = amplitude * 2.0 * std::f64::consts::PI * frequency * phase.cos();
wall.velocity = [
vel_mag * wall.normal_x,
vel_mag * wall.normal_y,
vel_mag * wall.normal_z,
];
}
WallMotion::Servo {
target_force,
max_velocity,
gain,
} => {
let error = target_force - wall.force_accumulator;
let vel_mag = (gain * error).clamp(-max_velocity, max_velocity);
wall.velocity = [
vel_mag * wall.normal_x,
vel_mag * wall.normal_y,
vel_mag * wall.normal_z,
];
wall.point_x += wall.velocity[0] * dt;
wall.point_y += wall.velocity[1] * dt;
wall.point_z += wall.velocity[2] * dt;
}
}
}
walls.time += dt;
}
pub fn wall_zero_force_accumulators(mut walls: ResMut<Walls>) {
for wall in &mut walls.planes {
wall.force_accumulator = 0.0;
}
for wall in &mut walls.cylinders {
wall.force_accumulator = 0.0;
}
for wall in &mut walls.spheres {
wall.force_accumulator = 0.0;
}
for wall in &mut walls.regions {
wall.force_accumulator = 0.0;
}
}