use std;
use std::{borrow::Borrow, borrow::BorrowMut};
use derive_more::From;
#[cfg(feature = "derive_serdes")]
use serde::{Deserialize, Serialize};
use crate::{collision, component, geometry, math};
use geometry::{shape, Shape};
pub type KeyType = u32;
pub const KEY_MAX : KeyType = collision::OBJECT_KEY_MAX;
pub trait Object : Clone + std::fmt::Debug {
fn kind() -> Kind;
fn position (&self) -> &component::Position;
fn position_mut (&mut self) -> &mut component::Position;
}
pub trait Bounded : Object + Shape <f64> {
fn bound (&self) -> &component::Bound;
fn bound_mut (&mut self) -> &mut component::Bound;
fn hit_test (&self, line_segment : geometry::Segment3 <f64>)
-> Option <(f64, math::Point3 <f64>)>
{
let component::Position (position) = self.position();
match self.bound().0 {
shape::Variant::Bounded (shape::Bounded::Sphere (ref sphere)) =>
line_segment.intersect_sphere (&sphere.sphere3 (*position))
.map (|(start, _)| start),
shape::Variant::Bounded (shape::Bounded::Capsule (ref capsule)) =>
line_segment.intersect_capsule (&capsule.capsule3 (*position))
.map (|(start, _)| start),
shape::Variant::Bounded (shape::Bounded::Cylinder (ref cylinder)) =>
line_segment.intersect_cylinder (&cylinder.cylinder3 (*position))
.map (|(start, _)| start),
shape::Variant::Bounded (shape::Bounded::Cuboid (ref cuboid)) =>
line_segment.intersect_aabb (&cuboid.aabb3 (*position))
.map (|(start, _)| start),
shape::Variant::Bounded (shape::Bounded::Cone (ref _cone)) =>
unimplemented!(),
shape::Variant::Bounded (shape::Bounded::Cube (ref _cube)) =>
unimplemented!(),
shape::Variant::Unbounded (shape::Unbounded::Halfspace (ref _halfspace))
=> unimplemented!(),
shape::Variant::Unbounded (shape::Unbounded::Orthant (ref _orthant))
=> unimplemented!()
}
}
}
pub trait Temporal : Object {
fn derivatives (&self) -> &component::Derivatives;
fn derivatives_mut (&mut self) -> &mut component::Derivatives;
}
pub trait Inertial : Temporal {
fn mass (&self) -> &component::Mass;
fn mass_mut (&mut self) -> &mut component::Mass;
fn momentum (&self) -> math::Vector3 <f64> {
self.mass().mass() * self.derivatives().velocity
}
fn compute_acceleration (&self) -> math::Vector3 <f64> {
self.mass().mass_reciprocal() * self.derivatives().force
}
fn compute_acceleration_inplace (&mut self) {
let acceleration = self.mass().mass_reciprocal() * self.derivatives().force;
self.derivatives_mut().acceleration = acceleration;
}
}
pub trait Massive : Bounded + Inertial {
fn drag (&self) -> f64;
fn density (&self) -> Option <f64> {
use geometry::shape::Stereometric;
if let component::Bound (shape::Variant::Bounded (bounded)) = self.bound() {
Some (self.mass().mass() / *bounded.volume())
} else {
None
}
}
}
pub trait Solid : Bounded {
fn material (&self) -> &component::Material;
fn material_mut (&mut self) -> &mut component::Material;
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Kind {
Static,
Dynamic,
Nodetect
}
#[derive(Clone, Debug, PartialEq, From)]
pub enum Variant {
Static (Static),
Dynamic (Dynamic),
Nodetect (Nodetect)
}
#[derive(Clone, Debug, PartialEq, From)]
pub enum VariantRef <'a> {
Static (&'a Static),
Dynamic (&'a Dynamic),
Nodetect (&'a Nodetect)
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Key (KeyType);
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Id {
pub kind : Kind,
pub key : Key
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct Static {
pub position : component::Position,
pub bound : component::Bound,
pub material : component::Material,
pub collidable : bool
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct Dynamic {
pub position : component::Position,
pub mass : component::Mass,
pub derivatives : component::Derivatives,
pub drag : component::Drag,
pub bound : component::Bound,
pub material : component::Material,
pub collidable : bool
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct Nodetect {
pub position : component::Position,
pub mass : component::Mass,
pub derivatives : component::Derivatives,
pub drag : component::Drag
}
pub fn report_sizes() {
use std::mem::size_of;
println!("object report sizes...");
println!(" size of Variant: {}", size_of::<Variant>());
println!(" size of Static: {}", size_of::<Static>());
println!(" size of Dynamic: {}", size_of::<Dynamic>());
println!(" size of Nodetect: {}", size_of::<Nodetect>());
println!("...object report sizes");
}
impl Variant {
pub fn kind (&self) -> Kind {
match self {
Variant::Static (_) => Kind::Static,
Variant::Dynamic (_) => Kind::Dynamic,
Variant::Nodetect (_) => Kind::Nodetect
}
}
}
impl Static {
pub (crate) fn aabb_dilated (&self) -> geometry::Aabb3 <f64> {
use shape::Aabb;
self.aabb().dilate (0.5 * collision::CONTACT_DISTANCE)
}
}
impl Object for Static {
fn kind() -> Kind { Kind::Static }
fn position (&self) -> &component::Position {
&self.position
}
fn position_mut (&mut self) -> &mut component::Position {
&mut self.position
}
}
impl Bounded for Static {
fn bound (&self) -> &component::Bound {
&self.bound
}
fn bound_mut (&mut self) -> &mut component::Bound {
&mut self.bound
}
}
impl Solid for Static {
fn material (&self) -> &component::Material {
&self.material
}
fn material_mut (&mut self) -> &mut component::Material {
&mut self.material
}
}
impl Shape <f64> for Static { }
impl shape::Aabb <f64> for Static {
fn aabb (&self) -> geometry::Aabb3 <f64> {
let component::Bound (variant) = self.bound();
let aabb_shape = variant.aabb();
geometry::Aabb3::with_minmax (
aabb_shape.min() + self.position().0.0,
aabb_shape.max() + self.position().0.0)
}
}
impl shape::Stereometric <f64> for Static {
fn volume (&self) -> math::Positive <f64> {
let component::Bound (variant) = self.bound();
variant.volume()
}
}
impl Dynamic {
pub (crate) fn aabb_dilated (&self) -> geometry::Aabb3 <f64> {
use shape::Aabb;
self.aabb().dilate (0.5 * collision::CONTACT_DISTANCE)
}
}
impl Object for Dynamic {
fn kind() -> Kind { Kind::Dynamic }
fn position (&self) -> &component::Position {
&self.position
}
fn position_mut (&mut self) -> &mut component::Position {
&mut self.position
}
}
impl Bounded for Dynamic {
fn bound (&self) -> &component::Bound {
&self.bound
}
fn bound_mut (&mut self) -> &mut component::Bound {
&mut self.bound
}
}
impl Solid for Dynamic {
fn material (&self) -> &component::Material {
&self.material
}
fn material_mut (&mut self) -> &mut component::Material {
&mut self.material
}
}
impl Temporal for Dynamic {
fn derivatives (&self) -> &component::Derivatives {
&self.derivatives
}
fn derivatives_mut (&mut self) -> &mut component::Derivatives {
&mut self.derivatives
}
}
impl Inertial for Dynamic {
fn mass (&self) -> &component::Mass {
&self.mass
}
fn mass_mut (&mut self) -> &mut component::Mass {
&mut self.mass
}
}
impl Borrow <component::Derivatives> for Dynamic {
fn borrow (&self) -> &component::Derivatives {
&self.derivatives
}
}
impl BorrowMut <component::Derivatives> for Dynamic {
fn borrow_mut (&mut self) -> &mut component::Derivatives {
&mut self.derivatives
}
}
impl Shape <f64> for Dynamic { }
impl shape::Aabb <f64> for Dynamic {
fn aabb (&self) -> geometry::Aabb3 <f64> {
let component::Bound (variant) = self.bound();
let aabb_shape = variant.aabb();
geometry::Aabb3::with_minmax (
aabb_shape.min() + self.position().0.0,
aabb_shape.max() + self.position().0.0)
}
}
impl shape::Stereometric <f64> for Dynamic {
fn volume (&self) -> math::Positive <f64> {
let component::Bound (variant) = self.bound();
variant.volume()
}
}
impl Object for Nodetect {
fn kind() -> Kind { Kind::Nodetect }
fn position (&self) -> &component::Position {
&self.position
}
fn position_mut (&mut self) -> &mut component::Position {
&mut self.position
}
}
impl Temporal for Nodetect {
fn derivatives (&self) -> &component::Derivatives {
&self.derivatives
}
fn derivatives_mut (&mut self) -> &mut component::Derivatives {
&mut self.derivatives
}
}
impl Inertial for Nodetect {
fn mass (&self) -> &component::Mass {
&self.mass
}
fn mass_mut (&mut self) -> &mut component::Mass {
&mut self.mass
}
}
impl Borrow <component::Derivatives> for Nodetect {
fn borrow (&self) -> &component::Derivatives {
&self.derivatives
}
}
impl BorrowMut <component::Derivatives> for Nodetect {
fn borrow_mut (&mut self) -> &mut component::Derivatives {
&mut self.derivatives
}
}
impl Key {
pub const fn from_raw (key : KeyType) -> Self {
Key (key)
}
pub const fn value (&self) -> KeyType {
self.0
}
pub const fn index (&self) -> usize {
self.0 as usize
}
}
impl std::ops::Deref for Key {
type Target = KeyType;
fn deref (&self) -> &KeyType {
&self.0
}
}
impl From <KeyType> for Key {
fn from (key : KeyType) -> Self {
debug_assert!(key < KEY_MAX);
Key (key)
}
}
impl From <usize> for Key {
fn from (key : usize) -> Self {
debug_assert!((key as KeyType) < KEY_MAX);
Key (key as KeyType)
}
}