use super::plane::GpuFacetPlane;
use glam::Vec3;
use std::f32::consts::PI;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FacetTierType {
Crown,
Pavilion,
Girdle,
}
#[derive(Debug, Clone)]
pub struct FacetTier {
pub tier_type: FacetTierType,
pub angle_deg: f32, pub indices: Vec<u32>, pub offset: f32, }
#[derive(Debug, Clone)]
pub struct CuttingSchedule {
pub gear_teeth: u32,
pub tiers: Vec<FacetTier>,
}
impl CuttingSchedule {
#[must_use]
pub const fn new(gear_teeth: u32) -> Self {
Self {
gear_teeth,
tiers: Vec::new(),
}
}
pub fn add_tier(
&mut self,
tier_type: FacetTierType,
angle_deg: f32,
indices: Vec<u32>,
offset: f32,
) {
self.tiers.push(FacetTier {
tier_type,
angle_deg,
indices,
offset,
});
}
#[must_use]
pub fn into_planes(&self) -> Vec<GpuFacetPlane> {
let mut planes = Vec::new();
for tier in &self.tiers {
let theta = tier.angle_deg.to_radians();
let sin_theta = theta.sin();
let cos_theta = theta.cos();
for &g in &tier.indices {
let phi = 2.0 * PI * (g as f32) / (self.gear_teeth as f32);
let sin_phi = phi.sin();
let cos_phi = phi.cos();
let n = match tier.tier_type {
FacetTierType::Crown => {
Vec3::new(sin_theta * cos_phi, cos_theta, sin_theta * sin_phi)
}
FacetTierType::Pavilion => {
Vec3::new(sin_theta * cos_phi, -cos_theta, sin_theta * sin_phi)
}
FacetTierType::Girdle => Vec3::new(cos_phi, 0.0, sin_phi),
};
planes.push(GpuFacetPlane::new(n, tier.offset));
}
}
planes
}
}
pub fn parse_gemcad_asc(content: &str) -> Result<CuttingSchedule, String> {
let mut schedule = CuttingSchedule::new(96);
let mut current_type = FacetTierType::Pavilion;
let mut tier_counter = 1;
for line in content.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with(';') {
continue;
}
if line.starts_with("GEAR") {
if let Some(num) = line.split_whitespace().nth(1) {
schedule.gear_teeth = num.parse().unwrap_or(96);
}
continue;
}
if line.starts_with("PAVILION") {
current_type = FacetTierType::Pavilion;
continue;
}
if line.starts_with("CROWN") {
current_type = FacetTierType::Crown;
continue;
}
if line.starts_with("GIRDLE") {
current_type = FacetTierType::Girdle;
continue;
}
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() < 2 {
continue;
}
if let Ok(angle) = parts[0].parse::<f32>() {
let mut indices = Vec::new();
let mut offset = (tier_counter as f32).mul_add(-0.1, -1.0);
for &p in &parts[1..] {
if let Some(rest) = p.strip_prefix("d=") {
if let Ok(d) = rest.parse::<f32>() {
offset = d;
if offset > 0.0 {
offset = -offset;
}
}
} else if let Ok(idx) = p.parse::<u32>() {
indices.push(idx);
}
}
if !indices.is_empty() {
schedule.add_tier(current_type, angle, indices, offset);
tier_counter += 1;
}
}
}
Ok(schedule)
}