1use std::cmp::Ordering;
26
27use crate::*;
28
29#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub struct KdTree<P>
34where
35 P: Is3D,
36{
37 root: Option<KdNode<P>>,
38}
39
40#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
43struct KdNode<P>
44where
45 P: Is3D,
46{
47 pub left: Option<Box<KdNode<P>>>,
48 pub right: Option<Box<KdNode<P>>>,
49 pub val: P,
50 pub dimension: i8,
51}
52
53impl<P> IsTree3D<P> for KdTree<P>
56where
57 P: Is3D + Clone,
58{
59 fn size(&self) -> usize {
60 match self.root {
61 None => 0,
62 Some(ref node) => node.size(),
63 }
64 }
65
66 fn to_pointcloud(&self) -> PointCloud3D<P> {
67 let mut result = PointCloud3D::new();
68 if let Some(ref node) = self.root {
69 node.to_pointcloud_3d(&mut result);
70 }
71 result
72 }
73
74 fn build(&mut self, pc: PointCloud3D<P>) -> Result<()> {
75 match pc.len() {
76 0 => Err(ErrorKind::TooFewPoints),
77 _ => {
78 self.root = Some(KdNode::new(0, pc.data));
79 Ok(())
80 }
81 }
82 }
83}
84
85impl<PSearch, PFind> IsKNearestSearchable<PSearch, PFind> for KdTree<PFind>
88where
89 PSearch: Is3D,
90 PFind: Is3D + Clone,
91{
92 fn knearest(&self, search: &PSearch, n: usize, result: &mut Vec<PFind>) {
93 if n < 1 {
94 return;
95 }
96 if let Some(ref node) = self.root {
97 node.knearest(search, n, result);
98 }
99 }
100
101 fn nearest(&self, search: &PSearch) -> Result<PFind> {
102 let mut result = Vec::new();
104 self.knearest(search, 1, &mut result);
105 match result.len() {
106 0 => Err(ErrorKind::TooFewPoints),
107 _ => {
108 let p = result[0].clone();
109 Ok(p)
110 }
111 }
112 }
113}
114
115impl<P> IsSphereSearchable<P> for KdTree<P>
116where
117 P: Is3D + Clone,
118{
119 fn in_sphere(&self, sphere: &Sphere, result: &mut Vec<P>) {
120 if let Some(ref node) = self.root {
121 node.in_sphere(sphere, result);
122 }
123 }
124}
125
126impl<P> IsBox3DSearchable<P> for KdTree<P>
127where
128 P: Is3D + Clone,
129{
130 fn in_box(&self, box_3d: &Box3D, result: &mut Vec<P>) {
131 if let Some(ref node) = self.root {
132 node.in_box(box_3d, result);
133 }
134 }
135}
136
137impl<P> KdNode<P>
138where
139 P: Is3D,
140{
141 pub fn size(&self) -> usize {
142 let mut result: usize = 0;
143 if let Some(ref n) = self.left {
144 result += n.size();
145 }
146 result += 1;
147 if let Some(ref n) = self.right {
148 result += n.size();
149 }
150 result
151 }
152
153 fn is_leaf(&self) -> bool {
154 self.left.is_none() && self.right.is_none()
155 }
156}
157
158impl<P> KdNode<P>
159where
160 P: Is3D + Clone,
161{
162 pub fn to_pointcloud_3d(&self, pc: &mut PointCloud3D<P>) {
163 if let Some(ref n) = self.left {
164 n.to_pointcloud_3d(pc);
165 }
166 pc.push(self.val.clone());
167 if let Some(ref n) = self.right {
168 n.to_pointcloud_3d(pc);
169 }
170 }
171
172 pub fn new(dim: i8, mut pc: Vec<P>) -> KdNode<P> {
173 let dimension = dim % 2;
174 if pc.len() == 1 {
175 return KdNode {
176 left: None,
177 right: None,
178 val: pc[0].clone(),
179 dimension,
180 };
181 }
182
183 pc.sort_by(|a, b| match dimension {
184 0 => a.x().partial_cmp(&b.x()).unwrap_or(Ordering::Equal),
185 1 => a.y().partial_cmp(&b.y()).unwrap_or(Ordering::Equal),
186 2 => a.z().partial_cmp(&b.z()).unwrap_or(Ordering::Equal),
187 _ => Ordering::Equal,
188 });
189 let median = pc.len() / 2;
190 let mut pc_left = Vec::new();
191 let mut pc_right = Vec::new();
192
193 let val = pc[median].clone();
194
195 for (i, p) in pc.into_iter().enumerate() {
196 if i < median {
197 pc_left.push(p);
198 } else if i > median {
199 pc_right.push(p);
200 }
201 }
202
203 let left = match pc_left.len() {
204 0 => None,
205 _ => Some(Box::new(KdNode::new(dimension + 1, pc_left))),
206 };
207
208 let right = match pc_right.len() {
209 0 => None,
210 _ => Some(Box::new(KdNode::new(dimension + 1, pc_right))),
211 };
212
213 KdNode {
214 left,
215 right,
216 val,
217 dimension,
218 }
219 }
220}
221
222impl<P> KdNode<P>
223where
224 P: Is3D + Clone,
225{
226 pub fn knearest<PSearch>(&self, search: &PSearch, n: usize, pc: &mut Vec<P>)
227 where
228 PSearch: Is3D,
229 {
230 if pc.len() < n || sqr_dist_3d(search, &self.val) < sqr_dist_3d(search, &pc[&pc.len() - 1])
231 {
232 pc.push(self.val.clone());
233 }
234
235 let comp = dimension_compare(search, &self.val, self.dimension);
236
237 match comp {
238 Ok(res) => match res {
239 Ordering::Less => {
240 if let Some(ref node) = self.left {
241 node.knearest(search, n, pc);
242 }
243 }
244 _ => {
245 if let Some(ref node) = self.right {
246 node.knearest(search, n, pc);
247 }
248 }
249 },
250 Err(_) => {}
251 }
252
253 Self::sort_and_limit(pc, search, n);
254
255 let (current_search, current_val) = match self.dimension {
256 0 => (search.x(), self.val.x()),
257 1 => (search.y(), self.val.y()),
258 _ => (search.z(), self.val.z()),
259 };
260
261 let distance_best = dist_3d(search, &pc[&pc.len() - 1]);
262 let border_left = current_search - distance_best;
263 let border_right = current_search + distance_best;
264
265 match comp {
266 Ok(res) => match res {
267 Ordering::Less => {
268 if let Some(ref node) = self.right {
269 if pc.len() < n || border_right >= current_val {
270 node.knearest(search, n, pc);
271 }
272 }
273 }
274 _ => {
275 if let Some(ref node) = self.left {
276 if pc.len() < n || border_left <= current_val {
277 node.knearest(search, n, pc);
278 }
279 }
280 }
281 },
282 Err(_) => {}
283 }
284
285 Self::sort_and_limit(pc, search, n);
286 }
287
288 pub fn in_sphere(&self, sphere: &Sphere, pc: &mut Vec<P>) {
289 if dist_3d(&sphere.center, &self.val) <= sphere.radius.get() {
290 pc.push(self.val.clone());
291 }
292
293 if self.is_leaf() {
294 return;
295 }
296
297 let comp = dimension_compare(&sphere.center, &self.val, self.dimension);
298
299 match comp {
300 Ok(res) => match res {
301 Ordering::Less => {
302 if let Some(ref node) = self.left {
303 node.in_sphere(sphere, pc);
304 }
305 }
306 _ => {
307 if let Some(ref node) = self.right {
308 node.in_sphere(sphere, pc);
309 }
310 }
311 },
312 Err(_) => {}
313 }
314
315 let (current_search, current_val) = match self.dimension {
316 0 => (sphere.x(), self.val.x()),
317 1 => (sphere.y(), self.val.y()),
318 _ => (sphere.z(), self.val.z()),
319 };
320
321 let border_left = current_search - sphere.radius.get();
322 let border_right = current_search + sphere.radius.get();
323
324 match comp {
325 Ok(res) => match res {
326 Ordering::Less => {
327 if let Some(ref node) = self.right {
328 if border_right >= current_val {
329 node.in_sphere(sphere, pc);
330 }
331 }
332 }
333 _ => {
334 if let Some(ref node) = self.left {
335 if border_left <= current_val {
336 node.in_sphere(sphere, pc);
337 }
338 }
339 }
340 },
341 Err(_) => {}
342 }
343 }
344
345 pub fn in_box(&self, box_3d: &Box3D, pc: &mut Vec<P>) {
346 if let (Ok(dist_x), Ok(dist_y), Ok(dist_z)) = (
347 dimension_dist(&box_3d.center, &self.val, 0),
348 dimension_dist(&box_3d.center, &self.val, 1),
349 dimension_dist(&box_3d.center, &self.val, 2),
350 ) {
351 if dist_x <= 0.5 * box_3d.size_x.get()
352 && dist_y <= 0.5 * box_3d.size_y.get()
353 && dist_z <= 0.5 * box_3d.size_z.get()
354 {
355 pc.push(self.val.clone());
356 }
357
358 if self.is_leaf() {
359 return;
360 }
361
362 let comp = dimension_compare(&box_3d.center, &self.val, self.dimension);
363
364 match comp {
365 Ok(res) => match res {
366 Ordering::Less => {
367 if let Some(ref node) = self.left {
368 node.in_box(box_3d, pc);
369 }
370 }
371 _ => {
372 if let Some(ref node) = self.right {
373 node.in_box(box_3d, pc);
374 }
375 }
376 },
377 Err(_) => {}
378 }
379
380 let (current_search, current_val, ref current_size) = match self.dimension {
381 0 => (box_3d.x(), self.val.x(), &box_3d.size_x),
382 1 => (box_3d.y(), self.val.y(), &box_3d.size_y),
383 _ => (box_3d.z(), self.val.z(), &box_3d.size_z),
384 };
385
386 let border_left = current_search - 0.5 * current_size.get();
387 let border_right = current_search + 0.5 * current_size.get();
388
389 match comp {
390 Ok(res) => match res {
391 Ordering::Less => {
392 if let Some(ref node) = self.right {
393 if border_right >= current_val {
394 node.in_box(box_3d, pc);
395 }
396 }
397 }
398 _ => {
399 if let Some(ref node) = self.left {
400 if border_left <= current_val {
401 node.in_box(box_3d, pc);
402 }
403 }
404 }
405 },
406 Err(_) => {}
407 }
408 }
409 }
410
411 fn sort_and_limit<'a, PSearch, PFind>(pc: &'a mut Vec<PFind>, search: &PSearch, max_size: usize)
412 where
413 PSearch: Is3D,
414 PFind: Is3D + Clone,
415 {
416 if pc.len() > max_size {
417 pc.sort_by(|a, b| {
418 sqr_dist_3d(search, a)
419 .partial_cmp(&sqr_dist_3d(search, b))
420 .unwrap_or(Ordering::Equal)
421 });
422 let mut result: Vec<PFind>;
423 result = Vec::new();
424 for i in pc.iter().take(max_size) {
425 result.push(i.clone());
426 }
427 *pc = result;
428 }
429 }
430}