use crate::*;
use alloc::{format, vec::Vec};
pub type GeoVar1 = GeoVar<na::Rotation<f64, 1>, 1>;
pub type GeoVar2 = GeoVar<na::UnitComplex<f64>, 2>;
pub type GeoVar3 = GeoVar<na::UnitQuaternion<f64>, 3>;
type Sim<R, const D: usize> = na::Similarity<f64, R, D>;
pub trait RotHint<const D: usize>:
na::AbstractRotation<f64, D> + Sync + Send + core::fmt::Debug
{
fn matrix(self) -> na::SMatrix<f64, D, D>;
}
impl<const D: usize> RotHint<D> for na::Rotation<f64, D> {
fn matrix(self) -> na::SMatrix<f64, D, D> {
self.into_inner()
}
}
impl RotHint<2> for na::UnitComplex<f64> {
fn matrix(self) -> na::SMatrix<f64, 2, 2> {
self.to_rotation_matrix().into_inner()
}
}
impl RotHint<3> for na::UnitQuaternion<f64> {
fn matrix(self) -> na::SMatrix<f64, 3, 3> {
self.to_rotation_matrix().into_inner()
}
}
#[derive(Clone)]
pub struct GeoVar<R: RotHint<D>, const D: usize> {
inner: Sim<R, D>,
}
impl<R: RotHint<D>, const D: usize> Default for GeoVar<R, D> {
fn default() -> Self {
Self::identity()
}
}
impl<R, const D: usize> core::fmt::Debug for GeoVar<R, D>
where
R: RotHint<D>,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct(&format!("GeoVar{D}"))
.field("translation", &self.trans())
.field("rotation", self.rot())
.field("scale", &self.scale())
.finish()
}
}
impl<R, const D: usize> GeoVar<R, D>
where
R: RotHint<D>,
{
pub fn identity() -> Self {
Self { inner: Sim::identity() }
}
pub fn new(trans: [f64; D], rot: R, scale: f64) -> Self {
Self { inner: Sim::from_parts(trans.into(), rot, scale) }
}
pub fn from_trans(trans: [f64; D]) -> Self {
Self::identity().with_trans(trans)
}
pub fn from_rot(rot: R) -> Self {
Self::identity().with_rot(rot)
}
pub fn from_scale(scale: f64) -> Self {
Self::identity().with_scale(scale)
}
pub fn only_trans(self) -> Self {
Self::from_trans(*self.trans())
}
pub fn only_rot(self) -> Self {
Self::from_rot(self.inner.isometry.rotation)
}
pub fn only_rot_scale(self) -> Self {
Self::from_scale(self.inner.scaling())
}
pub fn with_trans(mut self, trans: [f64; D]) -> Self {
self.set_trans(trans);
self
}
pub fn with_rot(mut self, rot: R) -> Self {
self.set_rot(rot);
self
}
pub fn with_scale(mut self, scale: f64) -> Self {
self.inner.set_scaling(scale);
self
}
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn to(&self, rhs: &Self) -> Self {
rhs * self.inverse()
}
#[must_use = "this returns the result of the operation, without modifying the original"]
#[inline]
pub fn inverse(&self) -> Self {
Self { inner: self.inner.inverse() }
}
#[inline]
pub fn trans(&self) -> &[f64; D] {
&self.inner.isometry.translation.vector.data.0[0]
}
#[inline]
pub fn rot(&self) -> &R {
&self.inner.isometry.rotation
}
#[inline]
pub fn scale(&self) -> f64 {
self.inner.scaling()
}
#[inline]
pub fn set_trans(&mut self, trans: [f64; D]) {
self.inner.isometry.translation = trans.into();
}
#[inline]
pub fn set_rot(&mut self, rot: R) {
self.inner.isometry.rotation = rot;
}
#[inline]
pub fn set_scale(&mut self, scale: f64) {
self.inner.set_scaling(scale);
}
#[must_use = "The transformed point is returned as a new value"]
#[inline]
pub fn transform_pt(&self, p: [f64; D]) -> [f64; D] {
self.inner.transform_point(&na::Point::from(p)).into()
}
#[must_use = "The transformed point is returned as a new value"]
pub fn transform<C>(&self, curve: C) -> Vec<[f64; D]>
where
C: Curve<D>,
{
curve
.to_curve()
.into_iter()
.map(|c| self.transform_pt(c))
.collect()
}
pub fn transform_inplace<C>(&self, mut curve: C)
where
C: AsMut<[[f64; D]]>,
{
for c in curve.as_mut() {
*c = self.transform_pt(*c);
}
}
pub fn transform_iter<'a, C>(&'a self, curve: C) -> impl Iterator<Item = [f64; D]> + 'a
where
C: IntoIterator<Item = [f64; D]> + 'a,
{
curve.into_iter().map(|c| self.transform_pt(c))
}
}
macro_rules! impl_mul {
($ty:ty) => {
impl_mul!(@$ty, $ty, &$ty, $ty, $ty, &$ty, &$ty, &$ty);
};
(@$($ty1:ty, $ty2:ty),+) => {$(
impl<R: RotHint<D>, const D: usize> core::ops::Mul<$ty2> for $ty1 {
type Output = GeoVar<R, D>;
fn mul(self, rhs: $ty2) -> Self::Output {
GeoVar { inner: &self.inner * &rhs.inner }
}
}
)+};
}
impl_mul!(GeoVar<R, D>);
impl<R: RotHint<D>, const D: usize> core::ops::MulAssign<Self> for GeoVar<R, D> {
fn mul_assign(&mut self, rhs: Self) {
*self *= &rhs;
}
}
impl<R: RotHint<D>, const D: usize> core::ops::MulAssign<&Self> for GeoVar<R, D> {
fn mul_assign(&mut self, rhs: &Self) {
self.inner *= &rhs.inner;
}
}