use ifc_model::{EntityId, Model};
#[cfg(feature = "lowering")]
pub(crate) mod linear;
#[cfg(feature = "compile")]
pub mod derive;
use crate::constraint::local::PlacementResolver;
use crate::error::{GeometryError, GeometryResult};
use crate::input::product::Product;
use crate::transform::Transform;
use crate::units::UnitScale;
pub fn product_world_transform(
model: &Model,
units: &UnitScale,
product: EntityId,
) -> GeometryResult<Transform> {
let mut resolver = PlacementResolver::new();
resolve_with(&mut resolver, model, units, product)
}
pub fn products_world_transforms(
model: &Model,
units: &UnitScale,
products: impl IntoIterator<Item = EntityId>,
) -> Vec<(EntityId, GeometryResult<Transform>)> {
let mut resolver = PlacementResolver::new();
products
.into_iter()
.map(|product| {
let resolved = resolve_with(&mut resolver, model, units, product);
(product, resolved)
})
.collect()
}
fn resolve_with(
resolver: &mut PlacementResolver,
model: &Model,
units: &UnitScale,
product: EntityId,
) -> GeometryResult<Transform> {
let entity = model.get(product).ok_or(GeometryError::MissingEntity {
referrer: product,
missing: product,
})?;
let Some(placement) = Product::new(product, entity).object_placement() else {
return Ok(Transform::identity());
};
#[cfg(feature = "lowering")]
if linear::is_linear_placement(model, placement) {
let file_units = linear::linear_placement_transform(model, units, placement)?;
return Ok(file_units.to_metres(units));
}
let file_units = resolver.world_transform(model, placement)?;
Ok(file_units.to_metres(units))
}
#[cfg(test)]
mod tests;