s2json_core/
vector_point.rs

1use core::{
2    cmp::Ordering,
3    f64::consts::PI,
4    fmt::Debug,
5    ops::{Add, Div, Mul, Neg, Rem, RemAssign, Sub},
6};
7use libm::{atan, fabs, fmod, log, pow, sin, sinh, sqrt};
8use serde::{Deserialize, Serialize};
9
10/// Importing necessary types (equivalent to importing from 'values')
11use crate::*;
12
13/// A Vector Point uses a structure for 2D or 3D points
14#[derive(Serialize, Deserialize, Debug, Clone, Default)]
15pub struct VectorPoint<M: MValueCompatible = MValue> {
16    /// X coordinate
17    pub x: f64,
18    /// Y coordinate
19    pub y: f64,
20    /// Z coordinate or "altitude". May be None
21    pub z: Option<f64>,
22    /// M-Value
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub m: Option<M>,
25    /// T for tolerance. A tmp value used for simplification
26    #[serde(skip)]
27    pub t: Option<f64>,
28}
29impl VectorPoint<MValue> {
30    /// Helper function for tests. Create a new point quickly from an xy coordinate
31    pub fn from_xy(x: f64, y: f64) -> Self {
32        Self { x, y, z: None, m: None, t: None }
33    }
34
35    /// Helper function for tests. Create a new point quickly from an xyz coordinate
36    pub fn from_xyz(x: f64, y: f64, z: f64) -> Self {
37        Self { x, y, z: Some(z), m: None, t: None }
38    }
39}
40impl<M: MValueCompatible> VectorPoint<M> {
41    /// Create a new point
42    pub fn new(x: f64, y: f64, z: Option<f64>, m: Option<M>) -> Self {
43        Self { x, y, z, m, t: None }
44    }
45
46    /// Create a new point with xy
47    pub fn new_xy(x: f64, y: f64, m: Option<M>) -> Self {
48        Self { x, y, z: None, m, t: None }
49    }
50
51    /// Create a new point with xyz
52    pub fn new_xyz(x: f64, y: f64, z: f64, m: Option<M>) -> Self {
53        Self { x, y, z: Some(z), m, t: None }
54    }
55
56    /// Project the point into the 0->1 coordinate system
57    pub fn project(&mut self, bbox: Option<&mut BBox3D>) {
58        let y = self.y;
59        let x = self.x;
60        let sin = sin((y * PI) / 180.);
61        let y2 = 0.5 - (0.25 * log((1. + sin) / (1. - sin))) / PI;
62        self.x = x / 360. + 0.5;
63        self.y = y2.clamp(0., 1.);
64
65        if let Some(bbox) = bbox {
66            bbox.extend_from_point(self)
67        };
68    }
69
70    /// Unproject the point from the 0->1 coordinate system back to a lon-lat coordinate
71    pub fn unproject(&mut self) {
72        let lon = (self.x - 0.5) * 360.;
73        let y2 = 0.5 - self.y;
74        let lat = atan(sinh(PI * (y2 * 2.))).to_degrees();
75
76        self.x = lon;
77        self.y = lat;
78    }
79
80    /// Calculate the distance between two points, allowing different M types
81    pub fn distance<M2: MValueCompatible>(&self, other: &VectorPoint<M2>) -> f64 {
82        sqrt(pow(other.x - self.x, 2.) + pow(other.y - self.y, 2.))
83    }
84
85    /// Apply modular arithmetic to x, y, and z using `modulus`
86    pub fn modulo(self, modulus: f64) -> Self {
87        let modulus = fabs(modulus); // Ensure positive modulus
88        Self {
89            x: fmod(self.x, modulus),
90            y: fmod(self.y, modulus),
91            z: self.z.map(|z| fmod(z, modulus)),
92            m: self.m,
93            t: None,
94        }
95    }
96}
97impl<M: MValueCompatible> From<Point> for VectorPoint<M> {
98    fn from(p: Point) -> Self {
99        Self { x: p.0, y: p.1, z: None, m: None, t: None }
100    }
101}
102impl<M: MValueCompatible> From<&Point> for VectorPoint<M> {
103    fn from(p: &Point) -> Self {
104        Self { x: p.0, y: p.1, z: None, m: None, t: None }
105    }
106}
107impl<M: MValueCompatible> From<Point3D> for VectorPoint<M> {
108    fn from(p: Point3D) -> Self {
109        Self { x: p.0, y: p.1, z: Some(p.2), m: None, t: None }
110    }
111}
112impl<M: MValueCompatible> From<&Point3D> for VectorPoint<M> {
113    fn from(p: &Point3D) -> Self {
114        Self { x: p.0, y: p.1, z: Some(p.2), m: None, t: None }
115    }
116}
117impl<M1: MValueCompatible, M2: MValueCompatible> Add<VectorPoint<M2>> for VectorPoint<M1> {
118    type Output = VectorPoint<M1>;
119    fn add(self, other: VectorPoint<M2>) -> Self::Output {
120        VectorPoint {
121            x: self.x + other.x,
122            y: self.y + other.y,
123            // Only add `z` if both `self.z` and `other.z` are `Some`
124            z: match (self.z, other.z) {
125                (Some(z1), Some(z2)) => Some(z1 + z2),
126                _ => None, // If either `z` is None, the result is `None`
127            },
128            m: self.m.clone(),     // Combine m values
129            t: self.t.or(other.t), // Handle `t` as necessary
130        }
131    }
132}
133impl<M: MValueCompatible> Add<f64> for VectorPoint<M> {
134    type Output = VectorPoint<M>;
135    fn add(self, other: f64) -> Self::Output {
136        VectorPoint {
137            x: self.x + other,
138            y: self.y + other,
139            z: self.z.map(|z| z + other),
140            m: self.m.clone(),
141            t: self.t,
142        }
143    }
144}
145// Implementing the Sub trait for VectorPoint
146impl<M1: MValueCompatible, M2: MValueCompatible> Sub<VectorPoint<M2>> for VectorPoint<M1> {
147    type Output = VectorPoint<M1>;
148    fn sub(self, other: VectorPoint<M2>) -> Self::Output {
149        VectorPoint {
150            x: self.x - other.x,
151            y: self.y - other.y,
152            z: match (self.z, other.z) {
153                (Some(z1), Some(z2)) => Some(z1 - z2),
154                _ => None, // If either `z` is None, the result is `None`
155            },
156            m: self.m.clone(),     // Combine m values
157            t: self.t.or(other.t), // Handle `t` as necessary
158        }
159    }
160}
161impl<M: MValueCompatible> Sub<f64> for VectorPoint<M> {
162    type Output = VectorPoint<M>;
163    fn sub(self, other: f64) -> Self::Output {
164        VectorPoint {
165            x: self.x - other,
166            y: self.y - other,
167            z: self.z.map(|z| z - other),
168            m: self.m.clone(),
169            t: self.t,
170        }
171    }
172}
173// Implementing the Neg trait for VectorPoint
174impl<M: MValueCompatible> Neg for VectorPoint<M> {
175    type Output = VectorPoint<M>;
176    fn neg(self) -> Self::Output {
177        VectorPoint { x: -self.x, y: -self.y, z: self.z.map(|z| -z), m: self.m.clone(), t: self.t }
178    }
179}
180// Implementing the Div trait for VectorPoint
181impl<M1: MValueCompatible, M2: MValueCompatible> Div<VectorPoint<M2>> for VectorPoint<M1> {
182    type Output = VectorPoint<M1>;
183    fn div(self, other: VectorPoint<M2>) -> Self::Output {
184        VectorPoint {
185            x: self.x / other.x,
186            y: self.y / other.y,
187            z: match (self.z, other.z) {
188                (Some(z1), Some(z2)) => Some(z1 / z2),
189                _ => None, // If either `z` is None, the result is `None`
190            },
191            m: self.m.clone(),     // Combine m values
192            t: self.t.or(other.t), // Handle `t` as necessary
193        }
194    }
195}
196impl<M: MValueCompatible> Div<f64> for VectorPoint<M> {
197    type Output = VectorPoint<M>;
198    fn div(self, other: f64) -> Self::Output {
199        VectorPoint {
200            x: self.x / other,
201            y: self.y / other,
202            z: self.z.map(|z| z / other),
203            m: self.m.clone(),
204            t: self.t,
205        }
206    }
207}
208// Implementing the Mul trait for VectorPoint
209impl<M1: MValueCompatible, M2: MValueCompatible> Mul<VectorPoint<M2>> for VectorPoint<M1> {
210    type Output = VectorPoint<M1>;
211    fn mul(self, other: VectorPoint<M2>) -> Self::Output {
212        VectorPoint {
213            x: self.x * other.x,
214            y: self.y * other.y,
215            z: match (self.z, other.z) {
216                (Some(z1), Some(z2)) => Some(z1 * z2),
217                _ => None, // If either `z` is None, the result is `None`
218            },
219            m: self.m.clone(),     // Combine m values
220            t: self.t.or(other.t), // Handle `t` as necessary
221        }
222    }
223}
224impl<M: MValueCompatible> Mul<f64> for VectorPoint<M> {
225    type Output = VectorPoint<M>;
226    fn mul(self, other: f64) -> Self::Output {
227        VectorPoint {
228            x: self.x * other,
229            y: self.y * other,
230            z: self.z.map(|z| z * other),
231            m: self.m.clone(),
232            t: self.t,
233        }
234    }
235}
236impl<M: MValueCompatible> Rem<f64> for VectorPoint<M> {
237    type Output = VectorPoint<M>;
238
239    fn rem(self, modulus: f64) -> Self::Output {
240        self.modulo(modulus)
241    }
242}
243impl<M: MValueCompatible> RemAssign<f64> for VectorPoint<M> {
244    fn rem_assign(&mut self, modulus: f64) {
245        let modulus = fabs(modulus);
246        self.x = fmod(self.x, modulus);
247        self.y = fmod(self.y, modulus);
248        if let Some(z) = self.z {
249            self.z = Some(fmod(z, modulus));
250        }
251    }
252}
253impl<M: MValueCompatible> Eq for VectorPoint<M> {}
254impl<M: MValueCompatible> Ord for VectorPoint<M> {
255    fn cmp(&self, other: &VectorPoint<M>) -> Ordering {
256        match self.x.partial_cmp(&other.x) {
257            Some(Ordering::Equal) => {}
258            other => return other.unwrap_or(Ordering::Greater), /* Handle cases where `x` comparison is not equal */
259        }
260        match self.y.partial_cmp(&other.y) {
261            Some(Ordering::Equal) => {}
262            other => return other.unwrap_or(Ordering::Greater), /* Handle cases where `y` comparison is not equal */
263        }
264        match self.z.partial_cmp(&other.z) {
265            Some(order) => order,
266            None => Ordering::Equal, // This handles the NaN case safely
267        }
268    }
269}
270impl<M: MValueCompatible> PartialEq for VectorPoint<M> {
271    fn eq(&self, other: &VectorPoint<M>) -> bool {
272        self.x == other.x && self.y == other.y && self.z == other.z
273    }
274}
275impl<M: MValueCompatible> PartialOrd for VectorPoint<M> {
276    fn partial_cmp(&self, other: &VectorPoint<M>) -> Option<Ordering> {
277        Some(self.cmp(other))
278    }
279}
280
281#[cfg(test)]
282mod tests {
283    use super::*;
284
285    #[test]
286    fn new() {
287        let vector_point: VectorPoint = VectorPoint::new(1.0, 2.0, None, None);
288        assert_eq!(vector_point.x, 1.0);
289        assert_eq!(vector_point.y, 2.0);
290        assert_eq!(vector_point.z, None);
291        assert_eq!(vector_point.m, None);
292        assert_eq!(vector_point.t, None);
293    }
294
295    #[test]
296    fn new_xy() {
297        let vector_point: VectorPoint = VectorPoint::new_xy(1.0, 2.0, None);
298        assert_eq!(vector_point.x, 1.0);
299        assert_eq!(vector_point.y, 2.0);
300        assert_eq!(vector_point.z, None);
301        assert_eq!(vector_point.m, None);
302        assert_eq!(vector_point.t, None);
303    }
304
305    #[test]
306    fn new_xyz() {
307        let vector_point: VectorPoint = VectorPoint::new_xyz(1.0, 2.0, 3.0, None);
308        assert_eq!(vector_point.x, 1.0);
309        assert_eq!(vector_point.y, 2.0);
310        assert_eq!(vector_point.z, Some(3.0));
311        assert_eq!(vector_point.m, None);
312        assert_eq!(vector_point.t, None);
313    }
314
315    #[test]
316    fn from_xy() {
317        let vector_point: VectorPoint = VectorPoint::from_xy(1.0, 2.0);
318        assert_eq!(vector_point.x, 1.0);
319        assert_eq!(vector_point.y, 2.0);
320        assert_eq!(vector_point.z, None);
321        assert_eq!(vector_point.m, None);
322        assert_eq!(vector_point.t, None);
323    }
324
325    #[test]
326    fn from_xyz() {
327        let vector_point: VectorPoint = VectorPoint::from_xyz(1.0, 2.0, 3.0);
328        assert_eq!(vector_point.x, 1.0);
329        assert_eq!(vector_point.y, 2.0);
330        assert_eq!(vector_point.z, Some(3.0));
331        assert_eq!(vector_point.m, None);
332        assert_eq!(vector_point.t, None);
333    }
334
335    #[test]
336    fn project() {
337        let mut vector_point: VectorPoint = VectorPoint::new(1.0, 2.0, Some(-3.), None);
338        let mut bbox: BBox3D = BBox3D::new(1., 1., 0., 0., 0., 1.);
339        vector_point.project(Some(&mut bbox));
340        assert_eq!(vector_point.x, 0.5027777777777778);
341        assert_eq!(vector_point.y, 0.4944433158879836);
342        assert_eq!(vector_point.z, Some(-3.));
343        assert_eq!(vector_point.m, None);
344        assert_eq!(vector_point.t, None);
345
346        assert_eq!(bbox.left, 0.5027777777777778);
347        assert_eq!(bbox.bottom, 0.4944433158879836);
348        assert_eq!(bbox.right, 0.5027777777777778);
349        assert_eq!(bbox.top, 0.4944433158879836);
350        assert_eq!(bbox.near, -3.);
351        assert_eq!(bbox.far, 1.0);
352    }
353
354    #[test]
355    fn unproject() {
356        let mut vector_point: VectorPoint =
357            VectorPoint::new(0.5027777777777778, 0.4944433158879836, Some(-3.), None);
358        vector_point.unproject();
359
360        assert_eq!(vector_point.x, 0.9999999999999964);
361        assert_eq!(vector_point.y, 2.0000000000000093);
362        assert_eq!(vector_point.z, Some(-3.));
363        assert_eq!(vector_point.m, None);
364        assert_eq!(vector_point.t, None);
365    }
366
367    #[test]
368    fn test_distance() {
369        let vector_point: VectorPoint = VectorPoint::new(1.0, 2.0, None, None);
370        let other: VectorPoint = VectorPoint::new(3.0, 4.0, None, None);
371        assert_eq!(vector_point.distance(&other), 2.8284271247461903);
372    }
373
374    #[test]
375    fn from_point() {
376        let point = Point(1.0, 2.0);
377        let vector_point: VectorPoint = point.into();
378        assert_eq!(vector_point.x, 1.0);
379        assert_eq!(vector_point.y, 2.0);
380        assert_eq!(vector_point.z, None);
381        assert_eq!(vector_point.m, None);
382        assert_eq!(vector_point.t, None);
383
384        let point = Point(1.0, 2.0);
385        let vector_point: VectorPoint = (&point).into();
386        assert_eq!(vector_point.x, 1.0);
387        assert_eq!(vector_point.y, 2.0);
388        assert_eq!(vector_point.z, None);
389        assert_eq!(vector_point.m, None);
390        assert_eq!(vector_point.t, None);
391    }
392
393    #[test]
394    fn from_point_3d() {
395        let point: Point3D = Point3D(1.0, 2.0, 3.0);
396        let vector_point: VectorPoint = point.into();
397        assert_eq!(vector_point.x, 1.0);
398        assert_eq!(vector_point.y, 2.0);
399        assert_eq!(vector_point.z, Some(3.0));
400        assert_eq!(vector_point.m, None);
401        assert_eq!(vector_point.t, None);
402
403        let point: Point3D = Point3D(1.0, 2.0, 3.0);
404        let vector_point: VectorPoint = (&point).into();
405        assert_eq!(vector_point.x, 1.0);
406        assert_eq!(vector_point.y, 2.0);
407        assert_eq!(vector_point.z, Some(3.0));
408        assert_eq!(vector_point.m, None);
409        assert_eq!(vector_point.t, None);
410    }
411
412    #[test]
413    fn vector_point() {
414        let vector_point: VectorPoint =
415            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
416        assert_eq!(vector_point.x, 1.0);
417        assert_eq!(vector_point.y, 2.0);
418        assert_eq!(vector_point.z, Some(3.0));
419        assert_eq!(vector_point.m, None);
420        assert_eq!(vector_point.t, None);
421    }
422
423    #[test]
424    fn vector_neg() {
425        let vector_point = VectorPoint::<MValue> { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
426        let result = -vector_point;
427        assert_eq!(result.x, -1.0);
428        assert_eq!(result.y, -2.0);
429        assert_eq!(result.z, Some(-3.0));
430        assert_eq!(result.m, None);
431        assert_eq!(result.t, None);
432    }
433
434    #[test]
435    fn vector_point_add() {
436        let vector_point1: VectorPoint =
437            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
438        let vector_point2: VectorPoint =
439            VectorPoint { x: 4.0, y: 5.0, z: Some(6.0), m: None, t: Some(5.2) };
440        let result = vector_point1 + vector_point2;
441        assert_eq!(result.x, 5.0);
442        assert_eq!(result.y, 7.0);
443        assert_eq!(result.z, Some(9.0));
444        assert_eq!(result.m, None);
445        assert_eq!(result.t, Some(5.2));
446    }
447
448    #[test]
449    fn vector_point_add_f64() {
450        let vector_point1: VectorPoint =
451            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
452        let float: f64 = 4.0;
453        let result = vector_point1 + float;
454        assert_eq!(result.x, 5.0);
455        assert_eq!(result.y, 6.0);
456        assert_eq!(result.z, Some(7.0));
457        assert_eq!(result.m, None);
458        assert_eq!(result.t, None);
459    }
460
461    #[test]
462    fn vector_point_sub() {
463        let vector_point1 =
464            VectorPoint::<MValue> { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
465        let vector_point2 =
466            VectorPoint::<MValue> { x: 4.0, y: 5.0, z: Some(6.0), m: None, t: Some(5.2) };
467        let result = vector_point1 - vector_point2;
468        assert_eq!(result.x, -3.0);
469        assert_eq!(result.y, -3.0);
470        assert_eq!(result.z, Some(-3.0));
471        assert_eq!(result.m, None);
472        assert_eq!(result.t, Some(5.2));
473    }
474
475    #[test]
476    fn vector_point_sub_f64() {
477        let vector_point1: VectorPoint =
478            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
479        let float: f64 = 4.0;
480        let result = vector_point1 - float;
481        assert_eq!(result.x, -3.0);
482        assert_eq!(result.y, -2.0);
483        assert_eq!(result.z, Some(-1.0));
484        assert_eq!(result.m, None);
485        assert_eq!(result.t, None);
486    }
487
488    #[test]
489    fn vector_point_mul() {
490        let vector_point1: VectorPoint =
491            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
492        let vector_point2: VectorPoint =
493            VectorPoint { x: 4.0, y: 5.0, z: Some(6.0), m: None, t: Some(5.2) };
494        let result = vector_point1 * vector_point2;
495        assert_eq!(result.x, 4.0);
496        assert_eq!(result.y, 10.0);
497        assert_eq!(result.z, Some(18.0));
498        assert_eq!(result.m, None);
499        assert_eq!(result.t, Some(5.2));
500    }
501
502    #[test]
503    fn vector_point_mul_f64() {
504        let vector_point1: VectorPoint =
505            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
506        let float: f64 = 4.0;
507        let result = vector_point1 * float;
508        assert_eq!(result.x, 4.0);
509        assert_eq!(result.y, 8.0);
510        assert_eq!(result.z, Some(12.0));
511        assert_eq!(result.m, None);
512        assert_eq!(result.t, None);
513    }
514
515    #[test]
516    fn vector_point_div() {
517        let vector_point1: VectorPoint =
518            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
519        let vector_point2: VectorPoint =
520            VectorPoint { x: 4.0, y: 5.0, z: Some(6.0), m: None, t: Some(5.2) };
521        let result = vector_point1 / vector_point2;
522        assert_eq!(result.x, 0.25);
523        assert_eq!(result.y, 0.4);
524        assert_eq!(result.z, Some(0.5));
525        assert_eq!(result.m, None);
526        assert_eq!(result.t, Some(5.2));
527    }
528
529    #[test]
530    fn vector_point_div_f64() {
531        let vector_point1: VectorPoint =
532            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
533        let float: f64 = 4.0;
534        let result = vector_point1 / float;
535        assert_eq!(result.x, 0.25);
536        assert_eq!(result.y, 0.5);
537        assert_eq!(result.z, Some(0.75));
538        assert_eq!(result.m, None);
539        assert_eq!(result.t, None);
540    }
541
542    #[test]
543    fn vector_point_rem() {
544        let vector_point1: VectorPoint =
545            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
546        let result = vector_point1 % 2.;
547        assert_eq!(result.x, 1.0);
548        assert_eq!(result.y, 0.0);
549        assert_eq!(result.z, Some(1.0));
550        assert_eq!(result.m, None);
551        assert_eq!(result.t, None);
552    }
553
554    #[test]
555    fn vector_point_rem_assigned() {
556        let mut vector_point1: VectorPoint =
557            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
558        vector_point1 %= 2.;
559        assert_eq!(vector_point1.x, 1.0);
560        assert_eq!(vector_point1.y, 0.0);
561        assert_eq!(vector_point1.z, Some(1.0));
562        assert_eq!(vector_point1.m, None);
563        assert_eq!(vector_point1.t, None);
564    }
565
566    #[test]
567    fn vector_equality() {
568        let vector_point1: VectorPoint =
569            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
570        let vector_point2: VectorPoint =
571            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
572        assert_eq!(vector_point1, vector_point2);
573
574        let vector_point1: VectorPoint =
575            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
576        let vector_point2: VectorPoint =
577            VectorPoint { x: 2.0, y: 3.0, z: Some(4.0), m: None, t: None };
578        assert_ne!(vector_point1, vector_point2);
579
580        let vector_point1: VectorPoint =
581            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
582        let vector_point2: VectorPoint = VectorPoint { x: 1.0, y: 2.0, z: None, m: None, t: None };
583        assert_ne!(vector_point1, vector_point2);
584
585        let vector_point1: VectorPoint =
586            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
587        let vector_point2: VectorPoint =
588            VectorPoint { x: 1.0, y: 2.0, z: Some(1.0), m: None, t: None };
589        assert_ne!(vector_point1, vector_point2);
590    }
591
592    #[test]
593    fn test_vectorpoint_ordering_x() {
594        let a: VectorPoint = VectorPoint { x: 1.0, y: 0.0, z: None, m: None, t: None };
595        let b: VectorPoint = VectorPoint { x: 2.0, y: 0.0, z: None, m: None, t: None };
596        assert_eq!(a.cmp(&b), Ordering::Less);
597        assert_eq!(b.cmp(&a), Ordering::Greater);
598    }
599
600    #[test]
601    fn test_vectorpoint_ordering_y() {
602        let a: VectorPoint = VectorPoint { x: 1.0, y: 1.0, z: None, m: None, t: None };
603        let b = VectorPoint { x: 1.0, y: 2.0, z: None, m: None, t: None };
604        assert_eq!(a.cmp(&b), Ordering::Less);
605        assert_eq!(b.cmp(&a), Ordering::Greater);
606    }
607
608    #[test]
609    fn test_vectorpoint_ordering_z() {
610        let a: VectorPoint = VectorPoint { x: 1.0, y: 1.0, z: Some(1.0), m: None, t: None };
611        let b = VectorPoint { x: 1.0, y: 1.0, z: Some(2.0), m: None, t: None };
612        assert_eq!(a.cmp(&b), Ordering::Less);
613        assert_eq!(b.cmp(&a), Ordering::Greater);
614    }
615
616    #[test]
617    fn test_vectorpoint_ordering_z_none() {
618        let a: VectorPoint = VectorPoint { x: 1.0, y: 1.0, z: None, m: None, t: None };
619        let b = VectorPoint { x: 1.0, y: 1.0, z: Some(2.0), m: None, t: None };
620        assert_eq!(a.cmp(&b), Ordering::Less); // `None` is treated as equal to any value in `z`
621        assert_eq!(b.cmp(&a), Ordering::Greater);
622    }
623
624    #[test]
625    fn test_vectorpoint_ordering_z_some() {
626        let a: VectorPoint = VectorPoint { x: 1.0, y: 1.0, z: Some(-1.0), m: None, t: None };
627        let b = VectorPoint { x: 1.0, y: 1.0, z: Some(2.0), m: None, t: None };
628        assert_eq!(a.cmp(&b), Ordering::Less); // `None` is treated as equal to any value in `z`
629        assert_eq!(b.cmp(&a), Ordering::Greater);
630    }
631
632    #[test]
633    fn test_vectorpoint_equality() {
634        let a: VectorPoint = VectorPoint { x: 1.0, y: 1.0, z: Some(1.0), m: None, t: None };
635        let b = VectorPoint { x: 1.0, y: 1.0, z: Some(1.0), m: None, t: None };
636        assert_eq!(a, b);
637        assert_eq!(a.cmp(&b), Ordering::Equal);
638    }
639
640    #[test]
641    fn test_vectorpoint_nan_handling() {
642        let nan_point: VectorPoint = VectorPoint { x: f64::NAN, y: 1.0, z: None, m: None, t: None };
643        let normal_point = VectorPoint { x: 1.0, y: 1.0, z: None, m: None, t: None };
644
645        // Since `partial_cmp` should return `None` for NaN, `cmp` must not panic.
646        assert_eq!(nan_point.cmp(&normal_point), Ordering::Greater);
647
648        // z nan
649        let nan_point: VectorPoint =
650            VectorPoint { x: 1.0, y: 1.0, z: Some(f64::NAN), m: None, t: None };
651        let normal_point = VectorPoint { x: 1.0, y: 1.0, z: Some(1.0), m: None, t: None };
652        assert_eq!(nan_point.cmp(&normal_point), Ordering::Equal);
653    }
654
655    #[test]
656    fn test_vectorpoint_partial_comp() {
657        let vector_point1: VectorPoint =
658            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
659        let vector_point2 = VectorPoint { x: 1.0, y: 2.0, z: Some(1.0), m: None, t: None };
660
661        assert_eq!(vector_point1.partial_cmp(&vector_point2), Some(Ordering::Greater));
662        assert_eq!(vector_point2.partial_cmp(&vector_point1), Some(Ordering::Less));
663    }
664
665    #[test]
666    fn test_vectorpoint_with_m() {
667        let vector_point1: VectorPoint<MValue> = VectorPoint {
668            x: 1.0,
669            y: 2.0,
670            z: Some(3.0),
671            m: Some(Value::from([
672                ("class".into(), ValueType::Primitive(PrimitiveValue::String("ocean".into()))),
673                ("offset".into(), ValueType::Primitive(PrimitiveValue::U64(22))),
674                (
675                    "info".into(),
676                    ValueType::Nested(Value::from([
677                        (
678                            "name".into(),
679                            ValueType::Primitive(PrimitiveValue::String("Pacific Ocean".into())),
680                        ),
681                        ("value".into(), ValueType::Primitive(PrimitiveValue::F32(22.2))),
682                    ])),
683                ),
684            ])),
685            t: Some(-1.2),
686        };
687        let vector_point2: VectorPoint<MValue> =
688            VectorPoint { x: 1.0, y: 2.0, z: Some(3.0), m: None, t: None };
689        assert_eq!(vector_point1.partial_cmp(&vector_point2), Some(Ordering::Equal));
690        // we only check for equality in x, y, z
691        assert!(vector_point1 == vector_point2);
692    }
693}