theta_chart/coord/
point.rs

1use na::{Isometry3, Point3, Vector3};
2use nalgebra as na;
3use robust::orient2d;
4
5use crate::{degree_to_radian, turn_to_radian};
6
7use super::Vector;
8
9pub type Point3D = Point3<f64>;
10
11#[derive(Debug, Clone, PartialEq)]
12/// Store data for a point on chart
13pub struct Point(Point3D);
14
15impl Default for Point {
16    fn default() -> Self {
17        Self(Point3::new(0., 0., 1.))
18    }
19}
20
21impl From<Point3D> for Point {
22    fn from(value: Point3D) -> Self {
23        Point(value)
24    }
25}
26
27impl From<&Point> for robust::Coord<f64> {
28    fn from(p: &Point) -> robust::Coord<f64> {
29        robust::Coord::<f64> { x: p.get_x(), y: p.get_y() }
30    }
31}
32
33impl Point {
34    pub fn new(x: f64, y: f64) -> Self {
35        Self(Point3::new(x, y, 1.))
36    }
37
38    pub fn value(&self) -> Point3D {
39        self.0
40    }
41
42    pub fn get_x(&self) -> f64 {
43        self.0.x
44    }
45
46    pub fn get_y(&self) -> f64 {
47        self.0.y
48    }
49
50    pub fn set_x(&mut self, x: f64) -> Self {
51        self.0.x = x;
52        self.clone()
53    }
54
55    pub fn set_y(&mut self, y: f64) -> Self {
56        self.0.y = y;
57        self.clone()
58    }
59
60    pub fn rotate_tau(&self, tau: f64) -> Point {
61        let axisangle = Vector3::z() * tau;
62        let iso = Isometry3::new(Vector3::default(), axisangle);
63        let p = iso * self.value();
64        Point(p)
65    }
66
67    pub fn rotate_turn(&self, turn: f64) -> Point {
68        let tau = turn_to_radian(turn);
69        self.rotate_tau(tau)
70    }
71
72    pub fn rotate_degree(&self, degree: f64) -> Point {
73        let tau = degree_to_radian(degree);
74        self.rotate_tau(tau)
75    }
76
77    pub fn translate(&self, v: &Vector) -> Point {
78        Point::new(self.get_x() + v.get_x(), self.get_y() + v.get_y())
79    }
80
81    // For delaunator
82    pub fn dist2(&self, p: &Self) -> f64 {
83        let dx = self.0.x - p.0.x;
84        let dy = self.0.y - p.0.y;
85        dx * dx + dy * dy
86    }
87    pub fn orient(&self, q: &Self, r: &Self) -> f64 {
88        // robust-rs orients Y-axis upwards, our convention is Y downwards. This means that the interpretation of the result must be flipped
89        orient2d(self.into(), q.into(), r.into())
90    }
91
92
93    pub fn circumdelta(&self, b: &Self, c: &Self) -> (f64, f64) {
94        let dx = b.0.x - self.0.x;
95        let dy = b.0.y - self.0.y;
96        let ex = c.0.x - self.0.x;
97        let ey = c.0.y - self.0.y;
98
99        let bl = dx * dx + dy * dy;
100        let cl = ex * ex + ey * ey;
101        let d = 0.5 / (dx * ey - dy * ex);
102
103        let x = (ey * bl - dy * cl) * d;
104        let y = (dx * cl - ex * bl) * d;
105        (x, y)
106    }
107
108    pub fn circumradius2(&self, b: &Self, c: &Self) -> f64 {
109        let (x, y) = self.circumdelta(b, c);
110        x * x + y * y
111    }
112
113    pub fn circumcenter(&self, b: &Self, c: &Self) -> Self {
114        let (x, y) = self.circumdelta(b, c);    
115        Self(Point3::new(self.0.x + x, self.0.y + y, 1.))
116    }
117
118    pub fn in_circle(&self, b: &Self, c: &Self, p: &Self) -> bool {
119        let dx = self.0.x - p.0.x;
120        let dy = self.0.y - p.0.y;
121        let ex = b.0.x - p.0.x;
122        let ey = b.0.y - p.0.y;
123        let fx = c.0.x - p.0.x;
124        let fy = c.0.y - p.0.y;
125
126        let ap = dx * dx + dy * dy;
127        let bp = ex * ex + ey * ey;
128        let cp = fx * fx + fy * fy;
129
130        dx * (ey * cp - bp * fy) - dy * (ex * cp - bp * fx) + ap * (ex * fy - ey * fx) < 0.0
131    }
132
133    pub fn midpoint(&self, b: &Self) -> Self {        
134        Self(Point3::new((self.0.x + b.0.x)/2., (self.0.y + b.0.y)/2., 1.))
135    }
136}
137
138impl approx::AbsDiffEq for Point {
139    type Epsilon = f64;
140
141    fn default_epsilon() -> Self::Epsilon {
142        1.0e-6
143    }
144
145    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
146        Point3::<f64>::abs_diff_eq(&self.0, &other.0, epsilon)
147    }
148
149    fn abs_diff_ne(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
150        !Self::abs_diff_eq(self, other, epsilon)
151    }
152}
153
154impl approx::RelativeEq for Point {
155    fn default_max_relative() -> Self::Epsilon {
156        1.0e-6
157    }
158
159    fn relative_eq(
160        &self,
161        other: &Self,
162        epsilon: Self::Epsilon,
163        max_relative: Self::Epsilon,
164    ) -> bool {
165        Point3::<f64>::relative_eq(&self.0, &other.0, epsilon, max_relative)
166    }
167}