Allow export of objects contained inside IfcSpace and other spatial elements

This commit is contained in:
Dion Moult
2020-03-19 14:37:18 +11:00
parent 772468d1ec
commit 41acb6c985
4 changed files with 60 additions and 46 deletions
+54 -43
View File
@@ -145,8 +145,6 @@ class IfcParser():
self.spatial_structure_elements = self.get_spatial_structure_elements() self.spatial_structure_elements = self.get_spatial_structure_elements()
self.structural_analysis_models = self.get_structural_analysis_models() self.structural_analysis_models = self.get_structural_analysis_models()
self.collection_name_filter = []
self.project = self.get_project() self.project = self.get_project()
self.libraries = self.get_libraries() self.libraries = self.get_libraries()
self.door_attributes = self.get_door_attributes() self.door_attributes = self.get_door_attributes()
@@ -157,8 +155,7 @@ class IfcParser():
self.map_conversion = self.get_map_conversion() self.map_conversion = self.get_map_conversion()
self.target_crs = self.get_target_crs() self.target_crs = self.get_target_crs()
self.library_information = self.get_library_information() self.library_information = self.get_library_information()
self.spatial_structure_elements_tree = self.get_spatial_structure_elements_tree( self.spatial_structure_elements_tree = self.get_spatial_structure_elements_tree(self.project)
self.project['raw'].children, self.collection_name_filter)
def get_units(self): def get_units(self):
return { return {
@@ -397,7 +394,7 @@ class IfcParser():
product['attributes'].update(attribute_override) product['attributes'].update(attribute_override)
product.update(metadata_override) product.update(metadata_override)
type_product = obj.BIMObjectProperties.type_product type_product = obj.BIMObjectProperties.relating_type
if type_product \ if type_product \
and self.is_a_type(self.get_ifc_class(type_product.name)): and self.is_a_type(self.get_ifc_class(type_product.name)):
reference = self.get_type_product_reference(type_product.name) reference = self.get_type_product_reference(type_product.name)
@@ -408,8 +405,7 @@ class IfcParser():
product['boundary_condition_attributes'] = {a.name: a.string_value product['boundary_condition_attributes'] = {a.name: a.string_value
for a in obj.BIMObjectProperties.boundary_condition.attributes} for a in obj.BIMObjectProperties.boundary_condition.attributes}
for collection in product['raw'].users_collection: self.get_product_relating_structure(product, obj)
self.parse_product_collection(product, collection)
if 'IfcRelNests' in obj.constraints: if 'IfcRelNests' in obj.constraints:
# TODO: I think get_product_index_from_raw_name should not be used # TODO: I think get_product_index_from_raw_name should not be used
@@ -494,6 +490,16 @@ class IfcParser():
return product return product
def get_product_relating_structure(self, product, obj):
relating_structure = obj.BIMObjectProperties.relating_structure
if relating_structure:
reference = self.get_spatial_structure_element_reference(relating_structure.name)
self.rel_contained_in_spatial_structure.setdefault(reference, []).append(self.product_index)
product['relating_structure'] = reference
return
for collection in product['raw'].users_collection:
self.parse_product_collection(product, collection)
def parse_product_collection(self, product, collection): def parse_product_collection(self, product, collection):
if collection is None: if collection is None:
return return
@@ -502,7 +508,6 @@ class IfcParser():
reference = self.get_spatial_structure_element_reference(collection.name) reference = self.get_spatial_structure_element_reference(collection.name)
self.rel_contained_in_spatial_structure.setdefault(reference, []).append(self.product_index) self.rel_contained_in_spatial_structure.setdefault(reference, []).append(self.product_index)
product['relating_structure'] = reference product['relating_structure'] = reference
self.collection_name_filter.append(collection.name)
elif self.is_a_structural_analysis_model(class_name): elif self.is_a_structural_analysis_model(class_name):
reference = self.get_structural_analysis_model_reference(collection.name) reference = self.get_structural_analysis_model_reference(collection.name)
self.rel_assigns_to_group.setdefault(reference, []).append(self.product_index) self.rel_assigns_to_group.setdefault(reference, []).append(self.product_index)
@@ -523,7 +528,7 @@ class IfcParser():
for obj in objects_to_sort: for obj in objects_to_sort:
if obj.name[0:3] != 'Ifc': if obj.name[0:3] != 'Ifc':
continue continue
elif obj.users_collection and obj.users_collection[0].name == obj.name: elif self.is_a_spatial_structure_element(self.get_ifc_class(obj.name)):
self.selected_spatial_structure_elements.append({'raw': obj, 'metadata': metadata}) self.selected_spatial_structure_elements.append({'raw': obj, 'metadata': metadata})
elif obj.instance_type == 'COLLECTION': elif obj.instance_type == 'COLLECTION':
self.categorise_selected_objects( self.categorise_selected_objects(
@@ -725,19 +730,16 @@ class IfcParser():
def get_spatial_structure_elements(self): def get_spatial_structure_elements(self):
elements = [] elements = []
for collection in bpy.data.collections: for selected_element in self.selected_spatial_structure_elements:
if self.is_a_spatial_structure_element(self.get_ifc_class(collection.name)): obj = selected_element['raw']
raw = bpy.data.objects.get(collection.name) element = {
if not raw: 'ifc': None,
raw = collection 'raw': obj,
element = { 'class': self.get_ifc_class(obj.name),
'ifc': None, 'attributes': self.get_object_attributes(obj)
'raw': raw, }
'class': self.get_ifc_class(raw.name), self.append_product_attributes(element, obj)
'attributes': self.get_object_attributes(raw) elements.append(element)
}
self.append_product_attributes(element, raw)
elements.append(element)
return elements return elements
def get_structural_analysis_models(self): def get_structural_analysis_models(self):
@@ -998,22 +1000,29 @@ class IfcParser():
names.append(mesh_name) names.append(mesh_name)
return names return names
def get_spatial_structure_elements_tree(self, collections, name_filter): def get_spatial_structure_elements_tree(self, parent):
collection_tree = [] children = []
if parent['raw'].name not in bpy.data.collections:
for collection in collections: return children
if not self.is_a_spatial_structure_element(self.get_ifc_class(collection.name)): for reference, element in enumerate(self.spatial_structure_elements):
continue if ( \
children = self.get_spatial_structure_elements_tree( # A convention is established that spatial elements may be
collection.children, name_filter) # an object placed in a collection of the same name
if collection.name in name_filter \ element['raw'].name == element['raw'].users_collection[0].name \
or children: and element['raw'].users_collection[0].name in [c.name \
collection_tree.append({ for c in bpy.data.collections[parent['raw'].name].children] \
'reference': self.get_spatial_structure_element_reference(collection.name), ) or ( \
'children': children # We allow finer grain spatial elements such as IfcSpace to
# break the convention to prevent collection overload in Blender
element['raw'].name != element['raw'].users_collection[0].name \
and element['raw'].users_collection[0].name in [o.name \
for o in bpy.data.collections[parent['raw'].name].objects] \
):
children.append({
'reference': reference,
'children': self.get_spatial_structure_elements_tree(element)
}) })
return children
return collection_tree
def get_spatial_structure_element_reference(self, name): def get_spatial_structure_element_reference(self, name):
return ['{}/{}'.format(e['class'], e['attributes']['Name']) return ['{}/{}'.format(e['class'], e['attributes']['Name'])
@@ -1038,12 +1047,14 @@ class IfcParser():
'Name "{}" does not follow the format of "IfcClass/Name"'.format(name)) 'Name "{}" does not follow the format of "IfcClass/Name"'.format(name))
def is_a_spatial_structure_element(self, class_name): def is_a_spatial_structure_element(self, class_name):
# We assume that any collection we can't identify is a spatial structure return class_name in [
return class_name[0:3] == 'Ifc' \ 'IfcBuilding',
and not self.is_a_project(class_name) \ 'IfcBuildingStorey',
and not self.is_a_library(class_name) \ 'IfcExternalSpatialElement',
and not self.is_a_rel_aggregates(class_name) \ 'IfcSite',
and not self.is_a_structural_analysis_model(class_name) 'IfcSpace',
'IfcSpatialZone'
]
def is_a_rel_aggregates(self, class_name): def is_a_rel_aggregates(self, class_name):
return class_name == 'IfcRelAggregates' return class_name == 'IfcRelAggregates'
@@ -426,7 +426,7 @@ class IfcImporter():
return return
related_type = element.IsTypedBy[0].RelatingType related_type = element.IsTypedBy[0].RelatingType
if related_type: if related_type:
obj.BIMObjectProperties.type_product = self.type_products[related_type.GlobalId] obj.BIMObjectProperties.relating_type = self.type_products[related_type.GlobalId]
def load_diff(self): def load_diff(self):
if not self.ifc_import_settings.diff_file: if not self.ifc_import_settings.diff_file:
+2 -1
View File
@@ -479,7 +479,8 @@ class BoundaryCondition(PropertyGroup):
class BIMObjectProperties(PropertyGroup): class BIMObjectProperties(PropertyGroup):
global_ids: CollectionProperty(name="GlobalIds", type=GlobalId) global_ids: CollectionProperty(name="GlobalIds", type=GlobalId)
attributes: CollectionProperty(name="Attributes", type=Attribute) attributes: CollectionProperty(name="Attributes", type=Attribute)
type_product: PointerProperty(name='Type Product', type=bpy.types.Object) relating_type: PointerProperty(name='Type Product', type=bpy.types.Object)
relating_structure: PointerProperty(name='Spatial Container', type=bpy.types.Object)
psets: CollectionProperty(name="Psets", type=Pset) psets: CollectionProperty(name="Psets", type=Pset)
applicable_attributes: EnumProperty(items=getApplicableAttributes, name="Attribute Names") applicable_attributes: EnumProperty(items=getApplicableAttributes, name="Attribute Names")
documents: CollectionProperty(name="Documents", type=Document) documents: CollectionProperty(name="Documents", type=Document)
+3 -1
View File
@@ -38,7 +38,9 @@ class BIM_PT_object(Panel):
row.prop(props, 'attributes') row.prop(props, 'attributes')
row = layout.row() row = layout.row()
row.prop(props, 'type_product') row.prop(props, 'relating_type')
row = layout.row()
row.prop(props, 'relating_structure')
layout.label(text="Property Sets:") layout.label(text="Property Sets:")
row = layout.row() row = layout.row()