1use core::ops::Range;
2
3use nalgebra::{RealField, SMatrix, SVector, SVectorViewMut, convert};
4
5use crate::constraint::{Constraint, DynConstraint};
6
7pub trait ProjectSingle<T, const D: usize> {
9 fn project_single(&self, point: SVectorViewMut<T, D>);
11}
12
13impl<T, const D: usize> ProjectSingle<T, D> for &dyn ProjectSingle<T, D> {
14 fn project_single(&self, point: SVectorViewMut<T, D>) {
15 (**self).project_single(point);
16 }
17}
18
19impl<P: ProjectSingle<T, D>, T, const D: usize> ProjectSingle<T, D> for &P {
20 fn project_single(&self, point: SVectorViewMut<T, D>) {
21 (**self).project_single(point);
22 }
23}
24
25impl<T, const D: usize> ProjectSingle<T, D> for () {
26 fn project_single(&self, mut _point: SVectorViewMut<T, D>) {}
27}
28
29macro_rules! derive_tuple_project {
30 ($($project:ident: $number:tt),+) => {
31 impl<$($project: ProjectSingle<T, D>),+, T, const D: usize> ProjectSingle<T, D>
32 for ( $($project,)+ )
33 {
34 fn project_single(&self, mut point: SVectorViewMut<T, D>) {
35 $(
36 self.$number.project_single(point.as_view_mut());
37 )+
38 }
39 }
40 };
41}
42
43derive_tuple_project! {P0: 0}
44derive_tuple_project! {P0: 0, P1: 1}
45derive_tuple_project! {P0: 0, P1: 1, P2: 2}
46derive_tuple_project! {P0: 0, P1: 1, P2: 2, P3: 3}
47derive_tuple_project! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4}
48derive_tuple_project! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5}
49derive_tuple_project! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6}
50derive_tuple_project! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7}
51derive_tuple_project! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8}
52derive_tuple_project! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9}
53
54pub trait ProjectSingleExt<T: RealField + Copy, const D: usize>:
55 ProjectSingle<T, D> + Sized
56{
57 fn time_fixed(self) -> time::Fixed<Self> {
58 time::Fixed::new(self)
59 }
60
61 fn time_ranged(self, range: Range<usize>) -> time::Ranged<Self> {
62 time::Ranged::new(self, range)
63 }
64
65 fn dim_lift<const N: usize>(self, indices: [usize; D]) -> dim::Lift<Self, D, N> {
66 dim::Lift::new(indices, self)
67 }
68}
69
70impl<P: ProjectSingle<T, D>, T: RealField + Copy, const D: usize> ProjectSingleExt<T, D> for P {}
71
72pub trait ProjectMulti<T, const D: usize, const H: usize> {
74 fn project_multi(&self, points: &mut SMatrix<T, D, H>);
75}
76
77impl<P: ProjectMulti<T, D, H>, T, const D: usize, const H: usize> ProjectMulti<T, D, H> for &P {
78 fn project_multi(&self, points: &mut SMatrix<T, D, H>) {
79 (**self).project_multi(points);
80 }
81}
82
83impl<T, const D: usize, const H: usize> ProjectMulti<T, D, H> for &dyn ProjectMulti<T, D, H> {
84 fn project_multi(&self, points: &mut SMatrix<T, D, H>) {
85 (**self).project_multi(points);
86 }
87}
88
89impl<T, const D: usize, const H: usize> ProjectMulti<T, D, H> for () {
90 fn project_multi(&self, _points: &mut SMatrix<T, D, H>) {}
91}
92
93macro_rules! derive_tuple_project_multi {
94 ($($project:ident: $number:tt),+) => {
95 impl<$($project: ProjectMulti<T, D, H>),+, T, const D: usize, const H: usize> ProjectMulti<T, D, H>
96 for ( $($project,)+ )
97 {
98 fn project_multi(&self, points: &mut SMatrix<T, D, H>) {
99 $(
100 self.$number.project_multi(points);
101 )+
102 }
103 }
104 };
105}
106
107derive_tuple_project_multi! {P0: 0}
108derive_tuple_project_multi! {P0: 0, P1: 1}
109derive_tuple_project_multi! {P0: 0, P1: 1, P2: 2}
110derive_tuple_project_multi! {P0: 0, P1: 1, P2: 2, P3: 3}
111derive_tuple_project_multi! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4}
112derive_tuple_project_multi! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5}
113derive_tuple_project_multi! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6}
114derive_tuple_project_multi! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7}
115derive_tuple_project_multi! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8}
116derive_tuple_project_multi! {P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9}
117
118pub trait ProjectMultiExt<T: RealField + Copy, const D: usize, const H: usize>:
119 ProjectMulti<T, D, H> + Sized
120{
121 fn dynamic(&self) -> &dyn ProjectMulti<T, D, H> {
122 self
123 }
124
125 fn constraint(&self) -> Constraint<T, &Self, D, H> {
126 Constraint::new(self)
127 }
128
129 fn dyn_constraint(&self) -> DynConstraint<'_, T, D, H> {
130 Constraint::new(self)
131 }
132
133 fn constraint_owned(self) -> Constraint<T, Self, D, H> {
134 Constraint::new(self)
135 }
136}
137
138impl<P: ProjectMulti<T, D, H>, T: RealField + Copy, const D: usize, const H: usize>
139 ProjectMultiExt<T, D, H> for P
140{
141}
142
143#[derive(Debug, Copy, Clone)]
145pub struct Box<T, const N: usize> {
146 pub lower: SVector<T, N>,
147 pub upper: SVector<T, N>,
148}
149
150impl<T: RealField + Copy, const N: usize> ProjectSingle<T, N> for Box<T, N> {
151 fn project_single(&self, mut point: SVectorViewMut<T, N>) {
152 for n in 0..N {
153 point[n] = point[n].clamp(self.lower[n], self.upper[n]);
154 }
155 }
156}
157
158#[derive(Debug, Copy, Clone)]
160pub struct Sphere<T, const D: usize> {
161 pub center: SVector<T, D>,
162 pub radius: T,
163}
164
165impl<T: RealField + Copy, const N: usize> ProjectSingle<T, N> for Sphere<T, N> {
166 fn project_single(&self, mut point: SVectorViewMut<T, N>) {
167 if self.radius <= T::zero() {
168 point.copy_from(&self.center);
169 } else {
170 let diff = &point - self.center;
171 let dist = diff.norm();
172
173 if dist > self.radius {
174 let scale = self.radius / dist;
175 point.copy_from(&self.center);
176 point.axpy(scale, &diff, T::one());
177 }
178 }
179 }
180}
181
182#[derive(Debug, Copy, Clone)]
184pub struct AntiSphere<T, const N: usize> {
185 pub center: SVector<T, N>,
186 pub radius: T,
187}
188
189impl<T: RealField + Copy, const N: usize> ProjectSingle<T, N> for AntiSphere<T, N> {
190 fn project_single(&self, mut point: SVectorViewMut<T, N>) {
191 if self.radius > T::zero() {
192 let diff = &point - self.center;
193 let dist = diff.norm();
194
195 if dist < self.radius {
196 let scale = self.radius / dist;
197 point.copy_from(&(self.center + diff * scale));
198 }
199 }
200 }
201}
202
203#[derive(Debug, Copy, Clone)]
205pub struct Affine<T, const N: usize> {
206 normal: SVector<T, N>,
207 distance: T,
208}
209
210impl<T: RealField + Copy, const D: usize> Default for Affine<T, D> {
211 fn default() -> Affine<T, D> {
212 Affine {
213 normal: SVector::identity(),
214 distance: T::zero(),
215 }
216 }
217}
218
219impl<T: RealField + Copy, const D: usize> Affine<T, D> {
220 #[must_use]
222 pub fn new() -> Affine<T, D> {
223 Affine::default()
224 }
225
226 #[must_use]
232 pub fn normal(mut self, normal: impl Into<SVector<T, D>>) -> Self {
233 self.normal = normal.into();
234 assert!(self.normal.norm() > convert(1e-9));
235 self.normal = self.normal.normalize();
236 self
237 }
238
239 #[must_use]
241 pub fn distance(mut self, distance: T) -> Self {
242 self.distance = distance;
243 self
244 }
245}
246
247impl<T: RealField + Copy, const N: usize> ProjectSingle<T, N> for Affine<T, N> {
248 fn project_single(&self, mut point: SVectorViewMut<T, N>) {
249 let dot = point.dot(&self.normal);
250 if dot > self.distance {
251 point -= self.normal.scale(dot - self.distance);
252 }
253 }
254}
255
256#[derive(Debug, Clone)]
258pub struct CircularCone<T: RealField + Copy, const D: usize> {
259 vertex: SVector<T, D>,
260 axis: SVector<T, D>,
261 mu: T,
262}
263
264impl<T: RealField + Copy, const D: usize> Default for CircularCone<T, D> {
265 fn default() -> Self {
266 CircularCone {
267 vertex: SVector::zeros(),
268 axis: SVector::identity(),
269 mu: nalgebra::convert(1.0),
270 }
271 }
272}
273
274impl<T: RealField + Copy, const D: usize> CircularCone<T, D> {
275 #[must_use]
277 pub fn new() -> CircularCone<T, D> {
278 CircularCone::default()
279 }
280
281 #[must_use]
283 pub fn axis(mut self, axis: impl Into<SVector<T, D>>) -> Self {
284 self.mut_axis(axis);
285 self
286 }
287
288 pub fn mut_axis(&mut self, axis: impl Into<SVector<T, D>>) {
290 self.axis = axis.into().normalize();
291 }
292
293 #[must_use]
295 pub fn vertex(mut self, vertex: impl Into<SVector<T, D>>) -> Self {
296 self.mut_vertex(vertex);
297 self
298 }
299
300 pub fn mut_vertex(&mut self, vertex: impl Into<SVector<T, D>>) {
302 self.vertex = vertex.into();
303 }
304
305 #[must_use]
307 pub fn mu(mut self, mu: T) -> Self {
308 self.mut_mu(mu);
309 self
310 }
311
312 pub fn mut_mu(&mut self, mu: T) {
314 self.mu = mu.max(T::zero());
315 }
316}
317
318impl<T: RealField + Copy, const D: usize> ProjectSingle<T, D> for CircularCone<T, D> {
319 fn project_single(&self, mut point: SVectorViewMut<T, D>) {
320 let v = &point - self.vertex;
322
323 let s_n = v.dot(&self.axis);
325 let s_v = v - self.axis.scale(s_n);
326
327 let a = s_v.norm();
329
330 if a <= self.mu * s_n {
332 }
333 else if (a * self.mu <= -s_n) || a.is_zero() {
335 point.copy_from(&self.vertex);
336 }
337 else {
339 let alpha = (self.mu * a + s_n) / (T::one() + self.mu * self.mu);
340 point.copy_from(&((self.axis + s_v * self.mu / a) * alpha + self.vertex));
341 }
342 }
343}
344
345pub mod dim {
347 use core::marker::PhantomData;
348
349 use nalgebra::{RealField, SVector, SVectorViewMut};
350
351 use crate::ProjectSingle;
352
353 #[derive(Debug, Clone)]
355 pub struct Lift<P, const D: usize, const N: usize> {
356 indices: [usize; D],
357 pub projector: P,
358 _p: PhantomData<[(); N]>,
359 }
360
361 impl<P, const D: usize, const N: usize> Lift<P, D, N> {
362 pub fn new(indices: [usize; D], projector: P) -> Self {
368 assert!(indices.iter().all(|e| e < &N));
369 Self {
370 indices,
371 projector,
372 _p: PhantomData,
373 }
374 }
375 }
376
377 impl<P: ProjectSingle<T, D>, T: RealField + Copy, const D: usize, const N: usize>
378 ProjectSingle<T, N> for Lift<P, D, N>
379 {
380 fn project_single(&self, mut point: SVectorViewMut<T, N>) {
381 let mut sub_point: SVector<T, D> = SVector::zeros();
382 for i in 0..D {
383 sub_point[i] = point[self.indices[i]];
384 }
385
386 self.projector.project_single(sub_point.as_view_mut());
387
388 for i in 0..D {
389 point[self.indices[i]] = sub_point[i];
390 }
391 }
392 }
393}
394
395pub mod time {
397 use core::ops::Range;
398
399 use nalgebra::{RealField, SMatrix};
400
401 use crate::{ProjectMulti, ProjectSingle};
402
403 pub struct Fixed<P> {
405 pub projector: P,
406 }
407
408 impl<P> Fixed<P> {
409 pub fn new(projector: P) -> Fixed<P> {
410 Fixed { projector }
411 }
412 }
413
414 impl<P: ProjectSingle<T, D>, T: RealField + Copy, const D: usize, const H: usize>
415 ProjectMulti<T, D, H> for Fixed<P>
416 {
417 fn project_multi(&self, points: &mut SMatrix<T, D, H>) {
418 for mut column in points.column_iter_mut() {
419 self.projector.project_single(column.as_view_mut());
420 }
421 }
422 }
423
424 pub struct Ranged<P> {
426 pub projector: P,
427 pub range: Range<usize>,
428 }
429
430 impl<P> Ranged<P> {
431 pub fn new(projector: P, range: Range<usize>) -> Ranged<P> {
432 Ranged { projector, range }
433 }
434 }
435
436 impl<P: ProjectSingle<T, D>, T: RealField + Copy, const D: usize, const H: usize>
437 ProjectMulti<T, D, H> for Ranged<P>
438 {
439 fn project_multi(&self, points: &mut SMatrix<T, D, H>) {
440 for mut column in points
441 .column_iter_mut()
442 .take(self.range.end)
443 .skip(self.range.start)
444 {
445 self.projector.project_single(column.as_view_mut());
446 }
447 }
448 }
449
450 pub struct Func<F> {
452 func: F,
453 }
454
455 impl<F> Func<F> {
456 pub fn new(func: F) -> Func<F> {
457 Func { func }
458 }
459 }
460
461 impl<
462 P: ProjectSingle<T, D>,
463 T: RealField + Copy,
464 F: Fn(usize) -> P,
465 const D: usize,
466 const H: usize,
467 > ProjectMulti<T, D, H> for Func<F>
468 {
469 fn project_multi(&self, points: &mut SMatrix<T, D, H>) {
470 for (index, mut column) in points.column_iter_mut().enumerate() {
471 (self.func)(index).project_single(column.as_view_mut());
472 }
473 }
474 }
475}