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 : Clone + 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) => {
63          let mut hull = hull.clone();
64          hull.translate (position.0);
65          line_segment.intersect_hull (&hull)
66        }
67        shape::Bounded::Cone (_cone) => unimplemented!(),
68        shape::Bounded::Cube (_cube) => unimplemented!(),
69      }
70      shape::Variant::Unbounded (unbounded) => match unbounded {
71        shape::Unbounded::Halfspace (_halfspace) => unimplemented!(),
72        shape::Unbounded::Orthant   (_orthant)   => unimplemented!()
73      }
74    }.map (|(start, _)| start)
75  }
76  fn to_primitive (&self) -> Box <dyn geometry::Primitive <f64, Point3 <f64>>> {
77    self.bound().0.to_primitive (self.position().0)
78  }
79}
80
81/// Object with time derivatives
82pub trait Temporal : Object {
83  fn derivatives     (&self)     -> &component::Derivatives;
84  fn derivatives_mut (&mut self) -> &mut component::Derivatives;
85}
86
87/// Inertial object
88pub trait Inertial : Temporal {
89  // required
90  fn mass     (&self)     -> &component::Mass;
91  fn mass_mut (&mut self) -> &mut component::Mass;
92  // provided
93  fn momentum (&self) -> Vector3 <f64> {
94    self.mass().mass() * self.derivatives().velocity
95  }
96  /// Computes acceleration from the current force vector and mass value
97  fn compute_acceleration (&self) -> Vector3 <f64> {
98    self.mass().mass_reciprocal() * self.derivatives().force
99  }
100  /// Computes acceleration from the current force vector and mass value, replacing the
101  /// current acceleration value
102  fn compute_acceleration_inplace (&mut self) {
103    let acceleration = self.mass().mass_reciprocal() * self.derivatives().force;
104    self.derivatives_mut().acceleration = acceleration;
105  }
106}
107
108/// A bounded object with mass
109pub trait Massive : Bounded + Inertial {
110  fn drag (&self) -> f64;
111  fn density (&self) -> Option <f64> {
112    use geometry::shape::Stereometric;
113    if let component::Bound (shape::Variant::Bounded (bounded)) = self.bound() {
114      Some (self.mass().mass() / *bounded.volume())
115    } else {
116      None
117    }
118  }
119}
120
121/// A bounded object with material properties
122pub trait Solid : Bounded {
123  fn material     (&self)     -> &component::Material;
124  fn material_mut (&mut self) -> &mut component::Material;
125}
126
127////////////////////////////////////////////////////////////////////////////////////////
128//  enums                                                                             //
129////////////////////////////////////////////////////////////////////////////////////////
130
131/// Object kind
132#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
133#[derive(Clone, Copy, Debug, Eq, PartialEq)]
134pub enum Kind {
135  Static,
136  Dynamic,
137  Nodetect
138}
139
140/// One of object variants
141#[derive(Clone, Debug, PartialEq, From)]
142pub enum Variant {
143  Static   (Static),
144  Dynamic  (Dynamic),
145  Nodetect (Nodetect)
146}
147
148/// Reference to one of object variants
149#[derive(Clone, Debug, PartialEq, From)]
150pub enum VariantRef <'a> {
151  Static   (&'a Static),
152  Dynamic  (&'a Dynamic),
153  Nodetect (&'a Nodetect)
154}
155
156////////////////////////////////////////////////////////////////////////////////////////
157//  structs                                                                           //
158////////////////////////////////////////////////////////////////////////////////////////
159
160/// A `VecMap` index
161#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
162#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
163pub struct Key (KeyType);
164
165/// Each value identifies a unique object by the kind of object and its key
166#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
167#[derive(Clone, Debug, Eq, PartialEq)]
168pub struct Id {
169  pub kind : Kind,
170  pub key  : Key
171}
172
173/// A fixed, bounded object
174#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
175#[derive(Clone, Debug, PartialEq)]
176pub struct Static {
177  pub position   : component::Position,
178  pub bound      : component::Bound,
179  pub material   : component::Material,
180  pub collidable : bool
181}
182
183/// A free, bounded, massive object
184#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
185#[derive(Clone, Debug, PartialEq)]
186pub struct Dynamic {
187  pub position    : component::Position,
188  pub mass        : component::Mass,
189  pub derivatives : component::Derivatives,
190  pub drag        : component::Drag,
191  pub bound       : component::Bound,
192  pub material    : component::Material,
193  pub collidable  : bool
194}
195
196/// A free, massive object
197#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
198#[derive(Clone, Debug, PartialEq)]
199pub struct Nodetect {
200  pub position    : component::Position,
201  pub mass        : component::Mass,
202  pub derivatives : component::Derivatives,
203  pub drag        : component::Drag
204}
205
206////////////////////////////////////////////////////////////////////////////////////////
207//  functions                                                                         //
208////////////////////////////////////////////////////////////////////////////////////////
209
210/// Print object size information
211pub fn report_sizes() {
212  use std::mem::size_of;
213  println!("object report sizes...");
214
215  println!("  size of Variant:  {}", size_of::<Variant>());
216  println!("  size of Static:   {}", size_of::<Static>());
217  println!("  size of Dynamic:  {}", size_of::<Dynamic>());
218  println!("  size of Nodetect: {}", size_of::<Nodetect>());
219
220  println!("...object report sizes");
221}
222
223////////////////////////////////////////////////////////////////////////////////////////
224//  impls                                                                             //
225////////////////////////////////////////////////////////////////////////////////////////
226
227//
228// impl Variant
229//
230impl Variant {
231  pub const fn kind (&self) -> Kind {
232    match self {
233      Variant::Static   (_) => Kind::Static,
234      Variant::Dynamic  (_) => Kind::Dynamic,
235      Variant::Nodetect (_) => Kind::Nodetect
236    }
237  }
238}
239
240//
241// impl Static
242//
243impl Static {
244  /// Collision pipeline uses dilated AABBs
245  pub (crate) fn aabb_dilated (&self) -> geometry::Aabb3 <f64> {
246    use shape::Aabb;
247    self.aabb().dilate (0.5 * collision::CONTACT_DISTANCE).unwrap()
248  }
249}
250impl Object for Static {
251  fn kind() -> Kind { Kind::Static }
252  fn position (&self) -> &component::Position {
253    &self.position
254  }
255  fn position_mut (&mut self) -> &mut component::Position {
256    &mut self.position
257  }
258}
259impl Bounded for Static {
260  fn bound (&self) -> &component::Bound {
261    &self.bound
262  }
263  fn bound_mut (&mut self) -> &mut component::Bound {
264    &mut self.bound
265  }
266}
267impl shape::Aabb <f64> for Static {
268  fn aabb (&self) -> geometry::Aabb3 <f64> {
269    let component::Bound (variant) = &self.bound;
270    let aabb_shape = variant.aabb();
271    geometry::Aabb3::with_minmax_unchecked (
272      aabb_shape.min() + self.position().0.0,
273      aabb_shape.max() + self.position().0.0)
274  }
275}
276impl shape::Stereometric <f64> for Static {
277  fn volume (&self) -> Positive <f64> {
278    let component::Bound (variant) = &self.bound;
279    variant.volume()
280  }
281}
282
283//
284// impl Dynamic
285//
286impl Dynamic {
287  /// Collision pipeline uses dilated AABBs
288  pub (crate) fn aabb_dilated (&self) -> geometry::Aabb3 <f64> {
289    use shape::Aabb;
290    self.aabb().dilate (0.5 * collision::CONTACT_DISTANCE).unwrap()
291  }
292}
293impl Object for Dynamic {
294  fn kind() -> Kind { Kind::Dynamic }
295  fn position (&self) -> &component::Position {
296    &self.position
297  }
298  fn position_mut (&mut self) -> &mut component::Position {
299    &mut self.position
300  }
301}
302impl Bounded for Dynamic {
303  fn bound (&self) -> &component::Bound {
304    &self.bound
305  }
306  fn bound_mut (&mut self) -> &mut component::Bound {
307    &mut self.bound
308  }
309}
310impl Temporal for Dynamic {
311  fn derivatives (&self) -> &component::Derivatives {
312    &self.derivatives
313  }
314  fn derivatives_mut (&mut self) -> &mut component::Derivatives {
315    &mut self.derivatives
316  }
317}
318impl Inertial for Dynamic {
319  fn mass (&self) -> &component::Mass {
320    &self.mass
321  }
322  fn mass_mut (&mut self) -> &mut component::Mass {
323    &mut self.mass
324  }
325}
326impl Borrow <component::Derivatives> for Dynamic {
327  fn borrow (&self) -> &component::Derivatives {
328    &self.derivatives
329  }
330}
331impl BorrowMut <component::Derivatives> for Dynamic {
332  fn borrow_mut (&mut self) -> &mut component::Derivatives {
333    &mut self.derivatives
334  }
335}
336impl shape::Aabb <f64> for Dynamic {
337  fn aabb (&self) -> geometry::Aabb3 <f64> {
338    let component::Bound (variant) = &self.bound;
339    let aabb_shape = variant.aabb();
340    geometry::Aabb3::with_minmax_unchecked (
341      aabb_shape.min() + self.position().0.0,
342      aabb_shape.max() + self.position().0.0)
343  }
344}
345impl shape::Stereometric <f64> for Dynamic {
346  fn volume (&self) -> Positive <f64> {
347    let component::Bound (variant) = &self.bound;
348    variant.volume()
349  }
350}
351
352//
353// impl Nodetect
354//
355impl Object for Nodetect {
356  fn kind() -> Kind { Kind::Nodetect }
357  fn position (&self) -> &component::Position {
358    &self.position
359  }
360  fn position_mut (&mut self) -> &mut component::Position {
361    &mut self.position
362  }
363}
364impl Temporal for Nodetect {
365  fn derivatives (&self) -> &component::Derivatives {
366    &self.derivatives
367  }
368  fn derivatives_mut (&mut self) -> &mut component::Derivatives {
369    &mut self.derivatives
370  }
371}
372impl Inertial for Nodetect {
373  fn mass (&self) -> &component::Mass {
374    &self.mass
375  }
376  fn mass_mut (&mut self) -> &mut component::Mass {
377    &mut self.mass
378  }
379}
380impl Borrow <component::Derivatives> for Nodetect {
381  fn borrow (&self) -> &component::Derivatives {
382    &self.derivatives
383  }
384}
385impl BorrowMut <component::Derivatives> for Nodetect {
386  fn borrow_mut (&mut self) -> &mut component::Derivatives {
387    &mut self.derivatives
388  }
389}
390
391//
392// impl Key
393//
394impl Key {
395  /// &#9888; Note: does not check against `KEY_MAX`
396  pub const fn from_raw (key : KeyType) -> Self {
397    Key (key)
398  }
399  pub const fn value (&self) -> KeyType {
400    self.0
401  }
402  pub const fn index (&self) -> usize {
403    self.0 as usize
404  }
405}
406impl std::ops::Deref for Key {
407  type Target = KeyType;
408  fn deref (&self) -> &KeyType {
409    &self.0
410  }
411}
412impl From <KeyType> for Key {
413  /// Debug panic if key greater or equal to `KEY_MAX`
414  fn from (key : KeyType) -> Self {
415    debug_assert!(key < KEY_MAX);
416    Key (key)
417  }
418}
419impl From <usize> for Key {
420  /// Debug panic if key greater or equal to `KEY_MAX`
421  fn from (key : usize) -> Self {
422    debug_assert!((key as KeyType) < KEY_MAX);
423    Key (key as KeyType)
424  }
425}
426
427// impl traits for (Position, Bound) used in tests
428impl Object for (component::Position, component::Bound) {
429  fn kind() -> Kind {
430    Kind::Static
431  }
432  fn position (&self) -> &component::Position {
433    &self.0
434  }
435  fn position_mut (&mut self) -> &mut component::Position {
436    &mut self.0
437  }
438}
439impl Bounded for (component::Position, component::Bound) {
440  fn bound (&self) -> &component::Bound {
441    &self.1
442  }
443  fn bound_mut (&mut self) -> &mut component::Bound {
444    &mut self.1
445  }
446}