1use crate::bounding_volume::Aabb;
2use crate::math::{Point, Real, Vector, DIM};
3use alloc::{vec, vec::Vec};
4#[cfg(not(feature = "std"))]
5use na::ComplexField;
6
7#[derive(Copy, Clone, Debug, PartialEq, Eq)]
9pub enum VoxelType {
10 Empty,
12 Vertex,
15 #[cfg(feature = "dim3")]
18 Edge,
19 Face,
22 Interior,
25}
26
27#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
28pub struct AxisMask(u8);
30
31bitflags::bitflags! {
32 impl AxisMask: u8 {
34 const X_POS = 1 << 0;
36 const X_NEG = 1 << 1;
38 const Y_POS = 1 << 2;
40 const Y_NEG = 1 << 3;
42 #[cfg(feature= "dim3")]
44 const Z_POS = 1 << 4;
45 #[cfg(feature= "dim3")]
47 const Z_NEG = 1 << 5;
48 }
49}
50
51#[derive(Copy, Clone, Debug, PartialEq, Eq)]
57pub struct OctantPattern;
58
59#[cfg(feature = "dim3")]
68impl OctantPattern {
69 pub const INTERIOR: u32 = 0;
71 pub const VERTEX: u32 = 1;
73 pub const EDGE_X: u32 = 2;
75 pub const EDGE_Y: u32 = 3;
77 pub const EDGE_Z: u32 = 4;
79 pub const FACE_X: u32 = 5;
81 pub const FACE_Y: u32 = 6;
83 pub const FACE_Z: u32 = 7;
85}
86
87#[cfg(feature = "dim2")]
96impl OctantPattern {
97 pub const INTERIOR: u32 = 0;
99 pub const VERTEX: u32 = 1;
101 pub const FACE_X: u32 = 2;
103 pub const FACE_Y: u32 = 3;
105}
106
107#[derive(Copy, Clone, Debug, PartialEq, Eq)]
126#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
127pub struct VoxelState(u8);
128
129impl VoxelState {
130 pub const EMPTY: VoxelState = VoxelState(EMPTY_FACE_MASK);
132 pub const INTERIOR: VoxelState = VoxelState(INTERIOR_FACE_MASK);
134
135 pub const fn is_empty(self) -> bool {
137 self.0 == EMPTY_FACE_MASK
138 }
139
140 pub const fn free_faces(self) -> AxisMask {
143 if self.0 == INTERIOR_FACE_MASK || self.0 == EMPTY_FACE_MASK {
144 AxisMask::empty()
145 } else {
146 AxisMask::from_bits_truncate((!self.0) & INTERIOR_FACE_MASK)
147 }
148 }
149
150 pub const fn voxel_type(self) -> VoxelType {
152 FACES_TO_VOXEL_TYPES[self.0 as usize]
153 }
154
155 pub(crate) const fn feature_mask(self) -> u16 {
157 FACES_TO_FEATURE_MASKS[self.0 as usize]
158 }
159
160 pub(crate) const fn octant_mask(self) -> u32 {
161 FACES_TO_OCTANT_MASKS[self.0 as usize]
162 }
163}
164
165#[derive(Copy, Clone, Debug, PartialEq)]
167pub struct VoxelData {
168 pub linear_id: u32,
173 pub grid_coords: Point<i32>,
175 pub center: Point<Real>,
177 pub state: VoxelState,
179}
180
181#[derive(Clone, Debug)]
191#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
192pub struct Voxels {
193 domain_mins: Point<i32>,
194 domain_maxs: Point<i32>,
195 states: Vec<VoxelState>, voxel_size: Vector<Real>,
197}
198
199impl Voxels {
200 pub fn new(voxel_size: Vector<Real>, grid_coordinates: &[Point<i32>]) -> Self {
205 let mut domain_mins = grid_coordinates[0];
206 let mut domain_maxs = grid_coordinates[0];
207
208 for vox in grid_coordinates {
209 domain_mins = domain_mins.inf(vox);
210 domain_maxs = domain_maxs.sup(vox);
211 }
212
213 domain_maxs += Vector::repeat(1);
214 let dimensions = domain_maxs - domain_mins;
215 let voxels_count = dimensions.product();
216 let mut result = Self {
217 domain_mins,
218 domain_maxs,
219 states: vec![VoxelState::EMPTY; voxels_count as usize],
220 voxel_size,
221 };
222
223 for vox in grid_coordinates {
224 let index = result.linear_index(*vox);
225 result.states[index as usize] = VoxelState::INTERIOR;
226 }
227
228 result.recompute_voxels_data();
229 result
230 }
231
232 pub fn from_points(voxel_size: Vector<Real>, points: &[Point<Real>]) -> Self {
238 let voxels: Vec<_> = points
239 .iter()
240 .map(|pt| {
241 Point::from(
242 pt.coords
243 .component_div(&voxel_size)
244 .map(|x| x.floor() as i32),
245 )
246 })
247 .collect();
248 Self::new(voxel_size, &voxels)
249 }
250
251 pub fn total_memory_size(&self) -> usize {
255 size_of::<Self>() + self.heap_memory_size()
256 }
257
258 pub fn heap_memory_size(&self) -> usize {
260 let Self {
262 domain_mins: _,
263 domain_maxs: _,
264 states: data,
265 voxel_size: _,
266 } = self;
267 data.capacity() * size_of::<VoxelState>()
268 }
269
270 pub fn extents(&self) -> Vector<Real> {
275 self.dimensions()
276 .cast::<Real>()
277 .component_mul(&self.voxel_size)
278 }
279
280 pub fn domain_center(&self) -> Point<Real> {
282 (self
283 .domain_mins
284 .coords
285 .cast::<Real>()
286 .component_mul(&self.voxel_size)
287 + self.extents() / 2.0)
288 .into()
289 }
290
291 pub fn set_voxel_size(&mut self, size: Vector<Real>) {
293 self.voxel_size = size;
294 }
295
296 pub fn domain(&self) -> [&Point<i32>; 2] {
301 [&self.domain_mins, &self.domain_maxs]
302 }
303
304 pub fn dimensions(&self) -> Vector<u32> {
306 (self.domain_maxs - self.domain_mins).map(|e| e as u32)
307 }
308
309 pub fn voxel_size(&self) -> Vector<Real> {
311 self.voxel_size
312 }
313
314 pub fn propagate_voxel_change(
323 &mut self,
324 other: &mut Self,
325 voxel: Point<i32>,
326 origin_shift: Vector<i32>,
327 ) {
328 let center_is_empty = self
329 .get_voxel_state(voxel)
330 .map(|vox| vox.is_empty())
331 .unwrap_or(true);
332 let center_state_delta =
333 other.update_neighbors_state(voxel - origin_shift, center_is_empty);
334
335 if let Some(state_id) = self.get_linear_index(voxel) {
336 self.states[state_id as usize].0 |= center_state_delta.0;
337 }
338 }
339
340 pub fn combine_voxel_states(&mut self, other: &mut Self, origin_shift: Vector<i32>) {
352 let one = Vector::repeat(1);
353
354 let d0 = [self.domain_mins - one, self.domain_maxs + one * 2];
356 let d1 = [
357 other.domain_mins - one + origin_shift,
358 other.domain_maxs + one * 2 + origin_shift,
359 ];
360
361 let d01 = [d0[0].sup(&d1[0]), d0[1].inf(&d1[1])];
362 for i in d01[0].x..d01[1].x {
368 for j in d01[0].y..d01[1].y {
369 #[cfg(feature = "dim2")]
370 let k_range = 0..1;
371 #[cfg(feature = "dim3")]
372 let k_range = d01[0].z..d01[1].z;
373 for _k in k_range {
374 #[cfg(feature = "dim2")]
375 let key0 = Point::new(i, j);
376 #[cfg(feature = "dim3")]
377 let key0 = Point::new(i, j, _k);
378 let key1 = key0 - origin_shift;
379 let id0 = self
380 .get_linear_index(key0)
381 .filter(|id| !self.states[*id as usize].is_empty());
382 let id1 = other
383 .get_linear_index(key1)
384 .filter(|id| !other.states[*id as usize].is_empty());
385
386 match (id0, id1) {
387 (Some(id0), Some(id1)) => {
388 self.states[id0 as usize].0 |= other.states[id1 as usize].0;
389 other.states[id1 as usize].0 |= self.states[id0 as usize].0;
390 }
391 (Some(id0), None) => {
392 self.states[id0 as usize].0 |=
393 other.compute_voxel_neighborhood_bits(key1).0;
394 }
395 (None, Some(id1)) => {
396 other.states[id1 as usize].0 |=
397 self.compute_voxel_neighborhood_bits(key0).0;
398 }
399 (None, None) => { }
400 }
401 }
402 }
403 }
404 }
405
406 fn recompute_voxels_data(&mut self) {
407 for i in 0..self.states.len() {
408 let key = self.voxel_at_id(i as u32);
409 self.states[i] = self.compute_voxel_state(key);
410 }
411 }
412
413 pub fn scaled(mut self, scale: &Vector<Real>) -> Self {
415 self.voxel_size.component_mul_assign(scale);
416 self
417 }
418
419 pub fn try_set_voxel(&mut self, key: Point<i32>, is_filled: bool) -> Option<VoxelState> {
424 let id = self.get_linear_index(key)?;
425 let prev = self.states[id as usize];
426 let new_is_empty = !is_filled;
427
428 if prev.is_empty() ^ new_is_empty {
429 self.states[id as usize] = self.update_neighbors_state(key, new_is_empty);
430 }
431
432 Some(prev)
433 }
434
435 pub fn set_voxel(&mut self, key: Point<i32>, is_filled: bool) -> Option<VoxelState> {
445 if !self.is_voxel_in_bounds(key) && is_filled {
446 let dims = self.dimensions();
447
448 let extra = dims.map(|k| k * 10 / 100);
450 let mut new_domain_mins = self.domain_mins;
451 let mut new_domain_maxs = self.domain_maxs;
452
453 for k in 0..DIM {
454 if key[k] < self.domain_mins[k] {
455 new_domain_mins[k] = key[k] - extra[k] as i32;
456 }
457
458 if key[k] >= self.domain_maxs[k] {
459 new_domain_maxs[k] = key[k] + extra[k] as i32 + 1;
460 }
461 }
462
463 self.resize_domain(new_domain_mins, new_domain_maxs);
464
465 self.try_set_voxel(key, is_filled)
466 } else {
467 self.try_set_voxel(key, is_filled)
468 }
469 }
470
471 pub fn resize_domain(&mut self, domain_mins: Point<i32>, domain_maxs: Point<i32>) {
479 if self.domain_mins == domain_mins && self.domain_maxs == domain_maxs {
480 return;
482 }
483
484 if let Some(new_shape) = self.with_resized_domain(domain_mins, domain_maxs) {
485 *self = new_shape;
486 }
487 }
488
489 #[must_use]
497 pub fn with_resized_domain(
498 &self,
499 domain_mins: Point<i32>,
500 domain_maxs: Point<i32>,
501 ) -> Option<Self> {
502 if self.domain_mins == domain_mins && self.domain_maxs == domain_maxs {
503 return Some(self.clone());
505 }
506
507 let new_dim = domain_maxs - domain_mins;
508 if new_dim.iter().any(|d| *d <= 0) {
509 log::error!("Invalid domain provided for resizing a voxels shape. New domain: {domain_mins:?} - {domain_maxs:?}; new domain size: {new_dim:?}");
510 return None;
511 }
512
513 let new_len = new_dim.iter().map(|x| *x as usize).product();
514
515 let mut new_shape = Self {
516 domain_mins,
517 domain_maxs,
518 states: vec![VoxelState::EMPTY; new_len],
519 voxel_size: self.voxel_size,
520 };
521
522 for i in 0..self.states.len() {
523 let key = self.voxel_at_id(i as u32);
524 let new_i = new_shape.linear_index(key);
525 new_shape.states[new_i as usize] = self.states[i];
526 }
527
528 Some(new_shape)
529 }
530
531 #[cfg(feature = "dim2")]
533 pub fn is_voxel_in_bounds(&self, key: Point<i32>) -> bool {
534 key[0] >= self.domain_mins[1]
535 && key[0] < self.domain_maxs[0]
536 && key[1] >= self.domain_mins[1]
537 && key[1] < self.domain_maxs[1]
538 }
539
540 #[cfg(feature = "dim3")]
542 pub fn is_voxel_in_bounds(&self, key: Point<i32>) -> bool {
543 key[0] >= self.domain_mins[0]
544 && key[0] < self.domain_maxs[0]
545 && key[1] >= self.domain_mins[1]
546 && key[1] < self.domain_maxs[1]
547 && key[2] >= self.domain_mins[2]
548 && key[2] < self.domain_maxs[2]
549 }
550
551 #[must_use]
556 fn update_neighbors_state(&mut self, key: Point<i32>, center_is_empty: bool) -> VoxelState {
557 let mut key_data = 0;
558
559 for k in 0..DIM {
560 let mut left = key;
561 let mut right = key;
562 left[k] -= 1;
563 right[k] += 1;
564
565 if let Some(left_id) = self.get_linear_index(left) {
566 if !self.states[left_id as usize].is_empty() {
567 if center_is_empty {
568 self.states[left_id as usize].0 &= !(1 << (k * 2));
569 } else {
570 self.states[left_id as usize].0 |= 1 << (k * 2);
571 key_data |= 1 << (k * 2 + 1);
572 }
573 }
574 }
575
576 if let Some(right_id) = self.get_linear_index(right) {
577 if !self.states[right_id as usize].is_empty() {
578 if center_is_empty {
579 self.states[right_id as usize].0 &= !(1 << (k * 2 + 1));
580 } else {
581 self.states[right_id as usize].0 |= 1 << (k * 2 + 1);
582 key_data |= 1 << (k * 2);
583 }
584 }
585 }
586 }
587
588 if center_is_empty {
589 VoxelState::EMPTY
590 } else {
591 VoxelState(key_data)
592 }
593 }
594
595 pub fn voxel_aabb(&self, key: Point<i32>) -> Aabb {
597 let center = self.voxel_center(key);
598 let hext = self.voxel_size / 2.0;
599 Aabb::from_half_extents(center, hext)
600 }
601
602 pub fn voxel_state(&self, key: Point<i32>) -> VoxelState {
606 self.states[self.linear_index(key) as usize]
607 }
608
609 pub fn get_voxel_state(&self, key: Point<i32>) -> Option<VoxelState> {
611 Some(self.states[self.get_linear_index(key)? as usize])
612 }
613
614 pub fn voxel_at_point_unchecked(&self, point: Point<Real>) -> Point<i32> {
617 point
618 .coords
619 .component_div(&self.voxel_size)
620 .map(|x| x.floor() as i32)
621 .into()
622 }
623
624 pub fn voxel_at_point(&self, pt: Point<Real>) -> Option<Point<i32>> {
629 let quant = self.voxel_at_point_unchecked(pt);
630 if quant[0] < self.domain_mins[0]
631 || quant[1] < self.domain_mins[1]
632 || quant[0] >= self.domain_maxs[0]
633 || quant[1] >= self.domain_maxs[1]
634 {
635 return None;
636 }
637
638 #[cfg(feature = "dim3")]
639 if quant[2] < self.domain_mins[2] || quant[2] >= self.domain_maxs[2] {
640 return None;
641 }
642
643 Some(quant)
644 }
645
646 pub fn clamp_voxel(&self, key: Point<i32>) -> Point<i32> {
648 key.coords
649 .zip_zip_map(
650 &self.domain_mins.coords,
651 &self.domain_maxs.coords,
652 |k, min, max| k.clamp(min, max - 1),
653 )
654 .into()
655 }
656
657 pub fn voxel_range_intersecting_local_aabb(&self, aabb: &Aabb) -> [Point<i32>; 2] {
664 let mins = aabb
665 .mins
666 .coords
667 .component_div(&self.voxel_size)
668 .map(|x| x.floor() as i32);
669 let maxs = aabb
670 .maxs
671 .coords
672 .component_div(&self.voxel_size)
673 .map(|x| x.ceil() as i32);
674 [mins.into(), maxs.into()]
675 }
676
677 pub fn voxel_range_aabb(&self, mins: Point<i32>, maxs: Point<i32>) -> Aabb {
682 Aabb {
683 mins: mins
684 .cast::<Real>()
685 .coords
686 .component_mul(&self.voxel_size)
687 .into(),
688 maxs: maxs
689 .cast::<Real>()
690 .coords
691 .component_mul(&self.voxel_size)
692 .into(),
693 }
694 }
695
696 pub fn align_aabb_to_grid(&self, aabb: &Aabb) -> Aabb {
701 let mins = aabb
702 .mins
703 .coords
704 .zip_map(&self.voxel_size, |m, sz| (m / sz).floor() * m)
705 .into();
706 let maxs = aabb
707 .maxs
708 .coords
709 .zip_map(&self.voxel_size, |m, sz| (m / sz).ceil() * m)
710 .into();
711 Aabb { mins, maxs }
712 }
713
714 pub fn voxels_intersecting_local_aabb(
718 &self,
719 aabb: &Aabb,
720 ) -> impl Iterator<Item = VoxelData> + '_ {
721 let [mins, maxs] = self.voxel_range_intersecting_local_aabb(aabb);
722 self.voxels_in_range(mins, maxs)
723 }
724
725 pub fn voxels(&self) -> impl Iterator<Item = VoxelData> + '_ {
730 self.voxels_in_range(self.domain_mins, self.domain_maxs)
731 }
732
733 pub fn split_with_box(&self, aabb: &Aabb) -> (Option<Self>, Option<Self>) {
738 let mut in_box = vec![];
740 let mut rest = vec![];
741 for vox in self.voxels() {
742 if !vox.state.is_empty() {
743 if aabb.contains_local_point(&vox.center) {
744 in_box.push(vox.center);
745 } else {
746 rest.push(vox.center);
747 }
748 }
749 }
750
751 let in_box = if !in_box.is_empty() {
752 Some(Voxels::from_points(self.voxel_size, &in_box))
753 } else {
754 None
755 };
756
757 let rest = if !rest.is_empty() {
758 Some(Voxels::from_points(self.voxel_size, &rest))
759 } else {
760 None
761 };
762
763 (in_box, rest)
764 }
765
766 #[cfg(feature = "dim2")]
771 pub fn voxels_in_range(
772 &self,
773 mins: Point<i32>,
774 maxs: Point<i32>,
775 ) -> impl Iterator<Item = VoxelData> + '_ {
776 let mins = mins.coords.sup(&self.domain_mins.coords);
777 let maxs = maxs.coords.inf(&self.domain_maxs.coords);
778
779 (mins[0]..maxs[0]).flat_map(move |ix| {
780 (mins[1]..maxs[1]).map(move |iy| {
781 let grid_coords = Point::new(ix, iy);
782 let vid = self.linear_index(grid_coords);
783 let center =
784 Vector::new(ix as Real + 0.5, iy as Real + 0.5).component_mul(&self.voxel_size);
785 VoxelData {
786 linear_id: vid,
787 grid_coords,
788 center: center.into(),
789 state: self.states[vid as usize],
790 }
791 })
792 })
793 }
794
795 #[cfg(feature = "dim3")]
800 pub fn voxels_in_range(
801 &self,
802 mins: Point<i32>,
803 maxs: Point<i32>,
804 ) -> impl Iterator<Item = VoxelData> + '_ {
805 let mins = mins.coords.sup(&self.domain_mins.coords);
806 let maxs = maxs.coords.inf(&self.domain_maxs.coords);
807
808 (mins[0]..maxs[0]).flat_map(move |ix| {
809 (mins[1]..maxs[1]).flat_map(move |iy| {
810 (mins[2]..maxs[2]).map(move |iz| {
811 let grid_coords = Point::new(ix, iy, iz);
812 let vid = self.linear_index(grid_coords);
813 let center = Vector::new(ix as Real + 0.5, iy as Real + 0.5, iz as Real + 0.5)
814 .component_mul(&self.voxel_size)
815 .into();
816 VoxelData {
817 linear_id: vid,
818 grid_coords,
819 center,
820 state: self.states[vid as usize],
821 }
822 })
823 })
824 })
825 }
826
827 pub fn get_linear_index(&self, key: Point<i32>) -> Option<u32> {
829 if key[0] < self.domain_mins[0]
830 || key[0] >= self.domain_maxs[0]
831 || key[1] < self.domain_mins[1]
832 || key[1] >= self.domain_maxs[1]
833 {
834 return None;
835 }
836
837 #[cfg(feature = "dim3")]
838 if key[2] < self.domain_mins[2] || key[2] >= self.domain_maxs[2] {
839 return None;
840 }
841
842 Some(self.linear_index(key))
843 }
844
845 #[cfg(feature = "dim2")]
847 pub fn linear_index(&self, voxel_key: Point<i32>) -> u32 {
848 let dims = self.dimensions();
849 let rel_key = voxel_key - self.domain_mins;
850 (rel_key.x + rel_key.y * dims[0] as i32) as u32
851 }
852
853 #[cfg(feature = "dim3")]
855 pub fn linear_index(&self, voxel_key: Point<i32>) -> u32 {
856 let dims = self.dimensions();
857 let rel_key = voxel_key - self.domain_mins;
858 rel_key.x as u32 + rel_key.y as u32 * dims[0] + rel_key.z as u32 * dims[0] * dims[1]
859 }
860
861 #[cfg(feature = "dim2")]
863 pub fn voxel_at_id(&self, linear_index: u32) -> Point<i32> {
864 let dim0 = self.domain_maxs[0] - self.domain_mins[0];
865 let y = linear_index as i32 / dim0;
866 let x = linear_index as i32 % dim0;
867 self.domain_mins + Vector::new(x, y)
868 }
869
870 #[cfg(feature = "dim3")]
872 pub fn voxel_at_id(&self, linear_index: u32) -> Point<i32> {
873 let dims = self.dimensions();
874
875 let d0d1 = dims[0] * dims[1];
876 let z = linear_index / d0d1;
877 let y = (linear_index - z * d0d1) / dims[0];
878 let x = linear_index % dims[0];
879 self.domain_mins + Vector::new(x as i32, y as i32, z as i32)
880 }
881
882 pub fn voxel_center(&self, key: Point<i32>) -> Point<Real> {
884 (key.cast::<Real>() + Vector::repeat(0.5))
885 .coords
886 .component_mul(&self.voxel_size)
887 .into()
888 }
889
890 fn compute_voxel_state(&self, key: Point<i32>) -> VoxelState {
891 if self.states[self.linear_index(key) as usize].is_empty() {
892 return VoxelState::EMPTY;
893 }
894
895 self.compute_voxel_neighborhood_bits(key)
896 }
897
898 fn compute_voxel_neighborhood_bits(&self, key: Point<i32>) -> VoxelState {
899 let mut occupied_faces = 0;
900
901 for k in 0..DIM {
902 let (mut prev, mut next) = (key, key);
903 prev[k] -= 1;
904 next[k] += 1;
905
906 if let Some(next_id) = self.get_linear_index(next) {
907 if !self.states[next_id as usize].is_empty() {
908 occupied_faces |= 1 << (k * 2);
909 }
910 }
911 if let Some(prev_id) = self.get_linear_index(prev) {
912 if !self.states[prev_id as usize].is_empty() {
913 occupied_faces |= 1 << (k * 2 + 1);
914 }
915 }
916 }
917
918 VoxelState(occupied_faces)
919 }
920}
921
922#[allow(dead_code)]
925#[cfg(feature = "dim2")]
926#[cfg(test)]
927fn gen_const_tables() {
928 let mut faces_adj_to_vtx = [0usize; 4];
933
934 for fid in 0..4 {
935 let vids = Aabb::FACES_VERTEX_IDS[fid];
936 let key = 1 << fid;
937 faces_adj_to_vtx[vids.0] |= key;
938 faces_adj_to_vtx[vids.1] |= key;
939 }
940
941 std::println!("const FACES_TO_VOXEL_TYPES: [VoxelType; 17] = [");
945 'outer: for i in 0usize..16 {
946 for adjs in faces_adj_to_vtx.iter() {
949 if (*adjs & i) == 0 {
950 std::println!("VoxelType::Vertex,");
951 continue 'outer;
952 }
953 }
954
955 for fid in 0..4 {
958 if ((1 << fid) & i) == 0 {
959 std::println!("VoxelType::Face,");
960 continue 'outer;
961 }
962 }
963 }
964
965 std::println!("VoxelType::Interior,");
967 std::println!("VoxelType::Empty,");
968 std::println!("];");
969
970 std::println!("const FACES_TO_FEATURE_MASKS: [u16; 17] = [");
974 for i in 0usize..16 {
975 let mut vtx_key = 0;
978 for (vid, adjs) in faces_adj_to_vtx.iter().enumerate() {
979 if (*adjs & i) == 0 {
980 vtx_key |= 1 << vid;
981 }
982 }
983
984 if vtx_key != 0 {
985 std::println!("0b{:b},", vtx_key as u16);
986 continue;
987 }
988
989 let mut face_key = 0;
992 for fid in 0..4 {
993 if ((1 << fid) & i) == 0 {
994 face_key |= 1 << fid;
995 }
996 }
997
998 if face_key != 0 {
999 std::println!("0b{:b},", face_key as u16);
1000 continue;
1001 }
1002 }
1003
1004 std::println!("0b{:b},", u16::MAX);
1005 std::println!("0,");
1006 std::println!("];");
1007
1008 std::println!("const FACES_TO_OCTANT_MASKS: [u32; 17] = [");
1012 for i in 0usize..16 {
1013 let mut octant_mask = 0;
1015 let mut set_mask = |mask, octant| {
1016 if (octant_mask >> (octant * 3)) & 0b0111 == 0 {
1018 octant_mask |= mask << (octant * 3);
1019 }
1020 };
1021
1022 for (vid, adjs) in faces_adj_to_vtx.iter().enumerate() {
1023 if (*adjs & i) == 0 {
1024 set_mask(1, vid);
1025 }
1026 }
1027
1028 const FX: u32 = OctantPattern::FACE_X;
1031 const FY: u32 = OctantPattern::FACE_Y;
1032 const FACE_NORMALS: [u32; 4] = [FX, FX, FY, FY];
1033
1034 #[allow(clippy::needless_range_loop)]
1035 for fid in 0..4 {
1036 if ((1 << fid) & i) == 0 {
1037 let vid = Aabb::FACES_VERTEX_IDS[fid];
1038 let mask = FACE_NORMALS[fid];
1039
1040 set_mask(mask, vid.0);
1041 set_mask(mask, vid.1);
1042 }
1043 }
1044 std::println!("0b{:b},", octant_mask);
1045 }
1046 std::println!("0,");
1047 std::println!("];");
1048}
1049
1050#[allow(dead_code)]
1053#[cfg(feature = "dim3")]
1054#[cfg(test)]
1055fn gen_const_tables() {
1056 let mut faces_adj_to_vtx = [0usize; 8];
1061
1062 let mut faces_adj_to_edge = [0usize; 12];
1067
1068 for fid in 0..6 {
1069 let vids = Aabb::FACES_VERTEX_IDS[fid];
1070 let key = 1 << fid;
1071 faces_adj_to_vtx[vids.0] |= key;
1072 faces_adj_to_vtx[vids.1] |= key;
1073 faces_adj_to_vtx[vids.2] |= key;
1074 faces_adj_to_vtx[vids.3] |= key;
1075 }
1076
1077 #[allow(clippy::needless_range_loop)]
1078 for eid in 0..12 {
1079 let evids = Aabb::EDGES_VERTEX_IDS[eid];
1080 for fid in 0..6 {
1081 let fvids = Aabb::FACES_VERTEX_IDS[fid];
1082 if (fvids.0 == evids.0
1083 || fvids.1 == evids.0
1084 || fvids.2 == evids.0
1085 || fvids.3 == evids.0)
1086 && (fvids.0 == evids.1
1087 || fvids.1 == evids.1
1088 || fvids.2 == evids.1
1089 || fvids.3 == evids.1)
1090 {
1091 let key = 1 << fid;
1092 faces_adj_to_edge[eid] |= key;
1093 }
1094 }
1095 }
1096
1097 std::println!("const FACES_TO_VOXEL_TYPES: [VoxelType; 65] = [");
1101 'outer: for i in 0usize..64 {
1102 for adjs in faces_adj_to_vtx.iter() {
1105 if (*adjs & i) == 0 {
1106 std::println!("VoxelType::Vertex,");
1107 continue 'outer;
1108 }
1109 }
1110
1111 for adjs in faces_adj_to_edge.iter() {
1114 if (*adjs & i) == 0 {
1115 std::println!("VoxelType::Edge,");
1116 continue 'outer;
1117 }
1118 }
1119
1120 for fid in 0..6 {
1123 if ((1 << fid) & i) == 0 {
1124 std::println!("VoxelType::Face,");
1125 continue 'outer;
1126 }
1127 }
1128 }
1129
1130 std::println!("VoxelType::Interior,");
1132 std::println!("VoxelType::Empty,");
1133 std::println!("];");
1134
1135 std::println!("const FACES_TO_FEATURE_MASKS: [u16; 65] = [");
1139 for i in 0usize..64 {
1140 let mut vtx_key = 0;
1143 for (vid, adjs) in faces_adj_to_vtx.iter().enumerate() {
1144 if (*adjs & i) == 0 {
1145 vtx_key |= 1 << vid;
1146 }
1147 }
1148
1149 if vtx_key != 0 {
1150 std::println!("0b{:b},", vtx_key as u16);
1151 continue;
1152 }
1153
1154 let mut edge_key = 0;
1157 for (eid, adjs) in faces_adj_to_edge.iter().enumerate() {
1158 if (*adjs & i) == 0 {
1159 edge_key |= 1 << eid;
1160 }
1161 }
1162
1163 if edge_key != 0 {
1164 std::println!("0b{:b},", edge_key as u16);
1165 continue;
1166 }
1167
1168 let mut face_key = 0;
1171 for fid in 0..6 {
1172 if ((1 << fid) & i) == 0 {
1173 face_key |= 1 << fid;
1174 }
1175 }
1176
1177 if face_key != 0 {
1178 std::println!("0b{:b},", face_key as u16);
1179 continue;
1180 }
1181 }
1182
1183 std::println!("0b{:b},", u16::MAX);
1184 std::println!("0,");
1185 std::println!("];");
1186
1187 std::println!("const FACES_TO_OCTANT_MASKS: [u32; 65] = [");
1191 for i in 0usize..64 {
1192 let mut octant_mask = 0;
1194 let mut set_mask = |mask, octant| {
1195 if (octant_mask >> (octant * 3)) & 0b0111 == 0 {
1197 octant_mask |= mask << (octant * 3);
1198 }
1199 };
1200
1201 for (vid, adjs) in faces_adj_to_vtx.iter().enumerate() {
1202 if (*adjs & i) == 0 {
1203 set_mask(1, vid);
1204 }
1205 }
1206
1207 const EX: u32 = OctantPattern::EDGE_X;
1210 const EY: u32 = OctantPattern::EDGE_Y;
1211 const EZ: u32 = OctantPattern::EDGE_Z;
1212 const EDGE_AXIS: [u32; 12] = [EX, EY, EX, EY, EX, EY, EX, EY, EZ, EZ, EZ, EZ];
1213 for (eid, adjs) in faces_adj_to_edge.iter().enumerate() {
1214 if (*adjs & i) == 0 {
1215 let vid = Aabb::EDGES_VERTEX_IDS[eid];
1216 let mask = EDGE_AXIS[eid];
1217
1218 set_mask(mask, vid.0);
1219 set_mask(mask, vid.1);
1220 }
1221 }
1222
1223 const FX: u32 = OctantPattern::FACE_X;
1226 const FY: u32 = OctantPattern::FACE_Y;
1227 const FZ: u32 = OctantPattern::FACE_Z;
1228 const FACE_NORMALS: [u32; 6] = [FX, FX, FY, FY, FZ, FZ];
1229
1230 #[allow(clippy::needless_range_loop)]
1231 for fid in 0..6 {
1232 if ((1 << fid) & i) == 0 {
1233 let vid = Aabb::FACES_VERTEX_IDS[fid];
1234 let mask = FACE_NORMALS[fid];
1235
1236 set_mask(mask, vid.0);
1237 set_mask(mask, vid.1);
1238 set_mask(mask, vid.2);
1239 set_mask(mask, vid.3);
1240 }
1241 }
1242 std::println!("0b{:b},", octant_mask);
1243 }
1244 std::println!("0,");
1245 std::println!("];");
1246}
1247
1248#[cfg(feature = "dim2")]
1250const INTERIOR_FACE_MASK: u8 = 0b0000_1111;
1251#[cfg(feature = "dim3")]
1252const INTERIOR_FACE_MASK: u8 = 0b0011_1111;
1253#[cfg(feature = "dim2")]
1256const EMPTY_FACE_MASK: u8 = 0b0001_0000;
1257#[cfg(feature = "dim3")]
1258const EMPTY_FACE_MASK: u8 = 0b0100_0000;
1259
1260#[cfg(feature = "dim3")]
1267const FACES_TO_VOXEL_TYPES: [VoxelType; 65] = [
1268 VoxelType::Vertex,
1269 VoxelType::Vertex,
1270 VoxelType::Vertex,
1271 VoxelType::Edge,
1272 VoxelType::Vertex,
1273 VoxelType::Vertex,
1274 VoxelType::Vertex,
1275 VoxelType::Edge,
1276 VoxelType::Vertex,
1277 VoxelType::Vertex,
1278 VoxelType::Vertex,
1279 VoxelType::Edge,
1280 VoxelType::Edge,
1281 VoxelType::Edge,
1282 VoxelType::Edge,
1283 VoxelType::Face,
1284 VoxelType::Vertex,
1285 VoxelType::Vertex,
1286 VoxelType::Vertex,
1287 VoxelType::Edge,
1288 VoxelType::Vertex,
1289 VoxelType::Vertex,
1290 VoxelType::Vertex,
1291 VoxelType::Edge,
1292 VoxelType::Vertex,
1293 VoxelType::Vertex,
1294 VoxelType::Vertex,
1295 VoxelType::Edge,
1296 VoxelType::Edge,
1297 VoxelType::Edge,
1298 VoxelType::Edge,
1299 VoxelType::Face,
1300 VoxelType::Vertex,
1301 VoxelType::Vertex,
1302 VoxelType::Vertex,
1303 VoxelType::Edge,
1304 VoxelType::Vertex,
1305 VoxelType::Vertex,
1306 VoxelType::Vertex,
1307 VoxelType::Edge,
1308 VoxelType::Vertex,
1309 VoxelType::Vertex,
1310 VoxelType::Vertex,
1311 VoxelType::Edge,
1312 VoxelType::Edge,
1313 VoxelType::Edge,
1314 VoxelType::Edge,
1315 VoxelType::Face,
1316 VoxelType::Edge,
1317 VoxelType::Edge,
1318 VoxelType::Edge,
1319 VoxelType::Face,
1320 VoxelType::Edge,
1321 VoxelType::Edge,
1322 VoxelType::Edge,
1323 VoxelType::Face,
1324 VoxelType::Edge,
1325 VoxelType::Edge,
1326 VoxelType::Edge,
1327 VoxelType::Face,
1328 VoxelType::Face,
1329 VoxelType::Face,
1330 VoxelType::Face,
1331 VoxelType::Interior,
1332 VoxelType::Empty,
1333];
1334
1335#[cfg(feature = "dim3")]
1346const FACES_TO_FEATURE_MASKS: [u16; 65] = [
1347 0b11111111,
1348 0b10011001,
1349 0b1100110,
1350 0b1010101,
1351 0b110011,
1352 0b10001,
1353 0b100010,
1354 0b10001,
1355 0b11001100,
1356 0b10001000,
1357 0b1000100,
1358 0b1000100,
1359 0b10101010,
1360 0b10001000,
1361 0b100010,
1362 0b110000,
1363 0b1111,
1364 0b1001,
1365 0b110,
1366 0b101,
1367 0b11,
1368 0b1,
1369 0b10,
1370 0b1,
1371 0b1100,
1372 0b1000,
1373 0b100,
1374 0b100,
1375 0b1010,
1376 0b1000,
1377 0b10,
1378 0b100000,
1379 0b11110000,
1380 0b10010000,
1381 0b1100000,
1382 0b1010000,
1383 0b110000,
1384 0b10000,
1385 0b100000,
1386 0b10000,
1387 0b11000000,
1388 0b10000000,
1389 0b1000000,
1390 0b1000000,
1391 0b10100000,
1392 0b10000000,
1393 0b100000,
1394 0b10000,
1395 0b111100000000,
1396 0b100100000000,
1397 0b11000000000,
1398 0b1100,
1399 0b1100000000,
1400 0b100000000,
1401 0b1000000000,
1402 0b1000,
1403 0b110000000000,
1404 0b100000000000,
1405 0b10000000000,
1406 0b100,
1407 0b11,
1408 0b10,
1409 0b1,
1410 0b1111111111111111,
1411 0,
1412];
1413
1414#[cfg(feature = "dim3")]
1416const FACES_TO_OCTANT_MASKS: [u32; 65] = [
1417 0b1001001001001001001001,
1418 0b1010010001001010010001,
1419 0b10001001010010001001010,
1420 0b10010010010010010010010,
1421 0b11011001001011011001001,
1422 0b11111010001011111010001,
1423 0b111011001010111011001010,
1424 0b111111010010111111010010,
1425 0b1001011011001001011011,
1426 0b1010111011001010111011,
1427 0b10001011111010001011111,
1428 0b10010111111010010111111,
1429 0b11011011011011011011011,
1430 0b11111111011011111111011,
1431 0b111011011111111011011111,
1432 0b111111111111111111111111,
1433 0b100100100100001001001001,
1434 0b100110110100001010010001,
1435 0b110100100110010001001010,
1436 0b110110110110010010010010,
1437 0b101101100100011011001001,
1438 0b101000110100011111010001,
1439 0b101100110111011001010,
1440 0b110110111111010010,
1441 0b100100101101001001011011,
1442 0b100110000101001010111011,
1443 0b110100101000010001011111,
1444 0b110110000000010010111111,
1445 0b101101101101011011011011,
1446 0b101000000101011111111011,
1447 0b101101000111011011111,
1448 0b111111111111,
1449 0b1001001001100100100100,
1450 0b1010010001100110110100,
1451 0b10001001010110100100110,
1452 0b10010010010110110110110,
1453 0b11011001001101101100100,
1454 0b11111010001101000110100,
1455 0b111011001010000101100110,
1456 0b111111010010000000110110,
1457 0b1001011011100100101101,
1458 0b1010111011100110000101,
1459 0b10001011111110100101000,
1460 0b10010111111110110000000,
1461 0b11011011011101101101101,
1462 0b11111111011101000000101,
1463 0b111011011111000101101000,
1464 0b111111111111000000000000,
1465 0b100100100100100100100100,
1466 0b100110110100100110110100,
1467 0b110100100110110100100110,
1468 0b110110110110110110110110,
1469 0b101101100100101101100100,
1470 0b101000110100101000110100,
1471 0b101100110000101100110,
1472 0b110110000000110110,
1473 0b100100101101100100101101,
1474 0b100110000101100110000101,
1475 0b110100101000110100101000,
1476 0b110110000000110110000000,
1477 0b101101101101101101101101,
1478 0b101000000101101000000101,
1479 0b101101000000101101000,
1480 0b0,
1481 0,
1482];
1483
1484#[cfg(feature = "dim2")]
1485const FACES_TO_VOXEL_TYPES: [VoxelType; 17] = [
1486 VoxelType::Vertex,
1487 VoxelType::Vertex,
1488 VoxelType::Vertex,
1489 VoxelType::Face,
1490 VoxelType::Vertex,
1491 VoxelType::Vertex,
1492 VoxelType::Vertex,
1493 VoxelType::Face,
1494 VoxelType::Vertex,
1495 VoxelType::Vertex,
1496 VoxelType::Vertex,
1497 VoxelType::Face,
1498 VoxelType::Face,
1499 VoxelType::Face,
1500 VoxelType::Face,
1501 VoxelType::Interior,
1502 VoxelType::Empty,
1503];
1504
1505#[cfg(feature = "dim2")]
1506const FACES_TO_FEATURE_MASKS: [u16; 17] = [
1507 0b1111,
1508 0b1001,
1509 0b110,
1510 0b1100,
1511 0b11,
1512 0b1,
1513 0b10,
1514 0b1000,
1515 0b1100,
1516 0b1000,
1517 0b100,
1518 0b100,
1519 0b11,
1520 0b10,
1521 0b1,
1522 0b1111111111111111,
1523 0,
1524];
1525
1526#[cfg(feature = "dim2")]
1529const FACES_TO_OCTANT_MASKS: [u32; 17] = [
1530 0b1001001001,
1531 0b1011011001,
1532 0b11001001011,
1533 0b11011011011,
1534 0b10010001001,
1535 0b10000011001,
1536 0b10001011,
1537 0b11011,
1538 0b1001010010,
1539 0b1011000010,
1540 0b11001010000,
1541 0b11011000000,
1542 0b10010010010,
1543 0b10000000010,
1544 0b10010000,
1545 0b0,
1546 0,
1547];
1548
1549#[cfg(test)]
1550mod test {
1551 #[test]
1552 fn gen_const_tables() {
1553 super::gen_const_tables();
1554 }
1555}