use crate::attributes::{AttrSparseVec, AttributeBind, AttributeError, AttributeUpdate};
use crate::cmap::{OrbitPolicy, VertexIdType};
use crate::geometry::{CoordsFloat, Vector2};
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct Vertex2<T: CoordsFloat>(pub T, pub T);
unsafe impl<T: CoordsFloat> Send for Vertex2<T> {}
unsafe impl<T: CoordsFloat> Sync for Vertex2<T> {}
impl<T: CoordsFloat> Vertex2<T> {
pub fn into_inner(self) -> (T, T) {
(self.0, self.1)
}
pub fn to_f32(self) -> Option<Vertex2<f32>> {
match (self.0.to_f32(), self.1.to_f32()) {
(Some(x), Some(y)) => Some(Vertex2(x, y)),
_ => None,
}
}
pub fn to_f64(self) -> Option<Vertex2<f64>> {
match (self.0.to_f64(), self.1.to_f64()) {
(Some(x), Some(y)) => Some(Vertex2(x, y)),
_ => None,
}
}
pub fn x(&self) -> T {
self.0
}
pub fn y(&self) -> T {
self.1
}
pub fn average(lhs: &Vertex2<T>, rhs: &Vertex2<T>) -> Vertex2<T> {
let two = T::from(2.0).unwrap();
Vertex2((lhs.0 + rhs.0) / two, (lhs.1 + rhs.1) / two)
}
pub fn cross_product_from_vertices(v1: &Self, v2: &Self, v3: &Self) -> T {
(v2.x() - v1.x()) * (v3.y() - v2.y()) - (v2.y() - v1.y()) * (v3.x() - v2.x())
}
}
impl<T: CoordsFloat> From<(T, T)> for Vertex2<T> {
fn from((x, y): (T, T)) -> Self {
Self(x, y)
}
}
impl<T: CoordsFloat> std::ops::Add<Vector2<T>> for Vertex2<T> {
type Output = Self;
fn add(self, rhs: Vector2<T>) -> Self::Output {
Self(self.0 + rhs.0, self.1 + rhs.1)
}
}
impl<T: CoordsFloat> std::ops::AddAssign<Vector2<T>> for Vertex2<T> {
fn add_assign(&mut self, rhs: Vector2<T>) {
self.0 += rhs.0;
self.1 += rhs.1;
}
}
impl<T: CoordsFloat> std::ops::Add<&Vector2<T>> for Vertex2<T> {
type Output = Self;
fn add(self, rhs: &Vector2<T>) -> Self::Output {
Self(self.0 + rhs.0, self.1 + rhs.1)
}
}
impl<T: CoordsFloat> std::ops::AddAssign<&Vector2<T>> for Vertex2<T> {
fn add_assign(&mut self, rhs: &Vector2<T>) {
self.0 += rhs.0;
self.1 += rhs.1;
}
}
impl<T: CoordsFloat> std::ops::Sub<Vector2<T>> for Vertex2<T> {
type Output = Self;
fn sub(self, rhs: Vector2<T>) -> Self::Output {
Self(self.0 - rhs.0, self.1 - rhs.1)
}
}
impl<T: CoordsFloat> std::ops::SubAssign<Vector2<T>> for Vertex2<T> {
fn sub_assign(&mut self, rhs: Vector2<T>) {
self.0 -= rhs.0;
self.1 -= rhs.1;
}
}
impl<T: CoordsFloat> std::ops::Sub<&Vector2<T>> for Vertex2<T> {
type Output = Self;
fn sub(self, rhs: &Vector2<T>) -> Self::Output {
Self(self.0 - rhs.0, self.1 - rhs.1)
}
}
impl<T: CoordsFloat> std::ops::SubAssign<&Vector2<T>> for Vertex2<T> {
fn sub_assign(&mut self, rhs: &Vector2<T>) {
self.0 -= rhs.0;
self.1 -= rhs.1;
}
}
impl<T: CoordsFloat> std::ops::Sub<Vertex2<T>> for Vertex2<T> {
type Output = Vector2<T>;
fn sub(self, rhs: Vertex2<T>) -> Self::Output {
Vector2(self.0 - rhs.0, self.1 - rhs.1)
}
}
impl<T: CoordsFloat> AttributeUpdate for Vertex2<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 Vertex2<T> {
type StorageType = AttrSparseVec<Self>;
type IdentifierType = VertexIdType;
const BIND_POLICY: OrbitPolicy = OrbitPolicy::Vertex;
}