#[cfg(test)]
mod tests;
mod trait_impl;
use std::{
fmt,
fmt::{Debug, Display},
ops::Sub,
};
use vector_traits::{
glam::{DVec2, DVec3, Vec2, Vec3, Vec3A, dvec2, dvec3, vec2, vec3, vec3a},
num_traits::Float,
prelude::glam_ext::{Vec2A, vec2a},
prelude::{GenericScalar, GenericVector2, GenericVector3, HasXY, HasXYZ},
};
#[derive(PartialEq, Copy, Clone)]
pub struct Circle<T: GenericVector2> {
pub center: T,
pub radius: T::Scalar,
}
impl<T: GenericVector2> Circle<T> {
pub fn new(center: T, radius: T::Scalar) -> Self {
Self { center, radius }
}
}
pub fn centroid_2d<T: GenericVector2>(p0: T, p1: T, p2: T) -> T {
let x = (p0.x() + p1.x() + p2.x()) / T::Scalar::THREE;
let y = (p0.y() + p1.y() + p2.y()) / T::Scalar::THREE;
T::new_2d(x, y)
}
#[derive(PartialEq, PartialOrd, Debug, Clone, Copy)]
pub struct Area2D<T: GenericVector2>(T::Scalar);
impl<T: GenericVector2> Area2D<T> {
#[inline]
pub fn value(&self) -> T::Scalar {
self.0
}
#[inline]
pub fn new(p0: T, p1: T, p2: T) -> Self {
Area2D(
(p0.x() * (p1.y() - p2.y()) + p1.x() * (p2.y() - p0.y()) + p2.x() * (p0.y() - p1.y()))
.abs()
/ T::Scalar::TWO,
)
}
}
pub struct PlaneFromTriangle<T: GenericVector2> {
a_over_c: T::Scalar,
b_over_c: T::Scalar,
d_over_c: T::Scalar,
}
impl<T: GenericVector2> PlaneFromTriangle<T> {
#[allow(dead_code)]
pub fn new(p0: T::Vector3, p1: T::Vector3, p2: T::Vector3) -> Self {
let n = (p1 - p0).cross(p2 - p0); let a = n.x();
let b = n.y();
let c = n.z();
let d = -(a * p0.x() + b * p0.y() + c * p0.z());
PlaneFromTriangle {
a_over_c: -a / c,
b_over_c: -b / c,
d_over_c: -d / c,
}
}
pub fn new_from_normal(normal: T::Vector3, p0: T::Vector3) -> Self {
let a = normal.x();
let b = normal.y();
let c = normal.z();
let d = -(a * p0.x() + b * p0.y() + c * p0.z());
PlaneFromTriangle {
a_over_c: -a / c,
b_over_c: -b / c,
d_over_c: -d / c,
}
}
#[allow(dead_code)]
pub fn new_from_z_coord(z_coord: T::Scalar) -> Self {
PlaneFromTriangle {
a_over_c: T::Scalar::ZERO,
b_over_c: T::Scalar::ZERO,
d_over_c: z_coord,
}
}
pub fn compute_z(&self, v: T) -> T::Scalar {
self.a_over_c * v.x() + self.b_over_c * v.y() + self.d_over_c
}
}
pub struct RigidTransform2D<T>
where
T: GenericVector3,
{
m00: T::Scalar,
m01: T::Scalar,
m02: T::Scalar,
m10: T::Scalar,
m11: T::Scalar,
m12: T::Scalar,
}
impl<T> RigidTransform2D<T>
where
T: GenericVector3,
{
pub fn identity() -> Self {
RigidTransform2D {
m00: T::Scalar::ONE,
m01: T::Scalar::ZERO,
m02: T::Scalar::ZERO,
m10: T::Scalar::ZERO,
m11: T::Scalar::ONE,
m12: T::Scalar::ZERO,
}
}
pub fn translate_rotate_align_x(
translation: T::Vector2,
p0: T::Vector2,
p1: T::Vector2,
) -> Option<Self> {
let d = (p1.sub(p0)).try_normalize(T::Scalar::EPSILON)?;
let cos_theta = d.x();
let neg_sin_theta = -d.y();
let rotated_tx = translation.x() * cos_theta - translation.y() * neg_sin_theta;
let rotated_ty = translation.x() * neg_sin_theta + translation.y() * cos_theta;
let mut matrix = RigidTransform2D::identity();
matrix.m00 = cos_theta;
matrix.m01 = -neg_sin_theta;
matrix.m02 = -rotated_tx;
matrix.m10 = neg_sin_theta;
matrix.m11 = cos_theta;
matrix.m12 = -rotated_ty;
Some(matrix)
}
#[inline(always)]
pub fn transform_point(&self, p: T) -> T {
let x = self.m00 * p.x() + self.m01 * p.y() + self.m02;
let y = self.m10 * p.x() + self.m11 * p.y() + self.m12;
T::new_3d(x, y, p.z())
}
#[inline(always)]
pub fn transform_2d_point(&self, p: T::Vector2) -> T::Vector2 {
let x = self.m00 * p.x() + self.m01 * p.y() + self.m02;
let y = self.m10 * p.x() + self.m11 * p.y() + self.m12;
T::Vector2::new_2d(x, y)
}
#[allow(dead_code)]
pub fn inverse(&self) -> Option<RigidTransform2D<T>> {
let denom = self.m00 * self.m11 - self.m01 * self.m10;
if !denom.is_normal() {
return self.inverse_determinant();
}
let inverse = RigidTransform2D {
m00: self.m11 / denom,
m01: -self.m01 / denom,
m02: (self.m01 * self.m12 - self.m02 * self.m11) / denom,
m10: -self.m10 / denom,
m11: self.m00 / denom,
m12: (-self.m00 * self.m12 + self.m02 * self.m10) / denom,
};
Some(inverse)
}
#[allow(dead_code)]
pub fn inverse_determinant(&self) -> Option<RigidTransform2D<T>> {
let det = self.m00 * self.m11 - self.m01 * self.m10;
if !det.abs().is_normal() {
return None; }
let inv_det = T::Scalar::ONE / det;
let inverse = RigidTransform2D {
m00: self.m11 * inv_det,
m01: self.m01 * inv_det,
m02: (self.m01 * self.m12 - self.m02 * self.m11) * inv_det,
m10: -self.m10 * inv_det,
m11: self.m00 * inv_det,
m12: (self.m02 * self.m10 - self.m00 * self.m12) * inv_det,
};
Some(inverse)
}
}
pub trait ConvertTo<T> {
fn to(self) -> T;
}
impl ConvertTo<DVec3> for DVec3 {
#[inline(always)]
fn to(self) -> Self {
self
}
}
impl ConvertTo<Vec2A> for Vec2A {
#[inline(always)]
fn to(self) -> Self {
self
}
}
impl ConvertTo<Vec2> for Vec2A {
#[inline(always)]
fn to(self) -> Vec2 {
vec2(self.x, self.y)
}
}
impl ConvertTo<Vec2A> for Vec2 {
#[inline(always)]
fn to(self) -> Vec2A {
vec2a(self.x, self.y)
}
}
impl ConvertTo<Vec3> for Vec3 {
#[inline(always)]
fn to(self) -> Self {
self
}
}
impl ConvertTo<Vec3A> for Vec3A {
#[inline(always)]
fn to(self) -> Self {
self
}
}
impl ConvertTo<DVec3> for Vec3 {
#[inline(always)]
fn to(self) -> DVec3 {
dvec3(self.x as f64, self.y as f64, self.z as f64)
}
}
impl ConvertTo<DVec3> for Vec3A {
#[inline(always)]
fn to(self) -> DVec3 {
dvec3(self.x as f64, self.y as f64, self.z as f64)
}
}
impl ConvertTo<Vec3> for DVec3 {
#[inline(always)]
fn to(self) -> Vec3 {
vec3(self.x as f32, self.y as f32, self.z as f32)
}
}
impl ConvertTo<Vec3A> for DVec3 {
#[inline(always)]
fn to(self) -> Vec3A {
vec3a(self.x as f32, self.y as f32, self.z as f32)
}
}
impl ConvertTo<Vec3A> for Vec3 {
#[inline(always)]
fn to(self) -> Vec3A {
vec3a(self.x, self.y, self.z)
}
}
impl ConvertTo<Vec3> for Vec3A {
#[inline(always)]
fn to(self) -> Vec3 {
vec3(self.x, self.y, self.z)
}
}
impl ConvertTo<DVec2> for DVec2 {
#[inline(always)]
fn to(self) -> Self {
self
}
}
impl ConvertTo<Vec2> for Vec2 {
#[inline(always)]
fn to(self) -> Self {
self
}
}
impl ConvertTo<DVec2> for Vec2 {
#[inline(always)]
fn to(self) -> DVec2 {
dvec2(self.x as f64, self.y as f64)
}
}
impl ConvertTo<Vec2> for DVec2 {
#[inline(always)]
fn to(self) -> Vec2 {
vec2(self.x as f32, self.y as f32)
}
}
impl ConvertTo<DVec2> for Vec2A {
#[inline(always)]
fn to(self) -> DVec2 {
dvec2(self.x as f64, self.y as f64)
}
}
impl ConvertTo<Vec2A> for DVec2 {
#[inline(always)]
fn to(self) -> Vec2A {
vec2a(self.x as f32, self.y as f32)
}
}