1use std::cmp::Reverse;
2use std::collections::{BinaryHeap, VecDeque};
3use std::vec;
4
5#[cfg(feature = "use-geo_0_31")]
6use geo_0_31::algorithm::BoundingRect;
7#[cfg(feature = "use-geo_0_31")]
8use geo_0_31::Geometry;
9use geo_traits::{CoordTrait, RectTrait};
10
11use crate::error::Result;
12use crate::indices::Indices;
13use crate::r#type::IndexableNum;
14#[cfg(feature = "use-geo_0_31")]
15use crate::rtree::distance::DistanceMetric;
16use crate::rtree::index::{RTree, RTreeRef};
17use crate::rtree::traversal::{IntersectionIterator, Node};
18use crate::rtree::util::upper_bound;
19use crate::rtree::RTreeMetadata;
20use crate::GeoIndexError;
21
22pub trait SimpleDistanceMetric<N: IndexableNum> {
26 fn distance(&self, x1: N, y1: N, x2: N, y2: N) -> N;
28
29 fn distance_to_bbox(&self, x: N, y: N, min_x: N, min_y: N, max_x: N, max_y: N) -> N;
31
32 fn max_distance(&self) -> N {
34 N::max_value()
35 }
36}
37
38#[cfg(feature = "use-geo_0_31")]
43pub trait GeometryAccessor {
44 fn get_geometry(&self, item_index: usize) -> Option<&Geometry<f64>>;
52}
53
54pub trait RTreeIndex<N: IndexableNum>: Sized {
56 fn boxes(&self) -> &[N];
59
60 fn indices(&self) -> Indices<'_>;
62
63 fn metadata(&self) -> &RTreeMetadata<N>;
65
66 fn num_items(&self) -> u32 {
68 self.metadata().num_items()
69 }
70
71 fn num_nodes(&self) -> usize {
73 self.metadata().num_nodes()
74 }
75
76 fn node_size(&self) -> u16 {
78 self.metadata().node_size()
79 }
80
81 fn level_bounds(&self) -> &[usize] {
85 self.metadata().level_bounds()
86 }
87
88 fn num_levels(&self) -> usize {
90 self.level_bounds().len()
91 }
92
93 fn boxes_at_level(&self, level: usize) -> Result<&[N]> {
96 let level_bounds = self.level_bounds();
97 if level >= level_bounds.len() {
98 return Err(GeoIndexError::General("Level out of bounds".to_string()));
99 }
100 let result = if level == 0 {
101 &self.boxes()[0..level_bounds[0]]
102 } else if level == level_bounds.len() {
103 &self.boxes()[level_bounds[level]..]
104 } else {
105 &self.boxes()[level_bounds[level - 1]..level_bounds[level]]
106 };
107 Ok(result)
108 }
109
110 fn search(&self, min_x: N, min_y: N, max_x: N, max_y: N) -> Vec<u32> {
114 let boxes = self.boxes();
115 let indices = self.indices();
116 if boxes.is_empty() {
117 return vec![];
118 }
119
120 let mut outer_node_index = boxes.len().checked_sub(4);
121
122 let mut queue = VecDeque::with_capacity(self.node_size() as usize);
123 let mut results = vec![];
124
125 while let Some(node_index) = outer_node_index {
126 let end = (node_index + self.node_size() as usize * 4)
128 .min(upper_bound(node_index, self.level_bounds()));
129
130 for pos in (node_index..end).step_by(4) {
132 let (node_min_x, node_min_y, node_max_x, node_max_y) = unsafe {
135 let node_min_x = *boxes.get_unchecked(pos);
136 let node_min_y = *boxes.get_unchecked(pos + 1);
137 let node_max_x = *boxes.get_unchecked(pos + 2);
138 let node_max_y = *boxes.get_unchecked(pos + 3);
139 (node_min_x, node_min_y, node_max_x, node_max_y)
140 };
141
142 if max_x < node_min_x
144 || max_y < node_min_y
145 || min_x > node_max_x
146 || min_y > node_max_y
147 {
148 continue;
149 }
150
151 let index = indices.get(pos >> 2);
152
153 if node_index >= self.num_items() as usize * 4 {
154 queue.push_back(index); } else {
156 results.push(index.try_into().unwrap()); }
159 }
160
161 outer_node_index = queue.pop_front();
162 }
163
164 results
165 }
166
167 fn search_rect(&self, rect: &impl RectTrait<T = N>) -> Vec<u32> {
171 self.search(
172 rect.min().x(),
173 rect.min().y(),
174 rect.max().x(),
175 rect.max().y(),
176 )
177 }
178
179 fn neighbors(
199 &self,
200 x: N,
201 y: N,
202 max_results: Option<usize>,
203 max_distance: Option<N>,
204 ) -> Vec<u32> {
205 struct SimpleSquaredDistance;
207 impl<N: IndexableNum> SimpleDistanceMetric<N> for SimpleSquaredDistance {
208 fn distance(&self, x1: N, y1: N, x2: N, y2: N) -> N {
209 let dx = x2 - x1;
210 let dy = y2 - y1;
211 dx * dx + dy * dy
212 }
213 fn distance_to_bbox(&self, x: N, y: N, min_x: N, min_y: N, max_x: N, max_y: N) -> N {
214 let dx = axis_dist(x, min_x, max_x);
215 let dy = axis_dist(y, min_y, max_y);
216 dx * dx + dy * dy
217 }
218 }
219 let simple_distance = SimpleSquaredDistance;
220 self.neighbors_with_simple_distance(x, y, max_results, max_distance, &simple_distance)
221 }
222
223 fn neighbors_with_simple_distance<M: SimpleDistanceMetric<N> + ?Sized>(
227 &self,
228 x: N,
229 y: N,
230 max_results: Option<usize>,
231 max_distance: Option<N>,
232 distance_metric: &M,
233 ) -> Vec<u32> {
234 let boxes = self.boxes();
235 let indices = self.indices();
236 let max_distance = max_distance.unwrap_or(distance_metric.max_distance());
237
238 let mut outer_node_index = Some(boxes.len() - 4);
239 let mut queue = BinaryHeap::new();
240 let mut results: Vec<u32> = vec![];
241
242 'outer: while let Some(node_index) = outer_node_index {
243 let end = (node_index + self.node_size() as usize * 4)
245 .min(upper_bound(node_index, self.level_bounds()));
246
247 for pos in (node_index..end).step_by(4) {
249 let index = indices.get(pos >> 2);
250
251 let dist = distance_metric.distance_to_bbox(
253 x,
254 y,
255 boxes[pos],
256 boxes[pos + 1],
257 boxes[pos + 2],
258 boxes[pos + 3],
259 );
260
261 if dist > max_distance {
262 continue;
263 }
264
265 if node_index >= self.num_items() as usize * 4 {
266 queue.push(Reverse(NeighborNode {
268 id: index << 1,
269 dist,
270 }));
271 } else {
272 queue.push(Reverse(NeighborNode {
275 id: (index << 1) + 1,
276 dist,
277 }));
278 }
279 }
280
281 while !queue.is_empty() && queue.peek().is_some_and(|val| (val.0.id & 1) != 0) {
283 let dist = queue.peek().unwrap().0.dist;
284 if dist > max_distance {
285 break 'outer;
286 }
287 let item = queue.pop().unwrap();
288 results.push((item.0.id >> 1).try_into().unwrap());
289 if max_results.is_some_and(|max_results| results.len() == max_results) {
290 break 'outer;
291 }
292 }
293
294 if let Some(item) = queue.pop() {
295 outer_node_index = Some(item.0.id >> 1);
296 } else {
297 outer_node_index = None;
298 }
299 }
300
301 results
302 }
303
304 #[cfg(feature = "use-geo_0_31")]
326 fn neighbors_with_distance<M: DistanceMetric<N> + ?Sized>(
327 &self,
328 x: N,
329 y: N,
330 max_results: Option<usize>,
331 max_distance: Option<N>,
332 distance_metric: &M,
333 ) -> Vec<u32> {
334 self.neighbors_with_simple_distance(x, y, max_results, max_distance, distance_metric)
335 }
336
337 fn neighbors_coord(
339 &self,
340 coord: &impl CoordTrait<T = N>,
341 max_results: Option<usize>,
342 max_distance: Option<N>,
343 ) -> Vec<u32> {
344 self.neighbors(coord.x(), coord.y(), max_results, max_distance)
345 }
346
347 #[cfg(feature = "use-geo_0_31")]
349 fn neighbors_coord_with_distance<M: DistanceMetric<N> + ?Sized>(
350 &self,
351 coord: &impl CoordTrait<T = N>,
352 max_results: Option<usize>,
353 max_distance: Option<N>,
354 distance_metric: &M,
355 ) -> Vec<u32> {
356 self.neighbors_with_distance(
357 coord.x(),
358 coord.y(),
359 max_results,
360 max_distance,
361 distance_metric,
362 )
363 }
364
365 #[cfg(feature = "use-geo_0_31")]
397 fn neighbors_geometry<M: DistanceMetric<N> + ?Sized, A: GeometryAccessor + ?Sized>(
398 &self,
399 query_geometry: &Geometry<f64>,
400 max_results: Option<usize>,
401 max_distance: Option<N>,
402 distance_metric: &M,
403 accessor: &A,
404 ) -> Vec<u32> {
405 let boxes = self.boxes();
406 let indices = self.indices();
407 let max_distance = max_distance.unwrap_or(distance_metric.max_distance());
408
409 let bounds = query_geometry.bounding_rect();
411 let (query_min_x, query_min_y, query_max_x, query_max_y) = if let Some(rect) = bounds {
412 let min = rect.min();
413 let max = rect.max();
414 (
415 N::from_f64(min.x).unwrap_or(N::zero()),
416 N::from_f64(min.y).unwrap_or(N::zero()),
417 N::from_f64(max.x).unwrap_or(N::zero()),
418 N::from_f64(max.y).unwrap_or(N::zero()),
419 )
420 } else {
421 (N::zero(), N::zero(), N::zero(), N::zero())
423 };
424
425 let mut outer_node_index = Some(boxes.len() - 4);
426 let mut queue = BinaryHeap::new();
427 let mut results: Vec<u32> = vec![];
428
429 'outer: while let Some(node_index) = outer_node_index {
430 let end = (node_index + self.node_size() as usize * 4)
432 .min(upper_bound(node_index, self.level_bounds()));
433
434 for pos in (node_index..end).step_by(4) {
436 let index = indices.get(pos >> 2);
437
438 let dist = if node_index >= self.num_items() as usize * 4 {
439 let center_x = (query_min_x + query_max_x) / (N::one() + N::one());
441 let center_y = (query_min_y + query_max_y) / (N::one() + N::one());
442
443 distance_metric.distance_to_bbox(
444 center_x,
445 center_y,
446 boxes[pos],
447 boxes[pos + 1],
448 boxes[pos + 2],
449 boxes[pos + 3],
450 )
451 } else {
452 if let Some(item_geom) = accessor.get_geometry(index) {
454 distance_metric.distance_to_geometry(query_geometry, item_geom)
455 } else {
456 distance_metric.max_distance()
457 }
458 };
459
460 if dist > max_distance {
461 continue;
462 }
463
464 if node_index >= self.num_items() as usize * 4 {
465 queue.push(Reverse(NeighborNode {
467 id: index << 1,
468 dist,
469 }));
470 } else {
471 queue.push(Reverse(NeighborNode {
473 id: (index << 1) + 1,
474 dist,
475 }));
476 }
477 }
478
479 while !queue.is_empty() && queue.peek().is_some_and(|val| (val.0.id & 1) != 0) {
481 let dist = queue.peek().unwrap().0.dist;
482 if dist > max_distance {
483 break 'outer;
484 }
485 let item = queue.pop().unwrap();
486 results.push((item.0.id >> 1).try_into().unwrap());
487 if max_results.is_some_and(|max_results| results.len() == max_results) {
488 break 'outer;
489 }
490 }
491
492 if let Some(item) = queue.pop() {
493 outer_node_index = Some(item.0.id >> 1);
494 } else {
495 outer_node_index = None;
496 }
497 }
498
499 results
500 }
501
502 fn intersection_candidates_with_other_tree<'a>(
507 &'a self,
508 other: &'a impl RTreeIndex<N>,
509 ) -> impl Iterator<Item = (u32, u32)> + 'a {
510 IntersectionIterator::from_trees(self, other)
511 }
512
513 fn root(&self) -> Node<'_, N, Self> {
515 Node::from_root(self)
516 }
517}
518
519#[derive(Debug, Clone, Copy, PartialEq)]
521struct NeighborNode<N: IndexableNum> {
522 id: usize,
523 dist: N,
524}
525
526impl<N: IndexableNum> Eq for NeighborNode<N> {}
527
528impl<N: IndexableNum> Ord for NeighborNode<N> {
529 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
530 self.dist.partial_cmp(&other.dist).unwrap()
532 }
533}
534
535impl<N: IndexableNum> PartialOrd for NeighborNode<N> {
536 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
537 Some(self.cmp(other))
538 }
539}
540
541impl<N: IndexableNum> RTreeIndex<N> for RTree<N> {
542 fn boxes(&self) -> &[N] {
543 self.metadata.boxes_slice(&self.buffer)
544 }
545
546 fn indices(&self) -> Indices<'_> {
547 self.metadata.indices_slice(&self.buffer)
548 }
549
550 fn metadata(&self) -> &RTreeMetadata<N> {
551 &self.metadata
552 }
553}
554
555impl<N: IndexableNum> RTreeIndex<N> for RTreeRef<'_, N> {
556 fn boxes(&self) -> &[N] {
557 self.boxes
558 }
559
560 fn indices(&self) -> Indices<'_> {
561 self.indices
562 }
563
564 fn metadata(&self) -> &RTreeMetadata<N> {
565 &self.metadata
566 }
567}
568
569#[inline]
571pub(crate) fn axis_dist<N: IndexableNum>(k: N, min: N, max: N) -> N {
572 if k < min {
573 min - k
574 } else if k <= max {
575 N::zero()
576 } else {
577 k - max
578 }
579}
580
581#[cfg(test)]
582mod test {
583 mod js {
585 use crate::rtree::RTreeIndex;
586 use crate::test::{flatbush_js_test_data, flatbush_js_test_index};
587
588 #[test]
589 fn performs_bbox_search() {
590 let data = flatbush_js_test_data();
591 let index = flatbush_js_test_index();
592 let ids = index.search(40., 40., 60., 60.);
593
594 let mut results: Vec<usize> = vec![];
595 for id in ids {
596 results.push(data[4 * id as usize] as usize);
597 results.push(data[4 * id as usize + 1] as usize);
598 results.push(data[4 * id as usize + 2] as usize);
599 results.push(data[4 * id as usize + 3] as usize);
600 }
601
602 results.sort();
603
604 let mut expected = vec![
605 57, 59, 58, 59, 48, 53, 52, 56, 40, 42, 43, 43, 43, 41, 47, 43,
606 ];
607 expected.sort();
608
609 assert_eq!(results, expected);
610 }
611 }
612
613 #[cfg(feature = "use-geo_0_31")]
614 mod distance_metrics {
615 use crate::rtree::distance::{EuclideanDistance, HaversineDistance};
616 use crate::rtree::r#trait::SimpleDistanceMetric;
617 use crate::rtree::sort::HilbertSort;
618 use crate::rtree::{RTreeBuilder, RTreeIndex};
619
620 #[test]
621 fn test_euclidean_distance_neighbors() {
622 let mut builder = RTreeBuilder::<f64>::new(3);
623 builder.add(0., 0., 1., 1.);
624 builder.add(2., 2., 3., 3.);
625 builder.add(4., 4., 5., 5.);
626 let tree = builder.finish::<HilbertSort>();
627
628 let euclidean = EuclideanDistance;
629 let results = tree.neighbors_with_distance(0., 0., None, None, &euclidean);
630
631 assert_eq!(results, vec![0, 1, 2]);
633 }
634
635 #[test]
636 fn test_haversine_distance_neighbors() {
637 let mut builder = RTreeBuilder::<f64>::new(3);
638 builder.add(-74.0, 40.7, -74.0, 40.7); builder.add(-0.1, 51.5, -0.1, 51.5); builder.add(139.7, 35.7, 139.7, 35.7); let tree = builder.finish::<HilbertSort>();
643
644 let haversine = HaversineDistance::default();
645 let results = tree.neighbors_with_distance(-74.0, 40.7, None, None, &haversine);
646
647 assert_eq!(results, vec![0, 1, 2]);
649 }
650
651 #[test]
652 fn test_backward_compatibility() {
653 let mut builder = RTreeBuilder::<f64>::new(3);
654 builder.add(0., 0., 1., 1.);
655 builder.add(2., 2., 3., 3.);
656 builder.add(4., 4., 5., 5.);
657 let tree = builder.finish::<HilbertSort>();
658
659 let results_original = tree.neighbors(0., 0., None, None);
661
662 let euclidean = EuclideanDistance;
664 let results_new = tree.neighbors_with_distance(0., 0., None, None, &euclidean);
665
666 assert_eq!(results_original, results_new);
667 }
668
669 #[test]
670 fn test_max_distance_filtering() {
671 let mut builder = RTreeBuilder::<f64>::new(3);
672 builder.add(0., 0., 1., 1.);
673 builder.add(2., 2., 3., 3.);
674 builder.add(10., 10., 11., 11.);
675 let tree = builder.finish::<HilbertSort>();
676
677 let euclidean = EuclideanDistance;
678 let results = tree.neighbors_with_distance(0., 0., None, Some(5.0), &euclidean);
680
681 assert_eq!(results.len(), 2);
683 assert_eq!(results, vec![0, 1]);
684 }
685
686 #[test]
687 #[cfg(feature = "use-geo_0_31")]
688 fn test_geometry_neighbors_euclidean() {
689 use crate::r#type::IndexableNum;
690 use crate::rtree::distance::{DistanceMetric, SliceGeometryAccessor};
691 use geo_0_31::algorithm::{Distance, Euclidean};
692 use geo_0_31::{Geometry, Point};
693
694 let mut builder = RTreeBuilder::<f64>::new(3);
695 builder.add(0., 0., 2., 2.); builder.add(5., 5., 7., 7.); builder.add(10., 10., 12., 12.); let tree = builder.finish::<HilbertSort>();
699
700 let geometries: Vec<Geometry<f64>> = vec![
702 Geometry::Point(Point::new(1.0, 1.0)), Geometry::Point(Point::new(6.0, 6.0)), Geometry::Point(Point::new(11.0, 11.0)), ];
706
707 struct SimpleMetric;
708 impl<N: IndexableNum> SimpleDistanceMetric<N> for SimpleMetric {
709 fn distance(&self, x1: N, y1: N, x2: N, y2: N) -> N {
710 let dx = x2 - x1;
711 let dy = y2 - y1;
712 (dx * dx + dy * dy).sqrt().unwrap_or(N::max_value())
713 }
714 fn distance_to_bbox(
715 &self,
716 x: N,
717 y: N,
718 min_x: N,
719 min_y: N,
720 max_x: N,
721 max_y: N,
722 ) -> N {
723 let dx = if x < min_x {
724 min_x - x
725 } else if x > max_x {
726 x - max_x
727 } else {
728 N::zero()
729 };
730 let dy = if y < min_y {
731 min_y - y
732 } else if y > max_y {
733 y - max_y
734 } else {
735 N::zero()
736 };
737 (dx * dx + dy * dy).sqrt().unwrap_or(N::max_value())
738 }
739 }
740 impl<N: IndexableNum> DistanceMetric<N> for SimpleMetric {
741 fn distance_to_geometry(&self, geom1: &Geometry<f64>, geom2: &Geometry<f64>) -> N {
742 N::from_f64(Euclidean.distance(geom1, geom2)).unwrap_or(N::max_value())
743 }
744 }
745
746 let query_geom = Geometry::Point(Point::new(3.0, 3.0));
747 let metric = SimpleMetric;
748 let accessor = SliceGeometryAccessor::new(&geometries);
749 let results = tree.neighbors_geometry(&query_geom, None, None, &metric, &accessor);
750
751 assert_eq!(results[0], 0);
753 assert_eq!(results[1], 1);
754 assert_eq!(results[2], 2);
755 }
756
757 #[test]
758 #[cfg(feature = "use-geo_0_31")]
759 fn test_geometry_neighbors_linestring() {
760 use crate::r#type::IndexableNum;
761 use crate::rtree::distance::{DistanceMetric, SliceGeometryAccessor};
762 use geo_0_31::algorithm::{Distance, Euclidean};
763 use geo_0_31::{coord, Geometry, LineString, Point};
764
765 let mut builder = RTreeBuilder::<f64>::new(3);
766 builder.add(0., 0., 10., 0.); builder.add(5., 5., 15., 5.); builder.add(0., 10., 10., 10.); let tree = builder.finish::<HilbertSort>();
770
771 let geometries: Vec<Geometry<f64>> = vec![
773 Geometry::LineString(LineString::new(vec![
774 coord! { x: 0.0, y: 0.0 },
775 coord! { x: 10.0, y: 0.0 },
776 ])),
777 Geometry::LineString(LineString::new(vec![
778 coord! { x: 5.0, y: 5.0 },
779 coord! { x: 15.0, y: 5.0 },
780 ])),
781 Geometry::LineString(LineString::new(vec![
782 coord! { x: 0.0, y: 10.0 },
783 coord! { x: 10.0, y: 10.0 },
784 ])),
785 ];
786
787 struct SimpleMetric;
788 impl<N: IndexableNum> SimpleDistanceMetric<N> for SimpleMetric {
789 fn distance(&self, x1: N, y1: N, x2: N, y2: N) -> N {
790 let dx = x2 - x1;
791 let dy = y2 - y1;
792 (dx * dx + dy * dy).sqrt().unwrap_or(N::max_value())
793 }
794 fn distance_to_bbox(
795 &self,
796 x: N,
797 y: N,
798 min_x: N,
799 min_y: N,
800 max_x: N,
801 max_y: N,
802 ) -> N {
803 let dx = if x < min_x {
804 min_x - x
805 } else if x > max_x {
806 x - max_x
807 } else {
808 N::zero()
809 };
810 let dy = if y < min_y {
811 min_y - y
812 } else if y > max_y {
813 y - max_y
814 } else {
815 N::zero()
816 };
817 (dx * dx + dy * dy).sqrt().unwrap_or(N::max_value())
818 }
819 }
820 impl<N: IndexableNum> DistanceMetric<N> for SimpleMetric {
821 fn distance_to_geometry(&self, geom1: &Geometry<f64>, geom2: &Geometry<f64>) -> N {
822 N::from_f64(Euclidean.distance(geom1, geom2)).unwrap_or(N::max_value())
823 }
824 }
825
826 let query_geom = Geometry::Point(Point::new(5.0, 2.0));
827 let metric = SimpleMetric;
828 let accessor = SliceGeometryAccessor::new(&geometries);
829 let results = tree.neighbors_geometry(&query_geom, None, None, &metric, &accessor);
830
831 assert_eq!(results[0], 0);
833 }
834
835 #[test]
836 #[cfg(feature = "use-geo_0_31")]
837 fn test_geometry_neighbors_with_max_results() {
838 use crate::r#type::IndexableNum;
839 use crate::rtree::distance::{DistanceMetric, SliceGeometryAccessor};
840 use geo_0_31::algorithm::{Distance, Euclidean};
841 use geo_0_31::{Geometry, Point};
842
843 let mut builder = RTreeBuilder::<f64>::new(5);
844 for i in 0..5 {
845 let x = (i * 3) as f64;
846 builder.add(x, x, x + 1., x + 1.);
847 }
848 let tree = builder.finish::<HilbertSort>();
849
850 let geometries: Vec<Geometry<f64>> = (0..5)
852 .map(|i| {
853 let x = (i * 3) as f64;
854 Geometry::Point(Point::new(x + 0.5, x + 0.5))
855 })
856 .collect();
857
858 struct SimpleMetric;
859 impl<N: IndexableNum> SimpleDistanceMetric<N> for SimpleMetric {
860 fn distance(&self, x1: N, y1: N, x2: N, y2: N) -> N {
861 let dx = x2 - x1;
862 let dy = y2 - y1;
863 (dx * dx + dy * dy).sqrt().unwrap_or(N::max_value())
864 }
865 fn distance_to_bbox(
866 &self,
867 x: N,
868 y: N,
869 min_x: N,
870 min_y: N,
871 max_x: N,
872 max_y: N,
873 ) -> N {
874 let dx = if x < min_x {
875 min_x - x
876 } else if x > max_x {
877 x - max_x
878 } else {
879 N::zero()
880 };
881 let dy = if y < min_y {
882 min_y - y
883 } else if y > max_y {
884 y - max_y
885 } else {
886 N::zero()
887 };
888 (dx * dx + dy * dy).sqrt().unwrap_or(N::max_value())
889 }
890 }
891 impl<N: IndexableNum> DistanceMetric<N> for SimpleMetric {
892 fn distance_to_geometry(&self, geom1: &Geometry<f64>, geom2: &Geometry<f64>) -> N {
893 N::from_f64(Euclidean.distance(geom1, geom2)).unwrap_or(N::max_value())
894 }
895 }
896
897 let query_geom = Geometry::Point(Point::new(5.0, 5.0));
898 let metric = SimpleMetric;
899 let accessor = SliceGeometryAccessor::new(&geometries);
900 let results = tree.neighbors_geometry(&query_geom, Some(3), None, &metric, &accessor);
901
902 assert_eq!(results.len(), 3);
903 }
905
906 #[test]
907 #[cfg(feature = "use-geo_0_31")]
908 fn test_geometry_neighbors_haversine() {
909 use crate::r#type::IndexableNum;
910 use crate::rtree::distance::{DistanceMetric, SliceGeometryAccessor};
911 use geo_0_31::algorithm::{Centroid, Distance, Haversine};
912 use geo_0_31::{Geometry, Point};
913
914 let mut builder = RTreeBuilder::<f64>::new(3);
915 builder.add(-74.1, 40.6, -74.0, 40.7); builder.add(-0.2, 51.4, -0.1, 51.5); builder.add(139.6, 35.6, 139.7, 35.7); let tree = builder.finish::<HilbertSort>();
920
921 let geometries: Vec<Geometry<f64>> = vec![
922 Geometry::Point(Point::new(-74.0, 40.7)), Geometry::Point(Point::new(-0.1, 51.5)), Geometry::Point(Point::new(139.7, 35.7)), ];
926
927 struct HaversineMetric;
928 impl<N: IndexableNum> SimpleDistanceMetric<N> for HaversineMetric {
929 fn distance(&self, lon1: N, lat1: N, lon2: N, lat2: N) -> N {
930 let p1 = Point::new(lon1.to_f64().unwrap_or(0.0), lat1.to_f64().unwrap_or(0.0));
931 let p2 = Point::new(lon2.to_f64().unwrap_or(0.0), lat2.to_f64().unwrap_or(0.0));
932 N::from_f64(Haversine.distance(p1, p2)).unwrap_or(N::max_value())
933 }
934 fn distance_to_bbox(
935 &self,
936 lon: N,
937 lat: N,
938 min_lon: N,
939 min_lat: N,
940 max_lon: N,
941 max_lat: N,
942 ) -> N {
943 let lon_f = lon.to_f64().unwrap_or(0.0);
944 let lat_f = lat.to_f64().unwrap_or(0.0);
945 let min_lon_f = min_lon.to_f64().unwrap_or(0.0);
946 let min_lat_f = min_lat.to_f64().unwrap_or(0.0);
947 let max_lon_f = max_lon.to_f64().unwrap_or(0.0);
948 let max_lat_f = max_lat.to_f64().unwrap_or(0.0);
949 let closest_lon = lon_f.clamp(min_lon_f, max_lon_f);
950 let closest_lat = lat_f.clamp(min_lat_f, max_lat_f);
951 let point = Point::new(lon_f, lat_f);
952 let closest_point = Point::new(closest_lon, closest_lat);
953 N::from_f64(Haversine.distance(point, closest_point)).unwrap_or(N::max_value())
954 }
955 }
956 impl<N: IndexableNum> DistanceMetric<N> for HaversineMetric {
957 fn distance_to_geometry(&self, geom1: &Geometry<f64>, geom2: &Geometry<f64>) -> N {
958 let c1 = geom1.centroid().unwrap_or(Point::new(0.0, 0.0));
959 let c2 = geom2.centroid().unwrap_or(Point::new(0.0, 0.0));
960 N::from_f64(Haversine.distance(c1, c2)).unwrap_or(N::max_value())
961 }
962 }
963
964 let query_geom = Geometry::Point(Point::new(-74.0, 40.7)); let metric = HaversineMetric;
966 let accessor = SliceGeometryAccessor::new(&geometries);
967 let results = tree.neighbors_geometry(&query_geom, None, None, &metric, &accessor);
968
969 assert_eq!(results[0], 0);
971 }
972 }
973}