repose_motion_planning/
validity.rs1use crate::MAX_ATTACHED_SHAPES;
9use crate::MAX_EXCLUSIONS;
10use crate::MAX_OBSTACLES;
11use cu29::units::si::length::meter;
12use repose_collision::CuCollisionEnv;
13use repose_collision::CuCollisionReport;
14use repose_collision::CuPlanningScene;
15use repose_collision::CuRobotCollisionModel;
16use repose_collision::CuSceneExclusions;
17use repose_collision::CuSceneRevision;
18use repose_kinematics::CuJointMetric;
19use repose_kinematics::CuJointPosition;
20use repose_kinematics::CuJointResolution;
21use repose_kinematics::CuKinematicChain;
22
23#[derive(Clone)]
29pub struct CuSceneValidity<const N: usize, const M: usize = N> {
30 chain: CuKinematicChain<N>,
31 model: CuRobotCollisionModel<N, M>,
32 resolution: CuJointResolution,
33 scene: CuPlanningScene<MAX_OBSTACLES, MAX_ATTACHED_SHAPES>,
34 exclusions: CuSceneExclusions<MAX_EXCLUSIONS>,
35 captured: bool,
37}
38
39impl<const N: usize, const M: usize> CuSceneValidity<N, M> {
40 pub fn new(
43 chain: CuKinematicChain<N>,
44 model: CuRobotCollisionModel<N, M>,
45 resolution: CuJointResolution,
46 ) -> Self {
47 Self {
48 chain,
49 model,
50 resolution,
51 scene: CuPlanningScene::new(),
52 exclusions: CuSceneExclusions::new(),
53 captured: true,
54 }
55 }
56
57 pub const fn chain(&self) -> &CuKinematicChain<N> {
59 &self.chain
60 }
61
62 pub const fn resolution(&self) -> CuJointResolution {
64 self.resolution
65 }
66
67 pub const fn scene_revision(&self) -> CuSceneRevision {
69 self.scene.revision()
70 }
71
72 pub const fn exclusions(&self) -> &CuSceneExclusions<MAX_EXCLUSIONS> {
74 &self.exclusions
75 }
76
77 pub fn capture(
82 &mut self,
83 scene: &CuPlanningScene<MAX_OBSTACLES, MAX_ATTACHED_SHAPES>,
84 exclusions: &CuSceneExclusions<MAX_EXCLUSIONS>,
85 ) -> bool {
86 self.scene = scene.clone();
87 self.exclusions = exclusions.clone();
88 self.captured = self.resolution.metric().validate().is_ok()
89 && self
90 .scene
91 .attached_shapes()
92 .iter()
93 .all(|a| a.frame.is_none_or(|frame| frame < N))
94 && exclusions
95 .validate(&self.scene, self.model.shape_count())
96 .is_ok();
97 self.captured
98 }
99
100 fn env(&self) -> CuCollisionEnv<'_> {
102 self.scene.collision_env().with_exclusions(&self.exclusions)
103 }
104
105 pub fn is_configuration_free(&self, q: &[CuJointPosition; N]) -> bool {
108 self.captured
109 && self
110 .model
111 .is_configuration_collision_free(&self.chain, q, &self.env())
112 .unwrap_or(false)
113 }
114
115 pub fn is_segment_free(&self, a: &[CuJointPosition; N], b: &[CuJointPosition; N]) -> bool {
118 let metric = self.resolution.metric();
119 let mut max_delta = 0.0_f64;
120 for j in 0..N {
121 let joint = &self.chain.joints()[j];
122 if joint.validate_coordinate(a[j]).is_err() || joint.validate_coordinate(b[j]).is_err()
123 {
124 return false;
125 }
126 max_delta = max_delta.max(libm::fabs(
127 metric.normalized(b[j]) - metric.normalized(a[j]),
128 ));
129 }
130 if !max_delta.is_finite() || max_delta > 1_000_000.0 {
131 return false;
132 }
133 let steps = (libm::ceil(max_delta) as usize).max(1);
134 for s in 0..=steps {
135 let alpha = s as f64 / steps as f64;
136 let mut q = [CuJointPosition::default(); N];
137 for j in 0..N {
138 match a[j].interpolate(b[j], alpha) {
139 Ok(value) => q[j] = value,
140 Err(_) => return false,
141 }
142 }
143 if !self.is_configuration_free(&q) {
144 return false;
145 }
146 }
147 true
148 }
149
150 pub fn clearance(&self, q: &[CuJointPosition; N]) -> Option<f64> {
154 if !self.captured {
155 return None;
156 }
157 let mut report = CuCollisionReport::<0>::default();
158 self.model
159 .check_configuration(&self.chain, q, &self.env(), &mut report)
160 .ok()?;
161 Some(report.min_signed_distance().get::<meter>())
162 }
163}
164
165pub fn joint_distance<const N: usize>(
167 a: &[CuJointPosition; N],
168 b: &[CuJointPosition; N],
169 metric: CuJointMetric,
170) -> f64 {
171 let mut sum = 0.0_f64;
172 for j in 0..N {
173 let d = metric.normalized(b[j]) - metric.normalized(a[j]);
174 sum += d * d;
175 }
176 libm::sqrt(sum)
177}