use nalgebra::{DVector, RowDVector}; use crate::algebra::distance_field::DistanceField; use crate::algebra::subspace::{Line, Subspace}; use crate::algebra::{Point, Scalar, N}; use crate::particle_system::ParticleSystem; use super::Constraint; /// Keep a particle at certain distance within distance field pub struct DistanceConstraint { particle_id: usize, distance_field: D, distance: Scalar, } impl ParticleSystem { pub fn add_distance_constraint(&mut self, particle_id: usize, subspace: Subspace, distance: Scalar) { let particle = &self.particles[particle_id]; self.constraints.push(Box::new(DistanceConstraint { particle_id, distance, distance_field: subspace, })); } } impl Constraint for DistanceConstraint { fn get_particles(&self) -> Vec { vec![self.particle_id] } fn c(&self, q: &DVector) -> Scalar { let position = q.fixed_rows::(self.particle_id * N); self.distance_field.distance(Point::from_coordinates(position.into())) - self.distance } fn jacobian(&self, q: &DVector) -> RowDVector { let point = Point::from_coordinates(q.fixed_rows::(self.particle_id * N).into()); let normal = self.distance_field.project_point(point) - point; let mut result = RowDVector::zeros(q.len()); for i in 0..N { result[self.particle_id * N + i] = normal[i]; } result } }