1use std::{collections::BinaryHeap, ops::ControlFlow};
23
24use crate::config::{DEFAULT_NEIGHBOR_QUEUE_CAPACITY, DEFAULT_SEARCH_STACK_CAPACITY};
25use crate::geometry::{Box2D, Point2D};
26use crate::join::{join_core, self_join_core};
27use crate::neighbors::{
28 NeighborNodeState, NeighborQuery2D, NeighborState, NeighborWorkspace, best_first, metric_knn,
29};
30use crate::persistence::{
31 LoadError, ParsedPayload, PayloadError, build_id_to_leaf, parse_index, payload_slice,
32 read_f64_le_unchecked, read_u64_le_unchecked,
33};
34use crate::range::{collect_overlaps, visit_overlaps};
35use crate::traversal::{SearchWorkspace, prefetch_read, upper_bound_level};
36use crate::tree_access::{TreeAccess, leaf_group_range};
37use crate::triangle::{Triangle2, blobs_as_records};
38
39mod raycast;
40mod region;
41mod serializer;
42pub use serializer::Serializer2D;
43
44#[inline]
45fn prefetch_aos_node(entries: &[Box2D], indices: &[usize], node_index: usize, node_size: usize) {
46 if node_index < entries.len() {
47 prefetch_read(entries.as_ptr().wrapping_add(node_index));
48 prefetch_read(indices.as_ptr().wrapping_add(node_index));
49 }
50 let next_line = node_index.saturating_add((64 / std::mem::size_of::<Box2D>()).max(1));
51 if node_size > 1 && next_line < entries.len() {
52 prefetch_read(entries.as_ptr().wrapping_add(next_line));
53 prefetch_read(indices.as_ptr().wrapping_add(next_line));
54 }
55}
56
57pub struct Index2D {
76 pub(crate) node_size: usize,
77 pub(crate) num_items: usize,
78 pub(crate) level_bounds: Vec<usize>,
79 pub(crate) entries: Vec<Box2D>,
80 pub(crate) indices: Vec<usize>,
81}
82
83impl Index2D {
84 pub fn num_items(&self) -> usize {
86 self.num_items
87 }
88
89 pub fn extent(&self) -> Option<Box2D> {
91 self.entries.last().copied()
92 }
93
94 pub fn node_size(&self) -> usize {
96 self.node_size
97 }
98
99 pub fn to_bytes(&self) -> Vec<u8> {
119 let mut out = Vec::new();
120 self.to_bytes_into(&mut out);
121 out
122 }
123
124 pub fn to_bytes_into(&self, out: &mut Vec<u8>) {
146 self.serialize()
147 .to_bytes_into(out)
148 .expect("serialization without payloads cannot fail");
149 }
150
151 pub fn to_bytes_with_payloads<P: AsRef<[u8]>>(
172 &self,
173 payloads: &[P],
174 ) -> Result<Vec<u8>, PayloadError> {
175 self.serialize().payloads(payloads).to_bytes()
176 }
177
178 pub fn to_bytes_with_payloads_into<P: AsRef<[u8]>>(
181 &self,
182 payloads: &[P],
183 out: &mut Vec<u8>,
184 ) -> Result<(), PayloadError> {
185 self.serialize().payloads(payloads).to_bytes_into(out)
186 }
187
188 #[cfg(feature = "stream")]
196 pub fn to_bytes_interleaved(&self) -> Vec<u8> {
197 self.serialize()
198 .interleaved()
199 .to_bytes()
200 .expect("serialization without payloads cannot fail")
201 }
202
203 #[cfg(feature = "stream")]
207 pub fn to_bytes_interleaved_with_payloads<P: AsRef<[u8]>>(
208 &self,
209 payloads: &[P],
210 ) -> Result<Vec<u8>, PayloadError> {
211 self.serialize().interleaved().payloads(payloads).to_bytes()
212 }
213
214 pub fn serialize(&self) -> Serializer2D<'_> {
232 Serializer2D::new(self)
233 }
234
235 pub fn from_triangles<T: Triangle2>(triangles: &[T]) -> Result<Self, crate::BuildError> {
242 let mut builder = crate::Index2DBuilder::new(triangles.len());
243 for t in triangles {
244 builder.add(t.aabb());
245 }
246 builder.finish()
247 }
248
249 pub fn from_bytes(bytes: &[u8]) -> Result<Self, LoadError> {
251 let view = Index2DView::from_bytes(bytes)?;
252
253 let mut level_bounds = Vec::with_capacity(view.level_count);
254 for i in 0..view.level_count {
255 level_bounds.push(view.level_bound_unchecked(i));
256 }
257
258 let mut entries = Vec::with_capacity(view.num_nodes);
259 for i in 0..view.num_nodes {
260 entries.push(view.entry_at_unchecked(i));
261 }
262
263 let mut indices = Vec::with_capacity(view.num_nodes);
264 for i in 0..view.num_nodes {
265 indices.push(view.index_at_unchecked(i));
266 }
267
268 Ok(Self {
269 node_size: view.node_size,
270 num_items: view.num_items,
271 level_bounds,
272 entries,
273 indices,
274 })
275 }
276
277 pub fn search(&self, query: Box2D) -> Vec<usize> {
290 let mut results = Vec::new();
291 self.search_into(query, &mut results);
292 results
293 }
294
295 pub fn search_into(&self, query: Box2D, results: &mut Vec<usize>) {
297 let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
298 self.search_into_stack(query, results, &mut stack);
299 }
300
301 pub fn search_with<'a>(&self, query: Box2D, workspace: &'a mut SearchWorkspace) -> &'a [usize] {
318 self.search_into_stack(query, &mut workspace.results, &mut workspace.stack);
319 &workspace.results
320 }
321
322 pub fn any(&self, query: Box2D) -> bool {
339 self.visit(query, |_| ControlFlow::Break(())).is_break()
340 }
341
342 pub fn first(&self, query: Box2D) -> Option<usize> {
359 match self.visit(query, ControlFlow::Break) {
360 ControlFlow::Break(index) => Some(index),
361 ControlFlow::Continue(()) => None,
362 }
363 }
364
365 pub fn neighbors(&self, point: Point2D, max_results: usize) -> Vec<usize> {
380 self.neighbors_within(point, max_results, f64::INFINITY)
381 }
382
383 pub fn neighbors_within(
385 &self,
386 point: Point2D,
387 max_results: usize,
388 max_distance: f64,
389 ) -> Vec<usize> {
390 let mut results = Vec::new();
391 self.neighbors_into(point, max_results, max_distance, &mut results);
392 results
393 }
394
395 pub fn neighbors_into(
397 &self,
398 point: Point2D,
399 max_results: usize,
400 max_distance: f64,
401 results: &mut Vec<usize>,
402 ) {
403 results.clear();
404 if max_results == 0 {
405 return;
406 }
407 if max_results == 1 {
408 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
409 if let Some(index) =
410 self.nearest_one_with_queue(NeighborQuery2D::Point(point), max_distance, &mut queue)
411 {
412 results.push(index);
413 }
414 return;
415 }
416
417 let mut item_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
418 let mut node_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
419 self.collect_neighbors_with_queues(
420 NeighborQuery2D::Point(point),
421 max_results,
422 max_distance,
423 results,
424 &mut item_queue,
425 &mut node_queue,
426 );
427 }
428
429 pub fn neighbors_with<'a>(
431 &self,
432 point: Point2D,
433 max_results: usize,
434 max_distance: f64,
435 workspace: &'a mut NeighborWorkspace,
436 ) -> &'a [usize] {
437 workspace.results.clear();
438 if max_results == 0 {
439 workspace.queue.clear();
440 workspace.node_queue.clear();
441 return &workspace.results;
442 }
443 if max_results == 1 {
444 workspace.queue.clear();
445 if let Some(index) = self.nearest_one_with_queue(
446 NeighborQuery2D::Point(point),
447 max_distance,
448 &mut workspace.node_queue,
449 ) {
450 workspace.results.push(index);
451 }
452 return &workspace.results;
453 }
454
455 self.collect_neighbors_with_queues(
456 NeighborQuery2D::Point(point),
457 max_results,
458 max_distance,
459 &mut workspace.results,
460 &mut workspace.queue,
461 &mut workspace.node_queue,
462 );
463 &workspace.results
464 }
465
466 pub fn visit_neighbors<B, F>(
471 &self,
472 point: Point2D,
473 max_distance: f64,
474 mut visitor: F,
475 ) -> ControlFlow<B>
476 where
477 F: FnMut(usize, f64) -> ControlFlow<B>,
478 {
479 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
480 self.visit_neighbors_with_queue(
481 NeighborQuery2D::Point(point),
482 max_distance,
483 &mut queue,
484 &mut visitor,
485 )
486 }
487
488 pub fn neighbors_metric<M: Fn(Box2D) -> f64>(
523 &self,
524 metric: M,
525 max_results: usize,
526 max_distance: f64,
527 ) -> Vec<usize> {
528 let mut results = Vec::new();
529 self.neighbors_metric_into(metric, max_results, max_distance, &mut results);
530 results
531 }
532
533 pub fn neighbors_metric_into<M: Fn(Box2D) -> f64>(
535 &self,
536 metric: M,
537 max_results: usize,
538 max_distance: f64,
539 results: &mut Vec<usize>,
540 ) {
541 results.clear();
542 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
543 metric_knn::collect_neighbors(
544 self.entries.len(),
545 self.num_items,
546 self.node_size,
547 |node| self.level_bounds[upper_bound_level(&self.level_bounds, node)],
548 |pos| self.indices[pos],
549 max_results,
550 max_distance,
551 |pos| metric(self.entries[pos]),
552 results,
553 &mut queue,
554 );
555 }
556
557 pub fn visit_neighbors_metric<B, M, F>(
561 &self,
562 metric: M,
563 max_distance: f64,
564 mut visitor: F,
565 ) -> ControlFlow<B>
566 where
567 M: Fn(Box2D) -> f64,
568 F: FnMut(usize, f64) -> ControlFlow<B>,
569 {
570 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
571 metric_knn::visit_neighbors(
572 self.entries.len(),
573 self.num_items,
574 self.node_size,
575 |node| self.level_bounds[upper_bound_level(&self.level_bounds, node)],
576 |pos| self.indices[pos],
577 max_distance,
578 |pos| metric(self.entries[pos]),
579 &mut queue,
580 &mut visitor,
581 )
582 }
583
584 pub fn neighbors_of_box(&self, query: Box2D, max_results: usize) -> Vec<usize> {
604 self.neighbors_of_box_within(query, max_results, f64::INFINITY)
605 }
606
607 pub fn neighbors_of_box_within(
610 &self,
611 query: Box2D,
612 max_results: usize,
613 max_distance: f64,
614 ) -> Vec<usize> {
615 let mut results = Vec::new();
616 self.neighbors_of_box_into(query, max_results, max_distance, &mut results);
617 results
618 }
619
620 pub fn neighbors_of_box_into(
622 &self,
623 query: Box2D,
624 max_results: usize,
625 max_distance: f64,
626 results: &mut Vec<usize>,
627 ) {
628 results.clear();
629 if max_results == 0 {
630 return;
631 }
632 if max_results == 1 {
633 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
634 if let Some(index) =
635 self.nearest_one_with_queue(NeighborQuery2D::Box(query), max_distance, &mut queue)
636 {
637 results.push(index);
638 }
639 return;
640 }
641
642 let mut item_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
643 let mut node_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
644 self.collect_neighbors_with_queues(
645 NeighborQuery2D::Box(query),
646 max_results,
647 max_distance,
648 results,
649 &mut item_queue,
650 &mut node_queue,
651 );
652 }
653
654 pub fn neighbors_of_box_with<'na>(
657 &self,
658 query: Box2D,
659 max_results: usize,
660 max_distance: f64,
661 workspace: &'na mut NeighborWorkspace,
662 ) -> &'na [usize] {
663 workspace.results.clear();
664 if max_results == 0 {
665 workspace.queue.clear();
666 workspace.node_queue.clear();
667 return &workspace.results;
668 }
669 if max_results == 1 {
670 workspace.queue.clear();
671 if let Some(index) = self.nearest_one_with_queue(
672 NeighborQuery2D::Box(query),
673 max_distance,
674 &mut workspace.node_queue,
675 ) {
676 workspace.results.push(index);
677 }
678 return &workspace.results;
679 }
680
681 self.collect_neighbors_with_queues(
682 NeighborQuery2D::Box(query),
683 max_results,
684 max_distance,
685 &mut workspace.results,
686 &mut workspace.queue,
687 &mut workspace.node_queue,
688 );
689 &workspace.results
690 }
691
692 pub fn visit_neighbors_of_box<B, F>(
697 &self,
698 query: Box2D,
699 max_distance: f64,
700 mut visitor: F,
701 ) -> ControlFlow<B>
702 where
703 F: FnMut(usize, f64) -> ControlFlow<B>,
704 {
705 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
706 self.visit_neighbors_with_queue(
707 NeighborQuery2D::Box(query),
708 max_distance,
709 &mut queue,
710 &mut visitor,
711 )
712 }
713
714 pub fn visit<B, F>(&self, query: Box2D, visitor: F) -> ControlFlow<B>
736 where
737 F: FnMut(usize) -> ControlFlow<B>,
738 {
739 let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
740 self.visit_with_stack(query, &mut stack, visitor)
741 }
742
743 pub fn search_iter(&self, query: Box2D) -> Search2DIter<'_> {
768 Search2DIter::new(self, query)
769 }
770
771 pub fn join(&self, other: &Index2D) -> Vec<(usize, usize)> {
797 let mut out = Vec::new();
798 let _: ControlFlow<()> = self.join_with(other, |i, j| {
799 out.push((i, j));
800 ControlFlow::Continue(())
801 });
802 out
803 }
804
805 pub fn join_with<B, F>(&self, other: &Index2D, visitor: F) -> ControlFlow<B>
812 where
813 F: FnMut(usize, usize) -> ControlFlow<B>,
814 {
815 join_core(self, other, visitor)
816 }
817
818 pub fn self_join(&self) -> Vec<(usize, usize)> {
844 let mut out = Vec::new();
845 let _: ControlFlow<()> = self.self_join_with(|i, j| {
846 out.push((i, j));
847 ControlFlow::Continue(())
848 });
849 out
850 }
851
852 pub fn self_join_with<B, F>(&self, visitor: F) -> ControlFlow<B>
857 where
858 F: FnMut(usize, usize) -> ControlFlow<B>,
859 {
860 self_join_core(self, visitor)
861 }
862
863 fn collect_neighbors_with_queues(
864 &self,
865 query: NeighborQuery2D,
866 max_results: usize,
867 max_distance: f64,
868 results: &mut Vec<usize>,
869 item_queue: &mut BinaryHeap<NeighborState>,
870 node_queue: &mut BinaryHeap<NeighborNodeState>,
871 ) {
872 best_first::collect_neighbors_two_queue(
873 self.entries.len(),
874 self.num_items,
875 self.node_size,
876 |n| self.level_bounds[upper_bound_level(&self.level_bounds, n)],
877 |pos| self.indices[pos],
878 max_results,
879 max_distance,
880 |pos| query.distance_squared_to(self.entries[pos]),
881 results,
882 item_queue,
883 node_queue,
884 );
885 }
886
887 fn nearest_one_with_queue(
888 &self,
889 query: NeighborQuery2D,
890 max_distance: f64,
891 queue: &mut BinaryHeap<NeighborNodeState>,
892 ) -> Option<usize> {
893 best_first::nearest_one(
894 self.entries.len(),
895 self.num_items,
896 self.node_size,
897 |n| self.level_bounds[upper_bound_level(&self.level_bounds, n)],
898 |pos| self.indices[pos],
899 max_distance,
900 |pos| query.distance_squared_to(self.entries[pos]),
901 queue,
902 )
903 }
904
905 fn visit_neighbors_with_queue<B, F>(
906 &self,
907 query: NeighborQuery2D,
908 max_distance: f64,
909 queue: &mut BinaryHeap<NeighborState>,
910 visitor: &mut F,
911 ) -> ControlFlow<B>
912 where
913 F: FnMut(usize, f64) -> ControlFlow<B>,
914 {
915 best_first::visit_neighbors(
916 self.entries.len(),
917 self.num_items,
918 self.node_size,
919 |n| self.level_bounds[upper_bound_level(&self.level_bounds, n)],
920 |pos| self.indices[pos],
921 max_distance,
922 |pos| query.distance_squared_to(self.entries[pos]),
923 queue,
924 visitor,
925 )
926 }
927
928 #[doc(hidden)]
930 pub fn visit_with_stack<B, F>(
931 &self,
932 query: Box2D,
933 stack: &mut Vec<usize>,
934 visitor: F,
935 ) -> ControlFlow<B>
936 where
937 F: FnMut(usize) -> ControlFlow<B>,
938 {
939 self.visit_with_stack_impl::<false, B, F>(query, stack, visitor)
945 }
946
947 #[doc(hidden)]
949 pub fn visit_with_stack_prefetch<B, F>(
950 &self,
951 query: Box2D,
952 stack: &mut Vec<usize>,
953 visitor: F,
954 ) -> ControlFlow<B>
955 where
956 F: FnMut(usize) -> ControlFlow<B>,
957 {
958 self.visit_with_stack_impl::<true, B, F>(query, stack, visitor)
959 }
960
961 #[doc(hidden)]
963 pub fn search_into_stack(
964 &self,
965 query: Box2D,
966 results: &mut Vec<usize>,
967 stack: &mut Vec<usize>,
968 ) {
969 self.search_into_stack_contained_impl(query, results, stack);
970 }
971
972 #[doc(hidden)]
974 pub fn search_into_stack_prefetch(
975 &self,
976 query: Box2D,
977 results: &mut Vec<usize>,
978 stack: &mut Vec<usize>,
979 ) {
980 results.clear();
981 if self.num_items == 0 {
982 stack.clear();
983 return;
984 }
985
986 let root = self.entries[self.entries.len() - 1];
987 if query.contains(root) {
988 stack.clear();
989 results.extend_from_slice(&self.indices[..self.num_items]);
990 return;
991 }
992
993 self.search_into_stack_overlaps_impl::<true>(query, results, stack);
994 }
995
996 fn search_into_stack_overlaps_impl<const PREFETCH: bool>(
997 &self,
998 query: Box2D,
999 results: &mut Vec<usize>,
1000 stack: &mut Vec<usize>,
1001 ) {
1002 results.clear();
1003 stack.clear();
1004 if self.num_items == 0 {
1005 return;
1006 }
1007
1008 let mut node_index = self.entries.len() - 1;
1009 let mut level = self.level_bounds.len() - 1;
1010
1011 loop {
1012 let end = (node_index + self.node_size).min(self.level_bounds[level]);
1013 let is_leaf = node_index < self.num_items;
1014 let node_entries = &self.entries[node_index..end];
1015 let node_indices = &self.indices[node_index..end];
1016
1017 if is_leaf {
1018 for (b, &index) in node_entries.iter().zip(node_indices) {
1019 if !b.overlaps(query) {
1020 continue;
1021 }
1022 results.push(index);
1023 }
1024 } else {
1025 let child_level = level - 1;
1026 for (b, &index) in node_entries.iter().zip(node_indices).rev() {
1027 if !b.overlaps(query) {
1028 continue;
1029 }
1030 stack.push(index);
1031 stack.push(child_level);
1032 }
1033 }
1034
1035 if stack.len() > 1 {
1036 if PREFETCH {
1037 prefetch_aos_node(
1038 &self.entries,
1039 &self.indices,
1040 stack[stack.len() - 2],
1041 self.node_size,
1042 );
1043 }
1044 level = stack.pop().unwrap();
1045 node_index = stack.pop().unwrap();
1046 } else {
1047 return;
1048 }
1049 }
1050 }
1051
1052 fn search_into_stack_contained_impl(
1053 &self,
1054 query: Box2D,
1055 results: &mut Vec<usize>,
1056 stack: &mut Vec<usize>,
1057 ) {
1058 results.clear();
1059 stack.clear();
1060 if self.num_items == 0 {
1061 return;
1062 }
1063
1064 const CONTAINED_FLAG: usize = 1usize << (usize::BITS - 1);
1065 const LEVEL_MASK: usize = !CONTAINED_FLAG;
1066
1067 let mut node_index = self.entries.len() - 1;
1068 let mut level = self.level_bounds.len() - 1;
1069 let mut contained = false;
1070
1071 loop {
1072 let end = (node_index + self.node_size).min(self.level_bounds[level]);
1073 let is_leaf = node_index < self.num_items;
1074 let node_entries = &self.entries[node_index..end];
1075 let node_indices = &self.indices[node_index..end];
1076
1077 if contained {
1078 self.extend_contained_leaf_indices(node_index, end, level, results);
1079 } else if is_leaf {
1080 for (b, &index) in node_entries.iter().zip(node_indices) {
1081 if !b.overlaps(query) {
1082 continue;
1083 }
1084 results.push(index);
1085 }
1086 } else {
1087 let child_level = level - 1;
1088 for (b, &index) in node_entries.iter().zip(node_indices).rev() {
1089 if !b.overlaps(query) {
1090 continue;
1091 }
1092 stack.push(index);
1093 let encoded_level = if query.contains(*b) {
1094 child_level | CONTAINED_FLAG
1095 } else {
1096 child_level
1097 };
1098 stack.push(encoded_level);
1099 }
1100 }
1101
1102 if stack.len() > 1 {
1103 prefetch_aos_node(
1104 &self.entries,
1105 &self.indices,
1106 stack[stack.len() - 2],
1107 self.node_size,
1108 );
1109 let encoded_level = stack.pop().unwrap();
1110 level = encoded_level & LEVEL_MASK;
1111 contained = (encoded_level & CONTAINED_FLAG) != 0;
1112 node_index = stack.pop().unwrap();
1113 } else {
1114 return;
1115 }
1116 }
1117 }
1118
1119 #[inline]
1120 fn extend_contained_leaf_indices(
1121 &self,
1122 node_index: usize,
1123 end: usize,
1124 level: usize,
1125 results: &mut Vec<usize>,
1126 ) {
1127 let (start, end) = leaf_group_range(self, node_index, end, level);
1128 results.extend_from_slice(&self.indices[start..end]);
1129 }
1130
1131 fn visit_with_stack_impl<const PREFETCH: bool, B, F>(
1132 &self,
1133 query: Box2D,
1134 stack: &mut Vec<usize>,
1135 mut visitor: F,
1136 ) -> ControlFlow<B>
1137 where
1138 F: FnMut(usize) -> ControlFlow<B>,
1139 {
1140 stack.clear();
1141 if self.num_items == 0 {
1142 return ControlFlow::Continue(());
1143 }
1144
1145 let mut node_index = self.entries.len() - 1;
1146 let mut level = self.level_bounds.len() - 1;
1147
1148 loop {
1149 let end = (node_index + self.node_size).min(self.level_bounds[level]);
1150 let is_leaf = node_index < self.num_items;
1151 let node_entries = &self.entries[node_index..end];
1152 let node_indices = &self.indices[node_index..end];
1153
1154 if is_leaf {
1155 for (b, &index) in node_entries.iter().zip(node_indices) {
1156 if !b.overlaps(query) {
1157 continue;
1158 }
1159 visitor(index)?;
1160 }
1161 } else {
1162 let child_level = level - 1;
1163 for (b, &index) in node_entries.iter().zip(node_indices).rev() {
1164 if !b.overlaps(query) {
1165 continue;
1166 }
1167 stack.push(index);
1168 stack.push(child_level);
1169 }
1170 }
1171
1172 if stack.len() > 1 {
1173 if PREFETCH {
1174 prefetch_aos_node(
1175 &self.entries,
1176 &self.indices,
1177 stack[stack.len() - 2],
1178 self.node_size,
1179 );
1180 }
1181 level = stack.pop().unwrap();
1182 node_index = stack.pop().unwrap();
1183 } else {
1184 return ControlFlow::Continue(());
1185 }
1186 }
1187 }
1188
1189 #[doc(hidden)]
1191 pub fn search_visited(&self, query: Box2D) -> (usize, usize) {
1192 let mut results = 0usize;
1193 let mut visited = 0usize;
1194 if self.num_items == 0 {
1195 return (0, 0);
1196 }
1197
1198 let mut node_index = self.entries.len() - 1;
1199 let mut level = self.level_bounds.len() - 1;
1200 let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
1201
1202 loop {
1203 let end = (node_index + self.node_size).min(self.level_bounds[level]);
1204 let is_leaf = node_index < self.num_items;
1205 for pos in node_index..end {
1206 visited += 1;
1207 let b = &self.entries[pos];
1208 if !b.overlaps(query) {
1209 continue;
1210 }
1211 let index = self.indices[pos];
1212 if is_leaf {
1213 results += 1;
1214 } else {
1215 stack.push(index);
1216 stack.push(level - 1);
1217 }
1218 }
1219
1220 if stack.len() > 1 {
1221 level = stack.pop().unwrap();
1222 node_index = stack.pop().unwrap();
1223 } else {
1224 return (results, visited);
1225 }
1226 }
1227 }
1228}
1229
1230pub struct Index2DView<'a> {
1249 node_size: usize,
1250 num_items: usize,
1251 num_nodes: usize,
1252 level_count: usize,
1253 level_bounds: Vec<usize>,
1255 entries: &'a [u8],
1256 indices: &'a [u8],
1257 payload: Option<ParsedPayload<'a>>,
1258 id_to_leaf: Option<Vec<u32>>,
1261}
1262
1263impl<'a> Index2DView<'a> {
1264 pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, LoadError> {
1280 let (parsed, payload) = parse_index(bytes, 2, 8)?;
1281 let id_to_leaf = payload
1284 .is_some()
1285 .then(|| build_id_to_leaf(parsed.indices, parsed.num_items));
1286 Ok(Self {
1287 node_size: parsed.node_size,
1288 num_items: parsed.num_items,
1289 num_nodes: parsed.num_nodes,
1290 level_count: parsed.level_count,
1291 level_bounds: parsed.level_bounds,
1292 entries: parsed.entries,
1293 indices: parsed.indices,
1294 payload,
1295 id_to_leaf,
1296 })
1297 }
1298
1299 pub fn has_payload(&self) -> bool {
1301 self.payload.is_some()
1302 }
1303
1304 pub fn payload(&self, id: usize) -> Option<&'a [u8]> {
1307 let payload = self.payload.as_ref()?;
1308 let id_to_leaf = self.id_to_leaf.as_ref()?;
1309 let leaf_rank = *id_to_leaf.get(id)? as usize;
1310 Some(payload_slice(payload, leaf_rank))
1311 }
1312
1313 pub fn triangles<T: Triangle2>(&self) -> Option<&'a [T]> {
1320 let payload = self.payload.as_ref()?;
1321 if payload.stride != T::STRIDE {
1322 return None;
1323 }
1324 blobs_as_records::<T>(payload.blobs)
1325 }
1326
1327 pub fn triangle<T: Triangle2>(&self, id: usize) -> Option<T> {
1333 let payload = self.payload.as_ref()?;
1334 if payload.stride != T::STRIDE {
1335 return None;
1336 }
1337 let id_to_leaf = self.id_to_leaf.as_ref()?;
1338 let leaf_rank = *id_to_leaf.get(id)? as usize;
1339 Some(T::read_le(payload_slice(payload, leaf_rank)))
1340 }
1341
1342 pub fn search_payloads(&self, query: Box2D) -> Vec<(usize, &'a [u8])> {
1348 let mut out = Vec::new();
1349 if self.payload.is_none() {
1350 return out;
1351 }
1352 for id in self.search(query) {
1353 if let Some(blob) = self.payload(id) {
1354 out.push((id, blob));
1355 }
1356 }
1357 out
1358 }
1359
1360 pub fn num_items(&self) -> usize {
1362 self.num_items
1363 }
1364
1365 pub fn extent(&self) -> Option<Box2D> {
1367 if self.num_items == 0 {
1368 None
1369 } else {
1370 Some(self.entry_at_unchecked(self.num_nodes - 1))
1371 }
1372 }
1373
1374 pub fn node_size(&self) -> usize {
1376 self.node_size
1377 }
1378
1379 pub fn search(&self, query: Box2D) -> Vec<usize> {
1381 let mut results = Vec::new();
1382 self.search_into(query, &mut results);
1383 results
1384 }
1385
1386 pub fn search_into(&self, query: Box2D, results: &mut Vec<usize>) {
1388 let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
1389 self.search_into_stack(query, results, &mut stack);
1390 }
1391
1392 pub fn search_with<'b>(&self, query: Box2D, workspace: &'b mut SearchWorkspace) -> &'b [usize] {
1394 self.search_into_stack(query, &mut workspace.results, &mut workspace.stack);
1395 &workspace.results
1396 }
1397
1398 pub fn any(&self, query: Box2D) -> bool {
1400 self.visit(query, |_| ControlFlow::Break(())).is_break()
1401 }
1402
1403 pub fn first(&self, query: Box2D) -> Option<usize> {
1405 match self.visit(query, ControlFlow::Break) {
1406 ControlFlow::Break(index) => Some(index),
1407 ControlFlow::Continue(()) => None,
1408 }
1409 }
1410
1411 pub fn neighbors(&self, point: Point2D, max_results: usize) -> Vec<usize> {
1413 self.neighbors_within(point, max_results, f64::INFINITY)
1414 }
1415
1416 pub fn neighbors_within(
1418 &self,
1419 point: Point2D,
1420 max_results: usize,
1421 max_distance: f64,
1422 ) -> Vec<usize> {
1423 let mut results = Vec::new();
1424 self.neighbors_into(point, max_results, max_distance, &mut results);
1425 results
1426 }
1427
1428 pub fn neighbors_into(
1430 &self,
1431 point: Point2D,
1432 max_results: usize,
1433 max_distance: f64,
1434 results: &mut Vec<usize>,
1435 ) {
1436 results.clear();
1437 if max_results == 0 {
1438 return;
1439 }
1440 if max_results == 1 {
1441 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1442 if let Some(index) =
1443 self.nearest_one_with_queue(NeighborQuery2D::Point(point), max_distance, &mut queue)
1444 {
1445 results.push(index);
1446 }
1447 return;
1448 }
1449
1450 let mut item_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1451 let mut node_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1452 self.collect_neighbors_with_queues(
1453 NeighborQuery2D::Point(point),
1454 max_results,
1455 max_distance,
1456 results,
1457 &mut item_queue,
1458 &mut node_queue,
1459 );
1460 }
1461
1462 pub fn neighbors_with<'b>(
1464 &self,
1465 point: Point2D,
1466 max_results: usize,
1467 max_distance: f64,
1468 workspace: &'b mut NeighborWorkspace,
1469 ) -> &'b [usize] {
1470 workspace.results.clear();
1471 if max_results == 0 {
1472 workspace.queue.clear();
1473 workspace.node_queue.clear();
1474 return &workspace.results;
1475 }
1476 if max_results == 1 {
1477 workspace.queue.clear();
1478 if let Some(index) = self.nearest_one_with_queue(
1479 NeighborQuery2D::Point(point),
1480 max_distance,
1481 &mut workspace.node_queue,
1482 ) {
1483 workspace.results.push(index);
1484 }
1485 return &workspace.results;
1486 }
1487
1488 self.collect_neighbors_with_queues(
1489 NeighborQuery2D::Point(point),
1490 max_results,
1491 max_distance,
1492 &mut workspace.results,
1493 &mut workspace.queue,
1494 &mut workspace.node_queue,
1495 );
1496 &workspace.results
1497 }
1498
1499 pub fn visit_neighbors<B, F>(
1501 &self,
1502 point: Point2D,
1503 max_distance: f64,
1504 mut visitor: F,
1505 ) -> ControlFlow<B>
1506 where
1507 F: FnMut(usize, f64) -> ControlFlow<B>,
1508 {
1509 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1510 self.visit_neighbors_with_queue(
1511 NeighborQuery2D::Point(point),
1512 max_distance,
1513 &mut queue,
1514 &mut visitor,
1515 )
1516 }
1517
1518 pub fn neighbors_metric<M: Fn(Box2D) -> f64>(
1524 &self,
1525 metric: M,
1526 max_results: usize,
1527 max_distance: f64,
1528 ) -> Vec<usize> {
1529 let mut results = Vec::new();
1530 self.neighbors_metric_into(metric, max_results, max_distance, &mut results);
1531 results
1532 }
1533
1534 pub fn neighbors_metric_into<M: Fn(Box2D) -> f64>(
1536 &self,
1537 metric: M,
1538 max_results: usize,
1539 max_distance: f64,
1540 results: &mut Vec<usize>,
1541 ) {
1542 results.clear();
1543 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1544 metric_knn::collect_neighbors(
1545 self.num_nodes,
1546 self.num_items,
1547 self.node_size,
1548 |node| self.level_bound_unchecked(self.upper_bound_level(node)),
1549 |pos| self.index_at_unchecked(pos),
1550 max_results,
1551 max_distance,
1552 |pos| metric(self.entry_at_unchecked(pos)),
1553 results,
1554 &mut queue,
1555 );
1556 }
1557
1558 pub fn visit_neighbors_metric<B, M, F>(
1563 &self,
1564 metric: M,
1565 max_distance: f64,
1566 mut visitor: F,
1567 ) -> ControlFlow<B>
1568 where
1569 M: Fn(Box2D) -> f64,
1570 F: FnMut(usize, f64) -> ControlFlow<B>,
1571 {
1572 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1573 metric_knn::visit_neighbors(
1574 self.num_nodes,
1575 self.num_items,
1576 self.node_size,
1577 |node| self.level_bound_unchecked(self.upper_bound_level(node)),
1578 |pos| self.index_at_unchecked(pos),
1579 max_distance,
1580 |pos| metric(self.entry_at_unchecked(pos)),
1581 &mut queue,
1582 &mut visitor,
1583 )
1584 }
1585
1586 pub fn neighbors_of_box(&self, query: Box2D, max_results: usize) -> Vec<usize> {
1606 self.neighbors_of_box_within(query, max_results, f64::INFINITY)
1607 }
1608
1609 pub fn neighbors_of_box_within(
1612 &self,
1613 query: Box2D,
1614 max_results: usize,
1615 max_distance: f64,
1616 ) -> Vec<usize> {
1617 let mut results = Vec::new();
1618 self.neighbors_of_box_into(query, max_results, max_distance, &mut results);
1619 results
1620 }
1621
1622 pub fn neighbors_of_box_into(
1624 &self,
1625 query: Box2D,
1626 max_results: usize,
1627 max_distance: f64,
1628 results: &mut Vec<usize>,
1629 ) {
1630 results.clear();
1631 if max_results == 0 {
1632 return;
1633 }
1634 if max_results == 1 {
1635 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1636 if let Some(index) =
1637 self.nearest_one_with_queue(NeighborQuery2D::Box(query), max_distance, &mut queue)
1638 {
1639 results.push(index);
1640 }
1641 return;
1642 }
1643
1644 let mut item_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1645 let mut node_queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1646 self.collect_neighbors_with_queues(
1647 NeighborQuery2D::Box(query),
1648 max_results,
1649 max_distance,
1650 results,
1651 &mut item_queue,
1652 &mut node_queue,
1653 );
1654 }
1655
1656 pub fn neighbors_of_box_with<'na>(
1659 &self,
1660 query: Box2D,
1661 max_results: usize,
1662 max_distance: f64,
1663 workspace: &'na mut NeighborWorkspace,
1664 ) -> &'na [usize] {
1665 workspace.results.clear();
1666 if max_results == 0 {
1667 workspace.queue.clear();
1668 workspace.node_queue.clear();
1669 return &workspace.results;
1670 }
1671 if max_results == 1 {
1672 workspace.queue.clear();
1673 if let Some(index) = self.nearest_one_with_queue(
1674 NeighborQuery2D::Box(query),
1675 max_distance,
1676 &mut workspace.node_queue,
1677 ) {
1678 workspace.results.push(index);
1679 }
1680 return &workspace.results;
1681 }
1682
1683 self.collect_neighbors_with_queues(
1684 NeighborQuery2D::Box(query),
1685 max_results,
1686 max_distance,
1687 &mut workspace.results,
1688 &mut workspace.queue,
1689 &mut workspace.node_queue,
1690 );
1691 &workspace.results
1692 }
1693
1694 pub fn visit_neighbors_of_box<B, F>(
1699 &self,
1700 query: Box2D,
1701 max_distance: f64,
1702 mut visitor: F,
1703 ) -> ControlFlow<B>
1704 where
1705 F: FnMut(usize, f64) -> ControlFlow<B>,
1706 {
1707 let mut queue = BinaryHeap::with_capacity(DEFAULT_NEIGHBOR_QUEUE_CAPACITY);
1708 self.visit_neighbors_with_queue(
1709 NeighborQuery2D::Box(query),
1710 max_distance,
1711 &mut queue,
1712 &mut visitor,
1713 )
1714 }
1715
1716 pub fn visit<B, F>(&self, query: Box2D, visitor: F) -> ControlFlow<B>
1718 where
1719 F: FnMut(usize) -> ControlFlow<B>,
1720 {
1721 let mut stack: Vec<usize> = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
1722 self.visit_with_stack(query, &mut stack, visitor)
1723 }
1724
1725 pub fn join(&self, other: &Index2DView<'_>) -> Vec<(usize, usize)> {
1728 let mut out = Vec::new();
1729 let _: ControlFlow<()> = self.join_with(other, |i, j| {
1730 out.push((i, j));
1731 ControlFlow::Continue(())
1732 });
1733 out
1734 }
1735
1736 pub fn join_with<B, F>(&self, other: &Index2DView<'_>, visitor: F) -> ControlFlow<B>
1739 where
1740 F: FnMut(usize, usize) -> ControlFlow<B>,
1741 {
1742 join_core(self, other, visitor)
1743 }
1744
1745 pub fn self_join(&self) -> Vec<(usize, usize)> {
1748 let mut out = Vec::new();
1749 let _: ControlFlow<()> = self.self_join_with(|i, j| {
1750 out.push((i, j));
1751 ControlFlow::Continue(())
1752 });
1753 out
1754 }
1755
1756 pub fn self_join_with<B, F>(&self, visitor: F) -> ControlFlow<B>
1759 where
1760 F: FnMut(usize, usize) -> ControlFlow<B>,
1761 {
1762 self_join_core(self, visitor)
1763 }
1764
1765 fn collect_neighbors_with_queues(
1766 &self,
1767 query: NeighborQuery2D,
1768 max_results: usize,
1769 max_distance: f64,
1770 results: &mut Vec<usize>,
1771 item_queue: &mut BinaryHeap<NeighborState>,
1772 node_queue: &mut BinaryHeap<NeighborNodeState>,
1773 ) {
1774 best_first::collect_neighbors_two_queue(
1775 self.num_nodes,
1776 self.num_items,
1777 self.node_size,
1778 |n| self.level_bound_unchecked(self.upper_bound_level(n)),
1779 |pos| self.index_at_unchecked(pos),
1780 max_results,
1781 max_distance,
1782 |pos| query.distance_squared_to(self.entry_at_unchecked(pos)),
1783 results,
1784 item_queue,
1785 node_queue,
1786 );
1787 }
1788
1789 fn nearest_one_with_queue(
1790 &self,
1791 query: NeighborQuery2D,
1792 max_distance: f64,
1793 queue: &mut BinaryHeap<NeighborNodeState>,
1794 ) -> Option<usize> {
1795 best_first::nearest_one(
1796 self.num_nodes,
1797 self.num_items,
1798 self.node_size,
1799 |n| self.level_bound_unchecked(self.upper_bound_level(n)),
1800 |pos| self.index_at_unchecked(pos),
1801 max_distance,
1802 |pos| query.distance_squared_to(self.entry_at_unchecked(pos)),
1803 queue,
1804 )
1805 }
1806
1807 #[doc(hidden)]
1808 pub fn search_into_stack(
1809 &self,
1810 query: Box2D,
1811 results: &mut Vec<usize>,
1812 stack: &mut Vec<usize>,
1813 ) {
1814 collect_overlaps(self, query, results, stack);
1815 }
1816
1817 #[doc(hidden)]
1818 pub fn visit_with_stack<B, F>(
1819 &self,
1820 query: Box2D,
1821 stack: &mut Vec<usize>,
1822 visitor: F,
1823 ) -> ControlFlow<B>
1824 where
1825 F: FnMut(usize) -> ControlFlow<B>,
1826 {
1827 visit_overlaps(self, query, stack, visitor)
1828 }
1829
1830 fn visit_neighbors_with_queue<B, F>(
1831 &self,
1832 query: NeighborQuery2D,
1833 max_distance: f64,
1834 queue: &mut BinaryHeap<NeighborState>,
1835 visitor: &mut F,
1836 ) -> ControlFlow<B>
1837 where
1838 F: FnMut(usize, f64) -> ControlFlow<B>,
1839 {
1840 best_first::visit_neighbors(
1841 self.num_nodes,
1842 self.num_items,
1843 self.node_size,
1844 |n| self.level_bound_unchecked(self.upper_bound_level(n)),
1845 |pos| self.index_at_unchecked(pos),
1846 max_distance,
1847 |pos| query.distance_squared_to(self.entry_at_unchecked(pos)),
1848 queue,
1849 visitor,
1850 )
1851 }
1852
1853 fn upper_bound_level(&self, node_index: usize) -> usize {
1854 let mut lo = 0usize;
1855 let mut hi = self.level_count - 1;
1856 while lo < hi {
1857 let mid = (lo + hi) / 2;
1858 if self.level_bound_unchecked(mid) > node_index {
1859 hi = mid;
1860 } else {
1861 lo = mid + 1;
1862 }
1863 }
1864 lo
1865 }
1866
1867 #[inline]
1868 fn level_bound_unchecked(&self, index: usize) -> usize {
1869 self.level_bounds[index]
1870 }
1871
1872 #[inline]
1873 fn entry_at_unchecked(&self, index: usize) -> Box2D {
1874 let offset = index * 32;
1875 Box2D::new(
1876 read_f64_le_unchecked(self.entries, offset),
1877 read_f64_le_unchecked(self.entries, offset + 8),
1878 read_f64_le_unchecked(self.entries, offset + 16),
1879 read_f64_le_unchecked(self.entries, offset + 24),
1880 )
1881 }
1882
1883 #[inline]
1884 fn index_at_unchecked(&self, index: usize) -> usize {
1885 read_u64_le_unchecked(self.indices, index * 8) as usize
1886 }
1887}
1888
1889impl TreeAccess for Index2D {
1890 type Bounds = Box2D;
1891
1892 #[inline]
1893 fn tree_num_items(&self) -> usize {
1894 self.num_items
1895 }
1896 #[inline]
1897 fn tree_num_nodes(&self) -> usize {
1898 self.entries.len()
1899 }
1900 #[inline]
1901 fn tree_node_size(&self) -> usize {
1902 self.node_size
1903 }
1904 #[inline]
1905 fn tree_level_count(&self) -> usize {
1906 self.level_bounds.len()
1907 }
1908 #[inline]
1909 fn tree_level_bound(&self, level: usize) -> usize {
1910 self.level_bounds[level]
1911 }
1912 #[inline]
1913 fn tree_bounds(&self, pos: usize) -> Box2D {
1914 self.entries[pos]
1915 }
1916 #[inline]
1917 fn tree_index(&self, pos: usize) -> usize {
1918 self.indices[pos]
1919 }
1920 #[inline]
1921 fn bounds_overlap(a: Box2D, b: Box2D) -> bool {
1922 a.overlaps(b)
1923 }
1924 #[inline]
1925 fn bounds_contain(outer: Box2D, inner: Box2D) -> bool {
1926 outer.contains(inner)
1927 }
1928}
1929
1930impl TreeAccess for Index2DView<'_> {
1931 type Bounds = Box2D;
1932
1933 #[inline]
1934 fn tree_num_items(&self) -> usize {
1935 self.num_items
1936 }
1937 #[inline]
1938 fn tree_num_nodes(&self) -> usize {
1939 self.num_nodes
1940 }
1941 #[inline]
1942 fn tree_node_size(&self) -> usize {
1943 self.node_size
1944 }
1945 #[inline]
1946 fn tree_level_count(&self) -> usize {
1947 self.level_count
1948 }
1949 #[inline]
1950 fn tree_level_bound(&self, level: usize) -> usize {
1951 self.level_bound_unchecked(level)
1952 }
1953 #[inline]
1954 fn tree_bounds(&self, pos: usize) -> Box2D {
1955 self.entry_at_unchecked(pos)
1956 }
1957 #[inline]
1958 fn tree_index(&self, pos: usize) -> usize {
1959 self.index_at_unchecked(pos)
1960 }
1961 #[inline]
1962 fn bounds_overlap(a: Box2D, b: Box2D) -> bool {
1963 a.overlaps(b)
1964 }
1965 #[inline]
1966 fn bounds_contain(outer: Box2D, inner: Box2D) -> bool {
1967 outer.contains(inner)
1968 }
1969}
1970
1971pub struct Search2DIter<'a> {
1978 index: &'a Index2D,
1979 query: Box2D,
1980 stack: Vec<usize>,
1982 leaf_pos: usize,
1984 leaf_end: usize,
1985}
1986
1987impl<'a> Search2DIter<'a> {
1988 fn new(index: &'a Index2D, query: Box2D) -> Self {
1989 let mut stack = Vec::with_capacity(DEFAULT_SEARCH_STACK_CAPACITY);
1990 if index.num_items != 0 {
1991 stack.push(index.entries.len() - 1);
1993 stack.push(index.level_bounds.len() - 1);
1994 }
1995 Self {
1996 index,
1997 query,
1998 stack,
1999 leaf_pos: 0,
2000 leaf_end: 0,
2001 }
2002 }
2003}
2004
2005impl Iterator for Search2DIter<'_> {
2006 type Item = usize;
2007
2008 fn next(&mut self) -> Option<usize> {
2009 let index = self.index;
2010 loop {
2011 while self.leaf_pos < self.leaf_end {
2013 let at = self.leaf_pos;
2014 self.leaf_pos += 1;
2015 if index.entries[at].overlaps(self.query) {
2016 return Some(index.indices[at]);
2017 }
2018 }
2019
2020 if self.stack.len() < 2 {
2022 return None;
2023 }
2024 let level = self.stack.pop().unwrap();
2025 let node_index = self.stack.pop().unwrap();
2026 let end = (node_index + index.node_size).min(index.level_bounds[level]);
2027
2028 if node_index < index.num_items {
2029 self.leaf_pos = node_index;
2031 self.leaf_end = end;
2032 } else {
2033 let child_level = level - 1;
2036 for (b, &child) in index.entries[node_index..end]
2037 .iter()
2038 .zip(&index.indices[node_index..end])
2039 .rev()
2040 {
2041 if b.overlaps(self.query) {
2042 self.stack.push(child);
2043 self.stack.push(child_level);
2044 }
2045 }
2046 }
2047 }
2048 }
2049
2050 fn size_hint(&self) -> (usize, Option<usize>) {
2051 (0, Some(self.index.num_items))
2053 }
2054}
2055
2056impl std::iter::FusedIterator for Search2DIter<'_> {}