use crate::{NurbsCurve, NurbsSurface, Vec3, Vec4};
use super::reader::ParsedEntity;
use super::writer::{real_field, IgesEntity};
const WEIGHT_TOL: f64 = 1e-12;
pub(crate) fn curve_to_126(curve: &NurbsCurve) -> Result<IgesEntity, String> {
let num = curve.control_points.len();
if num < 2 {
return Err("iges: curve has fewer than 2 control points".into());
}
let degree = curve.degree;
let k = (num - 1) as i64;
let expected_knots = num + degree + 1;
if curve.knots.len() != expected_knots {
return Err(format!(
"iges: curve knot count {} != control points {} + degree {} + 1",
curve.knots.len(),
num,
degree
));
}
let rational = curve
.control_points
.iter()
.any(|c| (c.w - 1.0).abs() > WEIGHT_TOL);
let [t0, t1] = curve.domain()?;
let mut params: Vec<String> = Vec::new();
params.push(k.to_string()); params.push((degree as i64).to_string()); params.push("0".into()); params.push("0".into()); params.push(if rational { "0" } else { "1" }.into()); params.push("0".into()); for knot in &curve.knots {
params.push(real_field(*knot));
}
for c in &curve.control_points {
params.push(real_field(c.w));
}
for c in &curve.control_points {
let p = c.point()?;
params.push(real_field(p.x));
params.push(real_field(p.y));
params.push(real_field(p.z));
}
params.push(real_field(t0)); params.push(real_field(t1)); params.push(real_field(0.0)); params.push(real_field(0.0));
params.push(real_field(0.0));
Ok(IgesEntity::new(126, params))
}
pub(crate) fn curve_from_126(entity: &ParsedEntity, coord_scale: Option<f64>) -> Result<NurbsCurve, String> {
let k = entity.int(0)?;
let degree = entity.int(1)? as usize;
if k < 1 {
return Err(format!("iges 126: invalid upper index K={k}"));
}
let num = (k + 1) as usize;
let knot_count = num + degree + 1;
let mut idx = 6; let mut knots = Vec::with_capacity(knot_count);
for _ in 0..knot_count {
knots.push(entity.real(idx)?);
idx += 1;
}
let mut weights = Vec::with_capacity(num);
for _ in 0..num {
weights.push(entity.real(idx)?);
idx += 1;
}
let scale = coord_scale.unwrap_or(1.0);
let mut control_points = Vec::with_capacity(num);
for i in 0..num {
let x = entity.real(idx)? * scale;
let y = entity.real(idx + 1)? * scale;
let z = entity.real(idx + 2)? * scale;
idx += 3;
control_points.push(Vec4::from_point(Vec3::new(x, y, z), weights[i]));
}
NurbsCurve::new(degree, knots, control_points)
}
pub(crate) fn surface_to_128(surface: &NurbsSurface) -> Result<IgesEntity, String> {
let num_u = surface.control_points.len();
if num_u < 2 {
return Err("iges: surface has fewer than 2 rows of control points".into());
}
let num_v = surface.control_points[0].len();
if num_v < 2 {
return Err("iges: surface has fewer than 2 columns of control points".into());
}
let (du, dv) = (surface.degree_u, surface.degree_v);
let k1 = (num_u - 1) as i64;
let k2 = (num_v - 1) as i64;
if surface.knots_u.len() != num_u + du + 1 {
return Err("iges: surface u-knot count inconsistent with control net".into());
}
if surface.knots_v.len() != num_v + dv + 1 {
return Err("iges: surface v-knot count inconsistent with control net".into());
}
let rational = surface
.control_points
.iter()
.flatten()
.any(|c| (c.w - 1.0).abs() > WEIGHT_TOL);
let [u0, u1] = surface.domain_u()?;
let [v0, v1] = surface.domain_v()?;
let mut params: Vec<String> = Vec::new();
params.push(k1.to_string());
params.push(k2.to_string());
params.push((du as i64).to_string());
params.push((dv as i64).to_string());
params.push("0".into()); params.push("0".into()); params.push(if rational { "0" } else { "1" }.into()); params.push("0".into()); params.push("0".into()); for knot in &surface.knots_u {
params.push(real_field(*knot));
}
for knot in &surface.knots_v {
params.push(real_field(*knot));
}
for j in 0..num_v {
for i in 0..num_u {
params.push(real_field(surface.control_points[i][j].w));
}
}
for j in 0..num_v {
for i in 0..num_u {
let p = surface.control_points[i][j].point()?;
params.push(real_field(p.x));
params.push(real_field(p.y));
params.push(real_field(p.z));
}
}
params.push(real_field(u0));
params.push(real_field(u1));
params.push(real_field(v0));
params.push(real_field(v1));
Ok(IgesEntity::new(128, params))
}
pub(crate) fn surface_from_128(entity: &ParsedEntity, coord_scale: f64) -> Result<NurbsSurface, String> {
let k1 = entity.int(0)?;
let k2 = entity.int(1)?;
let du = entity.int(2)? as usize;
let dv = entity.int(3)? as usize;
if k1 < 1 || k2 < 1 {
return Err(format!("iges 128: invalid upper indices K1={k1} K2={k2}"));
}
let num_u = (k1 + 1) as usize;
let num_v = (k2 + 1) as usize;
let u_knot_count = num_u + du + 1;
let v_knot_count = num_v + dv + 1;
let mut idx = 9; let mut knots_u = Vec::with_capacity(u_knot_count);
for _ in 0..u_knot_count {
knots_u.push(entity.real(idx)?);
idx += 1;
}
let mut knots_v = Vec::with_capacity(v_knot_count);
for _ in 0..v_knot_count {
knots_v.push(entity.real(idx)?);
idx += 1;
}
let count = num_u * num_v;
let mut weights = Vec::with_capacity(count);
for _ in 0..count {
weights.push(entity.real(idx)?);
idx += 1;
}
let mut control_points = vec![vec![Vec4::from_point(Vec3::new(0.0, 0.0, 0.0), 1.0); num_v]; num_u];
let mut w_index = 0;
for j in 0..num_v {
for i in 0..num_u {
let x = entity.real(idx)? * coord_scale;
let y = entity.real(idx + 1)? * coord_scale;
let z = entity.real(idx + 2)? * coord_scale;
idx += 3;
control_points[i][j] = Vec4::from_point(Vec3::new(x, y, z), weights[w_index]);
w_index += 1;
}
}
NurbsSurface::new(du, dv, knots_u, knots_v, control_points)
}
pub(crate) fn composite_102(members: &[i64]) -> IgesEntity {
let mut params: Vec<String> = Vec::with_capacity(members.len() + 1);
params.push(members.len().to_string());
for m in members {
params.push(m.to_string());
}
IgesEntity::new(102, params)
}
pub(crate) fn composite_members(entity: &ParsedEntity) -> Result<Vec<i64>, String> {
let n = entity.int(0)? as usize;
let mut out = Vec::with_capacity(n);
for i in 0..n {
out.push(entity.int(1 + i)?);
}
Ok(out)
}
pub(crate) fn curve_on_surface_142(sptr: i64, bptr: i64, cptr: i64) -> IgesEntity {
IgesEntity::new(
142,
vec![
"0".into(), sptr.to_string(), bptr.to_string(), cptr.to_string(), "1".into(), ],
)
}
pub(crate) struct CurveOnSurface {
pub surface: i64,
pub param_curve: i64,
pub model_curve: i64,
}
pub(crate) fn curve_on_surface_from_142(entity: &ParsedEntity) -> Result<CurveOnSurface, String> {
Ok(CurveOnSurface {
surface: entity.int(1)?,
param_curve: entity.int(2)?,
model_curve: entity.int(3)?,
})
}
pub(crate) fn trimmed_surface_144(pts: i64, outer: i64, holes: &[i64]) -> IgesEntity {
let mut params: Vec<String> = Vec::new();
params.push(pts.to_string()); params.push("1".into()); params.push(holes.len().to_string()); params.push(outer.to_string()); for h in holes {
params.push(h.to_string());
}
IgesEntity::new(144, params)
}
pub(crate) struct TrimmedSurface {
pub surface: i64,
pub outer: Option<i64>,
pub inner: Vec<i64>,
}
pub(crate) fn trimmed_surface_from_144(entity: &ParsedEntity) -> Result<TrimmedSurface, String> {
let surface = entity.int(0)?;
let n1 = entity.int(1)?;
let n2 = entity.int(2)? as usize;
let outer = entity.int(3)?;
let outer = if n1 != 0 && outer != 0 { Some(outer) } else { None };
let mut inner = Vec::with_capacity(n2);
for i in 0..n2 {
inner.push(entity.int(4 + i)?);
}
Ok(TrimmedSurface {
surface,
outer,
inner,
})
}