Implement COBie assemblies, connections, spares, resources, and jobs.

This commit is contained in:
Dion Moult
2023-09-12 17:46:57 +10:00
parent 8976cf5c52
commit cb264bac6e
+278 -4
View File
@@ -105,12 +105,66 @@ def get_systems(ifc_file):
return results
def get_assemblies(ifc_file):
results = []
layer_sets = ifc_file.by_type("IfcMaterialLayerSet")
layer_sets = [] # This is temporarily overridden because it is unclear exactly how this is stored in Type.
for layer_set in layer_sets:
for layer in layer_set.MaterialLayers:
results.append((None, layer_set, layer.Material))
rels = ifc_file.by_type("IfcRelAggregates") + ifc_file.by_type("IfcRelNests")
types = get_types(ifc_file)
components = get_components(ifc_file)
for rel in rels:
if rel.RelatingObject.is_a("IfcSpace"):
for related_object in rel.RelatedObjects:
if related_object.is_a("IfcSpace"):
results.append((rel, rel.RelatingObject, related_object))
elif rel.RelatingObject.is_a("IfcZone"):
for related_object in rel.RelatedObjects:
if related_object.is_a("IfcZone"):
results.append((rel, rel.RelatingObject, related_object))
elif rel.RelatingObject in types:
for related_object in rel.RelatedObjects:
if related_object in types:
results.append((rel, rel.RelatingObject, related_object))
elif rel.RelatingObject in components:
for related_object in rel.RelatedObjects:
if related_object in components:
results.append((rel, rel.RelatingObject, related_object))
elif rel.RelatingObject.is_a() in ("IfcSystem", "IfcDistributionSystem"):
for related_object in rel.RelatedObjects:
if related_object.is_a() in ("IfcSystem", "IfcDistributionSystem"):
results.append((rel, rel.RelatingObject, related_object))
return results
def get_connections(ifc_file):
return ifc_file.by_type("IfcRelConnectsPorts")
def get_spares(ifc_file):
return ifc_file.by_type("IfcConstructionProductResource")
def get_resources(ifc_file):
return ifc_file.by_type("IfcConstructionEquipmentResource")
def get_jobs(ifc_file):
return ifc_file.by_type("IfcTask")
def get_documents(ifc_file):
return [
r for r in ifc_file.by_type("IfcRelAssociatesDocument") if r.RelatingDocument.is_a("IfcDocumentInformation")
]
def get_contact_data(ifc_file, element):
email = get_email_from_pao(element)
history = get_history(ifc_file)
created_by = None
created_on = None
roles = []
for actor in [element, element.ThePerson, element.TheOrganization]:
@@ -523,13 +577,15 @@ def get_component_data(ifc_file, element):
def get_system_data(ifc_file, element):
system, component = element
category = get_category(system)
component_name = val(component.Name)
return {
"key": val(system.Name),
"key": str(val(system.Name)) + str(category) + str(component_name),
"Name": val(system.Name),
"CreatedBy": get_created_by(system),
"CreatedOn": get_created_on(system),
"Category": get_category(system),
"ComponentNames": val(component.Name),
"ComponentNames": component_name,
"ExternalSystem": get_external_system(system),
"ExternalObject": system.is_a(),
"ExternalIdentifier": system.GlobalId,
@@ -537,6 +593,201 @@ def get_system_data(ifc_file, element):
}
def get_assembly_data(ifc_file, element):
rel, relating_object, related_object = element
if relating_object.is_a("IfcMaterialLayerSet"):
name = val(relating_object.LayerSetName)
parent_name = name
if name:
name += " assembly"
assembly_type = "Layer"
sheet_name = "Type"
description = val(relating_object.LayerSetName)
else:
name = val(relating_object.Name)
parent_name = name
assembly_type = "Fixed"
sheet_name = "Component"
if relating_object.is_a("IfcSpace"):
sheet_name = "Space"
elif relating_object.is_a("IfcZone"):
sheet_name = "Zone"
elif relating_object.is_a("IfcSystem"):
sheet_name = "System"
elif relating_object.is_a("IfcElementType"):
sheet_name = "Type"
description = val(rel.Description) or val(rel.Name)
child_name = val(related_object.Name)
history = get_history(ifc_file)
return {
"key": str(name) + str(sheet_name) + str(parent_name),
"Name": name,
"CreatedBy": get_email_from_history(history) if history else None,
"CreatedOn": ifcopenshell.util.date.ifc2datetime(history.CreationDate).isoformat() if history else None,
"SheetName": sheet_name,
"ParentName": parent_name,
"ChildNames": child_name,
"AssemblyType": assembly_type,
"ExternalSystem": history.OwningApplication.ApplicationFullName if history else None,
"ExternalObject": rel.is_a() if rel else relating_object.is_a(),
"ExternalIdentifier": rel.GlobalId if rel else None,
"Description": description,
}
def get_connection_data(ifc_file, element):
connection_type = (
val(element.RelatingPort.ObjectType)
or val(element.RelatedPort.ObjectType)
or val(element.Description)
or val(element.Name)
)
name = val(element.Name)
row_name1 = val(ifcopenshell.util.system.get_port_element(element.RelatingPort).Name)
row_name2 = val(ifcopenshell.util.system.get_port_element(element.RelatedPort).Name)
return {
"key": str(name) + str(connection_type) + str(row_name1) + str(row_name2),
"Name": name,
"CreatedBy": get_created_by(element),
"CreatedOn": get_created_on(element),
"ConnectionType": connection_type,
"SheetName": "Component",
"RowName1": row_name1,
"RowName2": row_name2,
"RealizingElement": val(element.RealizingElement.Name) if element.RealizingElement else None,
"PortName1": val(element.RelatingPort.Name),
"PortName2": val(element.RelatedPort.Name),
"ExternalSystem": get_external_system(element),
"ExternalObject": element.is_a(),
"ExternalIdentifier": element.GlobalId,
"Description": val(element.Description) or val(element.Name),
}
def get_spare_data(ifc_file, element):
type_name = None
for rel in element.ResourceOf or []:
for related_object in rel.RelatedObjects or []:
if val(related_object.Name):
type_name = val(related_object.Name)
suppliers = None
set_number = None
part_number = None
for _, props in ifcopenshell.util.element.get_psets(element):
for name, value in props.items():
if name == "Suppliers" and val(value):
suppliers = str(value)
if name == "SetNumber" and val(value):
set_number = str(value)
if name == "PartNumber" and val(value):
part_number = str(value)
return {
"key": val(element),
"Name": val(element.Name),
"CreatedBy": get_created_by(element),
"CreatedOn": get_created_on(element),
"Category": get_category(element),
"TypeName": type_name,
"Suppliers": suppliers,
"ExternalSystem": get_external_system(element),
"ExternalObject": element.is_a(),
"ExternalIdentifier": element.GlobalId,
"Description": val(element.Description) or val(element.Name),
"SetNumber": set_number,
"PartNumber": part_number,
}
def get_resource_data(ifc_file, element):
return {
"key": val(element.Name),
"Name": val(element.Name),
"CreatedBy": get_created_by(element),
"CreatedOn": get_created_on(element),
"Category": val(element.ObjectType),
"ExternalSystem": get_external_system(element),
"ExternalObject": element.is_a(),
"ExternalIdentifier": element.GlobalId,
"Description": val(element.Description) or val(element.Name),
}
def get_job_data(ifc_file, element):
type_names = []
resource_names = []
for rel in element.OperatesOn or []:
for related_object in rel.RelatedObjects or []:
if not val(related_object.Name):
continue
if related_object.is_a("IfcTypeObject"):
type_names.append(related_object.Name)
elif related_object.is_a("IfcConstructionEquipmentResource"):
resource_names.append(related_object.Name)
type_name = ",".join(type_names) if type_names else None
resource_names = ",".join(resource_names) if resource_names else None
duration = None
duration_unit = None
start = None
task_start_unit = None
frequency = None
frequency_unit = None
for _, props in ifcopenshell.util.element.get_psets(element):
for name, value in props.items():
if not duration and name == "TaskDuration" and val(value):
duration = str(value)
if not duration_unit:
duration_unit = get_property_unit(props["id"], name)
if not start and name == "TaskStartDate" and val(value):
start = str(value)
if not task_start_unit:
task_start_unit = get_property_unit(props["id"], name)
if not frequency and name == "TaskInterval" and val(value):
frequency = str(value)
if not frequency_unit:
frequency_unit = get_property_unit(props["id"], name)
task_number = val(getattr(element, "Id", None)) or val(getattr(element, "Identification", None))
priors = []
for rel in element.IsSuccessorFrom or []:
if rel.RelatedProcess.is_a("IfcTask"):
prior_task = rel.RelatedProcess
prior_id = val(getattr(prior_task, "Id", None)) or val(getattr(prior_task, "Identification", None))
if prior_id:
priors.append(prior_id)
priors = ",".join(priors) if priors else task_number
return {
"key": val(element.Name),
"Name": val(element.Name),
"CreatedBy": get_created_by(element),
"CreatedOn": get_created_on(element),
"Category": val(element.ObjectType),
"Status": val(element.Status),
"TypeName": type_name,
"Description": val(element.Description) or val(element.Name),
"Duration": duration,
"DurationUnit": duration_unit,
"Start": start,
"TaskStartUnit": task_start_unit,
"Frequency": frequency,
"FrequencyUnit": frequency_unit,
"ExternalSystem": get_external_system(element),
"ExternalObject": element.is_a(),
"ExternalIdentifier": element.GlobalId,
"TaskNumber": task_number,
"Priors": priors,
"ResourceNames": resource_names,
}
def get_unit_type_name(ifc_file, unit_type):
for unit in ifc_file.by_type("IfcUnitAssignment")[0].Units:
if unit.is_a("IfcNamedUnit") and unit.UnitType == unit_type:
@@ -726,6 +977,18 @@ get_category_elements = {
"Type": get_types,
"Component": get_components,
"System": get_systems,
"Assembly": get_assemblies,
"Connection": get_connections,
"Spare": get_spares,
"Resource": get_resources,
"Job": get_jobs,
# "Impact": get_impacts, # Not implemented for some reason in BIMServer COBie-Plugins
"Document": get_documents,
"Attribute": get_attributes,
# Not implemented for some reason in BIMServer COBie-Plugins
# "Coordinate": get_coordinates,
# "Issue": get_issues,
# "Picklist": get_picklists,
}
get_element_data = {
@@ -737,6 +1000,17 @@ get_element_data = {
"Type": get_type_data,
"Component": get_component_data,
"System": get_system_data,
"Assembly": get_assembly_data,
"Connection": get_connection_data,
"Spare": get_spare_data,
"Resource": get_resource_data,
"Job": get_job_data,
# "Impact": get_impact_data,
"Document": get_document_data,
"Attribute": get_attribute_data,
# "Coordinate": get_coordinate_data,
# "Issue": get_issue_data,
# "Picklist": get_picklist_data,
}
config = {