honeycomb_core/geometry/dim3/
vertex.rs

1//! Custom spatial representation
2//!
3//! This module contains all code used to model vertices.
4
5use crate::attributes::{AttrSparseVec, AttributeBind, AttributeError, AttributeUpdate};
6use crate::cmap::{OrbitPolicy, VertexIdType};
7use crate::geometry::{CoordsFloat, Vector3, Vertex2};
8
9/// # 2D vertex structure
10///
11/// ## Attribute behavior
12///
13/// - binds to 0-cells,
14/// - merge policy: the new vertex is placed at the midpoint between the two existing ones,
15/// - split policy: the current vertex is duplicated,
16/// - fallback policies: default implementations are used.
17///
18/// ## Generics
19///
20/// - `T: CoordsFloat` -- Generic FP type for coordinates.
21///
22/// ## Example
23///
24/// ```
25/// # use honeycomb_core::geometry::CoordsError;
26/// # fn main() -> Result<(), CoordsError> {
27/// use honeycomb_core::geometry::{Vector3, Vertex3};
28///
29/// let v1 = Vertex3(1.0, 0.0, 0.0);
30/// let v2 = Vertex3(1.0, 1.0, 1.0);
31///
32/// assert_eq!(v1.x(), 1.0);
33/// assert_eq!(v1.y(), 0.0);
34/// assert_eq!(v1.z(), 0.0);
35///
36/// let two: f64 = 2.0;
37/// // vectorAB = vertexB - vertexA
38/// let v2_minus_v1: Vector3<f64> = v2 - v1;
39///
40/// assert_eq!(v2_minus_v1.norm(), two.sqrt());
41/// assert_eq!(v2_minus_v1.unit_dir()?, Vector3(0.0, 1.0 / two.sqrt(), 1.0 / two.sqrt()));
42///
43/// let mut v3 = Vertex3(0.0, 1.0, 1.0);
44/// // vertexA + vectorB = vertexA'
45/// v3 += v2_minus_v1;
46///
47/// assert_eq!(v3.x(), 0.0);
48/// assert_eq!(v3.y(), 2.0);
49/// assert_eq!(v3.z(), 2.0);
50///
51/// # Ok(())
52/// # }
53/// ```
54#[derive(Debug, Clone, Copy, Default, PartialEq)]
55pub struct Vertex3<T: CoordsFloat>(pub T, pub T, pub T);
56
57unsafe impl<T: CoordsFloat> Send for Vertex3<T> {}
58unsafe impl<T: CoordsFloat> Sync for Vertex3<T> {}
59
60impl<T: CoordsFloat> Vertex3<T> {
61    /// Consume `self` to return inner values.
62    pub fn into_inner(self) -> (T, T, T) {
63        (self.0, self.1, self.2)
64    }
65
66    /// Return the value of the `x` coordinate of the vertex.
67    pub fn x(&self) -> T {
68        self.0
69    }
70
71    /// Return the value of the `y` coordinate of the ver, Otex.
72    pub fn y(&self) -> T {
73        self.1
74    }
75
76    /// Return the value of the `z` coordinate of the vertex.
77    pub fn z(&self) -> T {
78        self.2
79    }
80
81    /// Compute the mid-point between two vertices.
82    ///
83    /// # Panics
84    ///
85    /// This function may panic if it cannot initialize an object `T: CoordsFloat` from the value
86    /// `2.0`. The chance of this happening when using `T = f64` or `T = f32` is most likely zero.
87    ///
88    /// # Example
89    ///
90    /// ```rust
91    /// use honeycomb_core::geometry::Vertex3;
92    ///
93    /// let far_far_away: Vertex3<f64> = Vertex3(2.0, 2.0, 2.0);
94    /// let origin: Vertex3<f64> = Vertex3::default();
95    ///
96    /// assert_eq!(Vertex3::average(&origin, &far_far_away), Vertex3(1.0, 1.0, 1.0));
97    /// ```
98    pub fn average(lhs: &Vertex3<T>, rhs: &Vertex3<T>) -> Vertex3<T> {
99        let two = T::from(2.0).unwrap();
100        Vertex3(
101            (lhs.0 + rhs.0) / two,
102            (lhs.1 + rhs.1) / two,
103            (lhs.2 + rhs.2) / two,
104        )
105    }
106}
107
108// Building trait
109
110impl<T: CoordsFloat> From<(T, T, T)> for Vertex3<T> {
111    fn from((x, y, z): (T, T, T)) -> Self {
112        Self(x, y, z)
113    }
114}
115
116impl<T: CoordsFloat> From<Vertex2<T>> for Vertex3<T> {
117    fn from(v: Vertex2<T>) -> Self {
118        Self(v.0, v.1, T::zero())
119    }
120}
121
122// Basic operations
123
124// -- add flavors
125
126impl<T: CoordsFloat> std::ops::Add<Vector3<T>> for Vertex3<T> {
127    // Vertex + Vector = Vertex
128    type Output = Self;
129    fn add(self, rhs: Vector3<T>) -> Self::Output {
130        Self(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
131    }
132}
133
134impl<T: CoordsFloat> std::ops::AddAssign<Vector3<T>> for Vertex3<T> {
135    fn add_assign(&mut self, rhs: Vector3<T>) {
136        self.0 += rhs.0;
137        self.1 += rhs.1;
138        self.2 += rhs.2;
139    }
140}
141
142impl<T: CoordsFloat> std::ops::Add<&Vector3<T>> for Vertex3<T> {
143    // Vertex + Vector = Vertex
144    type Output = Self;
145    fn add(self, rhs: &Vector3<T>) -> Self::Output {
146        Self(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
147    }
148}
149
150impl<T: CoordsFloat> std::ops::AddAssign<&Vector3<T>> for Vertex3<T> {
151    fn add_assign(&mut self, rhs: &Vector3<T>) {
152        self.0 += rhs.0;
153        self.1 += rhs.1;
154        self.2 += rhs.2;
155    }
156}
157
158// -- sub flavors
159impl<T: CoordsFloat> std::ops::Sub<Vector3<T>> for Vertex3<T> {
160    // Vertex - Vector = Vertex
161    type Output = Self;
162    fn sub(self, rhs: Vector3<T>) -> Self::Output {
163        Self(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
164    }
165}
166
167impl<T: CoordsFloat> std::ops::SubAssign<Vector3<T>> for Vertex3<T> {
168    fn sub_assign(&mut self, rhs: Vector3<T>) {
169        self.0 -= rhs.0;
170        self.1 -= rhs.1;
171        self.2 -= rhs.2;
172    }
173}
174
175impl<T: CoordsFloat> std::ops::Sub<&Vector3<T>> for Vertex3<T> {
176    // Vertex - Vector = Vertex
177    type Output = Self;
178    fn sub(self, rhs: &Vector3<T>) -> Self::Output {
179        Self(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
180    }
181}
182
183impl<T: CoordsFloat> std::ops::SubAssign<&Vector3<T>> for Vertex3<T> {
184    fn sub_assign(&mut self, rhs: &Vector3<T>) {
185        self.0 -= rhs.0;
186        self.1 -= rhs.1;
187        self.2 -= rhs.2;
188    }
189}
190
191impl<T: CoordsFloat> std::ops::Sub<Vertex3<T>> for Vertex3<T> {
192    type Output = Vector3<T>;
193    fn sub(self, rhs: Vertex3<T>) -> Self::Output {
194        Vector3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
195    }
196}
197
198impl<T: CoordsFloat> AttributeUpdate for Vertex3<T> {
199    fn merge(attr1: Self, attr2: Self) -> Result<Self, AttributeError> {
200        Ok(Self::average(&attr1, &attr2))
201    }
202
203    fn split(attr: Self) -> Result<(Self, Self), AttributeError> {
204        Ok((attr, attr))
205    }
206
207    fn merge_incomplete(attr: Self) -> Result<Self, AttributeError> {
208        Ok(attr)
209    }
210}
211
212impl<T: CoordsFloat> AttributeBind for Vertex3<T> {
213    type StorageType = AttrSparseVec<Self>;
214    type IdentifierType = VertexIdType;
215    const BIND_POLICY: OrbitPolicy = OrbitPolicy::Vertex;
216}