Skip to main content

rstar/algorithm/
selection_functions.rs

1use crate::object::PointDistance;
2use crate::object::RTreeObject;
3use crate::{envelope::Envelope, object::Distance};
4
5/// Advanced trait to iterate through an r-tree. Usually it should not be required to be implemented.
6///
7/// It is important to know some details about the inner structure of
8/// r-trees to understand this trait. Any node in an r-tree is either a *leaf* (containing exactly one `T: RTreeObject`) or
9/// a *parent* (containing multiple nodes).
10/// The main benefit of r-trees lies in their ability to efficiently guide searches through
11/// the tree. This is done by *pruning*: Knowing the envelopes of parent nodes
12/// often allows the search to completely skip them and all contained children instead of having
13/// to iterate through them, e.g. when searching for elements in a non-intersecting envelope.
14/// This often reduces the expected time from `O(n)` to `O(log(n))`.
15///
16/// This trait can be used to define searches through the r-tree by defining whether a node
17/// should be further investigated ("unpacked") or pruned.
18///
19/// Usually, the various `locate_[...]` methods of [`super::super::RTree`] should cover most
20/// common searches. Otherwise, implementing `SelectionFunction` and using
21/// [`crate::RTree::locate_with_selection_function`]
22/// can be used to tailor a custom search.
23pub trait SelectionFunction<T>
24where
25    T: RTreeObject,
26{
27    /// Return `true` if a parent node should be unpacked during a search.
28    ///
29    /// The parent node's envelope is given to guide the decision.
30    fn should_unpack_parent(&self, envelope: &T::Envelope) -> bool;
31
32    /// Returns `true` if a given child node should be returned during a search.
33    /// The default implementation will always return `true`.
34    fn should_unpack_leaf(&self, _leaf: &T) -> bool {
35        true
36    }
37}
38
39pub struct SelectInEnvelopeFunction<T>
40where
41    T: RTreeObject,
42{
43    envelope: T::Envelope,
44}
45
46impl<T> SelectInEnvelopeFunction<T>
47where
48    T: RTreeObject,
49{
50    pub fn new(envelope: T::Envelope) -> Self {
51        SelectInEnvelopeFunction { envelope }
52    }
53}
54
55impl<T> SelectionFunction<T> for SelectInEnvelopeFunction<T>
56where
57    T: RTreeObject,
58{
59    fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool {
60        self.envelope.intersects(parent_envelope)
61    }
62
63    fn should_unpack_leaf(&self, leaf: &T) -> bool {
64        self.envelope.contains_envelope(&leaf.envelope())
65    }
66}
67
68pub struct SelectInEnvelopeFuncIntersecting<T>
69where
70    T: RTreeObject,
71{
72    envelope: T::Envelope,
73}
74
75impl<T> SelectInEnvelopeFuncIntersecting<T>
76where
77    T: RTreeObject,
78{
79    pub fn new(envelope: T::Envelope) -> Self {
80        SelectInEnvelopeFuncIntersecting { envelope }
81    }
82}
83
84impl<T> SelectionFunction<T> for SelectInEnvelopeFuncIntersecting<T>
85where
86    T: RTreeObject,
87{
88    fn should_unpack_parent(&self, envelope: &T::Envelope) -> bool {
89        self.envelope.intersects(envelope)
90    }
91
92    fn should_unpack_leaf(&self, leaf: &T) -> bool {
93        leaf.envelope().intersects(&self.envelope)
94    }
95}
96
97pub struct SelectAllFunc;
98
99impl<T> SelectionFunction<T> for SelectAllFunc
100where
101    T: RTreeObject,
102{
103    fn should_unpack_parent(&self, _: &T::Envelope) -> bool {
104        true
105    }
106}
107
108/// A [trait.SelectionFunction] that only selects elements whose envelope
109/// contains a specific point.
110pub struct SelectAtPointFunction<T>
111where
112    T: RTreeObject,
113{
114    point: <T::Envelope as Envelope>::Point,
115}
116
117impl<T> SelectAtPointFunction<T>
118where
119    T: PointDistance,
120{
121    pub fn new(point: <T::Envelope as Envelope>::Point) -> Self {
122        SelectAtPointFunction { point }
123    }
124}
125
126impl<T> SelectionFunction<T> for SelectAtPointFunction<T>
127where
128    T: PointDistance,
129{
130    fn should_unpack_parent(&self, envelope: &T::Envelope) -> bool {
131        envelope.contains_point(&self.point)
132    }
133
134    fn should_unpack_leaf(&self, leaf: &T) -> bool {
135        leaf.contains_point(&self.point)
136    }
137}
138
139/// A selection function that only chooses elements equal (`==`) to a
140/// given element
141pub struct SelectEqualsFunction<'a, T>
142where
143    T: RTreeObject + PartialEq + 'a,
144{
145    /// Only elements equal to this object will be removed.
146    object_to_remove: &'a T,
147}
148
149impl<'a, T> SelectEqualsFunction<'a, T>
150where
151    T: RTreeObject + PartialEq,
152{
153    pub fn new(object_to_remove: &'a T) -> Self {
154        SelectEqualsFunction { object_to_remove }
155    }
156}
157
158impl<T> SelectionFunction<T> for SelectEqualsFunction<'_, T>
159where
160    T: RTreeObject + PartialEq,
161{
162    fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool {
163        parent_envelope.contains_envelope(&self.object_to_remove.envelope())
164    }
165
166    fn should_unpack_leaf(&self, leaf: &T) -> bool {
167        leaf == self.object_to_remove
168    }
169}
170
171pub struct SelectWithinDistanceFunction<T>
172where
173    T: RTreeObject + PointDistance,
174{
175    circle_origin: <T::Envelope as Envelope>::Point,
176    squared_max_distance: Distance<T>,
177}
178
179impl<T> SelectWithinDistanceFunction<T>
180where
181    T: RTreeObject + PointDistance,
182{
183    pub fn new(
184        circle_origin: <T::Envelope as Envelope>::Point,
185        squared_max_distance: Distance<T>,
186    ) -> Self {
187        SelectWithinDistanceFunction {
188            circle_origin,
189            squared_max_distance,
190        }
191    }
192}
193
194impl<T> SelectionFunction<T> for SelectWithinDistanceFunction<T>
195where
196    T: RTreeObject + PointDistance,
197{
198    fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool {
199        let envelope_distance = parent_envelope.distance_2(&self.circle_origin);
200        envelope_distance <= self.squared_max_distance
201    }
202
203    fn should_unpack_leaf(&self, leaf: &T) -> bool {
204        leaf.distance_2_if_less_or_equal(&self.circle_origin, self.squared_max_distance)
205            .is_some()
206    }
207}
208
209pub struct SelectByAddressFunction<T>
210where
211    T: RTreeObject,
212{
213    envelope: T::Envelope,
214    element_address: *const T,
215}
216
217impl<T> SelectByAddressFunction<T>
218where
219    T: RTreeObject,
220{
221    pub fn new(envelope: T::Envelope, element_address: &T) -> Self {
222        Self {
223            envelope,
224            element_address,
225        }
226    }
227}
228
229impl<T> SelectionFunction<T> for SelectByAddressFunction<T>
230where
231    T: RTreeObject,
232{
233    fn should_unpack_parent(&self, parent_envelope: &T::Envelope) -> bool {
234        parent_envelope.contains_envelope(&self.envelope)
235    }
236
237    fn should_unpack_leaf(&self, leaf: &T) -> bool {
238        core::ptr::eq(self.element_address, leaf)
239    }
240}