vdtfont/
point.rs

1use crate::delaunay::{DelaunayTriangle, DelaunayTriangleHandle, TriangleId};
2use crate::ocl::prm::Float2;
3
4use std::fmt;
5use std::hash;
6
7use arena_system::{Arena, Handle, Index, RawHandle};
8use smallvec::SmallVec;
9
10pub type PointId = i64;
11
12/// A (x; y) coordinate with additional information.
13#[derive(Debug, Default, Clone, PartialEq)]
14pub struct Point {
15    coords: Float2,
16
17    is_bounding: bool,
18    previous_in_outline: PointId,
19
20    triangle_fan: SmallVec<[TriangleId; 6]>,
21}
22
23impl Point {
24    /// Creates a new [`Point`].
25    pub fn new(x: f32, y: f32) -> Self {
26        Self {
27            coords: Float2::new(x, y),
28
29            is_bounding: false,
30            previous_in_outline: -1,
31
32            triangle_fan: SmallVec::new(),
33        }
34    }
35
36    /// Creates a new [`Point`] with the information if it is bounding or not.
37    pub fn with_is_bounding(x: f32, y: f32, is_bounding: bool) -> Self {
38        Self {
39            coords: Float2::new(x, y),
40
41            is_bounding,
42            previous_in_outline: -1,
43
44            triangle_fan: SmallVec::new(),
45        }
46    }
47
48    /// Creates a new [`Point`] with the information about the previous one in the outline.
49    pub fn with_previous(x: f32, y: f32, previous_in_outline: PointId) -> Self {
50        Self {
51            coords: Float2::new(x, y),
52
53            is_bounding: false,
54            previous_in_outline,
55
56            triangle_fan: SmallVec::new(),
57        }
58    }
59
60    /// Creates a new [`Point`] with the information about the previous one in the outline
61    /// and if it is bounding or not.
62    pub fn with_is_bounding_and_previous(
63        x: f32,
64        y: f32,
65        is_bounding: bool,
66        previous_in_outline: PointId,
67    ) -> Self {
68        Self {
69            coords: Float2::new(x, y),
70
71            is_bounding,
72            previous_in_outline,
73
74            triangle_fan: SmallVec::new(),
75        }
76    }
77
78    /// Returns the `x` coordinate of the point.
79    pub fn x(&self) -> f32 {
80        self.coords[0]
81    }
82
83    /// Returns the `y` coordinate of the point.
84    pub fn y(&self) -> f32 {
85        self.coords[1]
86    }
87
88    pub fn coords(&self) -> Float2 {
89        self.coords
90    }
91
92    /// Returns coordinates of the point.
93    pub fn set_coords(&mut self, coords: Float2) {
94        self.coords = coords;
95    }
96
97    /// Checks if the point is bounding.
98    pub fn is_bounding(&self) -> bool {
99        self.is_bounding
100    }
101
102    /// Returns the previous point in the outline.
103    pub fn previous_in_outline(&self) -> PointId {
104        self.previous_in_outline
105    }
106
107    /// Sets the previous point in the outline.
108    pub fn set_previous_in_outline(&mut self, previous_in_outline: PointId) {
109        self.previous_in_outline = previous_in_outline;
110    }
111
112    /// Returns the triangle fan of the point.
113    pub fn triangle_fan(&self) -> &SmallVec<[TriangleId; 6]> {
114        &self.triangle_fan
115    }
116
117    /// Sets the triangle fan of the point.
118    pub fn set_triangle_fan(&mut self, triangle_fan: SmallVec<[TriangleId; 6]>) {
119        self.triangle_fan = triangle_fan;
120    }
121
122    /// Returns a point between two points.
123    pub fn midpoint(&self, other: &Point) -> Point {
124        Point::new((self.x() + other.x()) / 2.0, (self.y() + other.y()) / 2.0)
125    }
126
127    /// Returns the squared distance between two points.
128    pub fn distance_squared(&self, other: &Point) -> f32 {
129        let p = Point::new(self.x() - other.x(), self.y() - other.y());
130
131        p.x().powi(2) + p.y().powi(2)
132    }
133
134    /// Returns the distance between two points.
135    pub fn distance(&self, other: &Point) -> f32 {
136        self.distance_squared(other).sqrt()
137    }
138}
139
140/// A handle of the [`Point`] which is used by [`Arena`].
141#[derive(Clone, Copy)]
142pub struct PointHandle<'arena> {
143    raw: RawHandle<'arena, Point>,
144    triangles: Option<&'arena Arena<DelaunayTriangle>>,
145}
146
147impl<'arena> PointHandle<'arena> {
148    /// Returns the `x` coordinate of the point.
149    pub fn x(&self) -> f32 {
150        self.get().unwrap().coords[0]
151    }
152
153    /// Returns the `y` coordinate of the point.
154    pub fn y(&self) -> f32 {
155        self.get().unwrap().coords[1]
156    }
157
158    /// Returns coordinates of the point.
159    pub fn coords(&self) -> Float2 {
160        self.get().unwrap().coords
161    }
162
163    /// Sets the coordinates of the point.
164    pub fn set_coords(&mut self, coords: Float2) {
165        self.get_mut().unwrap().coords = coords;
166    }
167
168    /// Checks if the point is bounding.
169    pub fn is_bounding(&self) -> bool {
170        self.get().unwrap().is_bounding
171    }
172
173    /// Returns the previous point in the outline.
174    pub fn previous_in_outline(&self) -> PointHandle<'arena> {
175        let this = self.get().expect("Can't get the point");
176
177        self.arena().handle(this.previous_in_outline().into(), self.triangles)
178    }
179
180    /// Returns the triangle fan of the point.
181    pub fn triangle_fan(&self) -> SmallVec<[DelaunayTriangleHandle<'arena>; 6]> {
182        self.get()
183            .unwrap()
184            .triangle_fan
185            .iter()
186            .copied()
187            .map(|i| i.into())
188            .map(|i| self.triangles.unwrap().handle(i, self.arena()))
189            .collect()
190    }
191
192    /// Sets the triangle fan of the point.
193    pub fn set_triangle_fan(
194        &mut self,
195        triangle_fan: SmallVec<[DelaunayTriangleHandle<'arena>; 6]>,
196    ) {
197        self.get_mut().unwrap().triangle_fan =
198            triangle_fan.into_iter().map(|h| h.index().into()).collect();
199    }
200
201    /// Adds `triangle` to the triangle fan of the point.
202    pub fn add_triangle_to_fan(&self, triangle: DelaunayTriangleHandle) {
203        let triangle_fan = &mut self.get_mut().unwrap().triangle_fan;
204
205        triangle_fan.push(triangle.index().into());
206    }
207
208    /// Removes `triangle` from the triangle fan of the point.
209    pub fn remove_triangle_from_fan(&self, triangle_index: Index) {
210        let triangle_fan = &mut self.get_mut().unwrap().triangle_fan;
211        let position = triangle_fan.iter().position(|t| *t == triangle_index.into());
212
213        if let Some(position) = position {
214            triangle_fan.remove(position);
215        }
216    }
217
218    /// Checks if the point is connected to the other one.
219    pub fn is_connected_to(&self, other: PointHandle<'arena>) -> bool {
220        self.triangle_fan().into_iter().any(|t| t.points().contains(&other)) && *self != other
221    }
222
223    /// Calculates skew product of `self` and `other` points
224    /// with the origin of coordinates at `origin`
225    pub fn skew_product(&self, origin: &Self, other: &Self) -> f32 {
226        let a = Point::new(self.x() - origin.x(), self.y() - origin.y());
227        let b = Point::new(other.x() - origin.x(), other.y() - origin.y());
228
229        a.x() * b.y() - a.y() * b.x()
230    }
231
232    /// Returns the distance between two points.
233    pub fn distance(&self, other: &PointHandle) -> f32 {
234        let this = self.get().expect("Can't get the point");
235        let other = other.get().expect("Can't get the other point");
236
237        this.distance(&other)
238    }
239}
240
241impl<'arena> Handle<'arena> for PointHandle<'arena> {
242    type Type = Point;
243    type Userdata = Option<&'arena Arena<DelaunayTriangle>>;
244
245    fn from_raw(raw: RawHandle<'arena, Self::Type>, userdata: Self::Userdata) -> Self {
246        Self { raw, triangles: userdata }
247    }
248
249    fn to_raw(&self) -> RawHandle<'arena, Self::Type> {
250        self.raw
251    }
252}
253
254impl fmt::Debug for PointHandle<'_> {
255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256        f.write_fmt(format_args!("PointHandle({:?})", self.to_raw()))
257    }
258}
259
260impl PartialEq for PointHandle<'_> {
261    fn eq(&self, other: &Self) -> bool {
262        self.to_raw() == other.to_raw()
263    }
264}
265impl Eq for PointHandle<'_> {}
266
267impl PartialOrd for PointHandle<'_> {
268    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
269        self.to_raw().partial_cmp(&other.to_raw())
270    }
271}
272
273impl Ord for PointHandle<'_> {
274    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
275        self.to_raw().cmp(&other.to_raw())
276    }
277}
278
279impl hash::Hash for PointHandle<'_> {
280    fn hash<H: hash::Hasher>(&self, state: &mut H) {
281        let index: i64 = self.index().into();
282        index.hash(state);
283    }
284}