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