rapier2d/dynamics/island_manager/
manager.rs1use super::Island;
2use crate::alloc_prelude::*;
3use crate::dynamics::{
4 ImpulseJointSet, MultibodyJointSet, RigidBody, RigidBodyChanges, RigidBodyHandle, RigidBodyIds,
5 RigidBodySet, RigidBodyType, SoftBodyHandle, SoftBodySet,
6};
7use crate::geometry::{ColliderSet, NarrowPhase};
8use crate::math::Real;
9use crate::utils::DotProduct;
10use parry::utils::VecMap;
11
12#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
29#[derive(Clone, Default)]
30pub struct IslandManager {
31 pub(crate) active_set_epoch: u32,
35 pub(crate) islands: VecMap<Island>,
36 pub(crate) awake_island: Option<usize>,
39 pub(crate) free_islands: Vec<usize>,
40 #[cfg_attr(feature = "serde-serialize", serde(skip))]
44 pub(crate) solve_groups: Vec<super::SolveGroup>,
45 #[cfg_attr(feature = "serde-serialize", serde(skip))]
47 pub(super) substep_groups_workspace: super::substep_groups::SubstepGroupsWorkspace,
48 pub(crate) persistent: super::PersistentIslands,
51}
52
53impl IslandManager {
54 pub fn new() -> Self {
56 Self::default()
57 }
58
59 #[inline]
60 pub(crate) fn bump_active_set_epoch(&mut self) {
61 self.active_set_epoch = self.active_set_epoch.wrapping_add(1);
62 }
63
64 pub(crate) fn rigid_body_removed_or_disabled(
65 &mut self,
66 removed_handle: RigidBodyHandle,
67 removed_ids: &RigidBodyIds,
68 bodies: &mut RigidBodySet,
69 ) {
70 self.bump_active_set_epoch();
71
72 if let Some(rb) = bodies.get_mut_internal(removed_handle) {
75 rb.ids.island_id = super::INVALID_ISLAND;
76 rb.ids.island_index = u32::MAX;
77 }
78 self.persistent
79 .remove_body_raw(bodies, removed_ids.island_id, removed_ids.island_index);
80
81 let Some(island) = self.islands.get_mut(removed_ids.active_island_id as usize) else {
82 return;
84 };
85
86 if let Some(body) = bodies.get_mut_internal(removed_handle) {
88 body.ids.active_island_id = u32::MAX;
89 body.ids.active_set_id = u32::MAX;
90 }
91
92 let swapped_handle = island.bodies.last().copied().unwrap_or(removed_handle);
93 island
94 .bodies
95 .swap_remove(removed_ids.active_set_id as usize);
96
97 if swapped_handle != removed_handle {
99 let swapped_body = bodies
100 .get_mut(swapped_handle)
101 .expect("Internal error: bodies must be removed from islands on at a times");
102 swapped_body.ids.active_set_id = removed_ids.active_set_id;
103 }
104
105 if island.bodies.is_empty() {
107 if self.awake_island == Some(removed_ids.active_island_id as usize) {
108 self.awake_island = None;
109 }
110 self.islands.remove(removed_ids.active_island_id as usize);
111 self.free_islands
112 .push(removed_ids.active_island_id as usize);
113 }
114 }
115
116 pub(crate) fn interaction_changed(
119 &mut self,
120 bodies: &mut RigidBodySet,
121 handle1: Option<RigidBodyHandle>,
122 handle2: Option<RigidBodyHandle>,
123 wake_up: bool,
124 ) {
125 if wake_up {
129 for handle in [handle1, handle2].into_iter().flatten() {
130 self.wake_up(bodies, handle, false);
131 }
132 }
133
134 #[cfg(debug_assertions)]
139 for handle in [handle1, handle2].into_iter().flatten() {
140 if let Some(rb) = bodies.get(handle).filter(|_| !self.islands.is_empty()) {
141 debug_assert!(
142 rb.is_fixed() || !rb.is_enabled() || rb.ids.active_island_id != u32::MAX
143 );
144 }
145 }
146 }
147
148 pub(crate) fn island(&self, island_id: usize) -> &Island {
149 &self.islands[island_id]
150 }
151
152 pub(crate) fn apply_impulse_joint_island_event(
156 &mut self,
157 bodies: &mut RigidBodySet,
158 event: crate::dynamics::ImpulseJointIslandEvent,
159 ) {
160 if let crate::dynamics::ImpulseJointIslandEvent::Link { body1, body2, .. } = event {
161 self.wake_for_link(bodies, body1, body2);
162 }
163 self.persistent.apply_impulse_joint_event(bodies, event);
164 }
165
166 pub(crate) fn update_multibody_chain(
170 &mut self,
171 bodies: &mut RigidBodySet,
172 multibody_joints: &MultibodyJointSet,
173 mb_id: crate::dynamics::MultibodyIndex,
174 ) {
175 if let Some(mb) = multibody_joints.get_multibody(mb_id) {
176 let mut any_awake = false;
177 let mut sleeping = Vec::new();
178 for link in mb.links() {
179 if let Some(rb) = bodies.get(link.rigid_body) {
180 if !rb.is_fixed() && rb.is_enabled() {
181 if rb.activation.sleeping {
182 sleeping.push(link.rigid_body);
183 } else {
184 any_awake = true;
185 }
186 }
187 }
188 }
189 if any_awake {
190 for handle in sleeping {
191 self.wake_up(bodies, handle, true);
192 }
193 }
194 }
195 self.persistent
196 .update_multibody_chain(bodies, multibody_joints, mb_id);
197 }
198
199 pub(crate) fn update_soft_body_attachments(
203 &mut self,
204 bodies: &mut RigidBodySet,
205 soft_bodies: &SoftBodySet,
206 handle: SoftBodyHandle,
207 ) {
208 if let Some(sb) = soft_bodies.get(handle) {
209 let root = sb.root_body();
210 for attachment in sb.particle_attachments() {
211 self.wake_for_link(bodies, root, attachment.body);
212 }
213 let mut any_awake = false;
214 let mut sleeping = Vec::new();
215 for (_, cluster) in sb.live_clusters() {
216 if let Some(rb) = bodies.get(cluster.proxy()) {
217 if rb.is_enabled() {
218 if rb.activation().sleeping {
219 sleeping.push(cluster.proxy());
220 } else {
221 any_awake = true;
222 }
223 }
224 }
225 }
226 if any_awake {
227 for proxy in sleeping {
228 self.wake_up(bodies, proxy, true);
229 }
230 }
231 }
232 self.persistent
233 .update_soft_body_attachments(bodies, soft_bodies, handle);
234 self.persistent
235 .update_soft_body_proxy_chain(bodies, soft_bodies, handle);
236 }
237
238 fn wake_for_link(
240 &mut self,
241 bodies: &mut RigidBodySet,
242 h1: RigidBodyHandle,
243 h2: RigidBodyHandle,
244 ) {
245 let state = |bodies: &RigidBodySet, h: RigidBodyHandle| {
246 bodies
247 .get(h)
248 .filter(|rb| !rb.is_fixed() && rb.is_enabled())
249 .map(|rb| rb.activation.sleeping)
250 };
251 match (state(bodies, h1), state(bodies, h2)) {
252 (Some(false), Some(true)) => self.wake_up(bodies, h2, true),
253 (Some(true), Some(false)) => self.wake_up(bodies, h1, true),
254 _ => {}
255 }
256 }
257
258 #[doc(hidden)]
262 pub fn persistent_island_of(
263 &self,
264 bodies: &RigidBodySet,
265 handle: RigidBodyHandle,
266 ) -> Option<u32> {
267 self.persistent.body_island(bodies, handle)
268 }
269
270 #[inline]
272 pub fn active_bodies(&self) -> impl Iterator<Item = RigidBodyHandle> + '_ {
273 self.awake_island
274 .into_iter()
275 .flat_map(|i| self.islands[i].bodies.iter().copied())
276 }
277
278 #[cfg(feature = "parallel")]
282 #[inline]
283 pub(crate) fn active_body_slices(&self) -> impl Iterator<Item = &[RigidBodyHandle]> {
284 self.awake_island
285 .into_iter()
286 .map(|i| self.islands[i].bodies.as_slice())
287 }
288
289 #[inline]
291 pub fn num_active_bodies(&self) -> usize {
292 self.awake_island
293 .map(|i| self.islands[i].bodies.len())
294 .unwrap_or(0)
295 }
296
297 pub(crate) fn rigid_body_updated(
298 &mut self,
299 handle: RigidBodyHandle,
300 bodies: &mut RigidBodySet,
301 ) {
302 self.bump_active_set_epoch();
303 let Some(rb) = bodies.get_mut(handle) else {
304 return;
305 };
306
307 if rb.is_fixed() {
308 self.persistent.remove_body(bodies, handle);
311 return;
312 }
313
314 if rb.ids.active_island_id == u32::MAX {
316 if !rb.is_sleeping() {
317 if let Some(id) = self.awake_island {
319 let target_island = &mut self.islands[id];
320 rb.ids.active_island_id = id as u32;
321 rb.ids.active_set_id = (target_island.bodies.len()) as u32;
322 target_island.bodies.push(handle);
323 } else {
324 let new_island = Island::singleton(handle);
325 let id = self.free_islands.pop().unwrap_or(self.islands.len());
326 self.awake_island = Some(id);
327 self.islands.insert(id, new_island);
328 rb.ids.active_island_id = id as u32;
329 rb.ids.active_set_id = 0;
330 }
331 } else {
332 let new_island = Island::singleton(handle);
334 let id = self.free_islands.pop().unwrap_or(self.islands.len());
335 self.islands.insert(id, new_island);
336 rb.ids.active_island_id = id as u32;
337 rb.ids.active_set_id = 0;
338 }
339 }
340
341 self.persistent.ensure_body(bodies, handle);
344 let rb = bodies.index_mut_internal(handle);
345
346 if (rb.changes.contains(RigidBodyChanges::SLEEP)
349 || rb.changes.contains(RigidBodyChanges::TYPE))
350 && rb.is_enabled()
351 && !rb.activation.sleeping
353 {
354 self.wake_up(bodies, handle, false);
355 }
356 }
357
358 pub(crate) fn update_body_energy(
361 rb: &mut RigidBody,
362 soft_bodies: &SoftBodySet,
363 dt: Real,
364 length_unit: Real,
365 ) {
366 let sq_linvel = if rb.body_type == RigidBodyType::SoftFrame {
370 let speed = soft_bodies
371 .get(rb.soft_body)
372 .map_or(0.0, |sb| sb.sleep_speed);
373 speed * speed
374 } else {
375 rb.vels.linvel.length_squared()
376 };
377 let sq_angvel = rb.vels.angvel.gdot(rb.vels.angvel);
378 let pose = rb.pos.position;
379 rb.activation.update_energy(
380 rb.body_type,
381 length_unit,
382 sq_linvel,
383 sq_angvel,
384 rb.mprops.max_extent(),
385 &pose,
386 dt,
387 );
388 }
389
390 pub(crate) fn update_islands(
391 &mut self,
392 bodies: &mut RigidBodySet,
393 colliders: &ColliderSet,
394 narrow_phase: &mut NarrowPhase,
395 impulse_joints: &ImpulseJointSet,
396 multibody_joints: &MultibodyJointSet,
397 soft_bodies: &SoftBodySet,
398 sleep_observations: &[(u32, bool)],
399 ) {
400 if !self.persistent.bootstrapped {
404 let to_wake = self.persistent.bootstrap(
405 bodies,
406 narrow_phase.touching_pairs_with_ids(colliders),
407 impulse_joints,
408 multibody_joints,
409 soft_bodies,
410 );
411 for handle in to_wake {
412 self.wake_up(bodies, handle, false);
413 }
414
415 let handles: Vec<RigidBodyHandle> = bodies.iter().map(|(h, _)| h).collect();
418 for handle in handles {
419 let rb = bodies.index_mut_internal(handle);
420 if rb.mprops.max_extent() == 0.0 {
421 rb.mprops.recompute_max_extent(colliders, &rb.colliders);
422 }
423 }
424 }
425
426 let mut chunks: Vec<Vec<RigidBodyHandle>> = Vec::new();
430 if !sleep_observations.is_empty() {
431 self.persistent.begin_sleep_scan();
432 for (island_id, eligible) in sleep_observations {
433 self.persistent
434 .observe_body_for_sleep(*island_id, *eligible);
435 }
436
437 let sleepable = self.persistent.finish_sleep_scan();
438 for id in sleepable {
439 self.persistent.mark_island_sleeping(id);
440 chunks.push(self.persistent.islands[id as usize].bodies.clone());
441 }
442 }
443
444 if !chunks.is_empty() {
445 let awake_id = self
446 .awake_island
447 .expect("sleep observations imply an awake island");
448 let awake_len = self.islands[awake_id].len();
449 self.commit_sleeping_chunks(bodies, narrow_phase, awake_id, awake_len, chunks);
450 }
451
452 #[cfg(debug_assertions)]
456 {
457 self.persistent.assert_consistent(bodies);
458 for (edge_id, h1, h2) in narrow_phase.touching_pairs_with_ids(colliders) {
459 let member = |h: Option<RigidBodyHandle>| {
460 h.and_then(|h| bodies.get(h))
461 .filter(|rb| !rb.is_fixed() && rb.is_enabled())
462 .map(|rb| rb.ids.island_id)
463 };
464 let m1 = member(h1);
465 let m2 = member(h2);
466 if m1.is_some() || m2.is_some() {
467 let loc = self.persistent.contact_link_loc(edge_id);
468 assert!(
469 loc.is_some(),
470 "touching pair (edge {edge_id}) not linked in the persistent islands"
471 );
472 let island = loc.unwrap().0;
473 for m in [m1, m2].into_iter().flatten() {
474 assert_eq!(
475 m, island,
476 "touching pair (edge {edge_id}) linked into the wrong island"
477 );
478 }
479 }
480 }
481 }
482 }
483}