use ifc_lite_core::{DecodedEntity, EntityDecoder, IfcType};
use super::Transform2D;
pub(in super::super) fn parse_cartesian_transformation_operator(
operator: &DecodedEntity,
decoder: &mut EntityDecoder,
unit_scale: f32,
) -> Transform2D {
let (tx, ty, tz) = match operator.get_ref(2) {
Some(loc_ref) => match decoder.decode_by_id(loc_ref) {
Ok(loc) if loc.ifc_type == IfcType::IfcCartesianPoint => {
let coords = loc
.get(0)
.and_then(|a| a.as_list())
.map(|l| l.to_vec())
.unwrap_or_default();
let x = coords.first().and_then(|v| v.as_float()).unwrap_or(0.0) as f32;
let y = coords.get(1).and_then(|v| v.as_float()).unwrap_or(0.0) as f32;
let z = coords.get(2).and_then(|v| v.as_float()).unwrap_or(0.0) as f32;
(x * unit_scale, y * unit_scale, z * unit_scale)
}
_ => (0.0, 0.0, 0.0),
},
None => (0.0, 0.0, 0.0),
};
let raw_scale = operator.get(3).and_then(|v| v.as_float()).unwrap_or(1.0) as f32;
let scale = if raw_scale.is_finite() { raw_scale.abs() } else { 1.0 };
let x_axis = match operator.get_ref(0) {
Some(ax_ref) => match decoder.decode_by_id(ax_ref) {
Ok(ax) if ax.ifc_type == IfcType::IfcDirection => {
let ratios = ax
.get(0)
.and_then(|a| a.as_list())
.map(|l| l.to_vec())
.unwrap_or_default();
let dx = ratios.first().and_then(|v| v.as_float()).unwrap_or(1.0) as f32;
let dy = ratios.get(1).and_then(|v| v.as_float()).unwrap_or(0.0) as f32;
let len = (dx * dx + dy * dy).sqrt();
if len > 0.0001 {
(dx / len, dy / len)
} else {
(1.0, 0.0)
}
}
_ => (1.0, 0.0),
},
None => (1.0, 0.0),
};
let default_y = (-x_axis.1, x_axis.0);
let y_axis = match operator.get_ref(1) {
Some(ax_ref) => match decoder.decode_by_id(ax_ref) {
Ok(ax) if ax.ifc_type == IfcType::IfcDirection => {
let ratios = ax
.get(0)
.and_then(|a| a.as_list())
.map(|l| l.to_vec())
.unwrap_or_default();
let ex = ratios.first().and_then(|v| v.as_float()).unwrap_or(0.0) as f32;
let ey = ratios.get(1).and_then(|v| v.as_float()).unwrap_or(1.0) as f32;
let dot = ex * x_axis.0 + ey * x_axis.1;
let px = ex - dot * x_axis.0;
let py = ey - dot * x_axis.1;
let len = (px * px + py * py).sqrt();
if len > 0.0001 {
let proj = (px / len, py / len);
let agreement = proj.0 * default_y.0 + proj.1 * default_y.1;
if agreement < 1.0 - 1e-6 {
proj
} else {
default_y
}
} else {
default_y
}
}
_ => default_y,
},
None => default_y,
};
Transform2D {
tx,
ty,
tz,
m00: x_axis.0 * scale,
m10: x_axis.1 * scale,
m01: y_axis.0 * scale,
m11: y_axis.1 * scale,
}
}