rstar/primitives/
rectangle.rs

1use crate::aabb::AABB;
2use crate::envelope::Envelope;
3use crate::object::{PointDistance, RTreeObject};
4use crate::point::{Point, PointExt};
5
6/// An n-dimensional rectangle defined by its two corners.
7///
8/// This rectangle can be directly inserted into an r-tree.
9///
10/// *Note*: Despite being called rectangle, this struct can be used
11/// with more than two dimensions by using an appropriate point type.
12///
13/// # Type parameters
14/// `P`: The rectangle's [Point] type.
15#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct Rectangle<P>
18where
19    P: Point,
20{
21    aabb: AABB<P>,
22}
23
24impl<P> Rectangle<P>
25where
26    P: Point,
27{
28    /// Creates a new rectangle defined by two corners.
29    pub fn from_corners(corner_1: P, corner_2: P) -> Self {
30        AABB::from_corners(corner_1, corner_2).into()
31    }
32
33    /// Creates a new rectangle defined by it's [axis aligned bounding box(AABB).
34    pub fn from_aabb(aabb: AABB<P>) -> Self {
35        Rectangle { aabb }
36    }
37
38    /// Returns the rectangle's lower corner.
39    ///
40    /// This is the point contained within the rectangle with the smallest coordinate value in each
41    /// dimension.
42    pub fn lower(&self) -> P {
43        self.aabb.lower()
44    }
45
46    /// Returns the rectangle's upper corner.
47    ///
48    /// This is the point contained within the AABB with the largest coordinate value in each
49    /// dimension.
50    pub fn upper(&self) -> P {
51        self.aabb.upper()
52    }
53}
54
55impl<P> From<AABB<P>> for Rectangle<P>
56where
57    P: Point,
58{
59    fn from(aabb: AABB<P>) -> Self {
60        Self::from_aabb(aabb)
61    }
62}
63
64impl<P> RTreeObject for Rectangle<P>
65where
66    P: Point,
67{
68    type Envelope = AABB<P>;
69
70    fn envelope(&self) -> Self::Envelope {
71        self.aabb.clone()
72    }
73}
74
75impl<P> Rectangle<P>
76where
77    P: Point,
78{
79    /// Returns the nearest point within this rectangle to a given point.
80    ///
81    /// If `query_point` is contained within this rectangle, `query_point` is returned.
82    pub fn nearest_point(&self, query_point: &P) -> P {
83        self.aabb.min_point(query_point)
84    }
85}
86
87impl<P> PointDistance for Rectangle<P>
88where
89    P: Point,
90{
91    fn distance_2(
92        &self,
93        point: &<Self::Envelope as Envelope>::Point,
94    ) -> <<Self::Envelope as Envelope>::Point as Point>::Scalar {
95        self.nearest_point(point).sub(point).length_2()
96    }
97
98    fn contains_point(&self, point: &<Self::Envelope as Envelope>::Point) -> bool {
99        self.aabb.contains_point(point)
100    }
101
102    fn distance_2_if_less_or_equal(
103        &self,
104        point: &<Self::Envelope as Envelope>::Point,
105        max_distance_2: <<Self::Envelope as Envelope>::Point as Point>::Scalar,
106    ) -> Option<<<Self::Envelope as Envelope>::Point as Point>::Scalar> {
107        let distance_2 = self.distance_2(point);
108        if distance_2 <= max_distance_2 {
109            Some(distance_2)
110        } else {
111            None
112        }
113    }
114}
115
116#[cfg(test)]
117mod test {
118    use super::Rectangle;
119    use crate::object::PointDistance;
120    use approx::*;
121
122    #[test]
123    fn rectangle_distance() {
124        let rectangle = Rectangle::from_corners([0.5, 0.5], [1.0, 2.0]);
125
126        assert_abs_diff_eq!(rectangle.distance_2(&[0.5, 0.5]), 0.0);
127        assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 0.5]), 0.5 * 0.5);
128        assert_abs_diff_eq!(rectangle.distance_2(&[0.5, 1.0]), 0.0);
129        assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 0.0]), 0.5);
130        assert_abs_diff_eq!(rectangle.distance_2(&[0.0, 1.0]), 0.5 * 0.5);
131        assert_abs_diff_eq!(rectangle.distance_2(&[1.0, 3.0]), 1.0);
132        assert_abs_diff_eq!(rectangle.distance_2(&[1.0, 1.0]), 0.0);
133    }
134}