1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::aabb::AABB;
use crate::envelope::Envelope;
use crate::object::{PointDistance, RTreeObject};
use crate::point::{Point, PointExt};

/// An n-dimensional rectangle defined by its two corners.
///
/// This rectangle can be directly inserted into an r-tree.
///
/// *Note*: Despite being called rectangle, this struct can be used
/// with more than two dimensions by using an appropriate point type.
///
/// # Type parameters
/// `P`: The rectangle's [Point](../trait.Point.html) type.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rectangle<P>
where
    P: Point,
{
    aabb: AABB<P>,
}

impl<P> Rectangle<P>
where
    P: Point,
{
    /// Creates a new rectangle defined by two corners.
    pub fn from_corners(corner_1: P, corner_2: P) -> Self {
        AABB::from_corners(corner_1, corner_2).into()
    }

    /// Creates a new rectangle defined by it's [axis aligned bounding box](../struct.AABB.html).
    pub fn from_aabb(aabb: AABB<P>) -> Self {
        Rectangle { aabb }
    }

    /// Returns the rectangle's lower corner.
    ///
    /// This is the point contained within the rectangle with the smallest coordinate value in each
    /// dimension.
    pub fn lower(&self) -> P {
        self.aabb.lower()
    }

    /// Returns the rectangle's upper corner.
    ///
    /// This is the point contained within the AABB with the largest coordinate value in each
    /// dimension.
    pub fn upper(&self) -> P {
        self.aabb.upper()
    }
}

impl<P> From<AABB<P>> for Rectangle<P>
where
    P: Point,
{
    fn from(aabb: AABB<P>) -> Self {
        Self::from_aabb(aabb)
    }
}

impl<P> RTreeObject for Rectangle<P>
where
    P: Point,
{
    type Envelope = AABB<P>;

    fn envelope(&self) -> Self::Envelope {
        self.aabb
    }
}

impl<P> Rectangle<P>
where
    P: Point,
{
    /// Returns the nearest point within this rectangle to a given point.
    ///
    /// If `query_point` is contained within this rectangle, `query_point` is returned.
    pub fn nearest_point(&self, query_point: &P) -> P {
        self.aabb.min_point(query_point)
    }
}

impl<P> PointDistance for Rectangle<P>
where
    P: Point,
{
    fn distance_2(
        &self,
        point: &<Self::Envelope as Envelope>::Point,
    ) -> <<Self::Envelope as Envelope>::Point as Point>::Scalar {
        self.nearest_point(point).sub(point).length_2()
    }

    fn contains_point(&self, point: &<Self::Envelope as Envelope>::Point) -> bool {
        self.aabb.contains_point(point)
    }

    fn distance_2_if_less_or_equal(
        &self,
        point: &<Self::Envelope as Envelope>::Point,
        max_distance_2: <<Self::Envelope as Envelope>::Point as Point>::Scalar,
    ) -> Option<<<Self::Envelope as Envelope>::Point as Point>::Scalar> {
        let distance_2 = self.distance_2(point);
        if distance_2 <= max_distance_2 {
            Some(distance_2)
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use super::Rectangle;
    use crate::object::PointDistance;
    use approx::*;

    #[test]
    fn rectangle_distance() {
        let rectangle = Rectangle::from_corners([0.5, 0.5], [1.0, 2.0]);

        assert_abs_diff_eq!(rectangle.distance_2(&[0.5, 0.5]), 0.0);
        assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 0.5]), 0.5 * 0.5);
        assert_abs_diff_eq!(rectangle.distance_2(&[0.5, 1.0]), 0.0);
        assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 0.0]), 0.5);
        assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 1.0]), 0.5 * 0.5);
        assert_abs_diff_eq!(rectangle.distance_2(&[1.0, 3.0]), 1.0);
        assert_abs_diff_eq!(rectangle.distance_2(&[1.0, 1.0]), 0.0);
    }
}