1use crate::geom::{BoundingBox, Coord, Point, Sphere, Transform, Vector};
82use crate::node::{CubeCounter, Node};
83use std::collections::HashMap;
84#[derive(PartialEq)]
86pub enum CoverageType {
87 None,
88 Partial,
89 Total,
90 Inside,
91}
92
93#[derive(Clone)]
94pub struct MapRoot<C> {
95 pub root: Node<C>,
96 transform: Transform,
97}
98
99pub trait MapLike {
101 fn new(scale: Vector, origin: Point, width: usize) -> Self;
102 fn zero(&mut self);
103}
104
105pub trait AddCoverage {
106 fn add_cov<B: BoxCoverage + Radius>(&mut self, obj: &B, f: &mut dyn FnMut([usize; 3]))
107 -> usize;
108}
109
110pub trait DelCoverage {
111 fn del_cov<B: BoxCoverage + Radius>(&mut self, obj: &B, f: &mut dyn FnMut([usize; 3]))
112 -> usize;
113}
114
115impl AddCoverage for MapRoot<Coverage> {
116 fn add_cov<B: BoxCoverage + Radius>(
117 &mut self,
118 obj: &B,
119 f: &mut dyn FnMut([usize; 3]),
120 ) -> usize {
121 self.root.node_add_cov(&self.transform, obj, f)
122 }
123}
124
125impl AddCoverage for MapRoot<DiffCoverage> {
126 fn add_cov<B: BoxCoverage + Radius>(
127 &mut self,
128 obj: &B,
129 f: &mut dyn FnMut([usize; 3]),
130 ) -> usize {
131 self.root.node_add_cov(&self.transform, obj, f)
132 }
133}
134
135impl DelCoverage for MapRoot<DiffCoverage> {
136 fn del_cov<B: BoxCoverage + Radius>(
137 &mut self,
138 obj: &B,
139 f: &mut dyn FnMut([usize; 3]),
140 ) -> usize {
141 self.root.node_del_cov(&self.transform, obj, f)
142 }
143}
144
145pub trait NodeAddCoverage {
146 fn node_add_cov<B: BoxCoverage + Radius>(
147 &mut self,
148 transform: &Transform,
149 obj: &B,
150 f: &mut dyn FnMut([usize; 3]),
151 ) -> usize;
152}
153
154pub trait NodeDelCoverage {
155 fn node_del_cov<B: BoxCoverage + Radius>(
156 &mut self,
157 transform: &Transform,
158 obj: &B,
159 f: &mut dyn FnMut([usize; 3]),
160 ) -> usize;
161}
162
163impl<C: Default + CoverageCheck> MapLike for MapRoot<C> {
164 fn new(scale: Vector, origin: Point, width: usize) -> MapRoot<C> {
165 Self {
166 root: Node::new([0; 3], width),
167 transform: Transform { origin, scale },
168 }
169 }
170
171 fn zero(&mut self) {
172 self.root.zero();
173 }
174}
175
176pub type DiffCoverageMap = MapRoot<DiffCoverage>;
178
179pub type CoverageMap = MapRoot<Coverage>;
184
185pub struct GridCoverageMap {
186 width: usize,
187 grid_width: usize,
188 transform: Transform,
189 counter_map: HashMap<Coord, CubeCounter>,
190}
191
192impl GridCoverageMap {
193 fn new(scale: Vector, origin: Point, width: usize) -> Self {
194 Self {
195 width,
196 grid_width: 16,
197 transform: Transform { origin, scale },
198 counter_map: HashMap::new(),
199 }
200 }
201
202 fn add_cov<B: BoxCoverage + Radius>(
203 &mut self,
204 sphere: &B,
205 f: &mut dyn FnMut([usize; 3]),
206 ) -> usize {
207 let bb = sphere.bounding_box();
208
209 let lc = self.transform.to_voxel(&bb.lower);
210 let uc = self.transform.to_voxel(&bb.upper);
211
212 let lgx = lc[0] / self.grid_width;
213 let lgy = lc[1] / self.grid_width;
214 let lgz = lc[2] / self.grid_width;
215
216 let ugx = uc[0] / self.grid_width;
217 let ugy = uc[1] / self.grid_width;
218 let ugz = uc[2] / self.grid_width;
219
220 let mut added = 0;
221 for i in lgx..=ugx {
222 for j in lgy..=ugy {
223 for k in lgz..=ugz {
224 let g = self
225 .counter_map
226 .entry([i, j, k])
227 .or_insert_with(|| CubeCounter::new(self.grid_width));
228 if !g.is_covered() {
229 added += g.add_coverage(
230 &[
231 i * self.grid_width,
232 j * self.grid_width,
233 k * self.grid_width,
234 ],
235 self.grid_width,
236 &self.transform,
237 &sphere.point(),
238 sphere.radius(),
239 f,
240 );
241 }
242 }
243 }
244 }
245 added
246 }
247}
248
249impl MapLike for GridCoverageMap {
250 fn new(scale: Vector, origin: Point, width: usize) -> Self {
251 GridCoverageMap::new(scale, origin, width)
252 }
253
254 fn zero(&mut self) {}
255}
256
257impl AddCoverage for GridCoverageMap {
258 fn add_cov<B: BoxCoverage + Radius>(
259 &mut self,
260 obj: &B,
261 f: &mut dyn FnMut([usize; 3]),
262 ) -> usize {
263 GridCoverageMap::add_cov(self, obj, f)
264 }
265}
266
267#[derive(Clone)]
276pub struct NaiveDiffCoverageMap {
277 width: usize,
278 voxel_counters: CubeCounter,
280 transform: Transform,
281}
282
283impl MapLike for NaiveDiffCoverageMap {
284 fn new(scale: Vector, origin: Point, width: usize) -> Self {
285 Self {
286 width,
287 voxel_counters: CubeCounter::new(width),
288 transform: Transform { origin, scale },
289 }
290 }
291
292 fn zero(&mut self) {
293 self.voxel_counters.zero();
294 }
295}
296
297impl AddCoverage for NaiveDiffCoverageMap {
298 fn add_cov<B: BoxCoverage + Radius>(
299 &mut self,
300 obj: &B,
301 f: &mut dyn FnMut([usize; 3]),
302 ) -> usize {
303 self.voxel_counters.add_coverage(
304 &[0; 3],
305 self.width,
306 &self.transform,
307 &obj.point(),
308 obj.radius(),
309 f,
310 )
311 }
312}
313
314impl DelCoverage for NaiveDiffCoverageMap {
315 fn del_cov<B: BoxCoverage + Radius>(
316 &mut self,
317 obj: &B,
318 f: &mut dyn FnMut([usize; 3]),
319 ) -> usize {
320 self.voxel_counters.del_coverage(
321 &[0; 3],
322 self.width,
323 &self.transform,
324 &obj.point(),
325 obj.radius(),
326 f,
327 )
328 }
329}
330impl Sphere {
331 fn inside_coverage(&self, l: &Point, u: &Point) -> bool {
333 self.point[0] - l[0] > self.radius
334 && self.point[1] - l[1] > self.radius
335 && self.point[2] - l[2] > self.radius
336 && u[0] - self.point[0] > self.radius
337 && u[1] - self.point[1] > self.radius
338 && u[2] - self.point[2] > self.radius
339 }
340
341 fn partial_coverage(&self, l: &Point, u: &Point) -> bool {
344 let mut d = self.radius * self.radius;
345 if self.point[0] < l[0] {
346 d -= f64::powf(self.point[0] - l[0], 2.0);
347 } else if self.point[0] > u[0] {
348 d -= f64::powf(self.point[0] - u[0], 2.0);
349 }
350 if d < 0f64 {
351 return false;
352 }
353
354 if self.point[1] < l[1] {
355 d -= f64::powf(self.point[1] - l[1], 2.0);
356 } else if self.point[1] > u[1] {
357 d -= f64::powf(self.point[1] - u[1], 2.0);
358 }
359
360 if d < 0f64 {
361 return false;
362 }
363
364 if self.point[2] < l[2] {
365 d -= f64::powf(self.point[2] - l[2], 2.0);
366 } else if self.point[2] > u[2] {
367 d -= f64::powf(self.point[2] - u[2], 2.0);
368 }
369
370 d > 0f64
371 }
372
373 fn total_coverage(&self, l: &Point, u: &Point) -> bool {
379 let mut d = self.radius * self.radius;
380 let p = self.point;
381
382 d -= f64::max(f64::powf(l[0] - p[0], 2f64), f64::powf(u[0] - p[0], 2f64));
383 d -= f64::max(f64::powf(l[1] - p[1], 2f64), f64::powf(u[1] - p[1], 2f64));
384 d -= f64::max(f64::powf(l[2] - p[2], 2f64), f64::powf(u[2] - p[2], 2f64));
385
386 d > 0f64
387 }
388 fn point_coverage(&self, l: &Point) -> bool {
390 let mut d = self.radius * self.radius;
391 let p = self.point;
392
393 d -= f64::powf(l[0] - p[0], 2f64);
394 d -= f64::powf(l[1] - p[1], 2f64);
395 d -= f64::powf(l[2] - p[2], 2f64);
396
397 d > 0f64
398 }
399}
400
401pub trait Radius {
402 fn radius(&self) -> f64;
403 fn point(&self) -> Point;
404 fn bounding_box(&self) -> BoundingBox;
405}
406
407impl BoxCoverage for Sphere {
408 fn box_coverage(&self, bounding_box: &BoundingBox) -> CoverageType {
409 let l = bounding_box.lower;
410 let u = bounding_box.upper;
411
412 if (l[0] - u[0]).abs() < f64::EPSILON {
414 return if self.point_coverage(&l) {
415 CoverageType::Total
416 } else {
417 CoverageType::None
418 };
419 }
420
421 if self.inside_coverage(&l, &u) {
422 CoverageType::Inside
423 } else if self.total_coverage(&l, &u) {
424 CoverageType::Total
425 } else if self.partial_coverage(&l, &u) {
426 CoverageType::Partial
427 } else {
428 CoverageType::None
429 }
430 }
431 fn partial_coverage(&self, bounding_box: &BoundingBox) -> bool {
434 let l = bounding_box.lower;
435 let u = bounding_box.upper;
436 let mut d = self.radius * self.radius;
437 if self.point[0] < l[0] {
438 d -= f64::powf(self.point[0] - l[0], 2.0);
439 } else if self.point[0] > u[0] {
440 d -= f64::powf(self.point[0] - u[0], 2.0);
441 }
442 if d < 0f64 {
443 return false;
444 }
445
446 if self.point[1] < l[1] {
447 d -= f64::powf(self.point[1] - l[1], 2.0);
448 } else if self.point[1] > u[1] {
449 d -= f64::powf(self.point[1] - u[1], 2.0);
450 }
451
452 if d < 0f64 {
453 return false;
454 }
455
456 if self.point[2] < l[2] {
457 d -= f64::powf(self.point[2] - l[2], 2.0);
458 } else if self.point[2] > u[2] {
459 d -= f64::powf(self.point[2] - u[2], 2.0);
460 }
461
462 d > 0f64
463 }
464
465 fn total_coverage(&self, bounding_box: &BoundingBox) -> bool {
471 let l = bounding_box.lower;
472 let u = bounding_box.upper;
473 let mut d = self.radius * self.radius;
474 let p = self.point;
475
476 d -= f64::max(f64::powf(l[0] - p[0], 2f64), f64::powf(u[0] - p[0], 2f64));
477 d -= f64::max(f64::powf(l[1] - p[1], 2f64), f64::powf(u[1] - p[1], 2f64));
478 d -= f64::max(f64::powf(l[2] - p[2], 2f64), f64::powf(u[2] - p[2], 2f64));
479
480 d > 0f64
481 }
482}
483
484impl Radius for Sphere {
485 fn radius(&self) -> f64 {
486 self.radius
487 }
488
489 fn point(&self) -> Point {
490 self.point
491 }
492
493 fn bounding_box(&self) -> BoundingBox {
494 self.bounding_box()
495 }
496}
497
498pub trait BoxCoverage {
503 fn box_coverage(&self, bounding_box: &BoundingBox) -> CoverageType;
504 fn total_coverage(&self, bounding_box: &BoundingBox) -> bool;
505 fn partial_coverage(&self, bounding_box: &BoundingBox) -> bool;
506}
507
508pub trait CoverageCheck {
509 fn is_covered(&self) -> bool;
510}
511
512#[derive(Default, Clone)]
513pub struct DiffCoverage {
514 partial: usize,
515 coverage: usize,
516}
517
518impl DiffCoverage {
519 fn is_dead(&self) -> bool {
520 !self.is_partial() && !self.is_covered()
521 }
522 fn add_part(&mut self) {
523 self.partial += 1;
524 }
525
526 fn del_part(&mut self) {
527 self.partial -= 1;
528 }
529
530 fn is_partial(&self) -> bool {
531 self.partial > 0
532 }
533
534 fn add_cov(&mut self) {
535 self.coverage += 1;
536 }
537
538 fn del_cov(&mut self) {
539 self.coverage -= 1;
540 }
541}
542
543impl CoverageCheck for DiffCoverage {
544 fn is_covered(&self) -> bool {
545 self.coverage > 0
546 }
547}
548
549#[derive(Default, Clone)]
550pub struct Coverage {
551 covered: bool,
552}
553
554impl Coverage {
555 fn add_cov(&mut self) {
556 self.covered = true;
557 }
558}
559
560impl CoverageCheck for Coverage {
561 fn is_covered(&self) -> bool {
562 self.covered
563 }
564}
565
566impl NodeAddCoverage for Node<DiffCoverage> {
567 fn node_add_cov<B: BoxCoverage + Radius>(
568 &mut self,
569 tf: &Transform,
570 obj: &B,
571 f: &mut dyn FnMut(Coord),
572 ) -> usize {
573 let bounding_box = self.bounding_box(tf);
574 match obj.box_coverage(&bounding_box) {
575 CoverageType::Total => {
576 if !self.coverage.is_covered() {
577 self.coverage.add_cov();
578 if let Some(children) = self.children() {
579 let mut change = 0;
580 for child in children.iter_mut() {
581 change += child.node_add_cov(tf, obj, f);
582 }
583 return change;
584 } else if self.width == 1 {
585 f(self.coord);
586 return 1;
587 }
588 }
589 self.coverage.add_cov();
590 0
591 }
592
593 CoverageType::Inside | CoverageType::Partial => {
594 self.coverage.add_part();
595 let children = self
596 .children()
597 .expect("Partially covered nodes should have children");
598 let mut change = 0;
599 for child in children.iter_mut() {
600 change += child.node_add_cov(tf, obj, f);
601 }
602 change
603 }
604
605 CoverageType::None => 0,
606 }
607 }
608}
609
610impl NodeDelCoverage for Node<DiffCoverage> {
611 fn node_del_cov<B: BoxCoverage + Radius>(
612 &mut self,
613 transform: &Transform,
614 obj: &B,
615 f: &mut dyn FnMut(Coord),
616 ) -> usize {
617 let bounding_box = self.bounding_box(transform);
618 match obj.box_coverage(&bounding_box) {
619 CoverageType::Total => {
620 assert!(
621 self.coverage.is_covered(),
622 "Deleted a sphere which was never added"
623 );
624
625 self.coverage.del_cov();
626
627 if !self.coverage.is_covered() {
628 let mut change = 0;
629 if let Some(children) = self.get_mut_children() {
630 for child in children.iter_mut() {
631 change += child.node_del_cov(transform, obj, f);
632 }
633 return change;
634 } else if self.width == 1 {
635 f(self.coord);
636 return 1;
637 } else {
638 for i in self.coord[0]..self.coord[0] + self.width {
639 for j in self.coord[1]..self.coord[1] + self.width {
640 for k in self.coord[2]..self.coord[2] + self.width {
641 f([i, j, k]);
642 }
643 }
644 }
645 return self.width * self.width * self.width;
646 }
647 }
648 }
649 CoverageType::Inside | CoverageType::Partial => {
650 self.coverage.del_part();
651 if let Some(children) = self.get_mut_children() {
652 let mut change = 0;
653 let mut all_dead = true;
654 for child in children.iter_mut() {
655 change += child.node_del_cov(transform, obj, f);
656 if !child.coverage.is_dead() {
657 all_dead = false;
658 }
659 }
660
661 if all_dead {
662 self.children = None;
663 }
664 return change;
665 }
666 }
667 CoverageType::None => (),
668 }
669 0
670 }
671}
672
673impl Node<Coverage> {
674 fn fold_children(&self, f: &mut dyn FnMut(Coord)) -> usize {
689 if self.coverage.is_covered() {
690 self.width * self.width * self.width
691 } else {
692 let mut voxels_covered = 0;
693 if let Some(children) = self.get_children() {
694 for child in children.iter() {
695 voxels_covered += child.fold_children(f);
696 }
697 } else {
698 for i in self.coord[0]..self.coord[0] + self.width {
699 for j in self.coord[1]..self.coord[1] + self.width {
700 for k in self.coord[2]..self.coord[2] + self.width {
701 f([i, j, k]);
702 }
703 }
704 }
705 }
706 voxels_covered
707 }
708 }
709
710 fn cleanup(&mut self) {
712 if let Some(children) = self.get_mut_children() {
713 let mut every_covered = true;
714 for child in children.iter_mut() {
715 if !child.coverage.is_covered() {
716 every_covered = false;
717 break;
718 }
719 }
720
721 if every_covered {
722 self.children = None;
723 self.coverage.add_cov();
724 }
725 }
726 }
727}
728
729impl NodeAddCoverage for Node<Coverage> {
730 fn node_add_cov<B: BoxCoverage + Radius>(
731 &mut self,
732 transform: &Transform,
733 obj: &B,
734 f: &mut dyn FnMut(Coord),
735 ) -> usize {
736 if self.coverage.is_covered() {
737 return 0;
738 }
739 let bounding_box = self.bounding_box(transform);
740 match obj.box_coverage(&bounding_box) {
741 CoverageType::Total => {
742 let fold = self.fold_children(f);
743 let vol = self.width * self.width * self.width;
744 self.coverage.add_cov();
745 self.children = None;
746 vol - fold
747 }
748
749 CoverageType::Inside | CoverageType::Partial => {
750 let mut change = 0;
751 let children = self
752 .children()
753 .expect("Partially covered nodes should have children");
754 for child in children.iter_mut() {
755 change += child.node_add_cov(transform, obj, f);
756 }
757 self.cleanup();
758 change
759 }
760 CoverageType::None => 0,
761 }
762 }
763}
764
765#[cfg(test)]
766mod tests {
767 use crate::coverage::{
768 AddCoverage, Coverage, CoverageMap, DelCoverage, DiffCoverageMap, MapLike,
769 NaiveDiffCoverageMap, Node, Sphere, Transform,
770 };
771 use approx::relative_eq;
772 use std::collections::HashSet;
773
774 #[test]
775 fn node_to_bounding_box() {
776 let node: Node<Coverage> = Node::new([0; 3], 4);
778
779 let transform = Transform {
782 origin: [0f64; 3],
783 scale: [2.2; 3],
784 };
785
786 let aabb = node.bounding_box(&transform);
790 relative_eq!(aabb.lower[0], 1.1);
791 relative_eq!(aabb.lower[1], 1.1);
792 relative_eq!(aabb.lower[2], 1.1);
793
794 relative_eq!(aabb.upper[0], 7.7);
795 relative_eq!(aabb.upper[1], 7.7);
796 relative_eq!(aabb.upper[2], 7.7);
797 }
798
799 #[test]
800 fn naive_diff_map() {
801 let mut nmt = NaiveDiffCoverageMap::new([1.0120482f64; 3], [-9.0, 11.0, -18.0], 256);
802 assert_eq!(
803 nmt.add_cov(
804 &Sphere::new([35.319, 51.331, 18.794], 4.675f64),
805 &mut |_| ()
806 ),
807 412
808 );
809 assert_eq!(
810 nmt.add_cov(
811 &Sphere::new([34.624, 50.910, 20.029], 4.675f64),
812 &mut |_| ()
813 ),
814 93
815 );
816 }
817
818 #[test]
820 fn diff_map() {
821 let mut mt = DiffCoverageMap::new([1.0120482f64; 3], [-9.0, 11.0, -18.0], 256);
822 assert_eq!(
823 mt.add_cov(
824 &Sphere::new([35.319, 51.331, 18.794], 4.675f64),
825 &mut |_| ()
826 ),
827 412
828 );
829
830 assert_eq!(
831 mt.del_cov(
832 &Sphere::new([35.319, 51.331, 18.794], 4.675f64),
833 &mut |_| ()
834 ),
835 412
836 );
837
838 assert_eq!(
839 mt.add_cov(
840 &Sphere::new([34.624, 50.910, 20.029], 4.675f64),
841 &mut |_| ()
842 ),
843 418
844 );
845 assert_eq!(
846 mt.del_cov(
847 &Sphere::new([34.624, 50.910, 20.029], 4.675f64),
848 &mut |_| ()
849 ),
850 418
851 );
852
853 assert_eq!(
854 mt.add_cov(
855 &Sphere::new([35.227, 49.610, 20.593], 4.675f64),
856 &mut |_| ()
857 ),
858 406
859 );
860 assert_eq!(
861 mt.del_cov(
862 &Sphere::new([35.227, 49.610, 20.593], 4.675f64),
863 &mut |_| ()
864 ),
865 406
866 );
867
868 assert_eq!(
869 mt.add_cov(
870 &Sphere::new([35.319, 51.331, 18.794], 4.675f64),
871 &mut |_| ()
872 ),
873 412
874 );
875 assert_eq!(
876 mt.add_cov(
877 &Sphere::new([34.624, 50.910, 20.029], 4.675f64),
878 &mut |_| ()
879 ),
880 93
881 );
882 assert_eq!(
883 mt.del_cov(
884 &Sphere::new([35.319, 51.331, 18.794], 4.675f64),
885 &mut |_| ()
886 ),
887 87
888 );
889 assert_eq!(
890 mt.del_cov(
891 &Sphere::new([34.624, 50.910, 20.029], 4.675f64),
892 &mut |_| ()
893 ),
894 418
895 );
896 }
897
898 #[test]
899 fn mono_map() {
900 let mut mt = CoverageMap::new([1.0120482f64; 3], [-9.0, 11.0, -18.0], 256);
901 assert_eq!(
902 mt.add_cov(
903 &Sphere::new([35.319, 51.331, 18.794], 4.675f64),
904 &mut |_| ()
905 ),
906 412
907 );
908 assert_eq!(
909 mt.add_cov(
910 &Sphere::new([34.624, 50.910, 20.029], 4.675f64),
911 &mut |_| ()
912 ),
913 93
914 );
915 assert_eq!(
916 mt.add_cov(
917 &Sphere::new([35.227, 49.610, 20.593], 4.675f64),
918 &mut |_| ()
919 ),
920 87
921 );
922 mt.add_cov(
923 &Sphere::new([35.227, 49.610, 20.593], 4.675f64),
924 &mut |_| (),
925 );
926 }
927
928 #[test]
929 fn same_output_map() {
930 let mut dif = DiffCoverageMap::new([1.0120482f64; 3], [-9.0, 11.0, -18.0], 256);
931 let mut cov = CoverageMap::new([1.0120482f64; 3], [-9.0, 11.0, -18.0], 256);
932 let mut dif_out = HashSet::new();
933 let mut cov_out = HashSet::new();
934 assert_eq!(
935 dif.add_cov(
936 &Sphere::new([35.319, 51.331, 18.794], 4.675f64),
937 &mut |coord| {
938 dif_out.insert(coord);
939 }
940 ),
941 412
942 );
943
944 assert_eq!(
945 dif.add_cov(
946 &Sphere::new([34.624, 50.910, 20.029], 4.675f64),
947 &mut |coord| {
948 dif_out.insert(coord);
949 }
950 ),
951 93
952 );
953 assert_eq!(
954 cov.add_cov(
955 &Sphere::new([35.319, 51.331, 18.794], 4.675f64),
956 &mut |coord| {
957 cov_out.insert(coord);
958 }
959 ),
960 412
961 );
962
963 assert_eq!(
964 cov.add_cov(
965 &Sphere::new([34.624, 50.910, 20.029], 4.675f64),
966 &mut |coord| {
967 cov_out.insert(coord);
968 }
969 ),
970 93
971 );
972 assert_eq!(cov_out.len(), dif_out.len());
973 }
974}