logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use approx::abs_diff_eq;
use num::{Signed, Zero};
use std::cmp::Ordering;
use theon::query::{Line, Plane};
use theon::space::{EuclideanSpace, FiniteDimensional};
use typenum::{U1, U2, U3};

// "Left" and "right" are arbitrary here and refer to the partitioned spaces
// formed by a geometric entity. This is a point, line, and plane in one, two,
// three dimensions, respectively.
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum BinaryPartition {
    Left,
    Right,
}

pub trait PointPartition<S>
where
    S: EuclideanSpace,
{
    fn partition(&self, point: S) -> Option<BinaryPartition>;
}

impl<S> PointPartition<S> for S
where
    S: EuclideanSpace + FiniteDimensional<N = U1>,
{
    // TODO: Should `IntrinsicOrd` be used here?
    fn partition(&self, point: S) -> Option<BinaryPartition> {
        let ax = self.into_x();
        let px = point.into_x();
        match px.partial_cmp(&ax) {
            Some(Ordering::Less) => Some(BinaryPartition::Left),
            Some(Ordering::Greater) => Some(BinaryPartition::Right),
            _ => None,
        }
    }
}

impl<S> PointPartition<S> for Line<S>
where
    S: EuclideanSpace + FiniteDimensional<N = U2>,
{
    fn partition(&self, point: S) -> Option<BinaryPartition> {
        // Compute the determinant of a matrix composed of points along the line
        // and the queried point. This can also be thought of as a two-
        // dimensional cross product.
        // TODO: Perhaps this should be exposed by Theon instead.
        let (ax, ay) = self.origin.into_xy();
        let (bx, by) = (self.origin + *self.direction.get()).into_xy();
        let (px, py) = point.into_xy();
        let determinant = ((bx - ax) * (py - ay)) - ((by - ay) * (px - ax));
        if abs_diff_eq!(determinant, Zero::zero()) {
            None
        }
        else {
            Some(if determinant.is_positive() {
                BinaryPartition::Left
            }
            else {
                BinaryPartition::Right
            })
        }
    }
}

impl<S> PointPartition<S> for Plane<S>
where
    S: EuclideanSpace + FiniteDimensional<N = U3>,
{
    fn partition(&self, point: S) -> Option<BinaryPartition> {
        let _ = point;
        todo!()
    }
}