1use mpi::traits::Equivalence;
4
5use crate::constants::DEEPEST_LEVEL;
6
7#[derive(Clone, Copy, Equivalence)]
13pub struct Point {
14 coords: [f64; 3],
15 global_id: usize,
16}
17
18impl Point {
19 pub fn new(coords: [f64; 3], global_id: usize) -> Self {
21 Self { coords, global_id }
22 }
23
24 pub fn coords(&self) -> [f64; 3] {
26 self.coords
27 }
28
29 pub fn coords_mut(&mut self) -> &mut [f64; 3] {
31 &mut self.coords
32 }
33
34 pub fn global_id(&self) -> usize {
36 self.global_id
37 }
38}
39
40pub struct PhysicalBox {
42 coords: [f64; 6],
43}
44
45impl PhysicalBox {
46 pub fn new(coords: [f64; 6]) -> Self {
50 Self { coords }
51 }
52
53 pub fn from_points(points: &[Point]) -> PhysicalBox {
58 let mut xmin = f64::MAX;
59 let mut xmax = f64::MIN;
60
61 let mut ymin = f64::MAX;
62 let mut ymax = f64::MIN;
63
64 let mut zmin = f64::MAX;
65 let mut zmax = f64::MIN;
66
67 for point in points {
68 let x = point.coords()[0];
69 let y = point.coords()[1];
70 let z = point.coords()[2];
71
72 xmin = f64::min(xmin, x);
73 xmax = f64::max(xmax, x);
74
75 ymin = f64::min(ymin, y);
76 ymax = f64::max(ymax, y);
77
78 zmin = f64::min(zmin, z);
79 zmax = f64::max(zmax, z);
80 }
81
82 let xdiam = xmax - xmin;
87 let ydiam = ymax - ymin;
88 let zdiam = zmax - zmin;
89
90 let xmean = xmin + 0.5 * xdiam;
91 let ymean = ymin + 0.5 * ydiam;
92 let zmean = zmin + 0.5 * zdiam;
93
94 let deepest_box_diam = 1.0 / (1 << DEEPEST_LEVEL) as f64;
99
100 let max_diam = [xdiam, ydiam, zdiam].into_iter().reduce(f64::max).unwrap();
101
102 let max_diam = max_diam * (1.0 + deepest_box_diam);
103
104 PhysicalBox {
105 coords: [
106 xmean - 0.5 * max_diam,
107 ymean - 0.5 * max_diam,
108 zmean - 0.5 * max_diam,
109 xmean + 0.5 * max_diam,
110 ymean + 0.5 * max_diam,
111 zmean + 0.5 * max_diam,
112 ],
113 }
114 }
115
116 pub fn coordinates(&self) -> [f64; 6] {
118 self.coords
119 }
120
121 pub fn reference_to_physical(&self, point: [f64; 3]) -> [f64; 3] {
123 let [xmin, ymin, zmin, xmax, ymax, zmax] = self.coords;
124
125 [
126 xmin + (xmax - xmin) * point[0],
127 ymin + (ymax - ymin) * point[1],
128 zmin + (zmax - zmin) * point[2],
129 ]
130 }
131
132 pub fn physical_to_reference(&self, point: [f64; 3]) -> [f64; 3] {
134 let [xmin, ymin, zmin, xmax, ymax, zmax] = self.coords;
135
136 [
137 (point[0] - xmin) / (xmax - xmin),
138 (point[1] - ymin) / (ymax - ymin),
139 (point[2] - zmin) / (zmax - zmin),
140 ]
141 }
142
143 pub fn corners(&self) -> [[f64; 3]; 8] {
155 let reference_points = [
156 [0.0, 0.0, 0.0],
157 [1.0, 0.0, 0.0],
158 [1.0, 1.0, 0.0],
159 [0.0, 1.0, 0.0],
160 [0.0, 0.0, 1.0],
161 [1.0, 0.0, 1.0],
162 [1.0, 1.0, 1.0],
163 [0.0, 1.0, 1.0],
164 ];
165
166 [
167 self.reference_to_physical(reference_points[0]),
168 self.reference_to_physical(reference_points[1]),
169 self.reference_to_physical(reference_points[2]),
170 self.reference_to_physical(reference_points[3]),
171 self.reference_to_physical(reference_points[4]),
172 self.reference_to_physical(reference_points[5]),
173 self.reference_to_physical(reference_points[6]),
174 self.reference_to_physical(reference_points[7]),
175 ]
176 }
177}
178
179impl std::fmt::Display for PhysicalBox {
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 let [xmin, ymin, zmin, xmax, ymax, zmax] = self.coords;
182
183 write!(
184 f,
185 "(xmin: {}, ymin: {}, zmin: {}, xmax: {}, ymax: {}, zmax: {})",
186 xmin, ymin, zmin, xmax, ymax, zmax
187 )
188 }
189}