linear_sim/collision/contact/
mod.rs

1use std;
2use stash::Stash;
3use vec_map::VecMap;
4#[cfg(feature = "derive_serdes")]
5use serde::{Deserialize, Serialize};
6
7use crate::{constraint, event, 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/// A "TOI contact".
20///
21/// A pair of objects together with a contact plane and non-negative restitution
22/// value.
23///
24/// A resting contact will have a restitution value of 0.0 and a colliding
25/// contact will usually have a positive non-zero restitution value.
26///
27/// ⚠ Note that the `PartialOrd` and `Ord` implementations are only so
28/// that contacts can be sorted in the narrow TOI list. Attempting to compare
29/// contacts will always panic.
30#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
31#[derive(Clone, Debug, PartialEq)]
32pub struct Colliding {
33  pub contact     : Contact,
34  pub restitution : f64
35}
36
37/// Persistent contact group manager
38#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
39#[derive(Clone, Debug)]
40pub (crate) struct Manager {
41  // NOTE: we put this field in an option so we can take and iterate over groups
42  // without borrowing the manager
43  pub contact_groups            : Option <Stash <Group>>,
44  /// Number of contacts for static objects.
45  ///
46  /// Entries are only occupied when the number of contacts is greater than
47  /// zero.
48  object_contacts_static        : VecMap <u32>,
49  /// Group key and number of contacts for dynamic objects
50  object_group_contacts_dynamic : VecMap <(group::KeyType, u32)>
51}
52
53impl Manager {
54  pub fn get_group (&self, key : group::KeyType) -> Option <&Group> {
55    self.contact_groups.as_ref().unwrap().get (key as usize)
56  }
57  pub 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 fn remove_group (&mut self, key : group::KeyType) -> Option <Group> {
61    self.contact_groups.as_mut().unwrap().take (key as usize)
62  }
63  pub 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        // dynamic object b joins existing group a
70        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        // object a joins existing group b
76        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          // merge groups
91          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        // new group
106        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  /// Remove the object if it belongs to a persistent contact group.
123  ///
124  /// Returns true if the object was found and removed, otherwise returns false
125  /// if the object was not in a contact group.
126  #[must_use]
127  pub 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())
140        .unwrap();
141      true
142    } else if object_id.kind() == object::Kind::Static {
143      let index = object_id.key().index();
144      if let Some (mut contact_count) =
145        self.object_contacts_static.remove (index)
146      {
147        debug_assert!(contact_count > 0);
148        let mut empty = vec![];
149        let mut contact_groups = self.contact_groups.take().unwrap();
150        for (i, group) in contact_groups.iter_mut() {
151          let removed = group.remove_object (object_id);
152          if group.contacts.is_empty() {
153            empty.push (i);
154          }
155          contact_count -= removed.len() as u32;
156          for id in removed {
157            self.decrement_contact (id);
158          }
159          if contact_count == 0 {
160            break
161          }
162        }
163        for i in empty {
164          contact_groups.take (i);
165        }
166        self.contact_groups = Some (contact_groups);
167        true
168      } else {
169        false
170      }
171    } else {
172      false
173    }
174  }
175
176  pub fn output_contacts (&self, output : &mut Vec <event::Output>) {
177    for group in self.contact_groups.as_ref().unwrap().values() {
178      for (object_pair, contact) in group.contacts.iter().cloned() {
179        let (id_a, id_b) = object_pair.into();
180        output.push (event::Contact {
181          object_id_a: id_a.into(),
182          object_id_b: id_b.into(),
183          contact
184        }.into())
185      }
186    }
187  }
188
189  /// Takes list of contact indices to remove.
190  ///
191  /// List should be non-empty. Note that the modified group may no longer be
192  /// connected and `group.partition()` should be called to get connected
193  /// components.
194  pub (crate) fn remove_contacts (&mut self,
195    group : &mut Group, remove_list : &[u32]
196  ) {
197    debug_assert!(!remove_list.is_empty());
198    group.contacts = group.contacts.drain (..).enumerate().filter_map (
199      |(i, contact@(object_pair, _))|
200      if remove_list.contains (&(i as u32)) {
201        let (object_id_a, object_id_b) = object_pair.into();
202        self.decrement_contact (object_id_a);
203        self.decrement_contact (object_id_b);
204        None
205      } else {
206        Some (contact)
207      }
208    ).collect();
209  }
210
211  /// Get the contact count for an object
212  pub (crate) fn get_contact_count (&self, object_id : InternalId)
213    -> Option <u32>
214  {
215    let index = object_id.key().index();
216    match object_id.kind() {
217      object::Kind::Static  => self.object_contacts_static.get (index).cloned(),
218      object::Kind::Dynamic => self.object_group_contacts_dynamic.get (index)
219        .map (|g| g.1),
220      _ => unreachable!()
221    }
222  }
223
224  /// Get the group key for dynamic object, if it exists, otherwise returns None
225  /// if the object is static
226  pub (crate) fn get_group_key (&self, object_id : InternalId)
227    -> Option <group::KeyType>
228  {
229    let index = object_id.key().index();
230    match object_id.kind() {
231      // static objects can be members of more than one group
232      object::Kind::Static  => None,
233      object::Kind::Dynamic => self.object_group_contacts_dynamic.get (index)
234        .map (|g| g.0),
235      _ => unreachable!()
236    }
237  }
238
239  /// Change existing group key
240  pub (crate) fn change_dynamic_group_key (&mut self,
241    object_id : InternalId, group_key : group::KeyType
242  ) {
243    match object_id.kind() {
244      object::Kind::Static  => unreachable!(),
245      object::Kind::Dynamic => {
246        let index = object_id.key().index();
247        self.object_group_contacts_dynamic[index].0 = group_key;
248      }
249      _ => unimplemented!()
250    }
251  }
252
253  /// Assign a new group key to a dynamic object
254  fn assign_dynamic_group_key (&mut self,
255    object_id : InternalId, group_key : group::KeyType
256  ) {
257    let index = object_id.key().index();
258    match object_id.kind() {
259      object::Kind::Static  => unreachable!("call increment_contact instead"),
260      object::Kind::Dynamic =>
261        assert!(self.object_group_contacts_dynamic.insert (index, (group_key, 1))
262          .is_none()),
263      _ => unimplemented!()
264    }
265  }
266
267  /// Increment the contact counter.
268  ///
269  /// Adds the contact counter if this is the first contact of a static object.
270  fn increment_contact (&mut self, object_id : InternalId) {
271    let index = object_id.key().index();
272    match object_id.kind() {
273      object::Kind::Static  =>
274        *self.object_contacts_static.entry (index).or_insert (0) += 1,
275      object::Kind::Dynamic =>
276        self.object_group_contacts_dynamic[index].1 += 1,
277      _ => unimplemented!()
278    }
279  }
280
281  /// Reduce the contact count for the given object ID
282  fn decrement_contact (&mut self, object_id : InternalId) {
283    let index = object_id.key().index();
284    match object_id.kind() {
285      object::Kind::Dynamic => {
286        let count = &mut self.object_group_contacts_dynamic.get_mut (index)
287          .unwrap().1;
288        *count -= 1;
289        if *count == 0 {
290          self.object_group_contacts_dynamic.remove (index);
291        }
292      }
293      object::Kind::Static  => {
294        let count = self.object_contacts_static.get_mut (index).unwrap();
295        *count -= 1;
296        if *count == 0 {
297          self.object_contacts_static.remove (index);
298        }
299      }
300      _ => unreachable!()
301    }
302  }
303}
304
305impl Default for Manager {
306  fn default() -> Self {
307    Manager {
308      contact_groups:                Some (Stash::default()),
309      object_contacts_static:        VecMap::default(),
310      object_group_contacts_dynamic: VecMap::default()
311    }
312  }
313}
314
315impl TryFrom <Proximity> for Contact {
316  type Error = ();
317  fn try_from (proximity : Proximity) -> Result <Self, Self::Error> {
318    if proximity.distance >= 0.0 && proximity.distance < CONTACT_DISTANCE {
319      Ok (Contact { constraint: proximity.into() })
320    } else {
321      Err (())
322    }
323  }
324}
325
326impl std::ops::Deref for Colliding {
327  type Target = Contact;
328  fn deref (&self) -> &Contact {
329    &self.contact
330  }
331}
332impl Eq for Colliding { }
333impl PartialOrd for Colliding {
334  /// Panics: should not be called; this trait is implemented so that narrow TOI
335  /// results can be automatically be sorted
336  fn partial_cmp (&self, _rhs : &Self) -> Option <std::cmp::Ordering> {
337    // TODO: compiler hint ?
338    unreachable!()
339  }
340}
341impl Ord for Colliding {
342  fn cmp (&self, _other : &Self) -> std::cmp::Ordering {
343    // TODO: compiler hint ?
344    unreachable!()
345  }
346}