theta_chart/coord/
point.rs1use 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)]
12pub 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 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 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}