pub mod aabb;
pub mod hyperplane;
pub mod hypersphere;
pub mod line;
pub mod segment;
pub mod triangle;
use crate::{AABB, FloatSign, Point, VectorMetricSquared, classify_to_zero};
use num_traits::Float;
pub trait SpatialRelation<T, const N: usize> {
fn closest_point(&self, p: &Point<T, N>) -> Point<T, N>;
#[inline]
fn distance_to_point_squared(&self, p: &Point<T, N>) -> T
where
T: Float + std::iter::Sum,
{
(self.closest_point(p) - *p).magnitude_squared()
}
#[inline]
fn distance_to_point(&self, p: &Point<T, N>) -> T
where
T: Float + std::iter::Sum,
{
self.distance_to_point_squared(p).sqrt()
}
#[inline]
fn contains(&self, point: &Point<T, N>) -> bool
where
T: Float + std::iter::Sum,
{
match classify_to_zero(
(self.closest_point(point) - *point).magnitude_squared(),
None,
) {
FloatSign::Zero => true,
_ => false,
}
}
#[inline]
fn is_inside(&self, point: &Point<T, N>) -> bool
where
T: Float + std::iter::Sum,
{
self.contains(point)
}
}
pub trait Bounded<T, const N: usize> {
fn aabb(&self) -> AABB<T, N>;
}
#[derive(Debug, Clone, PartialEq, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound(serialize = "T: serde::Serialize", deserialize = "T: serde::Deserialize<'de>")))]
pub enum IntersectionResult<T, const N: usize> {
None,
Tangent(Point<T, N>),
Secant(Point<T, N>, Point<T, N>),
Collinear,
Single(Point<T, N>),
HalfSpacePenetration(T),
}
#[cfg(all(test, feature = "serde"))]
mod serde_tests {
use super::*;
use crate::Point;
use serde_json;
#[test]
fn test_intersection_result_serialization_roundtrip() {
let none: IntersectionResult<f64, 2> = IntersectionResult::None;
let json = serde_json::to_string(&none).unwrap();
let restored: IntersectionResult<f64, 2> = serde_json::from_str(&json).unwrap();
assert_eq!(none, restored);
let tangent = IntersectionResult::Tangent(Point::new([1.0, 2.0]));
let json = serde_json::to_string(&tangent).unwrap();
let restored: IntersectionResult<f64, 2> = serde_json::from_str(&json).unwrap();
assert_eq!(tangent, restored);
let secant = IntersectionResult::Secant(
Point::new([0.0, 0.0]),
Point::new([1.0, 1.0]),
);
let json = serde_json::to_string(&secant).unwrap();
let restored: IntersectionResult<f64, 2> = serde_json::from_str(&json).unwrap();
assert_eq!(secant, restored);
let collinear: IntersectionResult<f64, 2> = IntersectionResult::Collinear;
let json = serde_json::to_string(&collinear).unwrap();
let restored: IntersectionResult<f64, 2> = serde_json::from_str(&json).unwrap();
assert_eq!(collinear, restored);
let single = IntersectionResult::Single(Point::new([3.0, 4.0]));
let json = serde_json::to_string(&single).unwrap();
let restored: IntersectionResult<f64, 2> = serde_json::from_str(&json).unwrap();
assert_eq!(single, restored);
let penetration = IntersectionResult::HalfSpacePenetration(2.5);
let json = serde_json::to_string(&penetration).unwrap();
let restored: IntersectionResult<f64, 2> = serde_json::from_str(&json).unwrap();
assert_eq!(penetration, restored);
}
}