use glam::{DVec3, Vec3};
#[must_use]
pub const fn tier_is_crown_side(angle_deg: f64) -> bool {
angle_deg > 0.0 || (angle_deg == 0.0 && !angle_deg.is_sign_negative())
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GpuFacetPlane {
pub normal: [f32; 3],
pub d: f32,
}
impl GpuFacetPlane {
#[must_use]
pub fn new(normal: Vec3, d: f32) -> Self {
let n = normal.normalize();
Self {
normal: [n.x, n.y, n.z],
d,
}
}
#[must_use]
pub fn to_halfspace_f64(self) -> (DVec3, f64) {
(
DVec3::new(
f64::from(self.normal[0]),
f64::from(self.normal[1]),
f64::from(self.normal[2]),
),
-f64::from(self.d),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tier_is_crown_side_reads_the_sign_of_zero() {
assert!(tier_is_crown_side(41.0));
assert!(tier_is_crown_side(90.0));
assert!(tier_is_crown_side(0.0), "a positive zero is the table");
assert!(
!tier_is_crown_side(-0.0),
"a sign-negative zero is the culet"
);
assert!(!tier_is_crown_side(-41.0));
assert!(!tier_is_crown_side(-90.0));
}
#[test]
fn to_halfspace_f64_inverts_the_gpu_facet_plane_sign_convention() {
let mast = 0.6_f32;
let plane = GpuFacetPlane::new(Vec3::Y, -mast);
let (n, m) = plane.to_halfspace_f64();
assert!((n - DVec3::Y).length() < 1e-12);
assert!((m - f64::from(mast)).abs() < 1e-12);
}
}