#![deny(missing_docs)]
use std::{hash::Hash, ops::Neg};
pub use vector_space::Transform;
#[derive(Copy, Clone, Debug)]
pub struct CollisionInfo<V> {
pub self_contact: V,
pub other_contact: V,
pub vector: V,
}
impl<V: Neg<Output = V>> Neg for CollisionInfo<V> {
type Output = Self;
fn neg(self) -> Self {
let Self {
self_contact,
other_contact,
vector,
} = self;
Self {
self_contact: other_contact,
other_contact: self_contact,
vector: -vector,
}
}
}
pub trait Collider<OtherCollider = Self> {
type Vector;
fn check_collision(&self, other: &OtherCollider) -> bool {
self.collision_info(other).is_some()
}
fn collision_info(&self, other: &OtherCollider) -> Option<CollisionInfo<Self::Vector>>;
}
pub trait BoundingVolume: Clone {
fn overlaps(&self, other: &Self) -> bool;
fn merged(&self, other: &Self) -> Self;
}
pub trait Bounded<B> {
fn bounding_volume(&self) -> B;
}
#[derive(Clone, Debug)]
pub struct BoundedCollider<B, C> {
pub bounding: B,
pub inner: C,
}
impl<B, C: Bounded<B>> BoundedCollider<B, C> {
pub fn new(inner: C) -> Self {
let bounding = inner.bounding_volume();
Self { bounding, inner }
}
}
impl<B: Collider, C: Collider<Vector = B::Vector>> Collider for BoundedCollider<B, C> {
type Vector = C::Vector;
fn check_collision(&self, other: &Self) -> bool {
self.bounding.check_collision(&other.bounding) && self.inner.check_collision(&other.inner)
}
fn collision_info(&self, other: &Self) -> Option<CollisionInfo<Self::Vector>> {
if !self.bounding.check_collision(&other.bounding) {
return None;
}
self.inner.collision_info(&other.inner)
}
}
impl<B: BoundingVolume, C: Bounded<B>> Bounded<B> for BoundedCollider<B, C> {
fn bounding_volume(&self) -> B {
self.bounding.clone()
}
}
pub trait Transformable<T> {
fn transformed(&self, transform: &T) -> Self;
}
#[derive(Clone, Debug)]
pub struct Transformed<C, T> {
pub transform: T,
pub inner: C,
}
impl<C, T> Transformed<C, T> {
pub fn new(inner: C, transform: T) -> Self {
Self { transform, inner }
}
}
impl<C, T, V> Collider for Transformed<C, T>
where
C: Collider<Vector = V> + Transformable<T>,
V: Copy,
{
type Vector = V;
fn check_collision(&self, other: &Self) -> bool {
self.inner
.transformed(&self.transform)
.check_collision(&other.inner.transformed(&other.transform))
}
fn collision_info(&self, other: &Self) -> Option<CollisionInfo<V>> {
self.inner
.transformed(&self.transform)
.collision_info(&other.inner.transformed(&other.transform))
}
}
pub trait SpatialPartition {
type Cell: Hash + Eq;
fn cells(&self) -> impl Iterator<Item = Self::Cell>;
}