instinct/
lib.rs

1use nalgebra::{self as na, *};
2use std::cmp::{PartialOrd, Ordering};
3
4pub type Line<N> = (Point3<N>, Point3<N>);
5pub type LineRef<'a, N> = (&'a Point3<N>, &'a Point3<N>);
6pub type Plane<N> = (Point3<N>, Point3<N>, Point3<N>);
7pub type PlaneRef<'a, N> = (&'a Point3<N>, &'a Point3<N>, &'a Point3<N>);
8
9pub trait InstinctUtils {
10    // fn avg(&self, other: &Self) -> Self;
11    fn instinct_eq(&self, other: &Self) -> bool;
12    fn instinct_gt(&self, other: &Self) -> bool;
13    fn instinct_ge(&self, other: &Self) -> bool;
14    fn instinct_lt(&self, other: &Self) -> bool;
15    fn instinct_le(&self, other: &Self) -> bool;
16
17    fn instinct_zero(&self) -> bool;
18    fn instinct_not_negative(&self) -> bool;
19    fn instinct_not_positive(&self) -> bool;
20    fn instinct_positive(&self) -> bool;
21    fn instinct_negative(&self) -> bool;
22    fn instinct_ord(&self, other: &Self) -> Ordering;
23    fn instinct_delta_ord(&self) -> Ordering;
24    fn instinct_ndelta_ord(&self) -> Ordering;
25}
26
27impl<'a, N: RealField> InstinctUtils for N {
28    fn instinct_eq(&self, other: &Self) -> bool {
29        (*self - *other).abs() <= N::default_max_relative()
30    }
31
32    fn instinct_gt(&self, other: &Self) -> bool {
33        (!self.instinct_eq(other)) && self > other
34    }
35
36    fn instinct_lt(&self, other: &Self) -> bool {
37        (!self.instinct_eq(other)) && self < other
38    }
39
40    fn instinct_ge(&self, other: &Self) -> bool {
41        self.instinct_eq(other) || self > other
42    }
43
44    fn instinct_le(&self, other: &Self) -> bool {
45        self.instinct_eq(other) || self < other
46    }
47
48    fn instinct_zero(&self) -> bool {
49        self.abs() <= N::default_max_relative()
50    }
51
52    fn instinct_not_negative(&self) -> bool {
53        self.is_positive() || self.instinct_zero()
54    }
55    fn instinct_not_positive(&self) -> bool {
56        self.is_negative() || self.instinct_zero()
57    }
58
59    fn instinct_positive(&self) -> bool {
60        self.is_positive() && !self.instinct_zero()
61    }
62    fn instinct_negative(&self) -> bool {
63        self.is_negative() && !self.instinct_zero()
64    }
65    fn instinct_ord(&self, other: &Self) -> Ordering {
66        //TODO: NaN cmp can appear here? 
67        if self.instinct_eq(other) {
68            Ordering::Equal
69        } else if self > other {
70            Ordering::Greater
71        } else {
72            Ordering::Less
73        }
74    }
75
76    fn instinct_delta_ord(&self) -> Ordering {
77        if self.instinct_zero() {
78            Ordering::Equal
79        } else if self.is_positive() {
80            Ordering::Greater
81        } else {
82            Ordering::Less
83        }
84    }
85
86    fn instinct_ndelta_ord(&self) -> Ordering {
87        self.instinct_delta_ord().reverse()
88    }
89}
90
91/// instinct_cmp only compare points and finite(truncated) lines and polygons
92/// Cross and Parallel cases would give a Equal
93///
94/// instinct_cmp_ext compare points and infinite lines and planes represented by polygons
95/// returns None when cross happens and Equal in parallel situations
96/// with edge cases below will gives Equal not None:
97/// two same points
98/// two same lines
99/// two same planes
100/// point in line
101/// point in plane
102/// line in plane
103pub trait InstinctOrd<Rhs> {
104    fn instinct_cmp(&self, other: &Rhs) -> Ordering;
105    fn instinct_cmp_ext(&self, other: &Rhs) -> Option<Ordering>;
106}
107
108/// Check if same point
109macro_rules! same_point {
110    ($self: expr, $other: expr) => {
111        $self.x.instinct_eq(&$other.x) &&
112        $self.y.instinct_eq(&$other.y) &&
113        $self.z.instinct_eq(&$other.z)
114    };
115    ($p0: expr, $p1: expr, $p2: expr) => {
116        same_point!($p0, $p1) && same_point!($p1, $p2)
117    }
118}
119
120/// Check if points share same  XY plane
121macro_rules! same_z {
122    ($a: expr, $b: expr, $c: expr) => {
123        $a.z.instinct_eq(&$b.z) &&
124        $a.z.instinct_eq(&$c.z) &&
125        $b.z.instinct_eq(&$c.z)
126    };
127    ($p: expr) => {
128        same_z!($p.0, $p.1, $p.2)
129    }
130}
131
132/// Sort two points in ndc
133macro_rules! sort_points {
134    ($self: expr, $other: expr) => {
135        if same_point!($self, $other) {
136            Ordering::Equal
137        } else {
138            $self.z.instinct_ord(&$other.z)
139        }
140    }
141}
142/// Check if two line is parallel
143macro_rules! is_lines_parallel {
144    ($a: expr, $b: expr, $c: expr, $d: expr) => {
145        {
146            let v1 = ($b.coords - $a.coords).normalize();
147            let v2 = ($d.coords - $c.coords).normalize();
148            same_point!(&v1, &v2) || same_point!(&v1, -v2)
149        }
150    }; 
151    ($a: expr, $b: expr, $c: expr) => {
152        is_lines_parallel!($a.0, $a.1, $b, $c)
153    };
154    ($a: expr, $b: expr) => {
155        is_lines_parallel!($a.0, $a.1, $b.0, $b.1)
156    }
157}
158
159/// Check if point is in line
160macro_rules! point_in_line {
161    ($p: expr, $l0: expr, $l1: expr) => {
162        if same_point!($p, $l0) || same_point!($p, $l1) {
163            true
164        } else {
165            let v = $p.coords - $l0.coords;
166            let v_line = $l1.coords - $l0.coords;
167            let dot = v.dot(&v_line);
168            (dot*dot).instinct_eq(&(v.norm_squared()*v_line.norm_squared()))
169        }
170    };
171    ($p: expr, $l: expr) => {
172        point_in_line!($p, $l.0, $l.1)
173    }
174}
175
176/// Sort points in a line
177macro_rules! sort_line_points {
178    ($a: expr, $b: expr, $c: expr) => {
179        {
180            let mut list = [$a, $b, $c];
181            if !$a.x.instinct_eq(&$b.x) {
182                list.sort_unstable_by(|a, b| a.x.partial_cmp(&b.x).unwrap());
183            } else if !$a.y.instinct_eq(&$b.y) {
184                list.sort_unstable_by(|a, b| a.y.partial_cmp(&b.y).unwrap());
185            } else if !$a.z.instinct_eq(&$b.z) {
186                list.sort_unstable_by(|a, b| a.z.partial_cmp(&b.z).unwrap());
187            }
188            list
189        }
190    };
191    ($p: expr) => {
192        sort_line_points!($p.0, $p.1, $p.2)
193    }
194}
195
196/// Check if a plane is represented by three points
197macro_rules! is_plane {
198    ($p0: expr, $p1: expr, $p2: expr) => {
199        if same_point!($p0, $p1) {
200            false
201        } else {
202            !point_in_line!($p2, $p0, $p1)
203        }
204    };
205    ($p: expr) => {
206        is_plane!($p.0, $p.1, $p.2)
207    }
208}
209
210/// Check if a point is in the plane represented by three points
211macro_rules! point_in_plane {
212    ($p: expr, $a: expr, $b: expr, $c: expr) => {
213        if same_point!($p, $a) {
214            true
215        } else {
216            let line1 = ($b.coords - $a.coords).normalize();
217            let line2 = ($c.coords - $a.coords).normalize();
218            let target = ($p.coords - $a.coords).normalize();
219
220            let normal = line1.cross(&line2);
221            normal.dot(&target).instinct_zero()
222        }
223    };
224    ($p: expr, $plane: expr) => {
225        point_in_plane!($p, $plane.0, $plane.1, $plane.2)
226    }
227}
228
229/// Sort point and plane represented by three points in ndc
230macro_rules! sort_point_and_plane {
231    ($p: expr, $a: expr, $b: expr, $c: expr) => {
232        if same_point!($p, $a) {
233            Ordering::Equal
234        } else {
235            let line1 = ($b.coords - $a.coords).normalize();
236            let line2 = ($c.coords - $a.coords).normalize();
237            let target = ($p.coords - $a.coords).normalize();
238
239            let normal = line1.cross(&line2);
240            let delta = normal.dot(&target);
241            
242            if normal.z.instinct_zero() {
243                Ordering::Equal
244            } else if normal.z.is_positive() {
245                delta.instinct_delta_ord()
246            } else {
247                delta.instinct_delta_ord().reverse()
248            }
249        }
250    };
251    ($p: expr, $plane: expr) => {
252        sort_point_and_plane!($p, $plane.0, $plane.1, $plane.2)
253    }
254}
255
256/// Sort point and line in ndc
257macro_rules! sort_point_and_line {
258    ($p: expr, $l0: expr, $l1: expr) => {
259        (($l1.z - $l0.z) * ($p.y - $l0.y) - ($l1.y - $l0.y) * ($p.z - $l0.z))
260            .instinct_delta_ord()
261    };
262    ($p: expr, $l: expr) => {
263        sort_point_and_line!($p, $l.0, $l.1)
264    } 
265}
266
267/// Get normal vector of two lines
268macro_rules! get_lines_normal {
269    ($a: expr, $b: expr, $c: expr, $d: expr) => {
270        {
271            let d1 = $b.coords - $a.coords;
272            let d2 = $d.coords - $c.coords;
273            let (s, t) = closest_points_line_line_parameters($a, &d1, $c, &d2);
274            let p1 = $a + d1*s;
275            let p2 = $c + d2*t;
276            p2.coords - p1.coords
277        }
278    };
279    ($a: expr, $b: expr) => {
280        get_lines_normal!($a.0, $a.1, $b.0, $b.1)
281    }
282}
283
284/// Get normal vector of point and a plane
285macro_rules! get_point_plane_normal {
286    ($p: expr, $a: expr, $b: expr, $c: expr) => {
287        {
288            let d1 = $c.coords - $b.coords;
289            let d2 = $b.coords - $a.coords;
290            let (s, t) = closest_points_line_line_parameters($p, &d1, $a, &d2);
291            let p1 = $p + d1*s;
292            let p2 = $a + d2*t;
293            p2.coords - p1.coords
294        }
295    };
296    ($p: expr, $plane: expr) => {
297        get_point_plane_normal!($p, $plane.0, $plane.1, $plane.2)
298    }
299}
300
301/// Get joint of line and a plane, when line go through a plane and points on the different side of
302/// the plane
303macro_rules! get_line_plane_joint {
304    ($l0 :expr, $l1: expr, $p0: expr, $p1: expr, $p2: expr) => {
305        {
306            let normal_0 = get_point_plane_normal!($l0, $p0, $p1, $p2);
307            let normal_1 = get_point_plane_normal!($l1, $p0, $p1, $p2);
308            let distance_0_plane = normal_0.norm();
309            let distance_1_plane = normal_1.norm();
310            if distance_0_plane.instinct_zero() {
311                $l0
312            } else if distance_1_plane.instinct_zero() {
313                $l1
314            } else {
315                $l0 + ($l1.coords - $l0.coords) * distance_0_plane /
316                    (distance_0_plane + distance_1_plane)
317            }
318        }
319    };
320    ($line: expr, $plane: expr) => {
321        get_line_plane_joint!($line.0, $line.1, $plane.0, $plane.1, $plane.2)
322    }
323}
324
325/// Get joint of line and a plane, when line go through a plane and points on the same side of
326/// the plane
327macro_rules! get_side_line_plane_joint {
328    ($l0 :expr, $l1: expr, $p0: expr, $p1: expr, $p2: expr) => {
329        {
330            let normal_0 = get_point_plane_normal!($l0, $p0, $p1, $p2);
331            let normal_1 = get_point_plane_normal!($l1, $p0, $p1, $p2);
332
333            let distance_0_plane = normal_0.norm();
334            let distance_1_plane = normal_1.norm();
335            if distance_0_plane.instinct_zero() {
336                $l0
337            } else if distance_1_plane.instinct_zero() {
338                $l1
339            } else if distance_0_plane < distance_1_plane {
340                $l0 - ($l1.coords - $l0.coords) * distance_1_plane / distance_0_plane
341            } else {
342                $l1 - ($l0.coords - $l1.coords) * distance_0_plane / distance_1_plane
343            }
344        }
345    };
346    ($line: expr, $plane: expr) => {
347        get_line_plane_joint!($line.0, $line.1, $plane.0, $plane.1, $plane.2)
348    }
349}
350
351
352/// Check if point is in side a triangle, when the point is on the same plane with the triangle
353macro_rules! point_in_triangle {
354    ($point: expr, $p0: expr, $p1: expr, $p2: expr) => {
355        {
356            // normal of plane
357            let normal_plane = ($p1.coords - $p0.coords).cross(&(
358                $p2.coords - $p0.coords)).normalize();
359
360            let cmp_normal_0 = ($p0.coords - $point.coords).cross(&normal_plane);
361            let cmp_0_1 = ($p1.coords - $point.coords).dot(&cmp_normal_0);
362            let cmp_0_2 = ($p2.coords - $point.coords).dot(&cmp_normal_0);
363            if !cmp_0_1.instinct_zero() && !cmp_0_2.instinct_zero() &&
364                cmp_0_1.is_positive() == cmp_0_2.is_negative() { 
365                let cmp_normal_1 = ($p1.coords - $point.coords).cross(&normal_plane);
366                let cmp_1_0 = ($p0.coords - $point.coords).dot(&cmp_normal_1);
367                let cmp_1_2 = ($p2.coords - $point.coords).dot(&cmp_normal_1);
368                if !cmp_1_0.instinct_zero() && !cmp_1_2.instinct_zero() &&
369                    cmp_1_0.is_positive() == cmp_1_2.is_negative() { 
370                    // Joint is in side the triangle
371                    true
372                } else {
373                    false
374                }
375            } else {
376                false
377            }
378        }
379
380    };
381    ($point: expr, $plane: expr) => {
382        point_in_triangle!($point, $plane.0, $plane.1, $plane.2)
383    }
384}
385
386/// sort line and triangle, when points of line are distributed on both side of the plane but the line
387/// does not cross the polygon
388macro_rules! sort_line_and_triangle {
389    ($l0 :expr, $l1: expr, $p0: expr, $p1: expr, $p2: expr) => {
390        {
391            let n_01 = get_lines_normal!($l0, $l1, $p0, $p1).z;
392            let n_02 = get_lines_normal!($l0, $l1, $p0, $p2).z;
393            if n_01.instinct_zero() && n_02.instinct_zero() {
394                Ordering::Equal
395            } else {
396                let n_12 = get_lines_normal!($l0, $l1, $p1, $p2).z;
397                let mut check: i8 = 0;
398                if !n_01.instinct_zero() {
399                    if n_01.is_positive() {
400                        check += 1;
401                    } else {
402                        check -= 1;
403                    }
404                }
405                if !n_02.instinct_zero() {
406                    if n_02.is_positive() {
407                        check += 1;
408                    } else {
409                        check -= 1;
410                    }
411                }
412                if !n_12.instinct_zero() {
413                    if n_12.is_positive() {
414                        check += 1;
415                    } else {
416                        check -= 1;
417                    }
418                }
419                if check > 1 {
420                    Ordering::Less
421                } else if check < -1 {
422                    Ordering::Greater
423                } else {
424                    Ordering::Equal
425                }
426            }
427        }
428    };
429    ($line: expr, $plane: expr) => {
430        sort_line_and_triangle!($line.0, $line.1, $plane.0, $plane.1, $plane.2)
431    }
432}
433
434/// sort two triangles, no cross happens and no parellel happens
435macro_rules! sort_triangles {
436    ($a: expr, $b: expr, $c: expr, $d: expr, $e: expr, $f: expr) => {
437        {
438            let o_ab = sort_line_and_triangle!($a, $b, $d, $e, $f);
439            let o_ac = sort_line_and_triangle!($a, $c, $d, $e, $f);
440            if o_ab == o_ac {
441                o_ab
442            } else {
443                let o_bc = sort_line_and_triangle!($b, $c, $d, $e, $f);
444                let mut check: i8 = 0;
445                match o_ab {
446                    Ordering::Greater => check += 1,
447                    Ordering::Less => check -= 1,
448                    _ => {},
449                }
450                match o_ac {
451                    Ordering::Greater => check += 1,
452                    Ordering::Less => check -= 1,
453                    _ => {},
454                }
455                match o_bc {
456                    Ordering::Greater => check += 1,
457                    Ordering::Less => check -= 1,
458                    _ => {},
459                }
460                if check > 1 {
461                    Ordering::Greater
462                } else if check < -1 {
463                    Ordering::Less
464                } else {
465                    Ordering::Equal
466                }
467            }
468        }
469    };
470    ($a: expr, $b: expr) => {
471        sort_triangles!($a.0, $a.1, $a.2, $b.0, $b.1, $b.2)
472    }
473}
474 
475/// Reverse Option<Ordering>
476macro_rules! reverse_cmp_ext {
477    ($self: expr, $other: expr) => {
478        match $other.instinct_cmp_ext($self) {
479            Some(res) => Some(res.reverse()),
480            None => None
481        }
482    }
483}
484
485//--------------------------------
486/// Compare two Point3
487impl<'a, N: RealField> InstinctOrd<Self> for Point3<N> {
488    fn instinct_cmp(&self, other: &Self) -> Ordering {
489        // self.z.instinct_ord(&other.z)
490        sort_points!(self, other)
491    }
492    fn instinct_cmp_ext(&self, other: &Self) -> Option<Ordering> {
493        // Edge case: two same points will give Equal not None
494        Some(sort_points!(self, other))
495    }
496}
497
498
499//--------------------------------
500/// Compare Point3 with a line linked by two points
501///
502/// It's comparing the point and the plane represented by the projection of the line on Z-Y plane
503impl<'a, N: RealField> InstinctOrd<LineRef<'a, N>> for Point3<N> {
504    fn instinct_cmp(&self, other: &LineRef<'a, N>) -> Ordering {
505        if other.0.z.instinct_eq(&other.1.z) {
506            sort_points!(self, &other.0)
507        } else {
508            let v = self.z;
509            let min = other.0.z.min(other.1.z);
510            let max = other.0.z.max(other.1.z);
511            /*
512            if v.instinct_eq(&min) || v.instinct_eq(&min) {
513                return Ordering::Equal;
514            }
515            */
516            if v.instinct_gt(&max) {
517                return Ordering::Greater;
518            }
519            if v.instinct_lt(&min) {
520                return Ordering::Less;
521            }
522
523            // Convert projection plane to YZ coords
524            // let plane = Unit::new_unchecked(Vector2::new(other.1.z - other.0.z, other.1.y - other.0.y));
525            // let target = Unit::new_unchecked(Vector2::new(self.z - other.0.z, self.y - other.0.y));
526            // TODO: Do we really need to normalize the vector for more exact result?
527            // let delta = plane.x * target.y - plane.y * target.x;
528            // let delta = ($other.1.z - $other.0.z) * ($self.y - $other.0.y) - ($other.1.y - $other.0.y) * ($self.z - $other.0.z);
529            // println!("line point {} {} {} {}", delta, delta.is_positive(), delta.is_negative(), delta.abs() <= N::zero());
530            // delta.instinct_delta_ord()
531            sort_point_and_line!(self, other)
532        }
533    }
534    fn instinct_cmp_ext(&self, other: &LineRef<'a, N>) -> Option<Ordering> {
535        // Same point
536        if same_point!(&other.0, &other.1) {
537           return Some(sort_points!(self, &other.0));
538        }
539
540        // Point in line
541        if point_in_line!(self, other) {
542            return None;
543        }
544        
545        // Point not in line
546        // let delta = ($other.1.z - $other.0.z) * ($self.y - $other.0.y) - ($other.1.y - $other.0.y) * ($self.z - $other.0.z);
547        // println!("line point {} {} {} {}", delta, delta.is_positive(), delta.is_negative(), delta.abs() <= N::zero());
548        // Some(delta.instinct_delta_ord())
549        Some(sort_point_and_line!(self, other))
550
551    }
552}
553
554impl<'a, N: RealField> InstinctOrd<Line<N>> for Point3<N> {
555    fn instinct_cmp(&self, other: &Line<N>) -> Ordering {
556        self.instinct_cmp(&(&other.0, &other.1))
557    }
558    fn instinct_cmp_ext(&self, other: &Line<N>) -> Option<Ordering> {
559        self.instinct_cmp_ext(&(&other.0, &other.1))
560    }
561}
562
563
564//--------------------------------
565/// Compare point and a plane linked by three points
566impl<'a, N: RealField> InstinctOrd<PlaneRef<'a, N>> for Point3<N> {
567    fn instinct_cmp(&self, other: &PlaneRef<'a, N>) -> Ordering {
568        if same_z!(other) {
569            return self.z.instinct_ord(&other.0.z);
570        }
571        let v = self.z;
572        let min = other.0.z.min(other.1.z).min(other.2.z);
573        let max = other.0.z.max(other.1.z).max(other.2.z);
574        /*
575        if v.instinct_eq(&max) || v.instinct_eq(&min) {
576            return Ordering::Equal;
577        }
578        */
579        if v.instinct_gt(&max) {
580            return Ordering::Greater;
581        }
582        if v.instinct_lt(&min) {
583            return Ordering::Less;
584        }
585
586        if !is_plane!(other) {
587            let line = sort_line_points!(other);
588            return self.instinct_cmp(&(line[0], line[2]));
589        }
590
591        let line1 = (other.1.coords - other.0.coords).normalize();
592        let line2 = (other.2.coords - other.0.coords).normalize();
593        let target = (self.coords - other.0.coords).normalize();
594
595        let normal = line1.cross(&line2);
596        let delta = normal.dot(&target);
597        
598        if normal.z.instinct_zero() {
599            Ordering::Equal
600        } else if normal.z.is_positive() {
601            delta.instinct_delta_ord()
602        } else {
603            delta.instinct_delta_ord().reverse()
604        }
605
606    }
607    fn instinct_cmp_ext(&self, other: &PlaneRef<'a, N>) -> Option<Ordering> {
608        if !is_plane!(other) {
609            let line = sort_line_points!(other);
610            return self.instinct_cmp_ext(&(line[0], line[2]));
611        }
612
613        let line1 = (other.1.coords - other.0.coords).normalize();
614        let line2 = (other.2.coords - other.0.coords).normalize();
615        let target = (self.coords - other.0.coords).normalize();
616
617        let normal = line1.cross(&line2);
618        let delta = normal.dot(&target);
619        if delta.instinct_zero() {
620            // Point in plane
621            Some(Ordering::Equal)
622        } else if normal.z.instinct_zero() {
623            // Plane parallel with z-axis
624            Some(Ordering::Equal)
625        } else if normal.z.is_positive() {
626            Some(delta.instinct_delta_ord())
627        } else {
628            Some(delta.instinct_delta_ord().reverse())
629        }
630    }
631}
632
633impl<N: RealField> InstinctOrd<Plane<N>> for Point3<N> {
634    fn instinct_cmp(&self, other: &Plane<N>) -> Ordering {
635        self.instinct_cmp(&(&other.0, &other.1, &other.2))
636    }
637    fn instinct_cmp_ext(&self, other: &Plane<N>) -> Option<Ordering> {
638        self.instinct_cmp_ext(&(&other.0, &other.1, &other.2))
639    }
640}
641
642impl<N: RealField> InstinctOrd<Point3<N>> for Plane<N> {
643    fn instinct_cmp(&self, other: &Point3<N>) -> Ordering {
644        other.instinct_cmp(&(&self.0, &self.1, &self.2)).reverse()
645    }
646    fn instinct_cmp_ext(&self, other: &Point3<N>) -> Option<Ordering> {
647        reverse_cmp_ext!(self, other)
648    }
649}
650
651impl<'a, N: RealField> InstinctOrd<Point3<N>> for PlaneRef<'a, N> {
652    fn instinct_cmp(&self, other: &Point3<N>) -> Ordering {
653        other.instinct_cmp(self).reverse()
654    }
655    fn instinct_cmp_ext(&self, other: &Point3<N>) -> Option<Ordering> {
656        reverse_cmp_ext!(self, other)
657    }
658}
659
660
661//--------------------------------
662/// Compare line linked by two points and a point
663impl<'a, N: RealField> InstinctOrd<Point3<N>> for Line<N> {
664    fn instinct_cmp(&self, other: &Point3<N>) -> Ordering {
665        other.instinct_cmp(self).reverse()
666    }
667    fn instinct_cmp_ext(&self, other: &Point3<N>) -> Option<Ordering> {
668        reverse_cmp_ext!(self, other)
669    }
670}
671
672impl<'a, N: RealField> InstinctOrd<Point3<N>> for LineRef<'a, N> {
673    fn instinct_cmp(&self, other: &Point3<N>) -> Ordering {
674        other.instinct_cmp(self).reverse()
675    }
676    fn instinct_cmp_ext(&self, other: &Point3<N>) -> Option<Ordering> {
677        reverse_cmp_ext!(self, other)
678    }
679}
680
681//--------------------------------
682/// Compare two lines linked by two points for each
683impl<'a, N: RealField> InstinctOrd<LineRef<'a, N>> for LineRef<'a, N> {
684    fn instinct_cmp(&self, other: &LineRef<'a, N>) -> Ordering {
685        if same_point!(self.0, self.1) {
686            return self.0.instinct_cmp(other);
687        } else if same_point!(other.0, other.1) {
688            return other.0.instinct_cmp(self).reverse();
689        }
690        let v_min = self.0.z.min(self.1.z);
691        let v_max = self.0.z.max(self.1.z);
692        let min = other.0.z.min(other.1.z);
693        let max = other.0.z.max(other.1.z);
694        if v_min.instinct_eq(&max) {
695            if v_max > max || min < v_min {
696                return Ordering::Greater;
697            }
698        } else if v_min > max {
699            return Ordering::Greater;
700        }
701        
702        if v_max.instinct_eq(&min) {
703            if v_min < max || max > v_max {
704                return Ordering::Less;
705            }
706        } else if v_max < min {
707            return Ordering::Less;
708        }
709
710        let o_0 = sort_point_and_line!(self.0, other);
711        let o_1 = sort_point_and_line!(self.1, other);
712
713        if point_in_line!(self.0, other) || o_0 == Ordering::Equal {
714            println!("{}", 1);
715            self.1.instinct_cmp(other)
716        } else if point_in_line!(self.1, other) || o_1 == Ordering::Equal {
717            println!("{}", 2);
718            self.0.instinct_cmp(other)
719        } else if o_0 == o_1 {
720            println!("{}", 3);
721            o_0
722        } else {
723            println!("{}", 4);
724            get_lines_normal!(self, other).z.instinct_delta_ord().reverse()
725        }
726    }
727    fn instinct_cmp_ext(&self, other: &LineRef<'a, N>) -> Option<Ordering> {
728        if same_point!(self.0, self.1) {
729            self.0.instinct_cmp_ext(other)
730        } else if same_point!(other.0, other.1) {
731            reverse_cmp_ext!(self, other.0)
732        } else if is_lines_parallel!(self, other) {
733            if point_in_line!(self.0, other) {
734                Some(Ordering::Equal)
735            } else {
736                self.0.instinct_cmp_ext(other)
737            }
738        } else {
739            let normal = get_lines_normal!(self, other);
740            if normal.z.instinct_zero() {
741                if normal.norm().instinct_zero() {
742                    None
743                } else {
744                    Some(Ordering::Equal)
745                }
746            } else if normal.z.is_negative() {
747                Some(Ordering::Greater)
748            } else {
749                Some(Ordering::Less)
750            }
751        }
752    }
753}
754
755impl<'a, N: RealField> InstinctOrd<LineRef<'a, N>> for Line<N> {
756    fn instinct_cmp(&self, other: &LineRef<'a, N>) -> Ordering {
757        (&self.0, &self.1).instinct_cmp(other)
758    }
759    fn instinct_cmp_ext(&self, other: &LineRef<'a, N>) -> Option<Ordering> {
760        (&self.0, &self.1).instinct_cmp_ext(other)
761    }
762}
763
764impl<'a, N: RealField> InstinctOrd<Line<N>> for Line<N> {
765    fn instinct_cmp(&self, other: &Line<N>) -> Ordering {
766        (&self.0, &self.1).instinct_cmp(&(&other.0, &other.1))
767    }
768    fn instinct_cmp_ext(&self, other: &Line<N>) -> Option<Ordering> {
769        (&self.0, &self.1).instinct_cmp_ext(&(&other.0, &other.1))
770    }
771}
772
773impl<'a, N: RealField> InstinctOrd<Line<N>> for LineRef<'a, N> {
774    fn instinct_cmp(&self, other: &Line<N>) -> Ordering {
775        self.instinct_cmp(&(&other.0, &other.1))
776    }
777    fn instinct_cmp_ext(&self, other: &Line<N>) -> Option<Ordering> {
778        self.instinct_cmp_ext(&(&other.0, &other.1))
779    }
780}
781
782//--------------------------------
783/// Compare a line and a plane
784impl<'a, N: RealField> InstinctOrd<PlaneRef<'a, N>> for LineRef<'a, N> {
785    fn instinct_cmp(&self, other: &PlaneRef<'a, N>) -> Ordering {
786        if same_point!(self.0, self.1) {
787            self.0.instinct_cmp(other)
788        } else {
789            let v_min = self.0.z.min(self.1.z);
790            let v_max = self.0.z.max(self.1.z);
791            let min = other.0.z.min(other.1.z).min(other.2.z);
792            let max = other.0.z.max(other.1.z).max(other.2.z);
793            if v_min.instinct_eq(&max) {
794                if v_max > max || min < v_min {
795                    return Ordering::Greater;
796                }
797            } else if v_min > max {
798                return Ordering::Greater;
799            }
800            
801            if v_max.instinct_eq(&min) {
802                if v_min < max || max > v_max {
803                    return Ordering::Less;
804                }
805            } else if v_max < min {
806                return Ordering::Less;
807            }
808
809            if !is_plane!(other) {
810                let line = sort_line_points!(other);
811                self.instinct_cmp(&(line[0], line[2]))
812            } else {
813                let normal_0 = get_point_plane_normal!(self.0, other);
814                let normal_1 = get_point_plane_normal!(self.1, other);
815                if normal_0.dot(&normal_1).instinct_not_negative() {
816                    if normal_0.z.abs() > normal_1.z.abs() {
817                        normal_0.z.instinct_delta_ord().reverse()
818                    } else {
819                        normal_1.z.instinct_delta_ord().reverse()
820                    }
821                } else {
822                    let distance_0_plane = normal_0.norm();
823                    let distance_1_plane = normal_1.norm();
824
825                    // joint of line and plane
826                    let joint = self.0 + (self.1.coords - self.0.coords) * distance_0_plane /
827                        (distance_0_plane + distance_1_plane);
828                    // normal of plane
829                    let normal_plane = (other.1.coords - other.0.coords).cross(&(
830                            other.2.coords - other.0.coords)).normalize();
831
832                    let cmp_normal_0 = (other.0.coords - joint.coords).cross(&normal_plane);
833                    let cmp_0_1 = (other.1.coords - joint.coords).dot(&cmp_normal_0);
834                    let cmp_0_2 = (other.2.coords - joint.coords).dot(&cmp_normal_0);
835                    if !cmp_0_1.instinct_zero() && !cmp_0_2.instinct_zero() &&
836                        cmp_0_1.is_positive() == cmp_0_2.is_negative() { 
837                        let cmp_normal_1 = (other.1.coords - joint.coords).cross(&normal_plane);
838                        let cmp_1_0 = (other.0.coords - joint.coords).dot(&cmp_normal_1);
839                        let cmp_1_2 = (other.2.coords - joint.coords).dot(&cmp_normal_1);
840                        if !cmp_1_0.instinct_zero() && !cmp_1_2.instinct_zero() &&
841                            cmp_1_0.is_positive() == cmp_1_2.is_negative() { 
842                            // Joint is in the triangle
843                            return Ordering::Equal;
844                        }
845                    }
846                    sort_line_and_triangle!(self, other)
847                }
848            }
849        }
850    }
851    fn instinct_cmp_ext(&self, other: &PlaneRef<'a, N>) -> Option<Ordering> {
852        if same_point!(self.0, self.1) {
853            self.0.instinct_cmp_ext(other)
854        } else if !is_plane!(other) {
855            let line = sort_line_points!(other);
856            self.instinct_cmp_ext(&(line[0], line[2]))
857        } else {
858            let c_0 = point_in_plane!(self.0, other);
859            let c_1 = point_in_plane!(self.1, other);
860            if c_0 {
861                if c_1 {
862                    Some(Ordering::Equal)
863                } else {
864                    None
865                }
866            } else if c_1 {
867                None
868            } else {
869                let v_0 = other.0.coords - other.2.coords;
870                let v_1 = other.1.coords - other.2.coords;
871                let normal = v_0.cross(&v_1);
872                let v = self.1.coords - self.0.coords;
873                if normal.dot(&v).instinct_zero() {
874                    Some(get_point_plane_normal!(self.0, other).z.instinct_delta_ord().reverse())
875                } else {
876                    None
877                }
878            }
879        }
880    }
881}
882
883impl<'a, N: RealField> InstinctOrd<PlaneRef<'a, N>> for Line<N> {
884    fn instinct_cmp(&self, other: &PlaneRef<'a, N>) -> Ordering {
885        (&self.0, &self.1).instinct_cmp(other)
886    }
887    fn instinct_cmp_ext(&self, other: &PlaneRef<'a, N>) -> Option<Ordering> {
888        (&self.0, &self.1).instinct_cmp_ext(other)
889    }
890}
891 
892impl<'a, N: RealField> InstinctOrd<Plane<N>> for LineRef<'a, N> {
893    fn instinct_cmp(&self, other: &Plane<N>) -> Ordering {
894        self.instinct_cmp(&(&other.0, &other.1, &other.2))
895    }
896    fn instinct_cmp_ext(&self, other: &Plane<N>) -> Option<Ordering> {
897        self.instinct_cmp_ext(&(&other.0, &other.1, &other.2))
898    }
899}
900
901impl<N: RealField> InstinctOrd<Plane<N>> for Line<N> {
902    fn instinct_cmp(&self, other: &Plane<N>) -> Ordering {
903        (&self.0, &self.1).instinct_cmp(&(&other.0, &other.1))
904    }
905    fn instinct_cmp_ext(&self, other: &Plane<N>) -> Option<Ordering> {
906        (&self.0, &self.1).instinct_cmp_ext(&(&other.0, &other.1))
907    }
908}
909
910impl<'a, N: RealField> InstinctOrd<LineRef<'a, N>> for PlaneRef<'a, N> {
911    fn instinct_cmp(&self, other: &LineRef<'a, N>) -> Ordering {
912        other.instinct_cmp(self).reverse()
913    }
914    fn instinct_cmp_ext(&self, other: &LineRef<'a, N>) -> Option<Ordering> {
915        reverse_cmp_ext!(self, other)
916    }
917}
918
919impl<'a, N: RealField> InstinctOrd<Line<N>> for PlaneRef<'a, N> {
920    fn instinct_cmp(&self, other: &Line<N>) -> Ordering {
921        (&other.0, &other.1).instinct_cmp(self).reverse()
922    }
923    fn instinct_cmp_ext(&self, other: &Line<N>) -> Option<Ordering> {
924        reverse_cmp_ext!(self, other)
925    }
926}
927
928impl<'a, N: RealField> InstinctOrd<LineRef<'a, N>> for Plane<N> {
929    fn instinct_cmp(&self, other: &LineRef<'a, N>) -> Ordering {
930        other.instinct_cmp(&(&self.0, &self.1, &self.2)).reverse()
931    }
932    fn instinct_cmp_ext(&self, other: &LineRef<'a, N>) -> Option<Ordering> {
933        reverse_cmp_ext!(self, other)
934    }
935}
936impl<N: RealField> InstinctOrd<Line<N>> for Plane<N> {
937    fn instinct_cmp(&self, other: &Line<N>) -> Ordering {
938        (&other.0, &other.1).instinct_cmp(&(&self.0, &self.1, &self.2)).reverse()
939    }
940    fn instinct_cmp_ext(&self, other: &Line<N>) -> Option<Ordering> {
941        reverse_cmp_ext!(self, other)
942    }
943}
944
945//--------------------------------
946/// Compare two planes
947impl<'a, N: RealField> InstinctOrd<PlaneRef<'a, N>> for PlaneRef<'a, N> {
948    fn instinct_cmp(&self, other: &PlaneRef<'a, N>) -> Ordering {
949            let v_min = self.0.z.min(self.1.z).min(self.2.z);
950            let v_max = self.0.z.max(self.1.z).max(self.2.z);
951            let min = other.0.z.min(other.1.z).min(other.2.z);
952            let max = other.0.z.max(other.1.z).max(other.2.z);
953            if v_min.instinct_eq(&max) {
954                if v_max > max || min < v_min {
955                    return Ordering::Greater;
956                }
957            } else if v_min > max {
958                return Ordering::Greater;
959            }
960            
961            if v_max.instinct_eq(&min) {
962                if v_min < max || max > v_max {
963                    return Ordering::Less;
964                }
965            } else if v_max < min {
966                return Ordering::Less;
967            }
968
969            if !is_plane!(other) {
970                let line = sort_line_points!(other);
971                (line[0], line[2]).instinct_cmp(self).reverse()
972            } else if !is_plane!(self) {
973                let line = sort_line_points!(self);
974                (line[0], line[2]).instinct_cmp(other)
975            } else {
976                macro_rules! check_normals_same_side {
977                    ($a: expr, $b: expr) => {
978                        if $a.dot(&$b).is_positive() {
979                            if $a.z.abs() > $b.z.abs() {
980                                return $a.z.instinct_delta_ord().reverse();
981                            } else {
982                                return $b.z.instinct_delta_ord().reverse();
983                            }
984                        }
985                    };
986                    ($a: expr, $b: expr, $c: expr) => {
987                        if $a.dot(&$b).is_positive() && $a.dot(&$c).is_positive() {
988                            if $a.z.abs() > $b.z.abs() && $a.z.abs() > $c.z.abs() {
989                                return $a.z.instinct_delta_ord().reverse();
990                            } else if $b.z.abs() > $c.z.abs() {
991                                return $b.z.instinct_delta_ord().reverse();
992                            } else {
993                                return $c.z.instinct_delta_ord().reverse();
994                            }
995                        }
996                    }
997                }
998
999                macro_rules! check_cross_side {
1000                    ($a: expr, $na: expr, $b: expr, $nb: expr, $other: expr) => {
1001                        {
1002                            let joint = $a + ($b.coords - $a.coords) * $na / ($na + $nb);
1003                            if point_in_triangle!(joint, $other) {
1004                                return Ordering::Equal;
1005                            } 
1006                        }
1007                    }
1008                }
1009
1010                macro_rules! check_cross_or_same_side {
1011                    ($a: expr, $b: expr) => {
1012                            let normal_0 = get_point_plane_normal!($a.0, $b);
1013                            let normal_1 = get_point_plane_normal!($a.1, $b);
1014                            let normal_2 = get_point_plane_normal!($a.2, $b);
1015                            let n_0 = normal_0.norm();
1016                            let n_1 = normal_1.norm();
1017                            let n_2 = normal_2.norm();
1018
1019                            if n_0.instinct_zero() {
1020                                if n_1.instinct_zero() {
1021                                    if n_2.instinct_zero() {
1022                                        return Ordering::Equal;
1023                                    } else {
1024                                        return normal_2.z.instinct_delta_ord().reverse();
1025                                    }
1026                                } else if n_2.instinct_zero() {
1027                                    return normal_1.z.instinct_delta_ord().reverse();
1028                                } else {
1029                                    // Check if 1, 2 on same side of other plane
1030                                    check_normals_same_side!(normal_1, normal_2);
1031                                    // Check if 1, 2 cross the triangle
1032                                    check_cross_side!($a.1, n_1, $a.2, n_2, $b);
1033                                }
1034                            } else if n_1.instinct_zero() {
1035                                if n_2.instinct_zero() {
1036                                    return normal_0.z.instinct_delta_ord().reverse();
1037                                } else {
1038                                    // check if 0, 2 on same side of other plane
1039                                    check_normals_same_side!(normal_0, normal_2);
1040                                    // check if 0, 2 cross the triangle
1041                                    check_cross_side!($a.0, n_0, $a.2, n_2, $b);
1042                                }
1043                            } else if n_2.instinct_zero() {
1044                                // check if 0, 1 on same side of other plane
1045                                check_normals_same_side!(normal_0, normal_1);
1046                                // check if 0, 1 cross the triangle
1047                                check_cross_side!($a.0, n_0, $a.1, n_1, $b);
1048                            } else {
1049                                // check if 0, 1, 2 on same side of other plane
1050                                // check_normals_same_side!(normal_0, normal_1, normal_2);
1051                                if normal_0.dot(&normal_1).is_positive() {
1052                                    if normal_0.dot(&normal_2).is_positive() {
1053                                        if normal_0.z.abs() > normal_1.z.abs()
1054                                            && normal_0.z.abs() > normal_2.z.abs() {
1055                                            return normal_0.z.instinct_delta_ord().reverse();
1056                                        } else if normal_1.z.abs() > normal_2.z.abs() {
1057                                            return normal_1.z.instinct_delta_ord().reverse();
1058                                        } else {
1059                                            return normal_2.z.instinct_delta_ord().reverse();
1060                                        }
1061                                    } else {
1062                                        // check if 0, 2 cross the triangle
1063                                        check_cross_side!($a.0, n_0, $a.2, n_2, $b);
1064                                        // check if 1, 2 cross the triangle
1065                                        check_cross_side!($a.1, n_1, $a.2, n_2, $b);
1066                                    }
1067                                } else if normal_0.dot(&normal_2).is_positive() {
1068                                    // check if 0, 1 cross the triangle
1069                                    check_cross_side!($a.0, n_0, $a.1, n_1, $b);
1070                                    // check if 1, 2 cross the triangle
1071                                    check_cross_side!($a.1, n_1, $a.2, n_2, $b);
1072                                } else {
1073                                    // check if 0, 1 cross the triangle
1074                                    check_cross_side!($a.0, n_0, $a.1, n_1, $b);
1075                                    // check if 0, 2 cross the triangle
1076                                    check_cross_side!($a.0, n_0, $a.2, n_2, $b);
1077                                }
1078                            }
1079                    }
1080                }
1081                check_cross_or_same_side!(self, other);
1082                check_cross_or_same_side!(other, self);
1083
1084                // Sort two planes
1085                sort_triangles!(self, other)
1086            }
1087    }
1088    fn instinct_cmp_ext(&self, other: &PlaneRef<'a, N>) -> Option<Ordering> {
1089        if !is_plane!(self) {
1090            let line = sort_line_points!(self);
1091            (line[0], line[2]).instinct_cmp_ext(other)
1092        } else if !is_plane!(other) {
1093            let line = sort_line_points!(other);
1094            self.instinct_cmp_ext(&(line[0], line[2]))
1095        } else {
1096            let n_0 = get_point_plane_normal!(self.0, other);
1097            let n_1 = get_point_plane_normal!(self.1, other);
1098            let n_2 = get_point_plane_normal!(self.2, other);
1099            if same_point!(&n_0, &n_1, &n_2) {
1100                Some(n_0.z.instinct_delta_ord().reverse())
1101            } else {
1102                None
1103            }
1104        }
1105    }
1106}
1107
1108impl<'a, N: RealField> InstinctOrd<Plane<N>> for PlaneRef<'a, N> {
1109    fn instinct_cmp(&self, other: &Plane<N>) -> Ordering {
1110        self.instinct_cmp(&(&other.0, &other.1, &other.2))
1111    }
1112    fn instinct_cmp_ext(&self, other: &Plane<N>) -> Option<Ordering> {
1113        self.instinct_cmp_ext(&(&other.0, &other.1, &other.2))
1114    }
1115}
1116 
1117impl<'a, N: RealField> InstinctOrd<PlaneRef<'a, N>> for Plane<N> {
1118    fn instinct_cmp(&self, other: &PlaneRef<'a, N>) -> Ordering {
1119        (&self.0, &self.1, &self.2).instinct_cmp(other)
1120    }
1121    fn instinct_cmp_ext(&self, other: &PlaneRef<'a, N>) -> Option<Ordering> {
1122        (&self.0, &self.1, &self.2).instinct_cmp_ext(other)
1123    }
1124}
1125 
1126impl<N: RealField> InstinctOrd<Plane<N>> for Plane<N> {
1127    fn instinct_cmp(&self, other: &Plane<N>) -> Ordering {
1128        (&self.0, &self.1, &self.2).instinct_cmp(&(&other.0, &other.1, &other.2))
1129    }
1130    fn instinct_cmp_ext(&self, other: &Plane<N>) -> Option<Ordering> {
1131        (&self.0, &self.1, &self.2).instinct_cmp_ext(&(&other.0, &other.1, &other.2))
1132    }
1133}
1134
1135
1136//--------------------Utils borrowed from ncollide
1137
1138/// Closest points between two lines.
1139///
1140/// The result, say `res`, is such that the closest points between both lines are
1141/// `orig1 + dir1 * res.0` and `orig2 + dir2 * res.1`.
1142#[inline]
1143pub fn closest_points_line_line_parameters<N: RealField>(
1144    orig1: &Point3<N>,
1145    dir1: &Vector3<N>,
1146    orig2: &Point3<N>,
1147    dir2: &Vector3<N>,
1148) -> (N, N) {
1149    let res =
1150        closest_points_line_line_parameters_eps(orig1, dir1, orig2, dir2, N::default_epsilon());
1151    (res.0, res.1)
1152}
1153
1154/// Closest points between two lines with a custom tolerance epsilon.
1155///
1156/// The result, say `res`, is such that the closest points between both lines are
1157/// `orig1 + dir1 * res.0` and `orig2 + dir2 * res.1`. If the lines are parallel
1158/// then `res.2` is set to `true` and the returned closest points are `orig1` and
1159/// its projection on the second line.
1160#[inline]
1161pub fn closest_points_line_line_parameters_eps<N: RealField>(
1162    orig1: &Point3<N>,
1163    dir1: &Vector3<N>,
1164    orig2: &Point3<N>,
1165    dir2: &Vector3<N>,
1166    eps: N,
1167) -> (N, N, bool) {
1168    // Inspired by RealField-time collision detection by Christer Ericson.
1169    let r = *orig1 - *orig2;
1170
1171    let a = dir1.norm_squared();
1172    let e = dir2.norm_squared();
1173    let f = dir2.dot(&r);
1174
1175    let _0: N = na::zero();
1176    let _1: N = na::one();
1177
1178    if a <= eps && e <= eps {
1179        (_0, _0, false)
1180    } else if a <= eps {
1181        (_0, f / e, false)
1182    } else {
1183        let c = dir1.dot(&r);
1184        if e <= eps {
1185            (-c / a, _0, false)
1186        } else {
1187            let b = dir1.dot(dir2);
1188            let ae = a * e;
1189            let bb = b * b;
1190            let denom = ae - bb;
1191
1192            // Use absolute and ulps error to test collinearity.
1193            // let parallel = denom <= eps || ulps_eq!(ae, bb);
1194            let parallel = denom <= eps;
1195
1196            let s = if !parallel {
1197                (b * f - c * e) / denom
1198            } else {
1199                _0
1200            };
1201
1202            (s, (b * s + f) / e, parallel)
1203        }
1204    }
1205}
1206
1207// FIXME: can we re-used this for the segment/segment case?
1208/// Closest points between two segments.
1209#[inline]
1210pub fn closest_points_line_line<N: RealField>(
1211    orig1: &Point3<N>,
1212    dir1: &Vector3<N>,
1213    orig2: &Point3<N>,
1214    dir2: &Vector3<N>,
1215) -> Line<N> {
1216    let (s, t) = closest_points_line_line_parameters(orig1, dir1, orig2, dir2);
1217    (*orig1 + *dir1 * s, *orig2 + *dir2 * t)
1218}
1219
1220
1221//-----------------test cases-------------------
1222#[cfg(test)]
1223mod tests {
1224    use super::*;
1225
1226    #[test]
1227    fn test_cmp_points() {
1228        assert_eq!(Point3::new(1.,2.,3.).instinct_cmp(&Point3::new(4.,5.,3.)), Ordering::Equal);
1229        assert_eq!(Point3::new(1.,2.,3.00000001).instinct_cmp(&Point3::new(4.,5.,3.)), Ordering::Greater);
1230        assert_eq!(Point3::new(1.,2.,2.999999).instinct_cmp(&Point3::new(4.,5.,3.)), Ordering::Less);
1231    }
1232
1233    #[test]
1234    fn test_cmp_point_line() {
1235        let line = (Point3::new(1., 2., 3.), Point3::new(5., 8., 9.));
1236        let mut point = Point3::new(1., 2., 3.);
1237        assert_eq!(line.instinct_cmp(&point), Ordering::Equal);
1238        point = Point3::new(3., 5., 6.);
1239        assert_eq!(line.instinct_cmp(&point), Ordering::Equal);
1240        point = Point3::new(3., 5., 6.0000001);
1241        assert_eq!(line.instinct_cmp(&point), Ordering::Greater);
1242        point = Point3::new(3., 5., 5.9999999);
1243        assert_eq!(line.instinct_cmp(&point), Ordering::Less);
1244    }
1245
1246    #[test]
1247    fn test_cmp_point_plane() {
1248        let plane = (Point3::new(1., 2., 3.), Point3::new(1.4, 4., 6.), Point3::new(0., 0., 0.));
1249        let mut point = Point3::new(0., 0., 0.);
1250        assert_eq!(plane.instinct_cmp(&point), Ordering::Equal);
1251        point = Point3::new(0.8, 2., 3.);
1252        assert_eq!(plane.instinct_cmp(&point), Ordering::Equal);
1253        point = Point3::new(0.8, 2., 2.999999);
1254        assert_eq!(plane.instinct_cmp(&point), Ordering::Greater);
1255        point = Point3::new(0.8, 2., 3.000001);
1256        assert_eq!(plane.instinct_cmp(&point), Ordering::Less);
1257    }
1258
1259    #[test]
1260    fn test_cmp_lines() {
1261        let a = (Point3::new(1., 2., 3.), Point3::new(5., 8., 9.));
1262        let b = (Point3::new(1., 2., 3.), Point3::new(5., 8., 9.));
1263        assert_eq!(a.instinct_cmp(&b), Ordering::Equal);
1264    }
1265
1266    #[test]
1267    fn test_lines_perpendicular_vector() {
1268        let p1 = Point3::new(-1., 0., -1.);
1269        let p2 = Point3::new(1., 32., 0.);
1270        let d1 = Vector3::new(-10., 0., -10.);
1271        let d2 = Vector3::new(3., 0., 0.);
1272        let (s, t) = closest_points_line_line_parameters(&p1, &d1, &p2, &d2);
1273        let t1 = p1 + d1*s;
1274        let t2 = p2 + d2*t;
1275        assert_eq!(t1, Point3::new(0., 0., 0.));
1276        assert_eq!(t2, Point3::new(0., 32., 0.));
1277    }
1278}
1279
1280
1281