1use crate::algebra::Vector3;
2use crate::{
3 math::{aabb::AxisAlignedBoundingBox, ray::Ray},
4 pool::{Handle, Pool},
5};
6use arrayvec::ArrayVec;
7
8#[derive(Clone, Debug)]
9pub enum OctreeNode {
10 Leaf {
11 indices: Vec<u32>,
12 bounds: AxisAlignedBoundingBox,
13 },
14 Branch {
15 bounds: AxisAlignedBoundingBox,
16 leaves: [Handle<OctreeNode>; 8],
17 },
18}
19
20#[derive(Default, Clone, Debug)]
21pub struct Octree {
22 nodes: Pool<OctreeNode>,
23 root: Handle<OctreeNode>,
24}
25
26impl Octree {
27 pub fn new(triangles: &[[Vector3<f32>; 3]], split_threshold: usize) -> Self {
28 let mut bounds = AxisAlignedBoundingBox::default();
30 for triangle in triangles {
31 for pt in triangle.iter() {
32 bounds.add_point(*pt);
33 }
34 }
35
36 let inflation = 2.0 * f32::EPSILON;
39 bounds.inflate(Vector3::new(inflation, inflation, inflation));
40
41 let mut indices = Vec::new();
43 for i in 0..triangles.len() {
44 indices.push(i as u32);
45 }
46
47 let mut nodes = Pool::new();
48 let root = build_recursive(&mut nodes, triangles, bounds, indices, split_threshold);
49
50 Self { nodes, root }
51 }
52
53 pub fn sphere_query(&self, position: Vector3<f32>, radius: f32, buffer: &mut Vec<u32>) {
54 buffer.clear();
55 self.sphere_recursive_query(self.root, position, radius, buffer);
56 }
57
58 fn sphere_recursive_query(
59 &self,
60 node: Handle<OctreeNode>,
61 position: Vector3<f32>,
62 radius: f32,
63 buffer: &mut Vec<u32>,
64 ) {
65 match self.nodes.borrow(node) {
66 OctreeNode::Leaf { indices, bounds } => {
67 if bounds.is_intersects_sphere(position, radius) {
68 buffer.extend_from_slice(indices)
69 }
70 }
71 OctreeNode::Branch { bounds, leaves } => {
72 if bounds.is_intersects_sphere(position, radius) {
73 for leaf in leaves {
74 self.sphere_recursive_query(*leaf, position, radius, buffer)
75 }
76 }
77 }
78 }
79 }
80
81 pub fn aabb_query(&self, aabb: &AxisAlignedBoundingBox, buffer: &mut Vec<u32>) {
82 buffer.clear();
83 self.aabb_recursive_query(self.root, aabb, buffer);
84 }
85
86 fn aabb_recursive_query(
87 &self,
88 node: Handle<OctreeNode>,
89 aabb: &AxisAlignedBoundingBox,
90 buffer: &mut Vec<u32>,
91 ) {
92 match self.nodes.borrow(node) {
93 OctreeNode::Leaf { indices, bounds } => {
94 if bounds.intersect_aabb(aabb) {
95 buffer.extend_from_slice(indices)
96 }
97 }
98 OctreeNode::Branch { bounds, leaves } => {
99 if bounds.intersect_aabb(aabb) {
100 for leaf in leaves {
101 self.aabb_recursive_query(*leaf, aabb, buffer)
102 }
103 }
104 }
105 }
106 }
107
108 pub fn ray_query(&self, ray: &Ray, buffer: &mut Vec<u32>) {
109 buffer.clear();
110 self.ray_recursive_query(self.root, ray, buffer);
111 }
112
113 fn ray_recursive_query(&self, node: Handle<OctreeNode>, ray: &Ray, buffer: &mut Vec<u32>) {
114 match self.nodes.borrow(node) {
115 OctreeNode::Leaf { indices, bounds } => {
116 if ray.box_intersection(&bounds.min, &bounds.max).is_some() {
117 buffer.extend_from_slice(indices)
118 }
119 }
120 OctreeNode::Branch { bounds, leaves } => {
121 if ray.box_intersection(&bounds.min, &bounds.max).is_some() {
122 for leaf in leaves {
123 self.ray_recursive_query(*leaf, ray, buffer)
124 }
125 }
126 }
127 }
128 }
129
130 pub fn node(&self, handle: Handle<OctreeNode>) -> &OctreeNode {
131 &self.nodes[handle]
132 }
133
134 pub fn nodes(&self) -> &Pool<OctreeNode> {
135 &self.nodes
136 }
137
138 pub fn ray_query_static<const CAP: usize>(
139 &self,
140 ray: &Ray,
141 buffer: &mut ArrayVec<Handle<OctreeNode>, CAP>,
142 ) {
143 buffer.clear();
144 self.ray_recursive_query_static(self.root, ray, buffer);
145 }
146
147 fn ray_recursive_query_static<const CAP: usize>(
148 &self,
149 node: Handle<OctreeNode>,
150 ray: &Ray,
151 buffer: &mut ArrayVec<Handle<OctreeNode>, CAP>,
152 ) {
153 match self.nodes.borrow(node) {
154 OctreeNode::Leaf { bounds, .. } => {
155 if ray.box_intersection(&bounds.min, &bounds.max).is_some() {
156 buffer.push(node);
157 }
158 }
159 OctreeNode::Branch { bounds, leaves } => {
160 if ray.box_intersection(&bounds.min, &bounds.max).is_some() {
161 for leaf in leaves {
162 self.ray_recursive_query_static(*leaf, ray, buffer)
163 }
164 }
165 }
166 }
167 }
168
169 pub fn point_query(&self, point: Vector3<f32>, buffer: &mut Vec<u32>) {
170 buffer.clear();
171 self.point_recursive_query(self.root, point, buffer);
172 }
173
174 fn point_recursive_query(
175 &self,
176 node: Handle<OctreeNode>,
177 point: Vector3<f32>,
178 buffer: &mut Vec<u32>,
179 ) {
180 match self.nodes.borrow(node) {
181 OctreeNode::Leaf { indices, bounds } => {
182 if bounds.is_contains_point(point) {
183 buffer.extend_from_slice(indices)
184 }
185 }
186 OctreeNode::Branch { bounds, leaves } => {
187 if bounds.is_contains_point(point) {
188 for leaf in leaves {
189 self.point_recursive_query(*leaf, point, buffer)
190 }
191 }
192 }
193 }
194 }
195}
196
197fn build_recursive(
198 nodes: &mut Pool<OctreeNode>,
199 triangles: &[[Vector3<f32>; 3]],
200 bounds: AxisAlignedBoundingBox,
201 indices: Vec<u32>,
202 split_threshold: usize,
203) -> Handle<OctreeNode> {
204 if indices.len() <= split_threshold {
205 nodes.spawn(OctreeNode::Leaf { bounds, indices })
206 } else {
207 let mut leaves = [Handle::NONE; 8];
208 let leaf_bounds = bounds.split();
209
210 for i in 0..8 {
211 let mut leaf_indices = Vec::new();
212
213 for index in indices.iter() {
214 let index = *index;
215
216 let triangle_bounds =
217 AxisAlignedBoundingBox::from_points(&triangles[index as usize]);
218
219 if triangle_bounds.intersect_aabb(&bounds) {
220 leaf_indices.push(index);
221 }
222 }
223
224 leaves[i] = build_recursive(
225 nodes,
226 triangles,
227 leaf_bounds[i],
228 leaf_indices,
229 split_threshold,
230 );
231 }
232
233 nodes.spawn(OctreeNode::Branch { leaves, bounds })
234 }
235}