use super::MeetTierInput;
use crate::geometry::plane::tier_is_crown_side;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Block {
Crown,
Pavilion,
Girdle,
}
#[must_use]
pub fn classify_blocks(tiers: &[MeetTierInput]) -> Vec<Block> {
let sides = tier_sides(tiers);
tiers
.iter()
.zip(&sides)
.map(|(t, &crown)| {
let theta = t.angle_deg.abs().to_radians();
let y = if crown { theta.cos() } else { -theta.cos() };
if y.abs() <= 1e-6 {
Block::Girdle
} else if y > 0.0 {
Block::Crown
} else {
Block::Pavilion
}
})
.collect()
}
pub(super) fn tier_sides(tiers: &[MeetTierInput]) -> Vec<bool> {
tiers
.iter()
.map(|tier| tier_is_crown_side(tier.angle_deg))
.collect()
}
#[cfg(test)]
mod tests {
use super::{super::MeetConstraint, *};
#[test]
fn classify_blocks_matches_angle_sign_and_girdle_threshold() {
let tiers = vec![
MeetTierInput {
angle_deg: 45.0,
indices: vec![],
constraint: MeetConstraint::MeetExisting,
names: vec![],
},
MeetTierInput {
angle_deg: -45.0,
indices: vec![],
constraint: MeetConstraint::MeetExisting,
names: vec![],
},
MeetTierInput {
angle_deg: 90.0,
indices: vec![],
constraint: MeetConstraint::MeetExisting,
names: vec![],
},
MeetTierInput {
angle_deg: -90.0,
indices: vec![],
constraint: MeetConstraint::MeetExisting,
names: vec![],
},
];
let blocks = classify_blocks(&tiers);
assert_eq!(
blocks,
vec![Block::Crown, Block::Pavilion, Block::Girdle, Block::Girdle]
);
}
}