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