1use nalgebra::constraint::{SameNumberOfRows, ShapeConstraint};
4use nalgebra::storage::Storage;
5use nalgebra::{Const, Dim, RealField, SVector, Vector};
6use num_traits::Float;
7use rand::distributions::{uniform::SampleUniform, Distribution};
8use rand::{thread_rng, SeedableRng};
9use serde::{de::DeserializeOwned, Deserialize, Serialize};
10
11use crate::error::{InvalidParamError, Result};
12use crate::params::FromParams;
13use crate::rng::{LinearCoordinates, RNG};
14use crate::scalar::Scalar;
15use crate::trajectories::{EuclideanTrajectory, FullTraj};
16use crate::util::bounds::Bounds;
17use crate::util::math::{atan2, unit_d_ball_vol};
18
19use super::super::CSpace;
20use super::LeaderFollowerCSpace;
21
22pub const D: usize = 2;
23pub const N: usize = D * 2;
24
25#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
26#[serde(bound(
27 serialize = "X: Serialize",
28 deserialize = "X: DeserializeOwned"
29))]
30pub struct LeaderFollowerPolarSpaceParams<X: Scalar> {
31 pub bounds: Bounds<X, D>,
32 pub seed: Option<u64>,
33 pub sensor_range: (X, X),
34}
35
36pub struct LeaderFollowerPolarSpace<X>
44where
45 X: Scalar + SampleUniform,
46{
47 bounds: Bounds<X, D>,
48 volume: X,
49 rng: RNG,
50 distribution: LinearCoordinates<X, N>,
51 intial_sensor_range: (X, X),
52 sensor_range: (X, X),
53 sensor_range_squared: (X, X),
54}
55
56impl<X> LeaderFollowerPolarSpace<X>
57where
58 X: Scalar + SampleUniform,
59{
60 pub fn new(
61 bounds: Bounds<X, D>,
62 rng: RNG,
63 sensor_range: (X, X),
64 ) -> Result<Self> {
65 debug_assert_eq!(D * 2, N);
66
67 if !bounds.is_valid() {
69 Err(InvalidParamError {
70 parameter_name: "bounds",
71 parameter_value: format!("{:?}", bounds),
72 })?;
73 }
74
75 if !(sensor_range.0 < sensor_range.1) {
77 Err(InvalidParamError {
78 parameter_name: "sensor_range",
79 parameter_value: format!("{:?}", sensor_range),
80 })?;
81 }
82
83 let sensor_range_squared = (
84 sensor_range.0 * sensor_range.0,
85 sensor_range.1 * sensor_range.1,
86 );
87
88 let sensor_space_volume = (sensor_range_squared.1 * unit_d_ball_vol(D))
89 - (sensor_range_squared.0 * unit_d_ball_vol(D));
90 let volume = bounds.volume() * sensor_space_volume;
91
92 let mins = SVector::<X, N>::from([
93 bounds.mins[0],
94 bounds.mins[1],
95 X::zero(),
96 X::zero(),
97 ]);
98
99 let maxs = SVector::<X, N>::from([
100 bounds.maxs[0],
101 bounds.maxs[1],
102 X::one(),
103 X::two_pi(),
104 ]);
105
106 let distribution = LinearCoordinates::new(mins, maxs);
107
108 Ok(Self {
109 bounds,
110 volume,
111 rng,
112 distribution,
113 intial_sensor_range: sensor_range,
114 sensor_range,
115 sensor_range_squared,
116 })
117 }
118
119 pub fn intial_sensor_range(&self) -> (X, X) {
120 self.intial_sensor_range
121 }
122
123 pub fn get_sensor_range(&self) -> (X, X) {
124 self.sensor_range
125 }
126
127 pub fn set_sensor_range(&mut self, sensor_range: (X, X)) -> Option<()> {
128 if sensor_range.0 < sensor_range.1 {
129 self.sensor_range = sensor_range;
131 self.sensor_range_squared = (
132 sensor_range.0 * sensor_range.0,
133 sensor_range.1 * sensor_range.1,
134 );
135 Some(())
136 } else {
137 None
139 }
140 }
141}
142
143impl<X> LeaderFollowerCSpace<X, D, N> for LeaderFollowerPolarSpace<X>
144where
145 X: Scalar + SampleUniform,
146{
147 }
149
150impl<X> CSpace<X, N> for LeaderFollowerPolarSpace<X>
151where
152 X: Scalar + SampleUniform,
153{
154 type Traj = EuclideanTrajectory<X, N>;
155
156 fn volume(&self) -> X {
157 self.volume
158 }
159
160 fn cost<R1, R2, S1, S2>(
161 &self,
162 a: &Vector<X, R1, S1>,
163 b: &Vector<X, R2, S2>,
164 ) -> X
165 where
166 X: Scalar,
167 R1: Dim,
168 R2: Dim,
169 S1: Storage<X, R1>,
170 S2: Storage<X, R2>,
171 ShapeConstraint: SameNumberOfRows<R1, R2>
172 + SameNumberOfRows<R1, Const<N>>
173 + SameNumberOfRows<R2, Const<N>>,
174 {
175 a.metric_distance(b)
176 }
177
178 fn trajectory<S1, S2>(
179 &self,
180 start: Vector<X, Const<N>, S1>,
181 end: Vector<X, Const<N>, S2>,
182 ) -> Option<FullTraj<X, Self::Traj, S1, S2, N>>
183 where
184 X: Scalar,
185 S1: Storage<X, Const<N>>,
186 S2: Storage<X, Const<N>>,
187 {
188 Some(FullTraj::new(start, end, EuclideanTrajectory::new()))
189 }
190
191 fn is_free<S>(&self, a: &Vector<X, Const<N>, S>) -> bool
192 where
193 S: Storage<X, Const<N>>,
194 {
195 let leader_abs = a.fixed_rows::<D>(0);
196 let follower_abs = a.fixed_rows::<D>(D);
197
198 if !self.bounds.within(&follower_abs) {
199 return false;
200 }
201
202 let r2 = leader_abs.metric_distance(&follower_abs);
204 self.sensor_range.0 <= r2 && r2 <= self.sensor_range.1
205 }
206
207 fn saturate(&self, a: &mut SVector<X, N>, b: &SVector<X, N>, delta: X) {
208 let delta = delta / (X::one() + X::one());
216
217 let mut a_lead_mut = a.fixed_rows_mut::<D>(0);
219 let b_lead = b.fixed_rows::<D>(0);
220
221 let lead_scale = delta / a_lead_mut.metric_distance(&b_lead);
225
226 a_lead_mut.set_column(0, &(&a_lead_mut - &b_lead));
227 a_lead_mut.set_column(0, &(&a_lead_mut * lead_scale));
228 a_lead_mut.set_column(0, &(&a_lead_mut + &b_lead));
229
230 let a_lead = a.fixed_rows::<D>(0);
235 let a_fol = a.fixed_rows::<D>(D);
236
237 let mut b = b.clone(); let mut b_lead_mut = b.fixed_rows_mut::<D>(0);
243 b_lead_mut.set_column(0, &a_lead); let mut b_rel = abs_to_rel(&b); let mut b_fol_rel_mut = b_rel.fixed_rows_mut::<D>(D).into_owned();
253 let a_fol_rel = cartesian_to_polar(&a_fol);
254
255 let mut delta = delta;
257 if self.sensor_range.1 < b_fol_rel_mut[0] {
258 delta -= b_fol_rel_mut[0] - self.sensor_range.1;
259 b_fol_rel_mut[0] = self.sensor_range.1;
260 }
261 if b_fol_rel_mut[0] < self.sensor_range.0 {
262 delta -= self.sensor_range.0 - b_fol_rel_mut[0];
263 b_fol_rel_mut[0] = self.sensor_range.0;
264 }
265
266 if X::zero() < delta {
267 let mut star_fol_rel = saturate_polar(&a_fol_rel, &b_fol_rel_mut, delta);
268
269 log::debug!(
270 "sensor_range: {:?}, star_fol_rel: {:?}",
271 self.sensor_range,
272 <[X; D]>::from(star_fol_rel)
273 );
274
275 if self.sensor_range.1 < star_fol_rel[0] {
277 log::warn!("rho too big: [{}, {}]", star_fol_rel[0], star_fol_rel[1]);
278 star_fol_rel[0] = self.sensor_range.1;
279 }
280 if star_fol_rel[0] < self.sensor_range.0 {
281 log::warn!("rho too small: [{}, {}]", star_fol_rel[0], star_fol_rel[1]);
282 star_fol_rel[0] = self.sensor_range.0;
283 }
284
285 let mut a_fol_mut = a.fixed_rows_mut::<D>(D);
287 a_fol_mut.set_column(0, &star_fol_rel);
288 } else {
289 let mut a_fol_mut = a.fixed_rows_mut::<D>(D);
291 a_fol_mut.set_column(0, &b_fol_rel_mut);
292 }
293
294 *a = rel_to_abs(&a);
296 }
297
298 fn sample(&mut self) -> SVector<X, N> {
299 let mut sample = self.distribution.sample(&mut self.rng);
300
301 let a_2 = self.sensor_range_squared.0;
302 let b_2 = self.sensor_range_squared.1;
303 sample[2] = <X as Float>::sqrt(sample[2] * (b_2 - a_2) + a_2);
304
305 rel_to_abs(&sample)
306 }
307}
308
309impl<X> FromParams for LeaderFollowerPolarSpace<X>
310where
311 X: Scalar + SampleUniform,
312{
313 type Params = LeaderFollowerPolarSpaceParams<X>;
314 fn from_params(params: Self::Params) -> Result<Self> {
315 let rng = match params.seed {
316 Some(seed) => RNG::seed_from_u64(seed),
317 None => RNG::from_rng(thread_rng())?,
318 };
319
320 LeaderFollowerPolarSpace::new(params.bounds, rng, params.sensor_range)
321 }
322}
323
324pub fn rel_to_abs<X, R, S>(v: &Vector<X, R, S>) -> SVector<X, N>
328where
329 X: RealField + Copy,
330 R: Dim,
331 S: Storage<X, R>,
332 ShapeConstraint: SameNumberOfRows<R, Const<N>>,
333{
334 let x1 = v[0];
335 let y1 = v[1];
336 let x2 = v[0] + (v[2] * v[3].cos());
337 let y2 = v[1] + (v[2] * v[3].sin());
338
339 [x1, y1, x2, y2].into()
340}
341
342pub fn polar_to_cartesian<X, R, S>(v: &Vector<X, R, S>) -> SVector<X, D>
344where
345 X: RealField + Copy,
346 R: Dim,
347 S: Storage<X, R>,
348 ShapeConstraint: SameNumberOfRows<R, Const<D>>,
349{
350 let x = v[0] * v[1].cos();
351 let y = v[0] * v[1].sin();
352 [x, y].into()
353}
354
355pub fn abs_to_rel<X, R, S>(v: &Vector<X, R, S>) -> SVector<X, N>
359where
360 X: RealField + Copy,
361 R: Dim,
362 S: Storage<X, R>,
363 ShapeConstraint: SameNumberOfRows<R, Const<N>>,
364{
365 let x1 = v[0];
366 let y1 = v[1];
367 let x2 = v[2] - x1; let y2 = v[3] - y1; let r2 = (x2 * x2 + y2 * y2).sqrt();
371 let theta2 = atan2(y2, x2).unwrap_or(X::zero());
372
373 [x1, y1, r2, bound_theta(theta2)].into()
374}
375
376pub fn cartesian_to_polar<X, R, S>(v: &Vector<X, R, S>) -> SVector<X, D>
378where
379 X: RealField + Copy,
380 R: Dim,
381 S: Storage<X, R>,
382 ShapeConstraint: SameNumberOfRows<R, Const<D>>,
383{
384 let r = (v[0] * v[0] + v[1] * v[1]).sqrt();
385 let theta = atan2(v[1], v[0]).unwrap_or(X::zero());
386 [r, bound_theta(theta)].into()
387}
388
389fn saturate_polar<X, R1, S1, R2, S2>(
390 a: &Vector<X, R1, S1>,
391 b: &Vector<X, R2, S2>,
392 delta: X,
393) -> SVector<X, D>
394where
395 X: RealField + Copy,
396 R1: Dim,
397 R2: Dim,
398 S1: Storage<X, R1>,
399 S2: Storage<X, R2>,
400 ShapeConstraint: SameNumberOfRows<R1, R2>
401 + SameNumberOfRows<R1, Const<D>>
402 + SameNumberOfRows<R2, Const<D>>,
403{
404 let r_a = a[0];
405 let theta_a = a[1];
406 let r_b = b[0];
407 let theta_b = b[1];
408
409 let (r_star, theta_star) =
410 saturate_polar_zero(r_a, bound_theta(theta_a - theta_b), r_b, delta);
411 [r_star, bound_theta(theta_star + theta_b)].into()
412}
413
414pub fn saturate_polar_zero<X>(r_a: X, theta_a: X, r_b: X, delta: X) -> (X, X)
416where
417 X: RealField + Copy,
418{
419 let two = X::one() + X::one();
420
421 log::debug!("delta: {:?}", delta);
422
423 assert!(X::zero() < delta);
425 assert!(X::zero() < r_a);
426 assert!(X::zero() < r_b);
427 assert!(X::zero() <= theta_a && theta_a < X::two_pi());
428
429 if theta_a == X::zero() {
431 let r_star = match r_b - r_a {
432 x if x > delta => r_a + delta,
433 x if -delta < x => r_a - delta,
434 _ => r_a,
435 };
436 return (r_star, X::zero());
437 }
438
439 let clockwise = X::pi() < theta_a;
441 log::debug!("clockwise: {:?}", clockwise);
442
443 let (theta_a, delta) = if clockwise {
444 (theta_a - X::two_pi(), -delta)
445 } else {
446 (theta_a, delta)
447 };
448
449 let m = (r_a - r_b) / theta_a;
453 let m_2 = m.powi(2);
454 let r_0 = r_b; let r = |theta: X| m * theta + r_0;
456
457 let integral = |theta: X| {
459 let r_theta = r(theta);
460 let temp = (r_theta.powi(2) + m_2).sqrt();
461
462 let term1 = (r_theta * temp) / (two * m);
463 let term2 = (m / two) * (temp + r_theta).ln();
464 term1 + term2
465 };
466
467 let constant = -integral(X::zero()) - delta;
469 let f = |theta: X| integral(theta) + constant;
470
471 let fd = |theta: X| (r(theta).powi(2) + m_2).sqrt();
474
475 let mut theta_star = delta * two / (r_a + r_b);
477 let iterations = 2;
478 for _ in 0..iterations {
479 theta_star -= f(theta_star) / fd(theta_star);
480 }
481
482 if clockwise {
484 assert!(theta_a < X::zero());
485 theta_star = theta_star.max(theta_a);
486 theta_star = theta_star.min(X::zero());
487 } else {
488 assert!(X::zero() < theta_a);
489 theta_star = theta_star.max(X::zero());
490 theta_star = theta_star.min(theta_a);
491 }
492
493 let r_star = r(theta_star);
494
495 (r_star, bound_theta(theta_star))
497}
498
499fn bound_theta<X>(mut theta: X) -> X
500where
501 X: RealField + Copy,
502{
503 while theta < X::zero() {
505 theta += X::two_pi()
506 }
507 while X::two_pi() <= theta {
509 theta -= X::two_pi()
510 }
511 theta
512}
513
514#[cfg(test)]
515mod tests {
516
517 use super::*;
518
519 fn rel_eq<X: RealField + Copy>(a: X, b: X) -> bool {
520 let abs_difference = (a - b).abs();
521 println!("{:?}", abs_difference);
522 abs_difference < X::from_subset(&10.0).powi(-3)
523 }
524
525 #[test]
526 fn test_polar_saturate() {
527 let params = LeaderFollowerPolarSpaceParams {
528 bounds: Bounds::new([-5.0, -5.0].into(), [5.0, 5.0].into()),
529 seed: Some(0x1234_5678_1234_5674),
530 sensor_range: (0.1, 2.0),
531 };
532
533 let space = LeaderFollowerPolarSpace::from_params(params).unwrap();
534
535 let mut a = [3.7375317, 0.9111872, 0.90473485, 4.3599744].into();
536 let b = [3.7432036, -2.570983, 2.502023, -4.0045195].into();
537
538 space.saturate(&mut a, &b, 1.0);
539
540 println!("a_star: {:?}", <[f32; N]>::from(a));
541 }
542
543 #[test]
544 fn test_saturate_polar_zero_counter_clockwise_f32() {
545 let r_b: f32 = 0.70710677;
546 let r_a = 1.7927681;
547 let theta_a = 1.4744684;
548 let _theta_b = 0.0;
549 let delta = 0.275;
550
551 let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
552
553 assert!(rel_eq(r_star, 0.893392428268));
554 assert!(rel_eq(theta_star, 0.253));
555 }
556
557 #[test]
558 fn test_saturate_polar_zero_counter_clockwise_f64() {
559 let r_b: f64 = 0.70710677;
560 let r_a = 1.7927681;
561 let theta_a = 1.4744684;
562 let _theta_b = 0.0;
563 let delta = 0.275;
564
565 let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
566
567 assert!(rel_eq(r_star, 0.893392428268));
568 assert!(rel_eq(theta_star, 0.253));
569 }
570
571 #[test]
572 fn test_saturate_polar_zero_clockwise_f32() {
573 let r_b: f32 = 0.70710677;
574 let r_a = 1.7927681;
575 let theta_a = bound_theta(-1.4744684);
576 let _theta_b = 0.0;
577 let delta = 0.275;
578
579 let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
580
581 assert!(rel_eq(r_star, 0.893392428268));
582 assert!(rel_eq(theta_star, bound_theta(-0.253)));
583 }
584
585 #[test]
586 fn test_saturate_polar_zero_clockwise_f64() {
587 let r_b: f64 = 0.70710677;
588 let r_a = 1.7927681;
589 let theta_a = bound_theta(-1.4744684);
590 let _theta_b = 0.0;
591 let delta = 0.275;
592
593 let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
594
595 assert!(rel_eq(r_star, 0.893392428268));
596 assert!(rel_eq(theta_star, bound_theta(-0.253)));
597 }
598
599 #[test]
600 fn test_saturate_polar_zero_counter_clockwise_long_f32() {
601 let r_b: f32 = 0.70710677;
602 let r_a = 1.7927681;
603 let theta_a = 3.127344367;
604 let _theta_b = 0.0;
605 let delta = 0.275;
606
607 let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
608
609 assert!(rel_eq(r_star, 0.820972361522));
610 assert!(rel_eq(theta_star, 0.328));
611 }
612
613 #[test]
614 fn test_saturate_polar_zero_counter_clockwise_long_f64() {
615 let r_b: f64 = 0.70710677;
616 let r_a = 1.7927681;
617 let theta_a = 3.127344367;
618 let _theta_b = 0.0;
619 let delta = 0.275;
620
621 let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
622
623 assert!(rel_eq(r_star, 0.820972361522));
624 assert!(rel_eq(theta_star, 0.328));
625 }
626
627 #[test]
628 fn test_saturate_polar_zero_clockwise_long_f32() {
629 let r_b: f32 = 0.70710677;
630 let r_a = 1.7927681;
631 let theta_a = bound_theta(-3.127344367);
632 let _theta_b = 0.0;
633 let delta = 0.275;
634
635 let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
636
637 assert!(rel_eq(r_star, 0.820972361522));
638 assert!(rel_eq(theta_star, bound_theta(-0.328)));
639 }
640
641 #[test]
642 fn test_saturate_polar_zero_clockwise_long_f64() {
643 let r_b: f64 = 0.70710677;
644 let r_a = 1.7927681;
645 let theta_a = bound_theta(-3.127344367);
646 let _theta_b = 0.0;
647 let delta = 0.275;
648
649 let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
650
651 assert!(rel_eq(r_star, 0.820972361522));
652 assert!(rel_eq(theta_star, bound_theta(-0.328)));
653 }
654
655 #[test]
656 fn test_saturate_polar_zero_counter_clockwise_short_f32() {
657 let r_b: f32 = 0.70710677;
658 let r_a = 1.7927681;
659 let theta_a = 0.3253262;
660 let _theta_b = 0.0;
661 let delta = 0.275;
662
663 let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
664
665 assert!(rel_eq(r_star, 0.974078524504));
666 assert!(rel_eq(theta_star, 0.080));
667 }
668}