rapier2d/dynamics/island_manager/
manager.rs1use super::Island;
2use crate::alloc_prelude::*;
3use crate::dynamics::{
4 ImpulseJointSet, MultibodyJointSet, RigidBody, RigidBodyChanges, RigidBodyHandle, RigidBodyIds,
5 RigidBodySet,
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)]
138 for handle in [handle1, handle2].into_iter().flatten() {
139 if let Some(rb) = bodies.get(handle) {
140 debug_assert!(
141 rb.is_fixed() || !rb.is_enabled() || rb.ids.active_island_id != u32::MAX
142 );
143 }
144 }
145 }
146
147 pub(crate) fn island(&self, island_id: usize) -> &Island {
148 &self.islands[island_id]
149 }
150
151 pub(crate) fn apply_impulse_joint_island_event(
155 &mut self,
156 bodies: &mut RigidBodySet,
157 event: crate::dynamics::ImpulseJointIslandEvent,
158 ) {
159 if let crate::dynamics::ImpulseJointIslandEvent::Link { body1, body2, .. } = event {
160 self.wake_for_link(bodies, body1, body2);
161 }
162 self.persistent.apply_impulse_joint_event(bodies, event);
163 }
164
165 pub(crate) fn refresh_multibody_chain(
169 &mut self,
170 bodies: &mut RigidBodySet,
171 multibody_joints: &MultibodyJointSet,
172 mb_id: crate::dynamics::MultibodyIndex,
173 ) {
174 if let Some(mb) = multibody_joints.get_multibody(mb_id) {
175 let mut any_awake = false;
176 let mut sleeping = Vec::new();
177 for link in mb.links() {
178 if let Some(rb) = bodies.get(link.rigid_body) {
179 if !rb.is_fixed() && rb.is_enabled() {
180 if rb.activation.sleeping {
181 sleeping.push(link.rigid_body);
182 } else {
183 any_awake = true;
184 }
185 }
186 }
187 }
188 if any_awake {
189 for handle in sleeping {
190 self.wake_up(bodies, handle, true);
191 }
192 }
193 }
194 self.persistent
195 .refresh_multibody_chain(bodies, multibody_joints, mb_id);
196 }
197
198 fn wake_for_link(
200 &mut self,
201 bodies: &mut RigidBodySet,
202 h1: RigidBodyHandle,
203 h2: RigidBodyHandle,
204 ) {
205 let state = |bodies: &RigidBodySet, h: RigidBodyHandle| {
206 bodies
207 .get(h)
208 .filter(|rb| !rb.is_fixed() && rb.is_enabled())
209 .map(|rb| rb.activation.sleeping)
210 };
211 match (state(bodies, h1), state(bodies, h2)) {
212 (Some(false), Some(true)) => self.wake_up(bodies, h2, true),
213 (Some(true), Some(false)) => self.wake_up(bodies, h1, true),
214 _ => {}
215 }
216 }
217
218 #[doc(hidden)]
222 pub fn persistent_island_of(
223 &self,
224 bodies: &RigidBodySet,
225 handle: RigidBodyHandle,
226 ) -> Option<u32> {
227 self.persistent.body_island(bodies, handle)
228 }
229
230 #[inline]
232 pub fn active_bodies(&self) -> impl Iterator<Item = RigidBodyHandle> + '_ {
233 self.awake_island
234 .into_iter()
235 .flat_map(|i| self.islands[i].bodies.iter().copied())
236 }
237
238 #[cfg(feature = "parallel")]
242 #[inline]
243 pub(crate) fn active_body_slices(&self) -> impl Iterator<Item = &[RigidBodyHandle]> {
244 self.awake_island
245 .into_iter()
246 .map(|i| self.islands[i].bodies.as_slice())
247 }
248
249 #[inline]
251 pub fn num_active_bodies(&self) -> usize {
252 self.awake_island
253 .map(|i| self.islands[i].bodies.len())
254 .unwrap_or(0)
255 }
256
257 pub(crate) fn rigid_body_updated(
258 &mut self,
259 handle: RigidBodyHandle,
260 bodies: &mut RigidBodySet,
261 ) {
262 self.bump_active_set_epoch();
263 let Some(rb) = bodies.get_mut(handle) else {
264 return;
265 };
266
267 if rb.is_fixed() {
268 self.persistent.remove_body(bodies, handle);
271 return;
272 }
273
274 if rb.ids.active_island_id == u32::MAX {
276 if !rb.is_sleeping() {
277 if let Some(id) = self.awake_island {
279 let target_island = &mut self.islands[id];
280 rb.ids.active_island_id = id as u32;
281 rb.ids.active_set_id = (target_island.bodies.len()) as u32;
282 target_island.bodies.push(handle);
283 } else {
284 let new_island = Island::singleton(handle);
285 let id = self.free_islands.pop().unwrap_or(self.islands.len());
286 self.awake_island = Some(id);
287 self.islands.insert(id, new_island);
288 rb.ids.active_island_id = id as u32;
289 rb.ids.active_set_id = 0;
290 }
291 } else {
292 let new_island = Island::singleton(handle);
294 let id = self.free_islands.pop().unwrap_or(self.islands.len());
295 self.islands.insert(id, new_island);
296 rb.ids.active_island_id = id as u32;
297 rb.ids.active_set_id = 0;
298 }
299 }
300
301 self.persistent.ensure_body(bodies, handle);
304 let rb = bodies.index_mut_internal(handle);
305
306 if (rb.changes.contains(RigidBodyChanges::SLEEP)
309 || rb.changes.contains(RigidBodyChanges::TYPE))
310 && rb.is_enabled()
311 && !rb.activation.sleeping
313 {
314 self.wake_up(bodies, handle, false);
315 }
316 }
317
318 pub(crate) fn update_body_energy(rb: &mut RigidBody, dt: Real, length_unit: Real) {
321 let sq_linvel = rb.vels.linvel.length_squared();
322 let sq_angvel = rb.vels.angvel.gdot(rb.vels.angvel);
323 let pose = rb.pos.position;
324 rb.activation.update_energy(
325 rb.body_type,
326 length_unit,
327 sq_linvel,
328 sq_angvel,
329 rb.mprops.max_extent(),
330 &pose,
331 dt,
332 );
333 }
334
335 pub(crate) fn update_islands(
336 &mut self,
337 bodies: &mut RigidBodySet,
338 colliders: &ColliderSet,
339 narrow_phase: &mut NarrowPhase,
340 impulse_joints: &ImpulseJointSet,
341 multibody_joints: &MultibodyJointSet,
342 sleep_observations: &[(u32, bool)],
343 ) {
344 if !self.persistent.bootstrapped {
348 let to_wake = self.persistent.bootstrap(
349 bodies,
350 narrow_phase.touching_pairs_with_ids(colliders),
351 impulse_joints,
352 multibody_joints,
353 );
354 for handle in to_wake {
355 self.wake_up(bodies, handle, false);
356 }
357
358 let handles: Vec<RigidBodyHandle> = bodies.iter().map(|(h, _)| h).collect();
361 for handle in handles {
362 let rb = bodies.index_mut_internal(handle);
363 if rb.mprops.max_extent() == 0.0 {
364 rb.mprops.recompute_max_extent(colliders, &rb.colliders);
365 }
366 }
367 }
368
369 let mut chunks: Vec<Vec<RigidBodyHandle>> = Vec::new();
373 if !sleep_observations.is_empty() {
374 self.persistent.begin_sleep_scan();
375 for (island_id, eligible) in sleep_observations {
376 self.persistent
377 .observe_body_for_sleep(*island_id, *eligible);
378 }
379
380 let sleepable = self.persistent.finish_sleep_scan();
381 for id in sleepable {
382 self.persistent.mark_island_sleeping(id);
383 chunks.push(self.persistent.islands[id as usize].bodies.clone());
384 }
385 }
386
387 if !chunks.is_empty() {
388 let awake_id = self
389 .awake_island
390 .expect("sleep observations imply an awake island");
391 let awake_len = self.islands[awake_id].len();
392 self.commit_sleeping_chunks(bodies, narrow_phase, awake_id, awake_len, chunks);
393 }
394
395 #[cfg(debug_assertions)]
399 {
400 self.persistent.assert_consistent(bodies);
401 for (edge_id, h1, h2) in narrow_phase.touching_pairs_with_ids(colliders) {
402 let member = |h: Option<RigidBodyHandle>| {
403 h.and_then(|h| bodies.get(h))
404 .filter(|rb| !rb.is_fixed() && rb.is_enabled())
405 .map(|rb| rb.ids.island_id)
406 };
407 let m1 = member(h1);
408 let m2 = member(h2);
409 if m1.is_some() || m2.is_some() {
410 let loc = self.persistent.contact_link_loc(edge_id);
411 assert!(
412 loc.is_some(),
413 "touching pair (edge {edge_id}) not linked in the persistent islands"
414 );
415 let island = loc.unwrap().0;
416 for m in [m1, m2].into_iter().flatten() {
417 assert_eq!(
418 m, island,
419 "touching pair (edge {edge_id}) linked into the wrong island"
420 );
421 }
422 }
423 }
424 }
425 }
426}