///|
fn product_kind(name : String) -> ProductKind {
match name.to_upper() {
"IFCPROJECT" => Project
"IFCSITE" => Site
"IFCBUILDING" => Building
"IFCBUILDINGSTOREY" => Storey
"IFCSPACE" => Space
"IFCWALL" | "IFCWALLELEMENTEDCASE" | "IFCWALLSTANDARDCASE" => Wall
"IFCDOOR" => Door
"IFCWINDOW" => Window
"IFCBEAM" => Beam
"IFCCOLUMN" => Column
"IFCSLAB" => Slab
"IFCROOF" => Roof
"IFCSTAIR" | "IFCSTAIRFLIGHT" => Stair
"IFCRAMP" | "IFCRAMPFLIGHT" => Ramp
"IFCOPENINGELEMENT" | "IFCVOIDINGFEATURE" => Opening
_ => Generic
}
}
///|
fn is_product_entity(name : String) -> Bool {
let upper = name.to_upper()
match product_kind(upper) {
Generic =>
upper == "IFCPRODUCT" ||
upper == "IFCFURNISHINGELEMENT" ||
upper == "IFCDISTRIBUTIONELEMENT"
_ => true
}
}
///|
fn optional_string_argument(entity : Entity, position : Int) -> String? {
match entity_value(entity, position) {
Some(value) => string_value(value)
None => None
}
}
///|
fn string_value(value : Value) -> String? {
value.as_string()
}
///|
fn optional_reference_argument(entity : Entity, position : Int) -> Int? {
value_reference(entity_value(entity, position))
}
///|
fn reference_list(value : Value?) -> Array[Int] {
match value {
Some(item) => references(item)
None => []
}
}
///|
fn relation_objects(entity : Entity, position : Int) -> Array[Int] {
reference_list(entity_value(entity, position))
}
///|
fn property_relation_maps(
index : ModelIndex,
) -> (Map[Int, Array[Int]], Map[Int, Int]) {
let property_sets : Map[Int, Array[Int]] = Map([])
let containers : Map[Int, Int] = Map([])
for relation in index.all() {
let name = relation.name.to_upper()
if name == "IFCRELDEFINESBYPROPERTIES" {
match optional_reference_argument(relation, 5) {
Some(property_set_id) =>
for object_id in relation_objects(relation, 4) {
property_sets.update_or_default(object_id, [property_set_id], values => {
values.push(property_set_id)
values
})
}
None => ()
}
} else if name == "IFCRELCONTAINEDINSPATIALSTRUCTURE" {
match optional_reference_argument(relation, 5) {
Some(container_id) =>
for object_id in relation_objects(relation, 4) {
containers[object_id] = container_id
}
None => ()
}
}
}
(property_sets, containers)
}
///|
fn make_product(
entity : Entity,
property_sets : Map[Int, Array[Int]],
containers : Map[Int, Int],
) -> Product {
let kind = product_kind(entity.name)
{
id: entity.id,
ifc_type: entity.name,
kind,
global_id: optional_string_argument(entity, 0),
name: optional_string_argument(entity, 2),
description: optional_string_argument(entity, 3),
object_type: optional_string_argument(entity, 4),
placement: optional_reference_argument(entity, 5),
representation: optional_reference_argument(entity, 6),
tag: optional_string_argument(entity, 7),
property_sets: property_sets.get(entity.id).unwrap_or([]),
container: containers.get(entity.id),
}
}
///|
/// Extract common IFC products while preserving the original generic entities.
pub fn extract_products(index : ModelIndex) -> Array[Product] {
let (property_sets, containers) = property_relation_maps(index)
index
.all()
.fold(init=Array::new(), (result, entity) => {
if is_product_entity(entity.name) {
result.push(make_product(entity, property_sets, containers))
}
result
})
}
///|
pub fn product_by_id(products : Array[Product], id : Int) -> Product? {
for product in products {
if product.id == id {
return Some(product)
}
}
None
}
///|
pub fn products_of_kind(
products : Array[Product],
kind : ProductKind,
) -> Array[Product] {
products.filter(product => product.kind == kind)
}