use mpi::traits::Equivalence;
use crate::constants::DEEPEST_LEVEL;
#[derive(Clone, Copy, Equivalence)]
pub struct Point {
coords: [f64; 3],
global_id: usize,
}
impl Point {
pub fn new(coords: [f64; 3], global_id: usize) -> Self {
Self { coords, global_id }
}
pub fn coords(&self) -> [f64; 3] {
self.coords
}
pub fn coords_mut(&mut self) -> &mut [f64; 3] {
&mut self.coords
}
pub fn global_id(&self) -> usize {
self.global_id
}
}
pub struct PhysicalBox {
coords: [f64; 6],
}
impl PhysicalBox {
pub fn new(coords: [f64; 6]) -> Self {
Self { coords }
}
pub fn from_points(points: &[Point]) -> PhysicalBox {
let mut xmin = f64::MAX;
let mut xmax = f64::MIN;
let mut ymin = f64::MAX;
let mut ymax = f64::MIN;
let mut zmin = f64::MAX;
let mut zmax = f64::MIN;
for point in points {
let x = point.coords()[0];
let y = point.coords()[1];
let z = point.coords()[2];
xmin = f64::min(xmin, x);
xmax = f64::max(xmax, x);
ymin = f64::min(ymin, y);
ymax = f64::max(ymax, y);
zmin = f64::min(zmin, z);
zmax = f64::max(zmax, z);
}
let xdiam = xmax - xmin;
let ydiam = ymax - ymin;
let zdiam = zmax - zmin;
let xmean = xmin + 0.5 * xdiam;
let ymean = ymin + 0.5 * ydiam;
let zmean = zmin + 0.5 * zdiam;
let deepest_box_diam = 1.0 / (1 << DEEPEST_LEVEL) as f64;
let max_diam = [xdiam, ydiam, zdiam].into_iter().reduce(f64::max).unwrap();
let max_diam = max_diam * (1.0 + deepest_box_diam);
PhysicalBox {
coords: [
xmean - 0.5 * max_diam,
ymean - 0.5 * max_diam,
zmean - 0.5 * max_diam,
xmean + 0.5 * max_diam,
ymean + 0.5 * max_diam,
zmean + 0.5 * max_diam,
],
}
}
pub fn coordinates(&self) -> [f64; 6] {
self.coords
}
pub fn reference_to_physical(&self, point: [f64; 3]) -> [f64; 3] {
let [xmin, ymin, zmin, xmax, ymax, zmax] = self.coords;
[
xmin + (xmax - xmin) * point[0],
ymin + (ymax - ymin) * point[1],
zmin + (zmax - zmin) * point[2],
]
}
pub fn physical_to_reference(&self, point: [f64; 3]) -> [f64; 3] {
let [xmin, ymin, zmin, xmax, ymax, zmax] = self.coords;
[
(point[0] - xmin) / (xmax - xmin),
(point[1] - ymin) / (ymax - ymin),
(point[2] - zmin) / (zmax - zmin),
]
}
pub fn corners(&self) -> [[f64; 3]; 8] {
let reference_points = [
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 1.0],
];
[
self.reference_to_physical(reference_points[0]),
self.reference_to_physical(reference_points[1]),
self.reference_to_physical(reference_points[2]),
self.reference_to_physical(reference_points[3]),
self.reference_to_physical(reference_points[4]),
self.reference_to_physical(reference_points[5]),
self.reference_to_physical(reference_points[6]),
self.reference_to_physical(reference_points[7]),
]
}
}
impl std::fmt::Display for PhysicalBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let [xmin, ymin, zmin, xmax, ymax, zmax] = self.coords;
write!(
f,
"(xmin: {}, ymin: {}, zmin: {}, xmax: {}, ymax: {}, zmax: {})",
xmin, ymin, zmin, xmax, ymax, zmax
)
}
}