mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 14:23:53 +00:00
Support element decomposition through IfcRelAggregates
This commit is contained in:
@@ -18,27 +18,43 @@ class IfcParser():
|
|||||||
with open(self.schema_dir + 'ifc_types_IFC4.json') as f:
|
with open(self.schema_dir + 'ifc_types_IFC4.json') as f:
|
||||||
self.type_map = json.load(f)
|
self.type_map = json.load(f)
|
||||||
|
|
||||||
|
self.already_parsed_collections = []
|
||||||
|
|
||||||
self.selected_products = []
|
self.selected_products = []
|
||||||
self.selected_types = []
|
self.selected_types = []
|
||||||
|
|
||||||
self.psets = []
|
self.psets = []
|
||||||
|
self.aggregates = {}
|
||||||
self.spatial_structure_elements = []
|
self.spatial_structure_elements = []
|
||||||
self.spatial_structure_elements_tree = []
|
self.spatial_structure_elements_tree = []
|
||||||
self.rel_contained_in_spatial_structure = {}
|
self.rel_contained_in_spatial_structure = {}
|
||||||
self.rel_defines_by_type = {}
|
self.rel_defines_by_type = {}
|
||||||
|
self.rel_aggregates = {}
|
||||||
self.representations = []
|
self.representations = []
|
||||||
self.type_products = []
|
self.type_products = []
|
||||||
self.context = {}
|
self.context = {}
|
||||||
self.products = []
|
self.products = []
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
self.sort_selected_into_products_and_types()
|
self.sort_into_products_and_types(bpy.context.selected_objects)
|
||||||
self.psets = self.get_psets()
|
self.psets = self.get_psets()
|
||||||
self.spatial_structure_elements = self.get_spatial_structure_elements()
|
self.spatial_structure_elements = self.get_spatial_structure_elements()
|
||||||
self.representations = self.get_representations()
|
self.representations = self.get_representations()
|
||||||
self.type_products = self.get_type_products()
|
self.type_products = self.get_type_products()
|
||||||
|
|
||||||
self.collection_name_filter = []
|
self.collection_name_filter = []
|
||||||
|
self.get_products()
|
||||||
|
|
||||||
|
self.context = self.get_context()
|
||||||
|
self.spatial_structure_elements_tree = self.get_spatial_structure_elements_tree(
|
||||||
|
self.context['raw'].children, self.collection_name_filter)
|
||||||
|
|
||||||
|
def get_object_attributes(self, object):
|
||||||
|
attributes = { 'Name': self.get_ifc_name(object.name) }
|
||||||
|
attributes.update({ key[3:]: object[key] for key in object.keys() if key[0:3] == 'Ifc'})
|
||||||
|
return attributes
|
||||||
|
|
||||||
|
def get_products(self):
|
||||||
index = 0
|
index = 0
|
||||||
for object in self.selected_products:
|
for object in self.selected_products:
|
||||||
self.products.append(self.get_product(object, index))
|
self.products.append(self.get_product(object, index))
|
||||||
@@ -56,15 +72,6 @@ class IfcParser():
|
|||||||
created_instances.append((o[0], location))
|
created_instances.append((o[0], location))
|
||||||
instance_objects.extend(created_instances)
|
instance_objects.extend(created_instances)
|
||||||
|
|
||||||
self.context = self.get_context()
|
|
||||||
self.spatial_structure_elements_tree = self.get_spatial_structure_elements_tree(
|
|
||||||
self.context['raw'].children, self.collection_name_filter)
|
|
||||||
|
|
||||||
def get_object_attributes(self, object):
|
|
||||||
attributes = { 'Name': self.get_ifc_name(object.name) }
|
|
||||||
attributes.update({ key[3:]: object[key] for key in object.keys() if key[0:3] == 'Ifc'})
|
|
||||||
return attributes
|
|
||||||
|
|
||||||
def get_product(self, object, index, attribute_override={}):
|
def get_product(self, object, index, attribute_override={}):
|
||||||
product = {
|
product = {
|
||||||
'ifc': None,
|
'ifc': None,
|
||||||
@@ -74,12 +81,17 @@ class IfcParser():
|
|||||||
'forward_axis': object.matrix_world.to_quaternion() @ Vector((1, 0, 0)),
|
'forward_axis': object.matrix_world.to_quaternion() @ Vector((1, 0, 0)),
|
||||||
'class': self.get_ifc_class(object.name),
|
'class': self.get_ifc_class(object.name),
|
||||||
'relating_structure': None,
|
'relating_structure': None,
|
||||||
'representation': self.get_representation_reference(object.data.name),
|
'representation': self.get_representation_reference_from_object(object),
|
||||||
'attributes': self.get_object_attributes(object)
|
'attributes': self.get_object_attributes(object)
|
||||||
}
|
}
|
||||||
product.update(attribute_override)
|
product.update(attribute_override)
|
||||||
|
|
||||||
for collection in product['raw'].users_collection:
|
for collection in product['raw'].users_collection:
|
||||||
self.parse_product_spatial_structure(product, index, collection)
|
self.parse_product_collection(product, index, collection)
|
||||||
|
|
||||||
|
if object.instance_type == 'COLLECTION' \
|
||||||
|
and self.is_a_rel_aggregates(self.get_ifc_class(object.instance_collection.name)):
|
||||||
|
self.rel_aggregates[index] = object.instance_collection.name
|
||||||
|
|
||||||
if object.parent \
|
if object.parent \
|
||||||
and self.is_a_type(self.get_ifc_class(object.parent.name)):
|
and self.is_a_type(self.get_ifc_class(object.parent.name)):
|
||||||
@@ -87,14 +99,17 @@ class IfcParser():
|
|||||||
self.rel_defines_by_type.setdefault(reference, []).append(index)
|
self.rel_defines_by_type.setdefault(reference, []).append(index)
|
||||||
return product
|
return product
|
||||||
|
|
||||||
def parse_product_spatial_structure(self, product, index, collection):
|
def parse_product_collection(self, product, index, collection):
|
||||||
if self.is_a_spatial_structure_element(self.get_ifc_class(collection.name)):
|
class_name = self.get_ifc_class(collection.name)
|
||||||
reference = self.get_spatial_structure_element_reference(collection.name)
|
if self.is_a_spatial_structure_element(class_name):
|
||||||
self.rel_contained_in_spatial_structure.setdefault(reference, []).append(index)
|
reference = self.get_spatial_structure_element_reference(collection.name)
|
||||||
product['relating_structure'] = reference
|
self.rel_contained_in_spatial_structure.setdefault(reference, []).append(index)
|
||||||
self.collection_name_filter.append(collection.name)
|
product['relating_structure'] = reference
|
||||||
else:
|
self.collection_name_filter.append(collection.name)
|
||||||
self.parse_product_spatial_structure(product, index, self.get_parent_collection(collection))
|
elif self.is_a_rel_aggregates(class_name):
|
||||||
|
self.aggregates.setdefault(collection.name, []).append(index)
|
||||||
|
else:
|
||||||
|
self.parse_product_collection(product, index, self.get_parent_collection(collection))
|
||||||
|
|
||||||
def get_parent_collection(self, child_collection):
|
def get_parent_collection(self, child_collection):
|
||||||
for parent_collection in bpy.data.collections:
|
for parent_collection in bpy.data.collections:
|
||||||
@@ -117,12 +132,16 @@ class IfcParser():
|
|||||||
instances.append(array)
|
instances.append(array)
|
||||||
return instances
|
return instances
|
||||||
|
|
||||||
def sort_selected_into_products_and_types(self):
|
def sort_into_products_and_types(self, objects_to_sort):
|
||||||
for object in bpy.context.selected_objects:
|
for object in objects_to_sort:
|
||||||
if self.is_object_in_types_collection(object):
|
if self.is_object_in_types_collection(object):
|
||||||
self.selected_types.append(object)
|
self.selected_types.append(object)
|
||||||
else:
|
else:
|
||||||
self.selected_products.append(object)
|
self.selected_products.append(object)
|
||||||
|
if object.instance_type == 'COLLECTION' \
|
||||||
|
and object.instance_collection.name not in self.already_parsed_collections:
|
||||||
|
self.already_parsed_collections.append(object.instance_collection.name)
|
||||||
|
self.sort_into_products_and_types(object.instance_collection.objects)
|
||||||
|
|
||||||
def get_psets(self):
|
def get_psets(self):
|
||||||
psets = []
|
psets = []
|
||||||
@@ -168,6 +187,8 @@ class IfcParser():
|
|||||||
def get_representations(self):
|
def get_representations(self):
|
||||||
representations = {}
|
representations = {}
|
||||||
for object in self.selected_products + self.selected_types:
|
for object in self.selected_products + self.selected_types:
|
||||||
|
if not object.data:
|
||||||
|
continue
|
||||||
representations[object.data.name] = object.data
|
representations[object.data.name] = object.data
|
||||||
results = []
|
results = []
|
||||||
for name, value in representations.items():
|
for name, value in representations.items():
|
||||||
@@ -188,10 +209,15 @@ class IfcParser():
|
|||||||
'up_axis': object.matrix_world.to_quaternion() @ Vector((0, 0, 1)),
|
'up_axis': object.matrix_world.to_quaternion() @ Vector((0, 0, 1)),
|
||||||
'forward_axis': object.matrix_world.to_quaternion() @ Vector((1, 0, 0)),
|
'forward_axis': object.matrix_world.to_quaternion() @ Vector((1, 0, 0)),
|
||||||
'class': self.get_ifc_class(object.name),
|
'class': self.get_ifc_class(object.name),
|
||||||
'representation': self.get_representation_reference(object.data.name),
|
'representation': self.get_representation_reference_from_object(object),
|
||||||
'attributes': self.get_object_attributes(object)
|
'attributes': self.get_object_attributes(object)
|
||||||
} for object in self.selected_types ]
|
} for object in self.selected_types ]
|
||||||
|
|
||||||
|
def get_representation_reference_from_object(self, object):
|
||||||
|
if not object.data:
|
||||||
|
return None
|
||||||
|
return self.get_representation_reference(object.data.name)
|
||||||
|
|
||||||
def get_representation_reference(self, name):
|
def get_representation_reference(self, name):
|
||||||
return [ r['attributes']['Name'] for r in self.representations ].index(name)
|
return [ r['attributes']['Name'] for r in self.representations ].index(name)
|
||||||
|
|
||||||
@@ -231,7 +257,11 @@ class IfcParser():
|
|||||||
# We assume that any collection we can't identify is a spatial structure
|
# We assume that any collection we can't identify is a spatial structure
|
||||||
return class_name[0:3] == 'Ifc' \
|
return class_name[0:3] == 'Ifc' \
|
||||||
and not self.is_a_context(class_name) \
|
and not self.is_a_context(class_name) \
|
||||||
and not self.is_a_types_collection(class_name)
|
and not self.is_a_types_collection(class_name) \
|
||||||
|
and not self.is_a_rel_aggregates(class_name)
|
||||||
|
|
||||||
|
def is_a_rel_aggregates(self, class_name):
|
||||||
|
return class_name == 'IfcRelAggregates'
|
||||||
|
|
||||||
def is_a_context(self, class_name):
|
def is_a_context(self, class_name):
|
||||||
return class_name in ['IfcProject', 'IfcProjectLibrary']
|
return class_name in ['IfcProject', 'IfcProjectLibrary']
|
||||||
@@ -259,6 +289,7 @@ class IfcExporter():
|
|||||||
self.create_type_products()
|
self.create_type_products()
|
||||||
self.create_spatial_structure_elements(self.ifc_parser.spatial_structure_elements_tree)
|
self.create_spatial_structure_elements(self.ifc_parser.spatial_structure_elements_tree)
|
||||||
self.create_products()
|
self.create_products()
|
||||||
|
self.relate_objects_to_objects()
|
||||||
self.relate_elements_to_spatial_structures()
|
self.relate_elements_to_spatial_structures()
|
||||||
self.relate_objects_to_types()
|
self.relate_objects_to_types()
|
||||||
self.file.write(self.output_file)
|
self.file.write(self.output_file)
|
||||||
@@ -337,6 +368,14 @@ class IfcExporter():
|
|||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
print('The type product "{}/{}" could not be created: {}'.format(product['class'], product['attributes']['Name'], e.args))
|
print('The type product "{}/{}" could not be created: {}'.format(product['class'], product['attributes']['Name'], e.args))
|
||||||
|
|
||||||
|
def relate_objects_to_objects(self):
|
||||||
|
for relating_object, related_objects in self.ifc_parser.rel_aggregates.items():
|
||||||
|
relating_object = self.ifc_parser.products[relating_object]
|
||||||
|
related_objects = [ self.ifc_parser.products[o]['ifc'] for o in self.ifc_parser.aggregates[related_objects] ]
|
||||||
|
self.file.createIfcRelAggregates(
|
||||||
|
ifcopenshell.guid.new(), self.owner_history, relating_object['attributes']['Name'], None,
|
||||||
|
relating_object['ifc'], related_objects)
|
||||||
|
|
||||||
def create_spatial_structure_elements(self, element_tree, relating_object=None):
|
def create_spatial_structure_elements(self, element_tree, relating_object=None):
|
||||||
if relating_object == None:
|
if relating_object == None:
|
||||||
relating_object = self.ifc_parser.context['ifc']
|
relating_object = self.ifc_parser.context['ifc']
|
||||||
@@ -365,27 +404,32 @@ class IfcExporter():
|
|||||||
|
|
||||||
def create_products(self):
|
def create_products(self):
|
||||||
for product in self.ifc_parser.products:
|
for product in self.ifc_parser.products:
|
||||||
try:
|
|
||||||
placement_rel_to = self.ifc_parser.spatial_structure_elements[product['relating_structure']]['ifc'].ObjectPlacement
|
|
||||||
except Exception as e:
|
|
||||||
print('The product "{}/{}" could not be placed on a spatial structure {}'.format(product['class'], product['attributes']['Name'], e.args))
|
|
||||||
continue
|
|
||||||
placement = self.file.createIfcLocalPlacement(placement_rel_to,
|
|
||||||
self.create_ifc_axis_2_placement_3d(product['location'],
|
|
||||||
product['up_axis'],
|
|
||||||
product['forward_axis']))
|
|
||||||
shape = self.file.createIfcProductDefinitionShape(
|
|
||||||
None, None,
|
|
||||||
[self.ifc_parser.representations[product['representation']]['ifc']])
|
|
||||||
product['attributes'].update({
|
|
||||||
'GlobalId': ifcopenshell.guid.new(), # TODO: unhardcode
|
|
||||||
'OwnerHistory': self.owner_history, # TODO: unhardcode
|
|
||||||
'ObjectPlacement': placement,
|
|
||||||
'Representation': shape
|
|
||||||
})
|
|
||||||
self.create_product(product)
|
self.create_product(product)
|
||||||
|
|
||||||
def create_product(self, product):
|
def create_product(self, product):
|
||||||
|
if product['relating_structure']:
|
||||||
|
placement_rel_to = self.ifc_parser.spatial_structure_elements[product['relating_structure']]['ifc'].ObjectPlacement
|
||||||
|
else:
|
||||||
|
placement_rel_to = None
|
||||||
|
|
||||||
|
placement = self.file.createIfcLocalPlacement(placement_rel_to,
|
||||||
|
self.create_ifc_axis_2_placement_3d(product['location'],
|
||||||
|
product['up_axis'],
|
||||||
|
product['forward_axis']))
|
||||||
|
|
||||||
|
try:
|
||||||
|
shape = self.file.createIfcProductDefinitionShape(None, None,
|
||||||
|
[self.ifc_parser.representations[product['representation']]['ifc']])
|
||||||
|
except:
|
||||||
|
shape = None
|
||||||
|
|
||||||
|
product['attributes'].update({
|
||||||
|
'GlobalId': ifcopenshell.guid.new(), # TODO: unhardcode
|
||||||
|
'OwnerHistory': self.owner_history, # TODO: unhardcode
|
||||||
|
'ObjectPlacement': placement,
|
||||||
|
'Representation': shape
|
||||||
|
})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
product['ifc'] = self.file.create_entity(product['class'], **product['attributes'])
|
product['ifc'] = self.file.create_entity(product['class'], **product['attributes'])
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user