rapier3d/dynamics/joint/multibody_joint/
multibody_joint_set.rs1use parry::utils::hashset::HashSet;
2
3use crate::data::{Arena, Coarena, Index};
4use crate::dynamics::joint::MultibodyLink;
5use crate::dynamics::{GenericJoint, Multibody, MultibodyJoint, RigidBodyHandle};
6use crate::geometry::{InteractionGraph, RigidBodyGraphIndex};
7
8#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
10#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
11#[repr(transparent)]
12pub struct MultibodyJointHandle(pub Index);
13
14#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
16#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
17#[repr(transparent)]
18pub struct MultibodyIndex(pub Index);
19
20impl MultibodyJointHandle {
21 pub fn into_raw_parts(self) -> (u32, u32) {
23 self.0.into_raw_parts()
24 }
25
26 pub fn from_raw_parts(id: u32, generation: u32) -> Self {
28 Self(Index::from_raw_parts(id, generation))
29 }
30
31 pub fn invalid() -> Self {
33 Self(Index::from_raw_parts(
34 crate::INVALID_U32,
35 crate::INVALID_U32,
36 ))
37 }
38}
39
40impl Default for MultibodyJointHandle {
41 fn default() -> Self {
42 Self::invalid()
43 }
44}
45
46#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
47#[derive(Copy, Clone, Debug, PartialEq, Eq)]
48pub struct MultibodyLinkId {
58 pub(crate) graph_id: RigidBodyGraphIndex,
59 pub multibody: MultibodyIndex,
62 pub id: usize,
64}
65
66impl Default for MultibodyLinkId {
67 fn default() -> Self {
68 Self {
69 graph_id: RigidBodyGraphIndex::new(crate::INVALID_U32),
70 multibody: MultibodyIndex(Index::from_raw_parts(
71 crate::INVALID_U32,
72 crate::INVALID_U32,
73 )),
74 id: 0,
75 }
76 }
77}
78
79#[derive(Default)]
80#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
82#[derive(Clone, Debug)]
83pub struct MultibodyJointSet {
84 pub(crate) multibodies: Arena<Multibody>, pub(crate) rb2mb: Coarena<MultibodyLinkId>,
86 pub(crate) connectivity_graph: InteractionGraph<RigidBodyHandle, ()>,
89 pub(crate) to_wake_up: HashSet<RigidBodyHandle>,
90}
91
92impl MultibodyJointSet {
93 pub fn new() -> Self {
95 Self {
96 multibodies: Arena::new(),
97 rb2mb: Coarena::new(),
98 connectivity_graph: InteractionGraph::new(),
99 to_wake_up: HashSet::default(),
100 }
101 }
102
103 pub fn iter(
105 &self,
106 ) -> impl Iterator<
107 Item = (
108 MultibodyJointHandle,
109 &MultibodyLinkId,
110 &Multibody,
111 &MultibodyLink,
112 ),
113 > {
114 self.rb2mb
115 .iter()
116 .filter(|(_, link)| link.id > 0) .map(|(h, link)| {
118 let mb = &self.multibodies[link.multibody.0];
119 (MultibodyJointHandle(h), link, mb, mb.link(link.id).unwrap())
120 })
121 }
122
123 pub fn insert_kinematic(
125 &mut self,
126 body1: RigidBodyHandle,
127 body2: RigidBodyHandle,
128 data: impl Into<GenericJoint>,
129 wake_up: bool,
130 ) -> Option<MultibodyJointHandle> {
131 self.do_insert(body1, body2, data, true, wake_up)
132 }
133
134 pub fn insert(
136 &mut self,
137 body1: RigidBodyHandle,
138 body2: RigidBodyHandle,
139 data: impl Into<GenericJoint>,
140 wake_up: bool,
141 ) -> Option<MultibodyJointHandle> {
142 self.do_insert(body1, body2, data, false, wake_up)
143 }
144
145 #[profiling::function]
147 fn do_insert(
148 &mut self,
149 body1: RigidBodyHandle,
150 body2: RigidBodyHandle,
151 data: impl Into<GenericJoint>,
152 kinematic: bool,
153 wake_up: bool,
154 ) -> Option<MultibodyJointHandle> {
155 let link1 = self.rb2mb.get(body1.0).copied().unwrap_or_else(|| {
156 let mb_handle = self.multibodies.insert(Multibody::with_root(body1, true));
157 MultibodyLinkId {
158 graph_id: self.connectivity_graph.graph.add_node(body1),
159 multibody: MultibodyIndex(mb_handle),
160 id: 0,
161 }
162 });
163
164 let link2 = self.rb2mb.get(body2.0).copied().unwrap_or_else(|| {
165 let mb_handle = self.multibodies.insert(Multibody::with_root(body2, true));
166 MultibodyLinkId {
167 graph_id: self.connectivity_graph.graph.add_node(body2),
168 multibody: MultibodyIndex(mb_handle),
169 id: 0,
170 }
171 });
172
173 if link1.multibody == link2.multibody || link2.id != 0 {
174 return None;
176 }
177
178 self.connectivity_graph
179 .graph
180 .add_edge(link1.graph_id, link2.graph_id, ());
181 self.rb2mb.insert(body1.0, link1);
182 self.rb2mb.insert(body2.0, link2);
183
184 let mb2 = self.multibodies.remove(link2.multibody.0).unwrap();
185 let multibody1 = &mut self.multibodies[link1.multibody.0];
186
187 for mb_link2 in mb2.links() {
188 let link = self.rb2mb.get_mut(mb_link2.rigid_body.0).unwrap();
189 link.multibody = link1.multibody;
190 link.id += multibody1.num_links();
191 }
192
193 multibody1.append(mb2, link1.id, MultibodyJoint::new(data.into(), kinematic));
194
195 if wake_up {
196 self.to_wake_up.insert(body1);
197 self.to_wake_up.insert(body2);
198 }
199
200 Some(MultibodyJointHandle(body2.0))
204 }
205
206 #[profiling::function]
208 pub fn remove(&mut self, handle: MultibodyJointHandle, wake_up: bool) {
209 if let Some(removed) = self.rb2mb.get(handle.0).copied() {
210 let multibody = self.multibodies.remove(removed.multibody.0).unwrap();
211
212 if let Some(parent_link) = multibody.link(removed.id).unwrap().parent_id() {
214 let parent_rb = multibody.link(parent_link).unwrap().rigid_body;
215 let parent_graph_id = self.rb2mb.get(parent_rb.0).unwrap().graph_id;
216 self.connectivity_graph
217 .remove_edge(parent_graph_id, removed.graph_id);
218
219 if wake_up {
220 self.to_wake_up.insert(RigidBodyHandle(handle.0));
221 self.to_wake_up.insert(parent_rb);
222 }
223
224 let multibodies = multibody.remove_link(removed.id, true);
228
229 for multibody in multibodies {
231 if multibody.num_links() == 1 {
232 let isolated_link = multibody.link(0).unwrap();
234 let isolated_graph_id =
235 self.rb2mb.get(isolated_link.rigid_body.0).unwrap().graph_id;
236 if let Some(other) = self.connectivity_graph.remove_node(isolated_graph_id)
237 {
238 self.rb2mb.get_mut(other.0).unwrap().graph_id = isolated_graph_id;
239 }
240 } else {
241 let mb_id = self.multibodies.insert(multibody);
242 for link in self.multibodies[mb_id].links() {
243 let ids = self.rb2mb.get_mut(link.rigid_body.0).unwrap();
244 ids.multibody = MultibodyIndex(mb_id);
245 ids.id = link.internal_id;
246 }
247 }
248 }
249 }
250 }
251 }
252
253 #[profiling::function]
255 pub fn remove_multibody_articulations(&mut self, handle: RigidBodyHandle, wake_up: bool) {
256 if let Some(removed) = self.rb2mb.get(handle.0).copied() {
257 let multibody = self.multibodies.remove(removed.multibody.0).unwrap();
259 for link in multibody.links() {
260 let rb_handle = link.rigid_body;
261
262 if wake_up {
263 self.to_wake_up.insert(rb_handle);
264 }
265
266 let removed = self.rb2mb.remove(rb_handle.0, Default::default()).unwrap();
268 if let Some(other) = self.connectivity_graph.remove_node(removed.graph_id) {
270 self.rb2mb.get_mut(other.0).unwrap().graph_id = removed.graph_id;
271 }
272 }
273 }
274 }
275
276 #[profiling::function]
278 pub fn remove_joints_attached_to_rigid_body(&mut self, rb_to_remove: RigidBodyHandle) {
279 if let Some(link_to_remove) = self.rb2mb.get(rb_to_remove.0).copied() {
281 let mut articulations_to_remove = vec![];
282 for (rb1, rb2, _) in self
283 .connectivity_graph
284 .interactions_with(link_to_remove.graph_id)
285 {
286 articulations_to_remove.push(MultibodyJointHandle(rb2.0));
288
289 self.to_wake_up.insert(rb1);
290 self.to_wake_up.insert(rb2);
291 }
292
293 for articulation_handle in articulations_to_remove {
294 self.remove(articulation_handle, true);
295 }
296 }
297 }
298
299 pub fn rigid_body_link(&self, rb: RigidBodyHandle) -> Option<&MultibodyLinkId> {
303 self.rb2mb.get(rb.0)
304 }
305
306 pub fn get_multibody(&self, index: MultibodyIndex) -> Option<&Multibody> {
308 self.multibodies.get(index.0)
309 }
310
311 pub fn get_multibody_mut(&mut self, index: MultibodyIndex) -> Option<&mut Multibody> {
314 self.multibodies.get_mut(index.0)
316 }
317
318 pub fn get_multibody_mut_internal(&mut self, index: MultibodyIndex) -> Option<&mut Multibody> {
323 self.multibodies.get_mut(index.0)
324 }
325
326 pub fn get(&self, handle: MultibodyJointHandle) -> Option<(&Multibody, usize)> {
328 let link = self.rb2mb.get(handle.0)?;
329 let multibody = self.multibodies.get(link.multibody.0)?;
330 Some((multibody, link.id))
331 }
332
333 pub fn get_mut(&mut self, handle: MultibodyJointHandle) -> Option<(&mut Multibody, usize)> {
335 let link = self.rb2mb.get(handle.0)?;
336 let multibody = self.multibodies.get_mut(link.multibody.0)?;
337 Some((multibody, link.id))
338 }
339
340 pub fn get_mut_internal(
344 &mut self,
345 handle: MultibodyJointHandle,
346 ) -> Option<(&mut Multibody, usize)> {
347 let link = self.rb2mb.get(handle.0)?;
349 let multibody = self.multibodies.get_mut(link.multibody.0)?;
350 Some((multibody, link.id))
351 }
352
353 pub fn get_unknown_gen(&self, i: u32) -> Option<(&Multibody, usize, MultibodyJointHandle)> {
363 let link = self.rb2mb.get_unknown_gen(i)?;
364 let generation = self.rb2mb.get_gen(i)?;
365 let multibody = self.multibodies.get(link.multibody.0)?;
366 Some((
367 multibody,
368 link.id,
369 MultibodyJointHandle(Index::from_raw_parts(i, generation)),
370 ))
371 }
372
373 pub fn joint_between(
375 &self,
376 rb1: RigidBodyHandle,
377 rb2: RigidBodyHandle,
378 ) -> Option<(MultibodyJointHandle, &Multibody, &MultibodyLink)> {
379 let id1 = self.rb2mb.get(rb1.0)?;
380 let id2 = self.rb2mb.get(rb2.0)?;
381
382 if id1.multibody != id2.multibody {
384 return None;
385 }
386
387 let mb = self.multibodies.get(id1.multibody.0)?;
388
389 let link1 = mb.link(id1.id)?;
392 let parent1 = link1.parent_id();
393
394 if parent1 == Some(id2.id) {
395 Some((MultibodyJointHandle(rb1.0), mb, link1))
396 } else {
397 let link2 = mb.link(id2.id)?;
398 let parent2 = link2.parent_id();
399
400 if parent2 == Some(id1.id) {
401 Some((MultibodyJointHandle(rb2.0), mb, link2))
402 } else {
403 None
404 }
405 }
406 }
407
408 #[profiling::function]
410 pub fn attached_joints(
411 &self,
412 rb: RigidBodyHandle,
413 ) -> impl Iterator<Item = (RigidBodyHandle, RigidBodyHandle, MultibodyJointHandle)> + '_ {
414 self.rb2mb
415 .get(rb.0)
416 .into_iter()
417 .flat_map(move |link| self.connectivity_graph.interactions_with(link.graph_id))
418 .map(|inter| {
419 (inter.0, inter.1, MultibodyJointHandle(inter.1.0))
421 })
422 }
423
424 pub fn attached_bodies(
427 &self,
428 body: RigidBodyHandle,
429 ) -> impl Iterator<Item = RigidBodyHandle> + '_ {
430 self.rb2mb
431 .get(body.0)
432 .into_iter()
433 .flat_map(move |id| self.connectivity_graph.interactions_with(id.graph_id))
434 .map(move |inter| crate::utils::select_other((inter.0, inter.1), body))
435 }
436
437 #[profiling::function]
440 pub fn bodies_attached_with_enabled_joint(
441 &self,
442 body: RigidBodyHandle,
443 ) -> impl Iterator<Item = RigidBodyHandle> + '_ {
444 self.attached_bodies(body).filter(move |other| {
445 if let Some((_, _, link)) = self.joint_between(body, *other) {
446 link.joint.data.is_enabled()
447 } else {
448 false
449 }
450 })
451 }
452
453 pub fn multibodies(&self) -> impl Iterator<Item = &Multibody> {
455 self.multibodies.iter().map(|e| e.1)
456 }
457}
458
459impl std::ops::Index<MultibodyIndex> for MultibodyJointSet {
460 type Output = Multibody;
461
462 fn index(&self, index: MultibodyIndex) -> &Multibody {
463 &self.multibodies[index.0]
464 }
465}
466
467