use crate::attributes::{AttrSparseVec, AttributeBind, AttributeError, AttributeUpdate};
use crate::cmap::{OrbitPolicy, VertexIdType};
use crate::geometry::{CoordsFloat, Vector3, Vertex2};
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct Vertex3<T: CoordsFloat>(pub T, pub T, pub T);
unsafe impl<T: CoordsFloat> Send for Vertex3<T> {}
unsafe impl<T: CoordsFloat> Sync for Vertex3<T> {}
impl<T: CoordsFloat> Vertex3<T> {
pub fn into_inner(self) -> (T, T, T) {
(self.0, self.1, self.2)
}
pub fn to_f32(self) -> Option<Vertex3<f32>> {
match (self.0.to_f32(), self.1.to_f32(), self.2.to_f32()) {
(Some(x), Some(y), Some(z)) => Some(Vertex3(x, y, z)),
_ => None,
}
}
pub fn to_f64(self) -> Option<Vertex3<f64>> {
match (self.0.to_f64(), self.1.to_f64(), self.2.to_f64()) {
(Some(x), Some(y), Some(z)) => Some(Vertex3(x, y, z)),
_ => None,
}
}
pub fn x(&self) -> T {
self.0
}
pub fn y(&self) -> T {
self.1
}
pub fn z(&self) -> T {
self.2
}
pub fn average(lhs: &Vertex3<T>, rhs: &Vertex3<T>) -> Vertex3<T> {
let two = T::from(2.0).unwrap();
Vertex3(
(lhs.0 + rhs.0) / two,
(lhs.1 + rhs.1) / two,
(lhs.2 + rhs.2) / two,
)
}
}
impl<T: CoordsFloat> From<(T, T, T)> for Vertex3<T> {
fn from((x, y, z): (T, T, T)) -> Self {
Self(x, y, z)
}
}
impl<T: CoordsFloat> From<Vertex2<T>> for Vertex3<T> {
fn from(v: Vertex2<T>) -> Self {
Self(v.0, v.1, T::zero())
}
}
impl<T: CoordsFloat> std::ops::Add<Vector3<T>> for Vertex3<T> {
type Output = Self;
fn add(self, rhs: Vector3<T>) -> Self::Output {
Self(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
}
}
impl<T: CoordsFloat> std::ops::AddAssign<Vector3<T>> for Vertex3<T> {
fn add_assign(&mut self, rhs: Vector3<T>) {
self.0 += rhs.0;
self.1 += rhs.1;
self.2 += rhs.2;
}
}
impl<T: CoordsFloat> std::ops::Add<&Vector3<T>> for Vertex3<T> {
type Output = Self;
fn add(self, rhs: &Vector3<T>) -> Self::Output {
Self(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
}
}
impl<T: CoordsFloat> std::ops::AddAssign<&Vector3<T>> for Vertex3<T> {
fn add_assign(&mut self, rhs: &Vector3<T>) {
self.0 += rhs.0;
self.1 += rhs.1;
self.2 += rhs.2;
}
}
impl<T: CoordsFloat> std::ops::Sub<Vector3<T>> for Vertex3<T> {
type Output = Self;
fn sub(self, rhs: Vector3<T>) -> Self::Output {
Self(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
}
}
impl<T: CoordsFloat> std::ops::SubAssign<Vector3<T>> for Vertex3<T> {
fn sub_assign(&mut self, rhs: Vector3<T>) {
self.0 -= rhs.0;
self.1 -= rhs.1;
self.2 -= rhs.2;
}
}
impl<T: CoordsFloat> std::ops::Sub<&Vector3<T>> for Vertex3<T> {
type Output = Self;
fn sub(self, rhs: &Vector3<T>) -> Self::Output {
Self(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
}
}
impl<T: CoordsFloat> std::ops::SubAssign<&Vector3<T>> for Vertex3<T> {
fn sub_assign(&mut self, rhs: &Vector3<T>) {
self.0 -= rhs.0;
self.1 -= rhs.1;
self.2 -= rhs.2;
}
}
impl<T: CoordsFloat> std::ops::Sub<Vertex3<T>> for Vertex3<T> {
type Output = Vector3<T>;
fn sub(self, rhs: Vertex3<T>) -> Self::Output {
Vector3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
}
}
impl<T: CoordsFloat> AttributeUpdate for Vertex3<T> {
fn merge(attr1: Self, attr2: Self) -> Result<Self, AttributeError> {
Ok(Self::average(&attr1, &attr2))
}
fn split(attr: Self) -> Result<(Self, Self), AttributeError> {
Ok((attr, attr))
}
fn merge_incomplete(attr: Self) -> Result<Self, AttributeError> {
Ok(attr)
}
}
impl<T: CoordsFloat> AttributeBind for Vertex3<T> {
type StorageType = AttrSparseVec<Self>;
type IdentifierType = VertexIdType;
const BIND_POLICY: OrbitPolicy = OrbitPolicy::Vertex;
}