use super::{HasPosition, VertexBasics};
use crate::{
math::{Scalar, Vector, Vector3D},
mesh::{EuclideanMeshType, MeshBasics, MeshType},
};
pub trait VertexInterpolator<const N: usize, T: MeshType> {
fn call(&self, mesh: &T::Mesh, vertices: [(usize, T::V); N]) -> T::VP;
}
pub struct LinearVertexInterpolator<const D: usize> {}
impl<const D: usize, T: EuclideanMeshType<D>> VertexInterpolator<3, T>
for LinearVertexInterpolator<D>
where
T::VP: HasPosition<D, T::Vec, S = T::S>,
{
fn call(&self, mesh: &T::Mesh, [(i, vi), (j, vj), (k, vk)]: [(usize, T::V); 3]) -> T::VP {
let pi = mesh.vertex(vi).pos();
let pj = mesh.vertex(vj).pos();
let pk = mesh.vertex(vk).pos();
T::VP::from_pos(
(pi * T::S::from_usize(i) + pj * T::S::from_usize(j) + pk * T::S::from_usize(k))
/ T::S::from_usize(i + j + k),
)
}
}
pub struct SlerpVertexInterpolator<const D: usize, T: EuclideanMeshType<D>> {
center: T::Vec,
radius: T::S,
}
impl<const D: usize, T: EuclideanMeshType<D>> SlerpVertexInterpolator<D, T> {
pub fn new(center: T::Vec, radius: T::S) -> Self {
Self { center, radius }
}
}
impl<const D: usize, T: EuclideanMeshType<D>> VertexInterpolator<3, T>
for SlerpVertexInterpolator<D, T>
where
T::Vec: Vector3D<S = T::S>,
{
fn call(&self, mesh: &T::Mesh, [(i, vi), (j, vj), (k, vk)]: [(usize, T::V); 3]) -> T::VP {
let pi = (mesh.vertex(vi).pos() - self.center).normalize();
let pj = (mesh.vertex(vj).pos() - self.center).normalize();
let pk = (mesh.vertex(vk).pos() - self.center).normalize();
let pos = if i == 0 {
pj.slerp(&pk, T::S::HALF)
} else if j == 0 {
pk.slerp(&pi, T::S::HALF)
} else if k == 0 {
pi.slerp(&pj, T::S::HALF)
} else {
todo!("slerp 3")
};
T::VP::from_pos(self.center + pos.normalize() * self.radius)
}
}