1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
use core::ops::{Add, Sub, Div, Mul};

use crate::util::{feq, Ray};

/// This structure conceptually represents a point or a vector on 
/// the 2-dimensional Cartesian plane.
/// 
/// It may be vary on the context which represents which.
#[derive(Clone, Default, Debug, Copy, PartialEq, PartialOrd)]
pub struct Coordinate(
    /// x-component of the Cartesian coordinates.
    pub f64, 
    /// y-component of the Cartesian coordinates.
    pub f64,
);

impl From<Coordinate> for (f64, f64){
    fn from(item: Coordinate) -> (f64, f64){
        (item.0, item.1)
    }
}

impl From<(f64, f64)> for Coordinate {
    fn from(item: (f64, f64)) -> Coordinate {
        Coordinate(item.0, item.1)
    }
}

impl From<geo_types::Coord<f64>> for Coordinate{
    fn from(value: geo_types::Coord<f64>) -> Self {
        Coordinate(value.x, value.y)
    }
}

impl From<Coordinate> for geo_types::Coord<f64>{
    fn from(value: Coordinate) -> geo_types::Coord<f64> {
        geo_types::geometry::Coord{x: value.0, y: value.1}
    }
}

impl Add for Coordinate{
    type Output = Self;
    fn add(self, rhs: Self) -> Self{
        Self(self.0+rhs.0, self.1+rhs.1)
    }
}

impl Sub for Coordinate{
    type Output = Self;
    fn sub(self, rhs: Self) -> Self{
        Self(self.0-rhs.0, self.1-rhs.1)
    }
}

impl Mul<f64> for Coordinate{
    type Output = Self;
    fn mul(self, rhs: f64) -> Self::Output {
        Self(self.0*rhs, self.1*rhs)
    }
}

impl Div<f64> for Coordinate{
    type Output = Self;
    fn div(self, rhs: f64) -> Self::Output {
        if rhs == 0. {return self;}
        Self(self.0/rhs, self.1/rhs)
    }
}

impl Div<Coordinate> for Coordinate{
    type Output = f64;
    fn div(self, rhs: Self) -> Self::Output{
        if rhs.0 == 0. && rhs.1 == 0. {return 0.;}
        else if rhs.1 == 0. {return self.0/rhs.0;}
        else {return self.1/rhs.1;}
    }
}

impl Coordinate{
    /// Creates and returns a [Coordinate] w.r.t. the given argument.
    /// 
    /// # Argument
    /// 
    /// + `x`: x-component of the `Coordinate`
    /// + `y`: y-component of the `Coordinate`
    /// 
    /// # Example
    /// 
    /// ```
    /// let c1 = geo_buffer::Coordinate::new(3., 4.);
    /// assert_eq!(c1, (3., 4.).into());
    /// ```
    pub fn new(x: f64, y: f64) -> Self{
        Self{0: x, 1: y}
    }

    /// Returns a tuple wihch has values of each component.
    /// 
    /// # Example
    /// 
    /// ```
    /// let c1 = geo_buffer::Coordinate::new(3., 4.);
    /// let t1 = c1.get_val();
    /// assert_eq!(t1, (3., 4.));
    /// ```
    pub fn get_val(&self) -> (f64, f64){
        (self.0, self.1)
    }

    /// Returns a value of inner product (i.e. dot product) of the Cartesian coordinates of
    /// two vectors.
    /// 
    /// # Argument
    /// 
    /// + `self`: The Cartesian coordinates of the first vector, **a**.
    /// + `rhs`: The Cartesian coordinates of the second vector, **b**.
    /// 
    /// # Return
    /// 
    /// **a** · **b**
    /// 
    /// # Example
    /// 
    /// ```
    /// let c1 = geo_buffer::Coordinate::new(1., 2.);
    /// let c2 = geo_buffer::Coordinate::new(3., 4.);
    /// let ip = c1.inner_product(&c2);
    /// assert_eq!(ip, 11.);
    /// ``` 
    /// 
    /// # Notes
    /// 
    /// + This operation is linear.
    /// + This operation is commutative.
    /// 
    pub fn inner_product(&self, rhs: &Self) -> f64{
        self.0*rhs.0 + self.1*rhs.1
    }

    /// Returns a value of the magnitude of cross product of the Cartesian coordinates of
    /// two vectors.
    /// 
    /// # Argument
    /// 
    /// + `self`: The Cartesian coordinates of the first vector, **a**.
    /// + `rhs`: The Cartesian coordinates of the second vector, **b**.
    /// 
    /// # Return
    /// 
    /// **a** × **b**
    /// 
    /// # Example
    /// 
    /// ```
    /// let c1 = geo_buffer::Coordinate::new(1., 2.);
    /// let c2 = geo_buffer::Coordinate::new(3., 4.);
    /// let op = c1.outer_product(&c2);
    /// assert_eq!(op, -2.);
    /// ``` 
    /// 
    /// # Notes
    /// 
    /// + This operation is linear.
    /// + This operation is *not* commutative. (More precisely, it is anti-commutative.)
    /// + The sign of cross product indicates the orientation of **a** and **b**. If **a** lies before **b** in
    /// the counter-clockwise (CCW for short) ordering, the sign of the result will be positive. If **a** lies after **b** in CCW ordering,
    /// the sign will be negative. The result will be zero if two vectors are colinear. (I.e. lay on the same line.)
    /// 
    pub fn outer_product(&self, rhs: &Self) -> f64{
        self.0*rhs.1-self.1*rhs.0
    }

    /// Returns the Euclidean norm (i.e. magnitude, or L2 norm) of the given vector.
    /// 
    /// # Example
    /// 
    /// ```
    /// let c1 = geo_buffer::Coordinate::new(3., 4.);
    /// assert_eq!(c1.norm(), 5.);
    /// ```
    pub fn norm(&self) -> f64{
        self.inner_product(self).sqrt()
    }

    /// Returns the distance between two Cartesian coordinates.
    ///
    /// # Example
    ///
    /// ```
    /// let c1 = geo_buffer::Coordinate::new(3., 4.);
    /// let c2 = geo_buffer::Coordinate::new(7., 7.);
    /// assert_eq!(c1.dist_coord(&c2), 5.);
    /// ```
    pub fn dist_coord(&self, rhs: &Coordinate) -> f64{
        f64::sqrt((self.0-rhs.0)*(self.0-rhs.0) + (self.1-rhs.1)*(self.1-rhs.1))
    }
    
    /// Returns the distance from `self` to the given ray.
    /// 
    /// Note that this function considers the given ray as a open-ended line.
    /// That is, the foot of perpendicular may lay on the extended line of the given ray.
    /// 
    /// # Example
    /// 
    /// ```
    /// use geo_buffer::{Coordinate, Ray};
    /// 
    /// let r1 = Ray::new((0., 3.).into(), (4., 0.).into());
    /// let c1 = Coordinate::new(0., 0.);
    /// assert_eq!(c1.dist_ray(&r1), 2.4);
    /// ```
    /// 
    pub fn dist_ray(&self, rhs: &Ray) -> f64{
        if rhs.is_degenerated() {return self.dist_coord(&rhs.origin);}
        return f64::abs((*self-rhs.origin).outer_product(&rhs.angle)) / rhs.angle.norm();
    }

    /// Checks whether the given two Cartesian coordinates are the same (by the equality test with a small epsilon).
    /// 
    /// # Result
    /// 
    /// + `true` if the given coordinates are the same.
    /// + `false` otherwise.
    /// 
    /// # Example
    /// 
    /// ```
    /// let c1 = geo_buffer::Coordinate::new(0.1, 0.2);
    /// let c2 = geo_buffer::Coordinate::new(0.2, 0.3);
    /// let c3 = geo_buffer::Coordinate::new(0.3, 0.5);
    /// let c4 = c1 + c2;
    /// assert!(c3.eq(&c4));
    /// ```
    /// 
    /// # Example (this example panics)
    /// 
    /// ```should_panic
    /// let c1 = geo_buffer::Coordinate::new(0.1, 0.2);
    /// let c2 = geo_buffer::Coordinate::new(0.2, 0.3);
    /// let c3 = geo_buffer::Coordinate::new(0.3, 0.5);
    /// let c4 = c1 + c2;
    /// assert_eq!(c3, c4); // should panic since 0.1 + 0.2 != 0.3 due to floating point errors
    /// ```
    pub fn eq(&self, rhs: &Self) -> bool{
        feq(self.0, rhs.0) && feq(self.1, rhs.1)
    }
}