1use super::{IndexStats, ProjectionMode, TriangleIndex};
9use crate::cancel::{Cancelled, Runner};
10use crate::mesh::TriangleSource;
11use crate::model::{Bounds3, Point3};
12use serde::{Deserialize, Serialize};
13
14#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
16#[serde(rename_all = "camelCase")]
17#[serde(default)]
18pub struct TreeOptions {
19 pub bucket_size: usize,
21 pub max_depth: usize,
23 pub min_extent: f64,
25}
26
27impl Default for TreeOptions {
28 fn default() -> Self {
29 Self { bucket_size: 16, max_depth: 32, min_extent: 1e-6 }
30 }
31}
32
33#[derive(Clone, Debug, PartialEq)]
34struct Node {
35 bounds: Bounds3,
36 first: u32,
38 second: u32,
40 leaf: bool,
41}
42
43#[derive(Clone, Debug, PartialEq)]
45pub struct TreeIndex {
46 nodes: Vec<Node>,
47 order: Vec<u32>,
48 bounds: Vec<Bounds3>,
49 max_depth: usize,
50 leaf_count: usize,
51}
52
53struct Item {
54 id: u32,
55 bounds: Bounds3,
56 centroid: Point3,
57}
58
59impl TreeIndex {
60 pub fn build(mesh: &dyn TriangleSource, options: TreeOptions) -> Self {
61 let mut sink = crate::cancel::NullSink;
62 let mut runner = Runner::detached(&mut sink);
63 Self::build_with_runner(mesh, options, &mut runner).expect("a detached runner never cancels")
64 }
65
66 pub fn build_with_runner(
70 mesh: &dyn TriangleSource,
71 options: TreeOptions,
72 runner: &mut Runner<'_>,
73 ) -> Result<Self, Cancelled> {
74 let n = mesh.triangle_count();
75 runner.stage("index-build-start", "building triangle index", 0, n as u64)?;
76 let mut items: Vec<Item> = (0..n)
77 .map(|i| {
78 let t = mesh.triangle(i as u32);
79 Item { id: t.id, bounds: t.bounds, centroid: t.centroid() }
80 })
81 .collect();
82 let bounds: Vec<Bounds3> = items.iter().map(|it| it.bounds).collect();
83 let mut tree = Self { nodes: Vec::new(), order: Vec::with_capacity(n), bounds, max_depth: 0, leaf_count: 0 };
84 if n > 0 {
85 let bucket = options.bucket_size.max(1);
86 tree.build_node(&mut items, 0, bucket, &options, runner)?;
87 }
88 runner.stage("index-build-complete", "triangle index built", n as u64, n as u64)?;
89 Ok(tree)
90 }
91
92 fn build_node(
93 &mut self,
94 items: &mut [Item],
95 depth: usize,
96 bucket: usize,
97 options: &TreeOptions,
98 runner: &mut Runner<'_>,
99 ) -> Result<u32, Cancelled> {
100 let bounds = items.iter().fold(Bounds3::empty(), |b, it| b.union(&it.bounds));
101 self.max_depth = self.max_depth.max(depth);
102 let index = self.nodes.len() as u32;
103 let axis = bounds.longest_axis();
104 let extent = bounds.size().axis(axis);
105 if items.len() <= bucket || depth >= options.max_depth || extent < options.min_extent {
106 let first = self.order.len() as u32;
107 items.sort_by_key(|it| it.id);
109 self.order.extend(items.iter().map(|it| it.id));
110 self.nodes.push(Node { bounds, first, second: self.order.len() as u32, leaf: true });
111 self.leaf_count += 1;
112 runner.work(items.len() as u64, "index-build-partition", self.order.len() as u64, self.bounds.len() as u64)?;
113 return Ok(index);
114 }
115 items.sort_by(|a, b| {
118 a.centroid
119 .axis(axis)
120 .partial_cmp(&b.centroid.axis(axis))
121 .unwrap_or(std::cmp::Ordering::Equal)
122 .then(a.id.cmp(&b.id))
123 });
124 let mid = items.len() / 2;
125 self.nodes.push(Node { bounds, first: 0, second: 0, leaf: false });
126 let (left_items, right_items) = items.split_at_mut(mid);
127 let left = self.build_node(left_items, depth + 1, bucket, options, runner)?;
128 let right = self.build_node(right_items, depth + 1, bucket, options, runner)?;
129 self.nodes[index as usize].first = left;
130 self.nodes[index as usize].second = right;
131 Ok(index)
132 }
133
134 pub fn node_count(&self) -> usize {
135 self.nodes.len()
136 }
137}
138
139impl TriangleIndex for TreeIndex {
140 fn query_aabb(&self, query: &Bounds3, mode: ProjectionMode, out: &mut Vec<u32>) {
141 if self.nodes.is_empty() {
142 return;
143 }
144 let start = out.len();
145 let mut stack: Vec<u32> = vec![0];
146 while let Some(index) = stack.pop() {
147 let node = &self.nodes[index as usize];
148 if !mode.overlaps(&node.bounds, query) {
149 continue;
150 }
151 if node.leaf {
152 for &id in &self.order[node.first as usize..node.second as usize] {
153 if mode.overlaps(&self.bounds[id as usize], query) {
154 out.push(id);
155 }
156 }
157 } else {
158 stack.push(node.second);
160 stack.push(node.first);
161 }
162 }
163 out[start..].sort_unstable();
164 }
165
166 fn stats(&self) -> IndexStats {
167 IndexStats {
168 triangle_count: self.bounds.len(),
169 node_count: Some(self.nodes.len()),
170 leaf_count: Some(self.leaf_count),
171 max_depth: Some(self.max_depth),
172 implementation: "median-split-tree".to_string(),
173 }
174 }
175}
176
177#[derive(Clone, Debug, PartialEq)]
179pub enum AnyIndex {
180 Brute(super::BruteForceIndex),
181 Tree(TreeIndex),
182}
183
184impl AnyIndex {
185 pub const TREE_THRESHOLD: usize = 256;
187
188 pub fn build(mesh: &dyn TriangleSource, options: TreeOptions) -> Self {
189 if mesh.triangle_count() < Self::TREE_THRESHOLD {
190 AnyIndex::Brute(super::BruteForceIndex::build(mesh))
191 } else {
192 AnyIndex::Tree(TreeIndex::build(mesh, options))
193 }
194 }
195}
196
197impl TriangleIndex for AnyIndex {
198 fn query_aabb(&self, query: &Bounds3, mode: ProjectionMode, out: &mut Vec<u32>) {
199 match self {
200 AnyIndex::Brute(i) => i.query_aabb(query, mode, out),
201 AnyIndex::Tree(i) => i.query_aabb(query, mode, out),
202 }
203 }
204
205 fn stats(&self) -> IndexStats {
206 match self {
207 AnyIndex::Brute(i) => i.stats(),
208 AnyIndex::Tree(i) => i.stats(),
209 }
210 }
211}