use crate::{block::Block, block_face_functions::Face, face_record::FaceRecord, Float};
const MIN_THETA_RANGE: Float = 1e-10;
const MIN_THETA_TOL: Float = 1e-8;
pub fn to_theta(x: Float, y: Float, z: Float, rotation_axis: char) -> Float {
match rotation_axis.to_ascii_lowercase() {
'x' => y.atan2(z),
'y' => z.atan2(x),
_ => y.atan2(x),
}
}
pub fn to_radius(x: Float, y: Float, z: Float, rotation_axis: char) -> Float {
match rotation_axis.to_ascii_lowercase() {
'x' => (y * y + z * z).sqrt(),
'y' => (z * z + x * x).sqrt(),
_ => (y * y + x * x).sqrt(),
}
}
fn global_theta_extreme(blocks: &[Block], axis: char) -> (Float, Float) {
let mut min_theta = Float::INFINITY;
let mut max_theta = Float::NEG_INFINITY;
for block in blocks {
for idx in 0..block.npoints() {
let theta = to_theta(block.x[idx], block.y[idx], block.z[idx], axis);
min_theta = min_theta.min(theta);
max_theta = max_theta.max(theta);
}
}
(min_theta, max_theta)
}
fn face_theta_extreme(face: &Face, axis: char) -> (Float, Float) {
let mut min_theta = Float::INFINITY;
let mut max_theta = Float::NEG_INFINITY;
for v in face.vertices() {
let theta = to_theta(v[0], v[1], v[2], axis);
min_theta = min_theta.min(theta);
max_theta = max_theta.max(theta);
}
(min_theta, max_theta)
}
pub fn find_angular_bounding_faces(
blocks: &[Block],
outer_faces: &[Face],
rotation_axis: char,
tol_rel: Float,
) -> (Vec<FaceRecord>, Vec<FaceRecord>, Vec<Face>, Vec<Face>) {
let (theta_min, theta_max) = global_theta_extreme(blocks, rotation_axis);
let theta_range = theta_max - theta_min;
if !(MIN_THETA_RANGE..=crate::PI).contains(&theta_range) {
return (Vec::new(), Vec::new(), Vec::new(), Vec::new());
}
let tol_abs: Float = (MIN_THETA_TOL as Float).max(tol_rel * theta_range);
let mut lower = Vec::new();
let mut upper = Vec::new();
for f in outer_faces {
let (f_theta_min, f_theta_max) = face_theta_extreme(f, rotation_axis);
if (f_theta_max - theta_min).abs() <= tol_abs {
lower.push(f.clone());
}
else if (theta_max - f_theta_min).abs() <= tol_abs {
upper.push(f.clone());
}
}
let lower_records = lower.iter().map(Face::to_record).collect();
let upper_records = upper.iter().map(Face::to_record).collect();
(lower_records, upper_records, lower, upper)
}