2021-05-13 15:11:18 +10:00
|
|
|
import ifcopenshell
|
|
|
|
|
|
|
|
|
|
|
2020-05-17 18:32:56 +10:00
|
|
|
def get_psets(element):
|
|
|
|
|
psets = {}
|
2021-06-06 20:54:40 +10:00
|
|
|
if element.is_a("IfcTypeObject"):
|
|
|
|
|
if element.HasPropertySets:
|
|
|
|
|
for definition in element.HasPropertySets:
|
|
|
|
|
psets[definition.Name] = get_property_definition(definition)
|
|
|
|
|
elif hasattr(element, "IsDefinedBy"):
|
|
|
|
|
for relationship in element.IsDefinedBy:
|
|
|
|
|
if relationship.is_a("IfcRelDefinesByProperties"):
|
|
|
|
|
definition = relationship.RelatingPropertyDefinition
|
|
|
|
|
psets[definition.Name] = get_property_definition(definition)
|
2020-05-17 18:32:56 +10:00
|
|
|
return psets
|
|
|
|
|
|
2020-08-04 20:18:08 +10:00
|
|
|
|
|
|
|
|
def get_property_definition(definition):
|
2020-05-17 18:32:56 +10:00
|
|
|
if definition is not None:
|
|
|
|
|
props = {}
|
2020-11-01 20:08:27 +07:00
|
|
|
if definition.is_a("IfcElementQuantity"):
|
2020-08-04 20:18:08 +10:00
|
|
|
props.update(get_quantities(definition.Quantities))
|
2020-11-01 20:08:27 +07:00
|
|
|
elif definition.is_a("IfcPropertySet"):
|
2020-08-04 20:18:08 +10:00
|
|
|
props.update(get_properties(definition.HasProperties))
|
2020-05-17 18:32:56 +10:00
|
|
|
else:
|
|
|
|
|
# Entity introduced in IFC4
|
|
|
|
|
# definition.is_a('IfcPreDefinedPropertySet'):
|
|
|
|
|
for prop in range(4, len(definition)):
|
2021-08-31 15:44:57 +10:00
|
|
|
if definition[prop] is not None:
|
|
|
|
|
props[definition.attribute_name(prop)] = definition[prop]
|
2020-05-17 18:32:56 +10:00
|
|
|
return props
|
2020-08-04 20:18:08 +10:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_quantities(quantities):
|
|
|
|
|
results = {}
|
|
|
|
|
for quantity in quantities:
|
2020-11-01 20:08:27 +07:00
|
|
|
if quantity.is_a("IfcPhysicalSimpleQuantity"):
|
2020-08-04 20:18:08 +10:00
|
|
|
results[quantity.Name] = quantity[3]
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_properties(properties):
|
|
|
|
|
results = {}
|
|
|
|
|
for prop in properties:
|
2020-11-01 20:08:27 +07:00
|
|
|
if prop.is_a("IfcPropertySingleValue"):
|
2021-02-01 10:18:10 +11:00
|
|
|
results[prop.Name] = prop.NominalValue.wrappedValue if prop.NominalValue else None
|
2020-11-01 20:08:27 +07:00
|
|
|
elif prop.is_a("IfcComplexProperty"):
|
2021-08-31 15:44:57 +10:00
|
|
|
data = {k: v for k, v in prop.get_info().items() if v is not None and k != "Name"}
|
2020-11-01 20:08:27 +07:00
|
|
|
data["properties"] = get_properties(prop.HasProperties)
|
|
|
|
|
del data["HasProperties"]
|
2020-08-04 20:18:08 +10:00
|
|
|
results[prop.Name] = data
|
|
|
|
|
return results
|
2020-08-04 21:08:49 +10:00
|
|
|
|
|
|
|
|
|
2020-08-08 17:58:45 +10:00
|
|
|
def get_type(element):
|
2021-06-07 19:43:02 +10:00
|
|
|
if element.is_a("IfcTypeObject"):
|
|
|
|
|
return element
|
|
|
|
|
elif hasattr(element, "IsTypedBy") and element.IsTypedBy:
|
2020-08-08 17:58:45 +10:00
|
|
|
return element.IsTypedBy[0].RelatingType
|
2020-11-01 20:08:27 +07:00
|
|
|
elif hasattr(element, "IsDefinedBy") and element.IsDefinedBy: # IFC2X3
|
2020-08-08 17:58:45 +10:00
|
|
|
for relationship in element.IsDefinedBy:
|
2020-11-01 20:08:27 +07:00
|
|
|
if relationship.is_a("IfcRelDefinesByType"):
|
2020-08-08 17:58:45 +10:00
|
|
|
return relationship.RelatingType
|
|
|
|
|
|
|
|
|
|
|
2021-06-21 12:21:46 +10:00
|
|
|
def get_material(element, should_skip_usage=False):
|
2020-12-02 09:03:18 +11:00
|
|
|
if hasattr(element, "HasAssociations") and element.HasAssociations:
|
|
|
|
|
for relationship in element.HasAssociations:
|
|
|
|
|
if relationship.is_a("IfcRelAssociatesMaterial"):
|
2021-06-21 12:21:46 +10:00
|
|
|
if should_skip_usage:
|
|
|
|
|
if relationship.RelatingMaterial.is_a("IfcMaterialLayerSetUsage"):
|
|
|
|
|
return relationship.RelatingMaterial.ForLayerSet
|
|
|
|
|
elif relationship.RelatingMaterial.is_a("IfcMaterialProfileSetUsage"):
|
|
|
|
|
return relationship.RelatingMaterial.ForProfileSet
|
2020-12-02 09:03:18 +11:00
|
|
|
return relationship.RelatingMaterial
|
|
|
|
|
relating_type = get_type(element)
|
2021-08-08 16:13:19 +10:00
|
|
|
if relating_type != element and hasattr(relating_type, "HasAssociations") and relating_type.HasAssociations:
|
2021-08-04 20:27:00 +10:00
|
|
|
return get_material(relating_type, should_skip_usage)
|
2020-12-02 09:03:18 +11:00
|
|
|
|
|
|
|
|
|
2021-01-22 15:52:48 +11:00
|
|
|
def get_container(element):
|
2021-09-13 09:12:51 +10:00
|
|
|
aggregate = get_aggregate(element)
|
|
|
|
|
if aggregate:
|
|
|
|
|
return get_container(aggregate)
|
2021-01-22 15:52:48 +11:00
|
|
|
if hasattr(element, "ContainedInStructure") and element.ContainedInStructure:
|
|
|
|
|
return element.ContainedInStructure[0].RelatingStructure
|
|
|
|
|
|
|
|
|
|
|
2021-09-17 15:40:27 +10:00
|
|
|
def get_decomposition(element):
|
|
|
|
|
queue = [element]
|
|
|
|
|
results = []
|
|
|
|
|
while queue:
|
|
|
|
|
element = queue.pop()
|
|
|
|
|
for rel in getattr(element, "ContainsElements", []):
|
|
|
|
|
queue.extend(rel.RelatedElements)
|
|
|
|
|
results.extend(rel.RelatedElements)
|
|
|
|
|
for rel in getattr(element, "IsDecomposedBy", []):
|
|
|
|
|
queue.extend(rel.RelatedObjects)
|
|
|
|
|
results.extend(rel.RelatedObjects)
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
2021-04-19 16:08:57 +10:00
|
|
|
def get_aggregate(element):
|
|
|
|
|
if hasattr(element, "Decomposes") and element.Decomposes:
|
|
|
|
|
return element.Decomposes[0].RelatingObject
|
|
|
|
|
|
|
|
|
|
|
2020-08-04 21:08:49 +10:00
|
|
|
def replace_attribute(element, old, new):
|
|
|
|
|
for i, attribute in enumerate(element):
|
2021-07-04 19:45:34 +10:00
|
|
|
if has_element_reference(attribute, old):
|
|
|
|
|
new_attribute = element.walk(lambda v: v == old, lambda v: new, attribute)
|
|
|
|
|
element[i] = new_attribute
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def has_element_reference(value, element):
|
|
|
|
|
if isinstance(value, (tuple, list)):
|
|
|
|
|
for v in value:
|
2021-08-30 21:32:03 +10:00
|
|
|
if has_element_reference(v, element):
|
|
|
|
|
return True
|
|
|
|
|
return False
|
2021-07-04 19:45:34 +10:00
|
|
|
return value == element
|
2021-01-01 12:15:18 +11:00
|
|
|
|
|
|
|
|
|
2021-01-24 14:32:04 +11:00
|
|
|
def remove_deep(ifc_file, element):
|
2021-04-18 19:02:39 +10:00
|
|
|
# @todo maybe some sort of try-finally mechanism.
|
|
|
|
|
ifc_file.batch()
|
2021-08-12 13:35:45 +02:00
|
|
|
subgraph = list(ifc_file.traverse(element, breadth_first=True))
|
2021-01-24 14:32:04 +11:00
|
|
|
subgraph_set = set(subgraph)
|
|
|
|
|
for ref in subgraph[::-1]:
|
|
|
|
|
if ref.id() and len(set(ifc_file.get_inverse(ref)) - subgraph_set) == 0:
|
|
|
|
|
ifc_file.remove(ref)
|
2021-03-13 12:16:40 +01:00
|
|
|
ifc_file.unbatch()
|
|
|
|
|
|
|
|
|
|
|
2021-05-13 15:11:18 +10:00
|
|
|
def copy(ifc_file, element):
|
|
|
|
|
new = ifc_file.create_entity(element.is_a())
|
|
|
|
|
for i, attribute in enumerate(element):
|
|
|
|
|
if attribute is None:
|
|
|
|
|
continue
|
2021-08-10 11:48:38 +10:00
|
|
|
if new.attribute_name(i) == "GlobalId":
|
|
|
|
|
new[i] = ifcopenshell.guid.new()
|
|
|
|
|
else:
|
|
|
|
|
new[i] = attribute
|
2021-05-13 15:11:18 +10:00
|
|
|
return new
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def copy_deep(ifc_file, element):
|
|
|
|
|
new = ifc_file.create_entity(element.is_a())
|
|
|
|
|
for i, attribute in enumerate(element):
|
|
|
|
|
if attribute is None:
|
|
|
|
|
continue
|
|
|
|
|
if isinstance(attribute, ifcopenshell.entity_instance):
|
|
|
|
|
attribute = copy_deep(ifc_file, attribute)
|
|
|
|
|
elif isinstance(attribute, tuple) and attribute and isinstance(attribute[0], ifcopenshell.entity_instance):
|
2021-05-14 15:12:25 +10:00
|
|
|
attribute = list(attribute)
|
2021-05-13 15:11:18 +10:00
|
|
|
for j, item in enumerate(attribute):
|
|
|
|
|
attribute[j] = copy_deep(ifc_file, item)
|
|
|
|
|
new[i] = attribute
|
|
|
|
|
return new
|