use super::super::GeometryRouter;
use crate::{Error, Result, Vector3};
use ifc_lite_core::{DecodedEntity, EntityDecoder, IfcType};
use nalgebra::Matrix4;
impl GeometryRouter {
pub(crate) fn mapped_item_transform(
&self,
item: &DecodedEntity,
source: &DecodedEntity,
decoder: &mut EntityDecoder,
) -> Result<Option<Matrix4<f64>>> {
let target = match item.get(1) {
Some(attr) if !attr.is_null() => match decoder.resolve_ref(attr)? {
Some(entity) => Some(self.parse_cartesian_transformation_operator(&entity, decoder)?),
None => None,
},
_ => None,
};
let origin = self.mapping_origin_transform(source, decoder)?;
Ok(match (target, origin) {
(Some(t), Some(o)) => Some(t * o),
(Some(t), None) => Some(t),
(None, Some(o)) => Some(o),
(None, None) => None,
})
}
pub(crate) fn mapping_origin_transform(
&self,
source: &DecodedEntity,
decoder: &mut EntityDecoder,
) -> Result<Option<Matrix4<f64>>> {
let Some(origin_attr) = source.get(0).filter(|a| !a.is_null()) else {
return Ok(None);
};
let Some(origin) = decoder.resolve_ref(origin_attr)? else {
return Err(Error::geometry(
"RepresentationMap MappingOrigin does not resolve".to_string(),
));
};
let m = match origin.ifc_type {
IfcType::IfcAxis2Placement3D => self.parse_axis2_placement_3d(&origin, decoder)?,
IfcType::IfcAxis2Placement2D => self.parse_axis2_placement_2d(&origin, decoder)?,
other => {
return Err(Error::geometry(format!(
"RepresentationMap MappingOrigin is {other}, not an IfcAxis2Placement"
)))
}
};
Ok(if m.is_identity(1e-12) { None } else { Some(m) })
}
#[inline]
pub(crate) fn parse_axis2_placement_2d(
&self,
placement: &DecodedEntity,
decoder: &mut EntityDecoder,
) -> Result<Matrix4<f64>> {
axis2_placement_2d_matrix(placement, decoder)
}
}
pub(crate) fn axis2_placement_2d_matrix(
placement: &DecodedEntity,
decoder: &mut EntityDecoder,
) -> Result<Matrix4<f64>> {
let location = super::cartesian_point_at(placement, decoder, 0)?;
let ref_dir = match placement.get(1) {
Some(attr) if !attr.is_null() => match decoder.resolve_ref(attr)? {
Some(e) => super::operator::parse_direction_ratios(&e)?
.try_normalize(1e-9)
.unwrap_or_else(|| Vector3::new(1.0, 0.0, 0.0)),
None => Vector3::new(1.0, 0.0, 0.0),
},
_ => Vector3::new(1.0, 0.0, 0.0),
};
let mut m = Matrix4::identity();
m[(0, 0)] = ref_dir.x;
m[(1, 0)] = ref_dir.y;
m[(0, 1)] = -ref_dir.y;
m[(1, 1)] = ref_dir.x;
m[(0, 3)] = location.x;
m[(1, 3)] = location.y;
m[(2, 3)] = location.z;
Ok(m)
}