linear_sim/
object.rs

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