Skip to main content

linear_sim/
object.rs

1//! Simulation object entities.
2//!
3//! Each object is uniquely identified by an `Id` consisting of the object `Kind` and
4//! the object `Key`.
5
6use std;
7use std::borrow::{Borrow, BorrowMut};
8use derive_more::{From, Into};
9
10#[cfg(feature = "derive_serdes")]
11use serde::{Deserialize, Serialize};
12
13use crate::component;
14use crate::constraint::contact::CONTACT_DISTANCE;
15use crate::geometry::{shape, Shape};
16use crate::math::*;
17
18/// Object keys are used to uniquely identify an object of a specific kind: static,
19/// dynamic, or nodetect.
20///
21/// Within the collision subsystem, one bit of this key type will be used to distinguish
22/// between dynamic and static keys so they can be stored together. So the actual number
23/// of static or dynamic objects that can be created is up to 2^31 with 32-bit keys.
24///
25/// Note that this should not exceed `usize` so if `u32` is used here then the code can
26/// only be guaranteed to run on 32-bit systems or higher, but not 16-bit.
27pub type KeyType = u32;
28
29/// The value of the dynamic bit also gives the maximum key value allowed for objects in
30/// the collision system.
31pub(crate) const KEY_MAX : KeyType = INTERNAL_ID_DYNAMIC_BIT - 1;
32
33/// Used by `InternalId` to indicate a dynamic object identifier, otherwise if this bit
34/// is zero the object identifier is for a static object
35// most significant bit
36pub(crate) const INTERNAL_ID_DYNAMIC_BIT : KeyType = 1 << (KeyType::BITS - 1);
37
38////////////////////////////////////////////////////////////////////////////////////////
39//  traits                                                                            //
40////////////////////////////////////////////////////////////////////////////////////////
41
42/// Base object trait: `position()` and `kind()` methods
43pub trait Object : std::fmt::Debug {
44  // required methods
45  fn kind() -> Kind;
46  fn position     (&self)     -> &component::Position;
47  fn position_mut (&mut self) -> &mut component::Position;
48}
49
50/// A bounded object
51pub trait Bounded : Object {
52  fn bound     (&self)     -> &component::Bound;
53  fn bound_mut (&mut self) -> &mut component::Bound;
54  // provided
55  /// NOTE: tangent 'intersections' are ignored
56  fn hit_test  (&self, line_segment : geometry::Segment3 <f64>)
57    -> Option <(Normalized <f64>, Point3 <f64>)>
58  {
59    use geometry::Primitive;
60    let position = self.position().0;
61    match &self.bound().0 {
62      shape::Variant::Bounded (bounded) => match bounded {
63        shape::Bounded::Sphere (sphere) =>
64          line_segment.intersect_sphere (sphere.sphere3 (position)),
65        shape::Bounded::Capsule (capsule) =>
66          line_segment.intersect_capsule (capsule.capsule3 (position)),
67        shape::Bounded::Cylinder (cylinder) =>
68          line_segment.intersect_cylinder (cylinder.cylinder3 (position)),
69        shape::Bounded::Cuboid (cuboid) =>
70          line_segment.intersect_aabb (cuboid.aabb3 (position)),
71        shape::Bounded::Hull ((hull, mesh)) => {
72          // TODO: can we avoid cloning?
73          let mut hull = hull.clone();
74          hull.translate (position.0);
75          line_segment.intersect_hull (&hull, mesh)
76        }
77        shape::Bounded::Cone (_cone) => unimplemented!(),
78        shape::Bounded::Cube (_cube) => unimplemented!(),
79      }
80      shape::Variant::Unbounded (unbounded) => match unbounded {
81        shape::Unbounded::Halfspace (_halfspace) => unimplemented!(),
82        shape::Unbounded::Orthant   (_orthant)   => unimplemented!()
83      }
84    }.map (|(start, _)| start)
85  }
86  fn to_primitive (&self) -> Box <dyn geometry::Primitive <f64, Point3 <f64>>> {
87    self.bound().0.to_primitive (self.position().0)
88  }
89}
90
91/// Object with time derivatives
92pub trait Temporal : Object {
93  fn derivatives     (&self)     -> &component::Derivatives;
94  fn derivatives_mut (&mut self) -> &mut component::Derivatives;
95}
96
97/// Inertial object
98pub trait Inertial : Temporal {
99  // required
100  fn mass     (&self)     -> &component::Mass;
101  fn mass_mut (&mut self) -> &mut component::Mass;
102  // provided
103  fn momentum (&self) -> Vector3 <f64> {
104    self.mass().mass() * self.derivatives().velocity
105  }
106  /// Computes acceleration from the current force vector and mass value
107  fn compute_acceleration (&self) -> Vector3 <f64> {
108    self.mass().mass_reciprocal() * self.derivatives().force
109  }
110  /// Computes acceleration from the current force vector and mass value, replacing the
111  /// current acceleration value
112  fn compute_acceleration_inplace (&mut self) {
113    let acceleration = self.mass().mass_reciprocal() * self.derivatives().force;
114    self.derivatives_mut().acceleration = acceleration;
115  }
116}
117
118/// A bounded object with mass
119pub trait Massive : Bounded + Inertial {
120  fn drag (&self) -> f64;
121  fn density (&self) -> Option <f64> {
122    use geometry::shape::Stereometric;
123    if let component::Bound (shape::Variant::Bounded (bounded)) = self.bound() {
124      Some (self.mass().mass() / *bounded.volume())
125    } else {
126      None
127    }
128  }
129}
130
131/// A bounded object with material properties
132pub trait Solid : Bounded {
133  fn material     (&self)     -> &component::Material;
134  fn material_mut (&mut self) -> &mut component::Material;
135}
136
137/// (Sorted) static/dynamic or dynamic/dynamic pair
138#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
139#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Into)]
140pub(crate) struct ObjectPair (pub InternalId, pub InternalId);
141
142/// Represents a static or dynamic object identifier by using the most significant bit
143/// of the object key type (0 for static, 1 for dynamic).
144#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
145#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
146pub(crate) struct InternalId (KeyType);
147
148////////////////////////////////////////////////////////////////////////////////////////
149//  enums                                                                             //
150////////////////////////////////////////////////////////////////////////////////////////
151
152/// Object kind
153#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
154#[derive(Clone, Copy, Debug, Eq, PartialEq)]
155pub enum Kind {
156  Static,
157  Dynamic,
158  Nodetect
159}
160
161/// One of object variants
162#[derive(Clone, Debug, PartialEq, From)]
163pub enum Variant {
164  Static   (Static),
165  Dynamic  (Dynamic),
166  Nodetect (Nodetect)
167}
168
169/// Reference to one of object variants
170#[derive(Clone, Debug, PartialEq, From)]
171pub enum VariantRef <'a> {
172  Static   (&'a Static),
173  Dynamic  (&'a Dynamic),
174  Nodetect (&'a Nodetect)
175}
176
177////////////////////////////////////////////////////////////////////////////////////////
178//  structs                                                                           //
179////////////////////////////////////////////////////////////////////////////////////////
180
181/// A `VecMap` index
182#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
183#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
184pub struct Key (KeyType);
185
186/// Each value identifies a unique object by the kind of object and its key
187#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
188#[derive(Clone, Copy, Debug, Eq, PartialEq)]
189pub struct Id {
190  pub kind : Kind,
191  pub key  : Key
192}
193
194/// A fixed, bounded object
195#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
196#[derive(Clone, Debug, PartialEq)]
197pub struct Static {
198  pub position   : component::Position,
199  pub bound      : component::Bound,
200  pub material   : component::Material,
201  pub collidable : bool
202}
203
204/// A free, bounded, massive object
205#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
206#[derive(Clone, Debug, PartialEq)]
207pub struct Dynamic {
208  pub position    : component::Position,
209  pub mass        : component::Mass,
210  pub derivatives : component::Derivatives,
211  pub drag        : component::Drag,
212  pub bound       : component::Bound,
213  pub material    : component::Material,
214  pub collidable  : bool
215}
216
217/// A free, massive object
218#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
219#[derive(Clone, Debug, PartialEq)]
220pub struct Nodetect {
221  pub position    : component::Position,
222  pub mass        : component::Mass,
223  pub derivatives : component::Derivatives,
224  pub drag        : component::Drag
225}
226
227////////////////////////////////////////////////////////////////////////////////////////
228//  functions                                                                         //
229////////////////////////////////////////////////////////////////////////////////////////
230
231/// Linear-interpolate an object with the given pseudovelocity
232pub fn lerp <O : Temporal> (
233  object : &mut O, pseudovelocity : Vector3 <f64>, t_relative : f64
234) {
235  let component::Position (position) = object.position();
236  object.position_mut().0 = position + t_relative * object.derivatives().velocity
237    + t_relative * pseudovelocity;
238}
239
240/// Print object size information
241pub fn report_sizes() {
242  use std::mem::size_of;
243  println!("object report sizes...");
244
245  println!("  size of Variant:  {}", size_of::<Variant>());
246  println!("  size of Static:   {}", size_of::<Static>());
247  println!("  size of Dynamic:  {}", size_of::<Dynamic>());
248  println!("  size of Nodetect: {}", size_of::<Nodetect>());
249
250  println!("...object report sizes");
251}
252
253////////////////////////////////////////////////////////////////////////////////////////
254//  impls                                                                             //
255////////////////////////////////////////////////////////////////////////////////////////
256
257//
258// impl Variant
259//
260impl Variant {
261  pub const fn kind (&self) -> Kind {
262    match self {
263      Variant::Static   (_) => Kind::Static,
264      Variant::Dynamic  (_) => Kind::Dynamic,
265      Variant::Nodetect (_) => Kind::Nodetect
266    }
267  }
268}
269
270//
271// impl Static
272//
273impl Static {
274  /// Collision pipeline uses dilated AABBs
275  pub (crate) fn aabb_dilated (&self) -> geometry::Aabb3 <f64> {
276    use shape::Aabb;
277    self.aabb().dilate (0.5 * CONTACT_DISTANCE).unwrap()
278  }
279}
280impl Object for Static {
281  fn kind() -> Kind { Kind::Static }
282  fn position (&self) -> &component::Position {
283    &self.position
284  }
285  fn position_mut (&mut self) -> &mut component::Position {
286    &mut self.position
287  }
288}
289impl Bounded for Static {
290  fn bound (&self) -> &component::Bound {
291    &self.bound
292  }
293  fn bound_mut (&mut self) -> &mut component::Bound {
294    &mut self.bound
295  }
296}
297impl shape::Aabb <f64> for Static {
298  fn aabb (&self) -> geometry::Aabb3 <f64> {
299    let component::Bound (variant) = &self.bound;
300    let aabb_shape = variant.aabb();
301    geometry::Aabb3::with_minmax_unchecked (
302      aabb_shape.min() + self.position().0.0,
303      aabb_shape.max() + self.position().0.0)
304  }
305}
306impl shape::Stereometric <f64> for Static {
307  fn volume (&self) -> Positive <f64> {
308    let component::Bound (variant) = &self.bound;
309    variant.volume()
310  }
311}
312
313//
314// impl Dynamic
315//
316impl Dynamic {
317  /// Collision pipeline uses dilated AABBs
318  pub (crate) fn aabb_dilated (&self) -> geometry::Aabb3 <f64> {
319    use shape::Aabb;
320    self.aabb().dilate (0.5 * CONTACT_DISTANCE).unwrap()
321  }
322}
323impl Object for Dynamic {
324  fn kind() -> Kind { Kind::Dynamic }
325  fn position (&self) -> &component::Position {
326    &self.position
327  }
328  fn position_mut (&mut self) -> &mut component::Position {
329    &mut self.position
330  }
331}
332impl Bounded for Dynamic {
333  fn bound (&self) -> &component::Bound {
334    &self.bound
335  }
336  fn bound_mut (&mut self) -> &mut component::Bound {
337    &mut self.bound
338  }
339}
340impl Temporal for Dynamic {
341  fn derivatives (&self) -> &component::Derivatives {
342    &self.derivatives
343  }
344  fn derivatives_mut (&mut self) -> &mut component::Derivatives {
345    &mut self.derivatives
346  }
347}
348impl Inertial for Dynamic {
349  fn mass (&self) -> &component::Mass {
350    &self.mass
351  }
352  fn mass_mut (&mut self) -> &mut component::Mass {
353    &mut self.mass
354  }
355}
356impl Borrow <component::Derivatives> for Dynamic {
357  fn borrow (&self) -> &component::Derivatives {
358    &self.derivatives
359  }
360}
361impl BorrowMut <component::Derivatives> for Dynamic {
362  fn borrow_mut (&mut self) -> &mut component::Derivatives {
363    &mut self.derivatives
364  }
365}
366impl shape::Aabb <f64> for Dynamic {
367  fn aabb (&self) -> geometry::Aabb3 <f64> {
368    let component::Bound (variant) = &self.bound;
369    let aabb_shape = variant.aabb();
370    geometry::Aabb3::with_minmax_unchecked (
371      aabb_shape.min() + self.position().0.0,
372      aabb_shape.max() + self.position().0.0)
373  }
374}
375impl shape::Stereometric <f64> for Dynamic {
376  fn volume (&self) -> Positive <f64> {
377    let component::Bound (variant) = &self.bound;
378    variant.volume()
379  }
380}
381
382//
383// impl Nodetect
384//
385impl Object for Nodetect {
386  fn kind() -> Kind { Kind::Nodetect }
387  fn position (&self) -> &component::Position {
388    &self.position
389  }
390  fn position_mut (&mut self) -> &mut component::Position {
391    &mut self.position
392  }
393}
394impl Temporal for Nodetect {
395  fn derivatives (&self) -> &component::Derivatives {
396    &self.derivatives
397  }
398  fn derivatives_mut (&mut self) -> &mut component::Derivatives {
399    &mut self.derivatives
400  }
401}
402impl Inertial for Nodetect {
403  fn mass (&self) -> &component::Mass {
404    &self.mass
405  }
406  fn mass_mut (&mut self) -> &mut component::Mass {
407    &mut self.mass
408  }
409}
410impl Borrow <component::Derivatives> for Nodetect {
411  fn borrow (&self) -> &component::Derivatives {
412    &self.derivatives
413  }
414}
415impl BorrowMut <component::Derivatives> for Nodetect {
416  fn borrow_mut (&mut self) -> &mut component::Derivatives {
417    &mut self.derivatives
418  }
419}
420
421//
422// impl Key
423//
424impl Key {
425  /// &#9888; Note: does not check against `KEY_MAX`
426  pub const fn from_raw (key : KeyType) -> Self {
427    Key (key)
428  }
429  pub const fn value (&self) -> KeyType {
430    self.0
431  }
432  pub const fn index (&self) -> usize {
433    self.0 as usize
434  }
435}
436impl std::ops::Deref for Key {
437  type Target = KeyType;
438  fn deref (&self) -> &KeyType {
439    &self.0
440  }
441}
442impl From <KeyType> for Key {
443  /// Debug panic if key greater or equal to `KEY_MAX`
444  fn from (key : KeyType) -> Self {
445    debug_assert!(key < KEY_MAX);
446    Key (key)
447  }
448}
449impl From <usize> for Key {
450  /// Debug panic if key greater or equal to `KEY_MAX`
451  fn from (key : usize) -> Self {
452    debug_assert!((key as KeyType) < KEY_MAX);
453    Key (key as KeyType)
454  }
455}
456
457//
458// impl traits for (Position, Bound)
459//
460impl Object for (component::Position, component::Bound) {
461  fn kind() -> Kind {
462    Kind::Static
463  }
464  fn position (&self) -> &component::Position {
465    &self.0
466  }
467  fn position_mut (&mut self) -> &mut component::Position {
468    &mut self.0
469  }
470}
471impl Bounded for (component::Position, component::Bound) {
472  fn bound (&self) -> &component::Bound {
473    &self.1
474  }
475  fn bound_mut (&mut self) -> &mut component::Bound {
476    &mut self.1
477  }
478}
479impl Object for (component::Position, &component::Bound) {
480  fn kind() -> Kind {
481    Kind::Static
482  }
483  fn position (&self) -> &component::Position {
484    &self.0
485  }
486  fn position_mut (&mut self) -> &mut component::Position {
487    &mut self.0
488  }
489}
490impl Bounded for (component::Position, &component::Bound) {
491  fn bound (&self) -> &component::Bound {
492    self.1
493  }
494  fn bound_mut (&mut self) -> &mut component::Bound {
495    unimplemented!()
496  }
497}
498
499//
500//  impl ObjectPair
501//
502impl ObjectPair {
503  /// Create a new object pair.
504  ///
505  /// One object must be dynamic. Internally the object IDs will be stored in sorted
506  /// order, and a static object will always be first.
507  pub(crate) fn new (id_a : InternalId, id_b : InternalId) -> Self {
508    debug_assert!(id_a.kind() == Kind::Dynamic || id_b.kind() == Kind::Dynamic);
509    if id_a < id_b {
510      ObjectPair (id_a, id_b)
511    } else {
512      debug_assert!(id_a > id_b, "object pair ids should not be identical");
513      ObjectPair (id_b, id_a)
514    }
515  }
516}
517
518impl From <(InternalId, InternalId)> for ObjectPair {
519  fn from ((id_a, id_b) : (InternalId, InternalId)) -> Self {
520    ObjectPair::new (id_a, id_b)
521  }
522}
523
524impl TryFrom <(Id, Id)> for ObjectPair {
525  type Error = (Id, Id);
526  fn try_from ((id_a, id_b) : (Id, Id)) -> Result <Self, Self::Error> {
527    match [id_a, id_b].map (InternalId::try_from) {
528      [Ok (internal_id_a), Ok (internal_id_b)]
529        => Ok ((internal_id_a, internal_id_b).into()),
530      _ => Err ((id_a, id_b))
531    }
532  }
533}
534
535//
536//  impl InternalId
537//
538impl InternalId {
539  #[inline]
540  pub(crate) fn new_static (key : Key) -> Self {
541    debug_assert!(key.value() < KEY_MAX);
542    InternalId (key.value())
543  }
544  #[inline]
545  pub(crate) fn new_dynamic (key : Key) -> Self {
546    debug_assert!(key.value() < KEY_MAX);
547    InternalId (key.value() | INTERNAL_ID_DYNAMIC_BIT)
548  }
549  #[inline]
550  pub(crate) const fn kind (self) -> Kind {
551    match self.0 & INTERNAL_ID_DYNAMIC_BIT > 0 {
552      true  => Kind::Dynamic,
553      false => Kind::Static
554    }
555  }
556  #[inline]
557  pub(crate) fn key (self) -> Key {
558    Key::from (self.0 & !INTERNAL_ID_DYNAMIC_BIT)
559  }
560}
561impl From <InternalId> for Id {
562  fn from (id : InternalId) -> Self {
563    Id {
564      kind: id.kind(),
565      key:  id.key()
566    }
567  }
568}
569impl TryFrom <Id> for InternalId {
570  type Error = Id;
571  fn try_from (id : Id) -> Result <Self, Self::Error> {
572    let out = match id.kind {
573      Kind::Dynamic  => InternalId::new_dynamic (id.key),
574      Kind::Static   => InternalId::new_static  (id.key),
575      Kind::Nodetect => return Err(id)
576    };
577    Ok(out)
578  }
579}