1use crate::core::NULL_INDEX;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct ContactLink {
14 pub contact_id: i32,
15 pub body_id_a: i32,
16 pub body_id_b: i32,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct JointLink {
23 pub joint_id: i32,
24 pub body_id_a: i32,
25 pub body_id_b: i32,
26}
27
28#[derive(Debug, Clone)]
35pub struct Island {
36 pub set_index: i32,
38
39 pub local_index: i32,
41
42 pub island_id: i32,
43
44 pub constraint_remove_count: i32,
47
48 pub bodies: Vec<i32>,
49
50 pub contacts: Vec<ContactLink>,
54 pub joints: Vec<JointLink>,
55}
56
57impl Default for Island {
58 fn default() -> Self {
59 Island {
60 set_index: NULL_INDEX,
61 local_index: NULL_INDEX,
62 island_id: NULL_INDEX,
63 constraint_remove_count: 0,
64 bodies: Vec::new(),
65 contacts: Vec::new(),
66 joints: Vec::new(),
67 }
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub struct IslandSim {
74 pub island_id: i32,
75}
76
77impl Default for IslandSim {
78 fn default() -> Self {
79 IslandSim {
80 island_id: NULL_INDEX,
81 }
82 }
83}
84
85use crate::solver_set::{AWAKE_SET, FIRST_SLEEPING_SET};
91use crate::world::World;
92
93pub fn create_island(world: &mut World, set_index: i32) -> i32 {
96 debug_assert!(set_index == AWAKE_SET || set_index >= FIRST_SLEEPING_SET);
97
98 let island_id = world.island_id_pool.alloc_id();
99
100 if island_id == world.islands.len() as i32 {
101 world.islands.push(Island::default());
102 } else {
103 debug_assert!(world.islands[island_id as usize].set_index == NULL_INDEX);
104 }
105
106 let set = &mut world.solver_sets[set_index as usize];
107
108 let local_index = set.island_sims.len() as i32;
109 set.island_sims.push(IslandSim { island_id });
110
111 let island = &mut world.islands[island_id as usize];
112 island.set_index = set_index;
113 island.local_index = local_index;
114 island.island_id = island_id;
115 island.bodies = Vec::new();
116 island.contacts = Vec::new();
117 island.joints = Vec::new();
118 island.constraint_remove_count = 0;
119
120 island_id
121}
122
123pub fn destroy_island(world: &mut World, island_id: i32) {
125 if world.split_island_id == island_id {
126 world.split_island_id = NULL_INDEX;
127 }
128
129 let (set_index, local_index) = {
131 let island = &world.islands[island_id as usize];
132 (island.set_index, island.local_index)
133 };
134 let set = &mut world.solver_sets[set_index as usize];
135 {
136 let last_index = set.island_sims.len() - 1;
137 debug_assert!(0 <= local_index && local_index as usize <= last_index);
138 let move_island_id = set.island_sims[last_index].island_id;
139 set.island_sims.swap_remove(local_index as usize);
140 world.islands[move_island_id as usize].local_index = local_index;
141 }
142
143 let island = &mut world.islands[island_id as usize];
145 island.bodies = Vec::new();
146 island.contacts = Vec::new();
147 island.joints = Vec::new();
148 island.constraint_remove_count = 0;
149 island.local_index = NULL_INDEX;
150 island.island_id = NULL_INDEX;
151 island.set_index = NULL_INDEX;
152
153 world.island_id_pool.free_id(island_id);
154}
155
156pub(crate) fn merge_islands(world: &mut World, island_id_a: i32, island_id_b: i32) -> i32 {
159 if island_id_a == island_id_b {
160 return island_id_a;
161 }
162
163 if island_id_a == NULL_INDEX {
164 debug_assert!(island_id_b != NULL_INDEX);
165 return island_id_b;
166 }
167
168 if island_id_b == NULL_INDEX {
169 debug_assert!(island_id_a != NULL_INDEX);
170 return island_id_a;
171 }
172
173 let (big_island_id, small_island_id) = {
175 let count_a = world.islands[island_id_a as usize].bodies.len();
176 let count_b = world.islands[island_id_b as usize].bodies.len();
177 if count_a >= count_b {
178 (island_id_a, island_id_b)
179 } else {
180 (island_id_b, island_id_a)
181 }
182 };
183
184 let small_bodies = std::mem::take(&mut world.islands[small_island_id as usize].bodies);
186 for &body_id in &small_bodies {
187 let body = &mut world.bodies[body_id as usize];
188 debug_assert!(body.island_id == small_island_id);
189 body.island_id = big_island_id;
190 body.island_index = world.islands[big_island_id as usize].bodies.len() as i32;
191 world.islands[big_island_id as usize].bodies.push(body_id);
192 }
193
194 let small_contacts = std::mem::take(&mut world.islands[small_island_id as usize].contacts);
196 for link in &small_contacts {
197 let contact = &mut world.contacts[link.contact_id as usize];
198 contact.island_id = big_island_id;
199 contact.island_index = world.islands[big_island_id as usize].contacts.len() as i32;
200 world.islands[big_island_id as usize].contacts.push(*link);
201 }
202
203 let small_joints = std::mem::take(&mut world.islands[small_island_id as usize].joints);
205 for link in &small_joints {
206 let joint = &mut world.joints[link.joint_id as usize];
207 joint.island_id = big_island_id;
208 joint.island_index = world.islands[big_island_id as usize].joints.len() as i32;
209 world.islands[big_island_id as usize].joints.push(*link);
210 }
211
212 let small_removed = world.islands[small_island_id as usize].constraint_remove_count;
214 world.islands[big_island_id as usize].constraint_remove_count += small_removed;
215
216 destroy_island(world, small_island_id);
217
218 validate_island(world, big_island_id);
219
220 big_island_id
221}
222
223fn add_contact_to_island(world: &mut World, island_id: i32, contact_id: i32) {
225 let (edge_body_a, edge_body_b) = {
226 let contact = &world.contacts[contact_id as usize];
227 debug_assert!(contact.island_id == NULL_INDEX);
228 debug_assert!(contact.island_index == NULL_INDEX);
229 (contact.edges[0].body_id, contact.edges[1].body_id)
230 };
231
232 let island = &mut world.islands[island_id as usize];
233
234 let island_index = island.contacts.len() as i32;
235 island.contacts.push(ContactLink {
236 contact_id,
237 body_id_a: edge_body_a,
238 body_id_b: edge_body_b,
239 });
240
241 let contact = &mut world.contacts[contact_id as usize];
242 contact.island_id = island_id;
243 contact.island_index = island_index;
244
245 validate_island(world, island_id);
246}
247
248pub fn link_contact(world: &mut World, contact_id: i32) {
251 use crate::contact::contact_flags::TOUCHING;
252 use crate::solver_set::DISABLED_SET;
253
254 let (body_id_a, body_id_b) = {
255 let contact = &world.contacts[contact_id as usize];
256 debug_assert!(contact.flags & TOUCHING != 0);
257 (contact.edges[0].body_id, contact.edges[1].body_id)
258 };
259
260 let set_a = world.bodies[body_id_a as usize].set_index;
261 let set_b = world.bodies[body_id_b as usize].set_index;
262
263 debug_assert!(set_a != DISABLED_SET && set_b != DISABLED_SET);
264 debug_assert!(set_a != crate::solver_set::STATIC_SET || set_b != crate::solver_set::STATIC_SET);
265
266 if set_a == AWAKE_SET && set_b >= FIRST_SLEEPING_SET {
268 crate::solver_set::wake_solver_set(world, set_b);
269 }
270
271 let set_a2 = world.bodies[body_id_a as usize].set_index;
273 let set_b2 = world.bodies[body_id_b as usize].set_index;
274 if set_b2 == AWAKE_SET && set_a2 >= FIRST_SLEEPING_SET {
275 crate::solver_set::wake_solver_set(world, set_a2);
276 }
277
278 let island_id_a = world.bodies[body_id_a as usize].island_id;
279 let island_id_b = world.bodies[body_id_b as usize].island_id;
280
281 debug_assert!(
283 world.bodies[body_id_a as usize].set_index != crate::solver_set::STATIC_SET
284 || island_id_a == NULL_INDEX
285 );
286 debug_assert!(
287 world.bodies[body_id_b as usize].set_index != crate::solver_set::STATIC_SET
288 || island_id_b == NULL_INDEX
289 );
290 debug_assert!(island_id_a != NULL_INDEX || island_id_b != NULL_INDEX);
291
292 let final_island_id = merge_islands(world, island_id_a, island_id_b);
294
295 add_contact_to_island(world, final_island_id, contact_id);
297}
298
299pub fn unlink_contact(world: &mut World, contact_id: i32) {
302 let (island_id, remove_index) = {
303 let contact = &world.contacts[contact_id as usize];
304 debug_assert!(contact.island_id != NULL_INDEX);
305 (contact.island_id, contact.island_index)
306 };
307
308 {
310 let island = &mut world.islands[island_id as usize];
311 debug_assert!(0 <= remove_index && (remove_index as usize) < island.contacts.len());
312 debug_assert!(island.contacts[remove_index as usize].contact_id == contact_id);
313
314 let moved_index = island.contacts.len() as i32 - 1;
315 island.contacts.swap_remove(remove_index as usize);
316 if moved_index != remove_index {
317 let moved_contact_id = island.contacts[remove_index as usize].contact_id;
319 let moved_contact = &mut world.contacts[moved_contact_id as usize];
320 debug_assert!(moved_contact.island_index == moved_index);
321 moved_contact.island_index = remove_index;
322 }
323 }
324
325 let contact = &mut world.contacts[contact_id as usize];
326 contact.island_id = NULL_INDEX;
327 contact.island_index = NULL_INDEX;
328 world.islands[island_id as usize].constraint_remove_count += 1;
329
330 validate_island(world, island_id);
331}
332
333fn add_joint_to_island(world: &mut World, island_id: i32, joint_id: i32) {
335 let (edge_body_a, edge_body_b) = {
336 let joint = &world.joints[joint_id as usize];
337 debug_assert!(joint.island_id == NULL_INDEX);
338 debug_assert!(joint.island_index == NULL_INDEX);
339 (joint.edges[0].body_id, joint.edges[1].body_id)
340 };
341
342 let island = &mut world.islands[island_id as usize];
343
344 let island_index = island.joints.len() as i32;
345 island.joints.push(JointLink {
346 joint_id,
347 body_id_a: edge_body_a,
348 body_id_b: edge_body_b,
349 });
350
351 let joint = &mut world.joints[joint_id as usize];
352 joint.island_id = island_id;
353 joint.island_index = island_index;
354
355 validate_island(world, island_id);
356}
357
358pub fn link_joint(world: &mut World, joint_id: i32) {
360 use crate::types::BodyType;
361
362 let (body_id_a, body_id_b) = {
363 let joint = &world.joints[joint_id as usize];
364 (joint.edges[0].body_id, joint.edges[1].body_id)
365 };
366
367 debug_assert!(
368 world.bodies[body_id_a as usize].type_ == BodyType::Dynamic
369 || world.bodies[body_id_b as usize].type_ == BodyType::Dynamic
370 );
371
372 let set_a = world.bodies[body_id_a as usize].set_index;
373 let set_b = world.bodies[body_id_b as usize].set_index;
374
375 if set_a == AWAKE_SET && set_b >= FIRST_SLEEPING_SET {
376 crate::solver_set::wake_solver_set(world, set_b);
377 } else if set_b == AWAKE_SET && set_a >= FIRST_SLEEPING_SET {
378 crate::solver_set::wake_solver_set(world, set_a);
379 }
380
381 let island_id_a = world.bodies[body_id_a as usize].island_id;
382 let island_id_b = world.bodies[body_id_b as usize].island_id;
383
384 debug_assert!(island_id_a != NULL_INDEX || island_id_b != NULL_INDEX);
385
386 let final_island_id = merge_islands(world, island_id_a, island_id_b);
388
389 add_joint_to_island(world, final_island_id, joint_id);
391}
392
393pub fn unlink_joint(world: &mut World, joint_id: i32) {
395 let (island_id, remove_index) = {
396 let joint = &world.joints[joint_id as usize];
397 if joint.island_id == NULL_INDEX {
398 return;
399 }
400 (joint.island_id, joint.island_index)
401 };
402
403 {
405 let island = &mut world.islands[island_id as usize];
406 debug_assert!(0 <= remove_index && (remove_index as usize) < island.joints.len());
407 debug_assert!(island.joints[remove_index as usize].joint_id == joint_id);
408
409 let moved_index = island.joints.len() as i32 - 1;
410 island.joints.swap_remove(remove_index as usize);
411 if moved_index != remove_index {
412 let moved_joint_id = island.joints[remove_index as usize].joint_id;
414 let moved_joint = &mut world.joints[moved_joint_id as usize];
415 debug_assert!(moved_joint.island_index == moved_index);
416 moved_joint.island_index = remove_index;
417 }
418 }
419
420 let joint = &mut world.joints[joint_id as usize];
421 joint.island_id = NULL_INDEX;
422 joint.island_index = NULL_INDEX;
423 world.islands[island_id as usize].constraint_remove_count += 1;
424
425 validate_island(world, island_id);
426}
427
428pub fn validate_island(world: &World, island_id: i32) {
433 if island_id == NULL_INDEX {
434 return;
435 }
436
437 let island = &world.islands[island_id as usize];
438 debug_assert!(island.island_id == island_id);
439 debug_assert!(island.set_index != NULL_INDEX);
440
441 {
442 debug_assert!(!island.bodies.is_empty());
443 debug_assert!(island.bodies.len() as i32 <= world.body_id_pool.id_count());
444
445 for (i, &body_id) in island.bodies.iter().enumerate() {
446 let body = &world.bodies[body_id as usize];
447 debug_assert!(body.island_id == island_id);
448 debug_assert!(body.island_index == i as i32);
449 debug_assert!(body.set_index == island.set_index);
450 let _ = (body, i);
451 }
452 }
453
454 if !island.contacts.is_empty() {
455 debug_assert!(island.contacts.len() as i32 <= world.contact_id_pool.id_count());
456
457 for (i, link) in island.contacts.iter().enumerate() {
458 let contact = &world.contacts[link.contact_id as usize];
459 debug_assert!(contact.set_index == island.set_index);
460 debug_assert!(contact.island_id == island_id);
461 debug_assert!(contact.island_index == i as i32);
462 let _ = (contact, i);
463 }
464 }
465
466 if !island.joints.is_empty() {
467 debug_assert!(island.joints.len() as i32 <= world.joint_id_pool.id_count());
468
469 for (i, link) in island.joints.iter().enumerate() {
470 let joint = &world.joints[link.joint_id as usize];
471 debug_assert!(joint.set_index == island.set_index);
472 debug_assert!(joint.island_id == island_id);
473 debug_assert!(joint.island_index == i as i32);
474 let _ = (joint, i);
475 }
476 }
477}
478
479fn island_find_parent(parents: &mut [i32], mut node: i32) -> i32 {
482 while parents[node as usize] != node {
485 let grand_parent = parents[parents[node as usize] as usize];
486 parents[node as usize] = grand_parent;
487 node = grand_parent;
488 }
489
490 node
491}
492
493fn island_union(
497 parents: &mut [i32],
498 ranks: &mut [i32],
499 node1: i32,
500 node2: i32,
501 contact_counts: &mut [i32],
502 joint_counts: &mut [i32],
503) {
504 let root1 = island_find_parent(parents, node1);
505 let root2 = island_find_parent(parents, node2);
506 if root1 != root2 {
507 if ranks[root1 as usize] < ranks[root2 as usize] {
508 parents[root1 as usize] = root2;
509 contact_counts[root2 as usize] += contact_counts[root1 as usize];
510 joint_counts[root2 as usize] += joint_counts[root1 as usize];
511 } else if ranks[root1 as usize] > ranks[root2 as usize] {
512 parents[root2 as usize] = root1;
513 contact_counts[root1 as usize] += contact_counts[root2 as usize];
514 joint_counts[root1 as usize] += joint_counts[root2 as usize];
515 } else {
516 parents[root2 as usize] = root1;
517 ranks[root1 as usize] += 1;
518 contact_counts[root1 as usize] += contact_counts[root2 as usize];
519 joint_counts[root1 as usize] += joint_counts[root2 as usize];
520 }
521 }
522}
523
524pub fn split_island(world: &mut World, base_id: i32) {
532 debug_assert!(world.islands[base_id as usize].constraint_remove_count > 0);
533 debug_assert!(world.islands[base_id as usize].set_index == AWAKE_SET);
534
535 validate_island(world, base_id);
536
537 let base_body_ids = std::mem::take(&mut world.islands[base_id as usize].bodies);
541 let base_contacts = std::mem::take(&mut world.islands[base_id as usize].contacts);
542 let base_joints = std::mem::take(&mut world.islands[base_id as usize].joints);
543
544 let base_body_count = base_body_ids.len();
545
546 let mut parents: Vec<i32> = (0..base_body_count as i32).collect();
548 let mut contact_counts: Vec<i32> = vec![0; base_body_count];
549 let mut joint_counts: Vec<i32> = vec![0; base_body_count];
550 let mut ranks: Vec<i32> = vec![0; base_body_count];
551
552 for link in &base_contacts {
554 let island_index_a = world.bodies[link.body_id_a as usize].island_index;
555 let island_index_b = world.bodies[link.body_id_b as usize].island_index;
556
557 if island_index_a != NULL_INDEX && island_index_b != NULL_INDEX {
559 island_union(
560 &mut parents,
561 &mut ranks,
562 island_index_a,
563 island_index_b,
564 &mut contact_counts,
565 &mut joint_counts,
566 );
567 let root = island_find_parent(&mut parents, island_index_a);
568 contact_counts[root as usize] += 1;
569 } else {
570 let island_index = if island_index_a != NULL_INDEX {
571 island_index_a
572 } else {
573 island_index_b
574 };
575 let root = island_find_parent(&mut parents, island_index);
576 contact_counts[root as usize] += 1;
577 }
578 }
579
580 for link in &base_joints {
582 let island_index_a = world.bodies[link.body_id_a as usize].island_index;
583 let island_index_b = world.bodies[link.body_id_b as usize].island_index;
584
585 if island_index_a != NULL_INDEX && island_index_b != NULL_INDEX {
587 island_union(
588 &mut parents,
589 &mut ranks,
590 island_index_a,
591 island_index_b,
592 &mut contact_counts,
593 &mut joint_counts,
594 );
595 let root = island_find_parent(&mut parents, island_index_a);
596 joint_counts[root as usize] += 1;
597 } else {
598 let island_index = if island_index_a != NULL_INDEX {
599 island_index_a
600 } else {
601 island_index_b
602 };
603 let root = island_find_parent(&mut parents, island_index);
604 joint_counts[root as usize] += 1;
605 }
606 }
607
608 let mut component_count = 0usize;
610 #[allow(clippy::needless_range_loop)]
611 for i in 0..base_body_count {
612 let root = island_find_parent(&mut parents, i as i32);
613 parents[i] = root;
614 if root == i as i32 {
615 component_count += 1;
616 }
617 }
618
619 if component_count == 1 {
621 let island = &mut world.islands[base_id as usize];
622 island.constraint_remove_count = 0;
623 island.bodies = base_body_ids;
624 island.contacts = base_contacts;
625 island.joints = base_joints;
626 return;
627 }
628
629 let mut root_map: Vec<i32> = vec![NULL_INDEX; base_body_count];
631
632 let mut component_body_counts: Vec<i32> = vec![0; component_count];
633 let mut component_contact_counts: Vec<i32> = vec![0; component_count];
634 let mut component_joint_counts: Vec<i32> = vec![0; component_count];
635 let mut island_count = 0usize;
636
637 #[allow(clippy::needless_range_loop)]
640 for i in 0..base_body_count {
641 let root_index = parents[i] as usize;
642 if root_map[root_index] == NULL_INDEX {
643 root_map[root_index] = island_count as i32;
644 component_body_counts[island_count] = 0;
645 component_contact_counts[island_count] = contact_counts[root_index];
646 component_joint_counts[island_count] = joint_counts[root_index];
647 island_count += 1;
648 }
649
650 component_body_counts[root_map[root_index] as usize] += 1;
651 }
652
653 debug_assert!(island_count == component_count);
654
655 let mut island_ids: Vec<i32> = Vec::with_capacity(island_count);
657
658 for i in 0..island_count {
660 let new_island_id = create_island(world, AWAKE_SET);
661 island_ids.push(new_island_id);
662
663 let new_island = &mut world.islands[new_island_id as usize];
665 new_island.bodies.reserve(component_body_counts[i] as usize);
666 new_island
667 .contacts
668 .reserve(component_contact_counts[i] as usize);
669 new_island
670 .joints
671 .reserve(component_joint_counts[i] as usize);
672 }
673
674 for (i, &body_id) in base_body_ids.iter().enumerate() {
676 let root = island_find_parent(&mut parents, i as i32);
677 let new_island_id = island_ids[root_map[root as usize] as usize];
678
679 let island_index = world.islands[new_island_id as usize].bodies.len() as i32;
680 let body = &mut world.bodies[body_id as usize];
681 body.island_id = new_island_id;
682 body.island_index = island_index;
683
684 world.islands[new_island_id as usize].bodies.push(body_id);
685 }
686
687 for link in &base_contacts {
689 let island_id_a = world.bodies[link.body_id_a as usize].island_id;
691 let target_island_id = if island_id_a != NULL_INDEX {
692 island_id_a
693 } else {
694 world.bodies[link.body_id_b as usize].island_id
695 };
696
697 let island_index = world.islands[target_island_id as usize].contacts.len() as i32;
698 let contact = &mut world.contacts[link.contact_id as usize];
699 contact.island_id = target_island_id;
700 contact.island_index = island_index;
701
702 world.islands[target_island_id as usize]
703 .contacts
704 .push(*link);
705 }
706
707 for link in &base_joints {
709 let island_id_a = world.bodies[link.body_id_a as usize].island_id;
711 let target_island_id = if island_id_a != NULL_INDEX {
712 island_id_a
713 } else {
714 world.bodies[link.body_id_b as usize].island_id
715 };
716
717 let island_index = world.islands[target_island_id as usize].joints.len() as i32;
718 let joint = &mut world.joints[link.joint_id as usize];
719 joint.island_id = target_island_id;
720 joint.island_index = island_index;
721
722 world.islands[target_island_id as usize].joints.push(*link);
723 }
724
725 destroy_island(world, base_id);
727}