spatial_neighbors/
quad_tree.rs

1use std::ops::Range;
2use crate::SpatialPartitioner;
3use crate::util::in_range;
4
5pub struct QuadTree<Data: Copy> {
6    node: QuadTreeNode<Data>,
7
8    capacity: u16,
9
10    x: Range<f64>,
11    y: Range<f64>,
12
13    count: usize,
14}
15
16impl<Data: Copy> QuadTree<Data> {
17    ///
18    /// # Arguments
19    ///
20    /// * `x`: min_x..max_x defines the area in wich data can be inserted
21    /// * `y`: min_y..max_y defines the area in wich data can be inserted
22    /// * `capacity`: capacity of each TreeNode
23    ///
24    pub fn with_capacity(x: Range<f64>, y: Range<f64>, capacity: u16) -> QuadTree<Data> {
25        QuadTree {
26            node: QuadTreeNode::new(((x.end - x.start) / 2.0, (y.end - y.start) / 2.0), ((x.end - x.start), (y.end - y.start)), capacity),
27            capacity,
28            x,
29            y,
30            count: 0,
31        }
32    }
33
34    ///
35    /// # Arguments
36    ///
37    /// returns : &QuadTreeNode<Data> the root node of the QuadTree
38    ///
39    pub fn node(&self) -> &QuadTreeNode<Data> {
40        &self.node
41    }
42}
43
44impl<Data: Copy> SpatialPartitioner<Data> for QuadTree<Data> {
45    ///
46    /// create a QuadTree with a default capacity of 50. More info here [`QuadTree::new()`]
47    ///
48    fn new(x: Range<f64>, y: Range<f64>) -> Self {
49        QuadTree::with_capacity(x, y, 50)
50    }
51
52    fn insert(&mut self, position: (f64, f64), data: Data) {
53        if position.0 < self.x.start || position.0 >= self.x.end || position.1 < self.y.start || position.1 >= self.y.end {
54            panic!("tried to insert position into QuadTree which was out of bounce")
55        }
56
57        self.insert_unchecked(position, data);
58    }
59
60    fn insert_unchecked(&mut self, position: (f64, f64), data: Data) {
61        self.count += 1;
62        self.node.insert(position, data);
63    }
64
65    fn count(&self) -> usize {
66        self.count
67    }
68
69    fn clear(&mut self) {
70        self.node = QuadTreeNode::new(((self.x.start - self.x.end) / 2.0, (self.y.start - self.y.end) / 2.0), ((self.x.start - self.x.end), (self.y.start - self.y.end)), self.capacity);
71        self.count = 0;
72    }
73
74    fn in_circle(&self, position: (f64, f64), radius: f64) -> Vec<Data> {
75        let mut data = Vec::new();
76
77        self.node.in_circle(position, radius, &mut data, false);
78
79        data
80    }
81}
82
83pub struct QuadTreeNode<Data: Copy> {
84    data: Vec<((f64, f64), Data)>,
85    capacity: u16,
86
87    is_full: bool,
88
89    nodes: Option<Box<[QuadTreeNode<Data>; 4]>>,
90
91    center: (f64, f64),
92    size: (f64, f64),
93}
94
95impl<Data: Copy> QuadTreeNode<Data> {
96    ///
97    /// # Arguments
98    ///
99    /// returns : &Option<Box<[QuadTreeNode<Data>; 4]>> the nodes of the current node
100    ///
101    pub fn nodes(&self) -> &Option<Box<[QuadTreeNode<Data>; 4]>> {
102        &self.nodes
103    }
104
105    ///
106    /// # Arguments
107    ///
108    /// returns : &Vec<((f64, f64), Data)> the Elements stored in the current node
109    ///
110    pub fn data(&self) -> &Vec<((f64, f64), Data)> {
111        &self.data
112    }
113
114    ///
115    /// # Arguments
116    ///
117    /// returns : &(f64, f64) the center of the current node
118    ///
119    pub fn center(&self) -> (f64, f64) {
120        self.center
121    }
122
123    ///
124    /// # Arguments
125    ///
126    /// returns : &(f64, f64) the size of the current node
127    ///
128    pub fn size(&self) -> (f64, f64) {
129        self.size
130    }
131
132    fn new(center: (f64, f64), size: (f64, f64), capacity: u16) -> QuadTreeNode<Data> {
133        QuadTreeNode {
134            data: Vec::new(),
135            nodes: None,
136            center,
137            size,
138            capacity,
139
140            is_full: false,
141        }
142    }
143
144    fn insert(&mut self, position: (f64, f64), data: Data) {
145        if !self.is_full {
146            self.data.push((position, data));
147
148            if self.data.len() >= self.capacity as usize {
149                self.is_full = true;
150
151                self.nodes = Some(Box::new([
152                    QuadTreeNode::new((self.center.0 - self.size.0 / 2.0, self.center.1 - self.size.1 / 2.0), (self.size.0 / 2.0, self.size.1 / 2.0), self.capacity),
153                    QuadTreeNode::new((self.center.0 - self.size.0 / 2.0, self.center.1 + self.size.1 / 2.0), (self.size.0 / 2.0, self.size.1 / 2.0), self.capacity),
154                    QuadTreeNode::new((self.center.0 + self.size.0 / 2.0, self.center.1 - self.size.1 / 2.0), (self.size.0 / 2.0, self.size.1 / 2.0), self.capacity),
155                    QuadTreeNode::new((self.center.0 + self.size.0 / 2.0, self.center.1 + self.size.1 / 2.0), (self.size.0 / 2.0, self.size.1 / 2.0), self.capacity),
156                ]))
157            }
158        } else {
159            let i = self.get_index(position);
160            self.nodes.as_mut().unwrap()[i].insert(position, data);
161        }
162    }
163
164    fn in_circle(&self, position: (f64, f64), radius: f64, data: &mut Vec<Data>, in_circle: bool) {
165        if in_circle || (self.data.len() > 4 && self.in_box(position, radius)) {
166            data.reserve(self.data.len());
167
168            data.extend(self.data.iter().map(|x| x.1));
169
170            if self.nodes.is_none() {
171                return;
172            }
173
174            self.nodes.as_ref().unwrap()[0].in_circle(position, radius, data, true);
175            self.nodes.as_ref().unwrap()[1].in_circle(position, radius, data, true);
176            self.nodes.as_ref().unwrap()[2].in_circle(position, radius, data, true);
177            self.nodes.as_ref().unwrap()[3].in_circle(position, radius, data, true);
178        } else {
179            for elements in &self.data {
180                if in_range(elements.0, position, radius) {
181                    data.push(elements.1)
182                }
183            }
184
185            if self.nodes.is_none() {
186                return;
187            }
188
189            let mut indexes = [false; 4];
190
191            indexes[self.get_index((position.0 - radius, position.1 - radius))] = true;
192            indexes[self.get_index((position.0 - radius, position.1 + radius))] = true;
193            indexes[self.get_index((position.0 + radius, position.1 - radius))] = true;
194            indexes[self.get_index((position.0 + radius, position.1 + radius))] = true;
195
196            for (i, bool) in indexes.iter().enumerate() {
197                if *bool {
198                    self.nodes.as_ref().unwrap()[i].in_circle(position, radius, data, false);
199                }
200            }
201        }
202    }
203
204    fn in_box(&self, location: (f64, f64), radius: f64) -> bool {
205        if in_range(location, (self.center.0 - self.size.0, self.center.1 + self.size.1), radius)
206            && in_range(location, (self.center.0 + self.size.0, self.center.1 + self.size.1), radius)
207            && in_range(location, (self.center.0 - self.size.0, self.center.1 - self.size.1), radius)
208            && in_range(location, (self.center.0 + self.size.0, self.center.1 - self.size.1), radius) {
209            return true;
210        }
211
212        false
213    }
214
215    fn get_index(&self, location: (f64, f64)) -> usize {
216        if self.center.0 > location.0 {
217            if self.center.1 > location.1 {
218                0
219            } else {
220                1
221            }
222        } else if self.center.1 > location.1 {
223            2
224        } else {
225            3
226        }
227    }
228}