linear_sim/collision/contact/
mod.rs1use std;
2use stash::Stash;
3use vec_map::VecMap;
4#[cfg(feature = "derive_serdes")]
5use serde::{Deserialize, Serialize};
6
7use crate::{constraint, event, math, object};
8use super::{CONTACT_DISTANCE, InternalId, ObjectPair, Proximity};
9
10pub (crate) mod group;
11pub (crate) use self::group::Group;
12
13#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
14#[derive(Clone, Debug, PartialEq)]
15pub struct Contact {
16 pub constraint : constraint::Planar
17}
18
19#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
31#[derive(Clone, Debug, PartialEq)]
32pub struct Colliding {
33 pub contact : Contact,
34 pub restitution : math::Normalized <f64>
35}
36
37#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
39#[derive(Clone, Debug)]
40pub (crate) struct Manager {
41 pub contact_groups : Option <Stash <Group>>,
44 object_contacts_static : VecMap <u32>,
49 object_group_contacts_dynamic : VecMap <(group::KeyType, u32)>
51}
52
53impl Manager {
54 pub(super) fn get_group (&self, key : group::KeyType) -> Option <&Group> {
55 self.contact_groups.as_ref().unwrap().get (key as usize)
56 }
57 pub(super) fn get_group_mut (&mut self, key : group::KeyType) -> Option <&mut Group> {
58 self.contact_groups.as_mut().unwrap().get_mut (key as usize)
59 }
60 pub(super) fn remove_group (&mut self, key : group::KeyType) -> Option <Group> {
61 self.contact_groups.as_mut().unwrap().take (key as usize)
62 }
63 pub(super) fn add_contact (&mut self, object_pair : ObjectPair, contact : Contact) {
64 let (object_id_a, object_id_b) = object_pair.into();
65 let group = match (
66 self.get_group_key (object_id_a), self.get_group_key (object_id_b)
67 ) {
68 (Some (group_a), None) => {
69 self.increment_contact (object_id_a);
71 self.assign_dynamic_group_key (object_id_b, group_a);
72 self.get_group_mut (group_a).unwrap()
73 }
74 (None, Some (group_b)) => {
75 if object_id_a.kind() == object::Kind::Dynamic {
77 self.assign_dynamic_group_key (object_id_a, group_b);
78 } else {
79 self.increment_contact (object_id_a);
80 }
81 self.increment_contact (object_id_b);
82 self.get_group_mut (group_b).unwrap()
83 }
84 (Some (group_a), Some (group_b)) => {
85 self.increment_contact (object_id_a);
86 self.increment_contact (object_id_b);
87 if group_a == group_b {
88 self.get_group_mut (group_a).unwrap()
89 } else {
90 let group_b = self.remove_group (group_b).unwrap();
92 for (pair, _) in group_b.contacts.iter() {
93 let (id_a, id_b) = (*pair).into();
94 if id_a.kind() == object::Kind::Dynamic {
95 self.change_dynamic_group_key (id_a, group_a);
96 }
97 self.change_dynamic_group_key (id_b, group_a);
98 }
99 let group_a = self.get_group_mut (group_a).unwrap();
100 group_a.contacts.extend (group_b.contacts);
101 group_a
102 }
103 }
104 (None, None) => {
105 let new_group_index = self.contact_groups.as_mut().unwrap()
107 .put (Group::default());
108 debug_assert!(new_group_index < group::KeyType::MAX as usize);
109 let new_group_key = new_group_index as group::KeyType;
110 if object_id_a.kind() == object::Kind::Dynamic {
111 self.assign_dynamic_group_key (object_id_a, new_group_key);
112 } else {
113 self.increment_contact (object_id_a);
114 }
115 self.assign_dynamic_group_key (object_id_b, new_group_key);
116 self.get_group_mut (new_group_key).unwrap()
117 }
118 };
119 group.contacts.push ((object_pair, contact));
120 }
121
122 #[must_use]
127 pub(super) fn remove_object (&mut self, object_id : InternalId) -> bool {
128 if let Some (group_key) = self.get_group_key (object_id) {
129 debug_assert_eq!(object_id.kind(), object::Kind::Dynamic);
130 let group = self.get_group_mut (group_key).unwrap();
131 let removed = group.remove_object (object_id);
132 let empty = group.contacts.is_empty();
133 if empty {
134 let _ = self.remove_group (group_key).unwrap();
135 }
136 for id in removed {
137 self.decrement_contact (id);
138 }
139 self.object_group_contacts_dynamic.remove (object_id.key().index()).unwrap();
140 true
141 } else if object_id.kind() == object::Kind::Static {
142 let index = object_id.key().index();
143 if let Some (mut contact_count) = self.object_contacts_static.remove (index) {
144 debug_assert!(contact_count > 0);
145 let mut empty = vec![];
146 let mut contact_groups = self.contact_groups.take().unwrap();
147 for (i, group) in contact_groups.iter_mut() {
148 let removed = group.remove_object (object_id);
149 if group.contacts.is_empty() {
150 empty.push (i);
151 }
152 contact_count -= removed.len() as u32;
153 for id in removed {
154 self.decrement_contact (id);
155 }
156 if contact_count == 0 {
157 break
158 }
159 }
160 for i in empty {
161 contact_groups.take (i);
162 }
163 self.contact_groups = Some (contact_groups);
164 true
165 } else {
166 false
167 }
168 } else {
169 false
170 }
171 }
172
173 pub(super) fn output_contacts (&self, output : &mut Vec <event::Output>) {
174 for group in self.contact_groups.as_ref().unwrap().values() {
175 for (object_pair, contact) in group.contacts.iter().cloned() {
176 let (id_a, id_b) = object_pair.into();
177 output.push (event::Contact {
178 object_id_a: id_a.into(),
179 object_id_b: id_b.into(),
180 contact
181 }.into())
182 }
183 }
184 }
185
186 pub(super) fn remove_contacts (&mut self, group : &mut Group, remove_list : &[u32]) {
192 debug_assert!(!remove_list.is_empty());
193 group.contacts = group.contacts.drain (..).enumerate().filter_map (
194 |(i, contact@(object_pair, _))|
195 if remove_list.contains (&(i as u32)) {
196 let (object_id_a, object_id_b) = object_pair.into();
197 self.decrement_contact (object_id_a);
198 self.decrement_contact (object_id_b);
199 None
200 } else {
201 Some (contact)
202 }
203 ).collect();
204 }
205
206 pub(super) fn get_contact_count (&self, object_id : InternalId) -> Option <u32> {
208 let index = object_id.key().index();
209 match object_id.kind() {
210 object::Kind::Static => self.object_contacts_static.get (index).copied(),
211 object::Kind::Dynamic => self.object_group_contacts_dynamic.get (index)
212 .map (|g| g.1),
213 object::Kind::Nodetect => unreachable!()
214 }
215 }
216
217 pub(super) fn get_group_key (&self, object_id : InternalId)
220 -> Option <group::KeyType>
221 {
222 let index = object_id.key().index();
223 match object_id.kind() {
224 object::Kind::Static => None,
226 object::Kind::Dynamic => self.object_group_contacts_dynamic.get (index)
227 .map (|g| g.0),
228 object::Kind::Nodetect => unreachable!()
229 }
230 }
231
232 pub(super) fn change_dynamic_group_key (&mut self,
234 object_id : InternalId, group_key : group::KeyType
235 ) {
236 match object_id.kind() {
237 object::Kind::Static => unreachable!(),
238 object::Kind::Dynamic => {
239 let index = object_id.key().index();
240 self.object_group_contacts_dynamic[index].0 = group_key;
241 }
242 object::Kind::Nodetect => unimplemented!()
243 }
244 }
245
246 fn assign_dynamic_group_key (&mut self,
248 object_id : InternalId, group_key : group::KeyType
249 ) {
250 let index = object_id.key().index();
251 match object_id.kind() {
252 object::Kind::Static => unreachable!("call increment_contact instead"),
253 object::Kind::Dynamic =>
254 assert!(self.object_group_contacts_dynamic.insert (index, (group_key, 1))
255 .is_none()),
256 object::Kind::Nodetect => unimplemented!()
257 }
258 }
259
260 fn increment_contact (&mut self, object_id : InternalId) {
264 let index = object_id.key().index();
265 match object_id.kind() {
266 object::Kind::Static =>
267 *self.object_contacts_static.entry (index).or_insert (0) += 1,
268 object::Kind::Dynamic => self.object_group_contacts_dynamic[index].1 += 1,
269 object::Kind::Nodetect => unimplemented!()
270 }
271 }
272
273 fn decrement_contact (&mut self, object_id : InternalId) {
275 let index = object_id.key().index();
276 match object_id.kind() {
277 object::Kind::Dynamic => {
278 let count = &mut self.object_group_contacts_dynamic.get_mut (index).unwrap().1;
279 *count -= 1;
280 if *count == 0 {
281 self.object_group_contacts_dynamic.remove (index);
282 }
283 }
284 object::Kind::Static => {
285 let count = self.object_contacts_static.get_mut (index).unwrap();
286 *count -= 1;
287 if *count == 0 {
288 self.object_contacts_static.remove (index);
289 }
290 }
291 object::Kind::Nodetect => unreachable!()
292 }
293 }
294}
295
296impl Default for Manager {
297 fn default() -> Self {
298 Manager {
299 contact_groups: Some (Stash::default()),
300 object_contacts_static: VecMap::default(),
301 object_group_contacts_dynamic: VecMap::default()
302 }
303 }
304}
305
306impl TryFrom <Proximity> for Contact {
307 type Error = ();
308 fn try_from (proximity : Proximity) -> Result <Self, Self::Error> {
309 if proximity.distance >= 0.0 && proximity.distance < CONTACT_DISTANCE {
310 Ok (Contact { constraint: proximity.into() })
311 } else {
312 Err (())
313 }
314 }
315}
316
317impl std::ops::Deref for Colliding {
318 type Target = Contact;
319 fn deref (&self) -> &Contact {
320 &self.contact
321 }
322}
323impl Eq for Colliding { }
324#[expect(clippy::non_canonical_partial_ord_impl)]
325impl PartialOrd for Colliding {
326 fn partial_cmp (&self, _rhs : &Self) -> Option <std::cmp::Ordering> {
329 unreachable!()
331 }
332}
333impl Ord for Colliding {
334 fn cmp (&self, _other : &Self) -> std::cmp::Ordering {
335 unreachable!()
337 }
338}