geo_buffer/util/coordinate/mod.rs
1use core::ops::{Add, Sub, Div, Mul};
2
3use crate::util::{feq, Ray};
4
5/// This structure conceptually represents a point or a vector on
6/// the 2-dimensional Cartesian plane.
7///
8/// It may be vary on the context which represents which.
9#[derive(Clone, Default, Debug, Copy, PartialEq, PartialOrd)]
10pub struct Coordinate(
11 /// x-component of the Cartesian coordinates.
12 pub f64,
13 /// y-component of the Cartesian coordinates.
14 pub f64,
15);
16
17impl From<Coordinate> for (f64, f64){
18 fn from(item: Coordinate) -> (f64, f64){
19 (item.0, item.1)
20 }
21}
22
23impl From<(f64, f64)> for Coordinate {
24 fn from(item: (f64, f64)) -> Coordinate {
25 Coordinate(item.0, item.1)
26 }
27}
28
29impl From<geo_types::Coord<f64>> for Coordinate{
30 fn from(value: geo_types::Coord<f64>) -> Self {
31 Coordinate(value.x, value.y)
32 }
33}
34
35impl From<Coordinate> for geo_types::Coord<f64>{
36 fn from(value: Coordinate) -> geo_types::Coord<f64> {
37 geo_types::geometry::Coord{x: value.0, y: value.1}
38 }
39}
40
41impl Add for Coordinate{
42 type Output = Self;
43 fn add(self, rhs: Self) -> Self{
44 Self(self.0+rhs.0, self.1+rhs.1)
45 }
46}
47
48impl Sub for Coordinate{
49 type Output = Self;
50 fn sub(self, rhs: Self) -> Self{
51 Self(self.0-rhs.0, self.1-rhs.1)
52 }
53}
54
55impl Mul<f64> for Coordinate{
56 type Output = Self;
57 fn mul(self, rhs: f64) -> Self::Output {
58 Self(self.0*rhs, self.1*rhs)
59 }
60}
61
62impl Div<f64> for Coordinate{
63 type Output = Self;
64 fn div(self, rhs: f64) -> Self::Output {
65 if rhs == 0. {return self;}
66 Self(self.0/rhs, self.1/rhs)
67 }
68}
69
70impl Div<Coordinate> for Coordinate{
71 type Output = f64;
72 fn div(self, rhs: Self) -> Self::Output{
73 if rhs.0 == 0. && rhs.1 == 0. {return 0.;}
74 else if rhs.1 == 0. {return self.0/rhs.0;}
75 else {return self.1/rhs.1;}
76 }
77}
78
79impl Coordinate{
80 /// Creates and returns a [Coordinate] w.r.t. the given argument.
81 ///
82 /// # Argument
83 ///
84 /// + `x`: x-component of the `Coordinate`.
85 /// + `y`: y-component of the `Coordinate`.
86 ///
87 /// # Example
88 ///
89 /// ```
90 /// let c1 = geo_buffer::Coordinate::new(3., 4.);
91 /// assert_eq!(c1, (3., 4.).into());
92 /// ```
93 pub fn new(x: f64, y: f64) -> Self{
94 Self{0: x, 1: y}
95 }
96
97 /// Returns a tuple wihch has values of each component.
98 ///
99 /// # Example
100 ///
101 /// ```
102 /// let c1 = geo_buffer::Coordinate::new(3., 4.);
103 /// let t1 = c1.get_val();
104 /// assert_eq!(t1, (3., 4.));
105 /// ```
106 pub fn get_val(&self) -> (f64, f64){
107 (self.0, self.1)
108 }
109
110 /// Returns a value of inner product (i.e. dot product) of the Cartesian coordinates of
111 /// two vectors.
112 ///
113 /// # Argument
114 ///
115 /// + `self`: The Cartesian coordinates of the first vector, **a**.
116 /// + `rhs`: The Cartesian coordinates of the second vector, **b**.
117 ///
118 /// # Return
119 ///
120 /// **a** · **b**
121 ///
122 /// # Example
123 ///
124 /// ```
125 /// let c1 = geo_buffer::Coordinate::new(1., 2.);
126 /// let c2 = geo_buffer::Coordinate::new(3., 4.);
127 /// let ip = c1.inner_product(&c2);
128 /// assert_eq!(ip, 11.);
129 /// ```
130 ///
131 /// # Notes
132 ///
133 /// + This operation is linear.
134 /// + This operation is commutative.
135 ///
136 pub fn inner_product(&self, rhs: &Self) -> f64{
137 self.0*rhs.0 + self.1*rhs.1
138 }
139
140 /// Returns a value of the magnitude of cross product of the Cartesian coordinates of
141 /// two vectors.
142 ///
143 /// # Argument
144 ///
145 /// + `self`: The Cartesian coordinates of the first vector, **a**.
146 /// + `rhs`: The Cartesian coordinates of the second vector, **b**.
147 ///
148 /// # Return
149 ///
150 /// **a** × **b**
151 ///
152 /// # Example
153 ///
154 /// ```
155 /// let c1 = geo_buffer::Coordinate::new(1., 2.);
156 /// let c2 = geo_buffer::Coordinate::new(3., 4.);
157 /// let op = c1.outer_product(&c2);
158 /// assert_eq!(op, -2.);
159 /// ```
160 ///
161 /// # Notes
162 ///
163 /// + This operation is linear.
164 /// + This operation is *not* commutative. (More precisely, it is anti-commutative.)
165 /// + The sign of cross product indicates the orientation of **a** and **b**. If **a** lies before **b** in
166 /// the counter-clockwise (CCW for short) ordering, the sign of the result will be positive. If **a** lies after **b** in CCW ordering,
167 /// the sign will be negative. The result will be zero if two vectors are colinear. (I.e. lay on the same line.)
168 ///
169 pub fn outer_product(&self, rhs: &Self) -> f64{
170 self.0*rhs.1-self.1*rhs.0
171 }
172
173 /// Returns the Euclidean norm (i.e. magnitude, or L2 norm) of the given vector.
174 ///
175 /// # Example
176 ///
177 /// ```
178 /// let c1 = geo_buffer::Coordinate::new(3., 4.);
179 /// assert_eq!(c1.norm(), 5.);
180 /// ```
181 pub fn norm(&self) -> f64{
182 self.inner_product(self).sqrt()
183 }
184
185 /// Returns the distance between two Cartesian coordinates.
186 ///
187 /// # Example
188 ///
189 /// ```
190 /// let c1 = geo_buffer::Coordinate::new(3., 4.);
191 /// let c2 = geo_buffer::Coordinate::new(7., 7.);
192 /// assert_eq!(c1.dist_coord(&c2), 5.);
193 /// ```
194 pub fn dist_coord(&self, rhs: &Coordinate) -> f64{
195 f64::sqrt((self.0-rhs.0)*(self.0-rhs.0) + (self.1-rhs.1)*(self.1-rhs.1))
196 }
197
198 /// Returns the distance from `self` to the given ray.
199 ///
200 /// Note that this function considers the given ray as a open-ended line.
201 /// That is, the foot of perpendicular may lay on the extended line of the given ray.
202 ///
203 /// # Example
204 ///
205 /// ```
206 /// use geo_buffer::{Coordinate, Ray};
207 ///
208 /// let r1 = Ray::new((0., 3.).into(), (4., 0.).into());
209 /// let c1 = Coordinate::new(0., 0.);
210 /// assert_eq!(c1.dist_ray(&r1), 2.4);
211 /// ```
212 ///
213 pub fn dist_ray(&self, rhs: &Ray) -> f64{
214 if rhs.is_degenerated() {return self.dist_coord(&rhs.origin);}
215 return f64::abs((*self-rhs.origin).outer_product(&rhs.angle)) / rhs.angle.norm();
216 }
217
218 /// Checks whether the given two Cartesian coordinates are the same (by the equality test with a small epsilon).
219 ///
220 /// # Result
221 ///
222 /// + `true` if the given coordinates are the same.
223 /// + `false` otherwise.
224 ///
225 /// # Example
226 ///
227 /// ```
228 /// let c1 = geo_buffer::Coordinate::new(0.1, 0.2);
229 /// let c2 = geo_buffer::Coordinate::new(0.2, 0.3);
230 /// let c3 = geo_buffer::Coordinate::new(0.3, 0.5);
231 /// let c4 = c1 + c2;
232 /// assert!(c3.eq(&c4));
233 /// ```
234 ///
235 /// # Example (this example panics)
236 ///
237 /// ```should_panic
238 /// let c1 = geo_buffer::Coordinate::new(0.1, 0.2);
239 /// let c2 = geo_buffer::Coordinate::new(0.2, 0.3);
240 /// let c3 = geo_buffer::Coordinate::new(0.3, 0.5);
241 /// let c4 = c1 + c2;
242 /// assert_eq!(c3, c4); // should panic since 0.1 + 0.2 != 0.3 due to floating point errors
243 /// ```
244 pub fn eq(&self, rhs: &Self) -> bool{
245 feq(self.0, rhs.0) && feq(self.1, rhs.1)
246 }
247}