use ifc_lite_core::{DecodedEntity, EntityDecoder, IfcType};
use super::transform::{parse_axis2_placement_2d, Transform2D};
pub(super) fn conic_basis(
conic: &DecodedEntity,
decoder: &mut EntityDecoder,
unit_scale: f32,
) -> Transform2D {
let Some(pos_ref) = conic.get_ref(0) else {
return Transform2D::unresolved(); };
match decoder.decode_by_id(pos_ref) {
Ok(position) => parse_axis2_placement_2d(&position, decoder, unit_scale),
Err(_) => Transform2D::unresolved(), }
}
pub(super) struct Conic {
pub(super) basis: Transform2D,
pub(super) semi_a: f32,
pub(super) semi_b: f32,
}
impl Conic {
pub(super) fn read(
curve: &DecodedEntity,
decoder: &mut EntityDecoder,
unit_scale: f32,
) -> Option<Self> {
let length =
|i: usize| curve.get(i).and_then(|a| a.as_float()).unwrap_or(0.0) as f32 * unit_scale;
let (semi_a, semi_b) = match curve.ifc_type {
IfcType::IfcCircle => (length(1), length(1)),
IfcType::IfcEllipse => (length(1), length(2)),
_ => return None,
};
let valid = |v: f32| v.is_finite() && v > 0.0;
if !valid(semi_a) || !valid(semi_b) {
return None;
}
let basis = conic_basis(curve, decoder, unit_scale);
if !basis.tx.is_finite() || !basis.ty.is_finite() {
return None;
}
Some(Self {
basis,
semi_a,
semi_b,
})
}
pub(super) fn point_at(&self, theta: f32) -> (f32, f32) {
self.basis
.transform_point(self.semi_a * theta.cos(), self.semi_b * theta.sin())
}
}