Support IfcProjectLibrary as related to IfcProject

This commit is contained in:
Dion Moult
2019-09-08 11:07:40 +10:00
parent 58be8e95b0
commit 04aa0ad04d
+83 -62
View File
@@ -73,7 +73,6 @@ class IfcParser():
self.type_map = json.load(f) self.type_map = json.load(f)
self.selected_products = [] self.selected_products = []
self.selected_types = []
self.product_index = 0 self.product_index = 0
@@ -88,25 +87,27 @@ class IfcParser():
self.rel_aggregates = {} self.rel_aggregates = {}
self.representations = [] self.representations = []
self.type_products = [] self.type_products = []
self.context = {} self.project = {}
self.libraries = []
self.products = [] self.products = []
def parse(self): def parse(self):
self.sort_into_products_and_types(bpy.context.selected_objects) self.convert_selected_objects_into_products(bpy.context.selected_objects)
self.psets = self.get_psets() self.psets = self.get_psets()
self.spatial_structure_elements = self.get_spatial_structure_elements()
self.representations = self.get_representations() self.representations = self.get_representations()
self.qtos = self.get_qtos() self.qtos = self.get_qtos()
self.type_products = self.get_type_products() self.spatial_structure_elements = self.get_spatial_structure_elements()
self.collection_name_filter = [] self.collection_name_filter = []
self.get_products() self.get_products()
self.context = self.get_context() self.project = self.get_project()
self.libraries = self.get_libraries()
self.type_products = self.get_type_products()
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.spatial_structure_elements_tree = self.get_spatial_structure_elements_tree( self.spatial_structure_elements_tree = self.get_spatial_structure_elements_tree(
self.context['raw'].children, self.collection_name_filter) self.project['raw'].children, self.collection_name_filter)
def get_object_attributes(self, object): def get_object_attributes(self, object):
attributes = { 'Name': self.get_ifc_name(object.name) } attributes = { 'Name': self.get_ifc_name(object.name) }
@@ -116,20 +117,20 @@ class IfcParser():
return attributes return attributes
def get_products(self): def get_products(self):
for selected in self.selected_products: for product in self.selected_products:
object = selected['object'] object = product['raw']
self.add_product(self.get_product(selected)) self.add_product(self.get_product(product))
self.resolve_array_modifier(selected) self.resolve_array_modifier(product)
def resolve_array_modifier(self, selected): def resolve_array_modifier(self, product):
object = selected['object'] object = product['raw']
instance_objects = [(object, object.location)] instance_objects = [(object, object.location)]
for instance in self.get_instances(object): for instance in self.get_instances(object):
created_instances = [] created_instances = []
for n in range(instance.count-1): for n in range(instance.count-1):
for o in instance_objects: for o in instance_objects:
location = o[1] + ((n+1) * instance.offset) location = o[1] + ((n+1) * instance.offset)
self.add_product(self.get_product({ 'object': o[0], 'metadata': selected['metadata'] }, self.add_product(self.get_product({ 'raw': o[0], 'metadata': product['metadata'] },
{'location': location}, {'GlobalId': ifcopenshell.guid.new()})) {'location': location}, {'GlobalId': ifcopenshell.guid.new()}))
created_instances.append((o[0], location)) created_instances.append((o[0], location))
instance_objects.extend(created_instances) instance_objects.extend(created_instances)
@@ -138,8 +139,8 @@ class IfcParser():
self.products.append(product) self.products.append(product)
self.product_index += 1 self.product_index += 1
def get_product(self, selected, metadata_override={}, attribute_override={}): def get_product(self, selected_product, metadata_override={}, attribute_override={}):
object = selected['object'] object = selected_product['raw']
product = { product = {
'ifc': None, 'ifc': None,
'raw': object, 'raw': object,
@@ -162,8 +163,8 @@ class IfcParser():
and self.is_a_rel_aggregates(self.get_ifc_class(object.instance_collection.name)): and self.is_a_rel_aggregates(self.get_ifc_class(object.instance_collection.name)):
self.rel_aggregates[self.product_index] = object.name self.rel_aggregates[self.product_index] = object.name
if 'rel_aggregates_relating_object' in selected['metadata']: if 'rel_aggregates_relating_object' in selected_product['metadata']:
relating_object = selected['metadata']['rel_aggregates_relating_object'] relating_object = selected_product['metadata']['rel_aggregates_relating_object']
product['location'] = relating_object.matrix_world @ product['location'] product['location'] = relating_object.matrix_world @ product['location']
product['up_axis'] = (relating_object.matrix_world.to_quaternion() @ object.matrix_world.to_quaternion()) @ Vector((0, 0, 1)) product['up_axis'] = (relating_object.matrix_world.to_quaternion() @ object.matrix_world.to_quaternion()) @ Vector((0, 0, 1))
product['forward_axis'] = (relating_object.matrix_world.to_quaternion() @ object.matrix_world.to_quaternion()) @ Vector((1, 0, 0)) product['forward_axis'] = (relating_object.matrix_world.to_quaternion() @ object.matrix_world.to_quaternion()) @ Vector((1, 0, 0))
@@ -211,16 +212,14 @@ class IfcParser():
instances.append(array) instances.append(array)
return instances return instances
def sort_into_products_and_types(self, objects_to_sort, metadata = None): def convert_selected_objects_into_products(self, objects_to_sort, metadata = None):
if not metadata: if not metadata:
metadata = {} metadata = {}
for object in objects_to_sort: for object in objects_to_sort:
if self.is_object_in_types_collection(object): if not self.is_a_library(self.get_ifc_class(object.users_collection[0].name)):
self.selected_types.append({ 'object': object, 'metadata': metadata }) self.selected_products.append({ 'raw': object, 'metadata': metadata })
else:
self.selected_products.append({ 'object': object, 'metadata': metadata })
if object.instance_type == 'COLLECTION': if object.instance_type == 'COLLECTION':
self.sort_into_products_and_types(object.instance_collection.objects, self.convert_selected_objects_into_products(object.instance_collection.objects,
{'rel_aggregates_relating_object': object}) {'rel_aggregates_relating_object': object})
def get_psets(self): def get_psets(self):
@@ -236,15 +235,9 @@ class IfcParser():
}) })
return psets return psets
def is_object_in_types_collection(self, object): def get_project(self):
for collection in object.users_collection:
if self.is_a_types_collection(self.get_ifc_class(collection.name)):
return True
return False
def get_context(self):
for collection in bpy.data.collections: for collection in bpy.data.collections:
if self.is_a_context(self.get_ifc_class(collection.name)): if self.is_a_project(self.get_ifc_class(collection.name)):
return { return {
'ifc': None, 'ifc': None,
'raw': collection, 'raw': collection,
@@ -252,6 +245,19 @@ class IfcParser():
'attributes': { 'Name': self.get_ifc_name(collection.name) } 'attributes': { 'Name': self.get_ifc_name(collection.name) }
} }
def get_libraries(self):
results = []
for collection in self.project['raw'].children:
if not self.is_a_library(self.get_ifc_class(collection.name)):
continue
results.append({
'ifc': None,
'raw': collection,
'class': self.get_ifc_class(collection.name),
'attributes': { 'Name': self.get_ifc_name(collection.name) }
})
return results
def get_map_conversion(self): def get_map_conversion(self):
scene = bpy.context.scene scene = bpy.context.scene
if 'HasMapConversion' not in scene: if 'HasMapConversion' not in scene:
@@ -301,8 +307,8 @@ class IfcParser():
results = [] results = []
if not self.ifc_export_settings.has_representations: if not self.ifc_export_settings.has_representations:
return results return results
for selected in self.selected_products + self.selected_types: for product in self.selected_products + self.type_products:
object = selected['object'] object = product['raw']
if not object.data: if not object.data:
continue continue
results.append({ results.append({
@@ -317,8 +323,8 @@ class IfcParser():
if not self.ifc_export_settings.has_quantities: if not self.ifc_export_settings.has_quantities:
return {} return {}
results = {} results = {}
for selected in self.selected_products + self.selected_types: for product in self.selected_products + self.type_products:
object = selected['object'] object = product['raw']
if not object.data: if not object.data:
continue continue
for property in object.keys(): for property in object.keys():
@@ -336,18 +342,25 @@ class IfcParser():
return results return results
def get_type_products(self): def get_type_products(self):
if not self.selected_types: results = []
return [] for library in self.libraries:
return [{ for object in library['raw'].objects:
'ifc': None, if not self.is_a_type(self.get_ifc_class(object.name)):
'raw': selected['object'], continue
'location': selected['object'].location, try:
'up_axis': selected['object'].matrix_world.to_quaternion() @ Vector((0, 0, 1)), results.append({
'forward_axis': selected['object'].matrix_world.to_quaternion() @ Vector((1, 0, 0)), 'ifc': None,
'class': self.get_ifc_class(selected['object'].name), 'raw': object,
'representation': self.get_representation_reference_from_object(selected['object']), 'location': object.location,
'attributes': self.get_object_attributes(selected['object']) 'up_axis': object.matrix_world.to_quaternion() @ Vector((0, 0, 1)),
} for selected in self.selected_types ] 'forward_axis': object.matrix_world.to_quaternion() @ Vector((1, 0, 0)),
'class': self.get_ifc_class(object.name),
'representation': self.get_representation_reference_from_object(object),
'attributes': self.get_object_attributes(object)
})
except Exception as e:
print('The type product "{}" could not be parsed: {}'.format(object.name, e.args))
return results
def get_representation_reference_from_object(self, object): def get_representation_reference_from_object(self, object):
if not self.ifc_export_settings.has_representations \ if not self.ifc_export_settings.has_representations \
@@ -393,22 +406,22 @@ class IfcParser():
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 # 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_project(class_name) \
and not self.is_a_types_collection(class_name) \ and not self.is_a_library(class_name) \
and not self.is_a_rel_aggregates(class_name) and not self.is_a_rel_aggregates(class_name)
def is_a_rel_aggregates(self, class_name): def is_a_rel_aggregates(self, class_name):
return class_name == 'IfcRelAggregates' return class_name == 'IfcRelAggregates'
def is_a_context(self, class_name): def is_a_project(self, class_name):
return class_name in ['IfcProject', 'IfcProjectLibrary'] return class_name == 'IfcProject'
def is_a_library(self, class_name):
return class_name == 'IfcProjectLibrary'
def is_a_type(self, class_name): def is_a_type(self, class_name):
return class_name[0:3] == 'Ifc' and class_name[-4:] == 'Type' return class_name[0:3] == 'Ifc' and class_name[-4:] == 'Type'
def is_a_types_collection(self, class_name):
return class_name == 'IfcTypeProduct'
class SIUnitHelper: class SIUnitHelper:
prefixes = ["EXA", "PETA", "TERA", "GIGA", "MEGA", "KILO", "HECTO", prefixes = ["EXA", "PETA", "TERA", "GIGA", "MEGA", "KILO", "HECTO",
"DECA", "DECI", "CENTI", "MILLI", "MICRO", "NANO", "PICO", "FEMTO", "DECA", "DECI", "CENTI", "MILLI", "MICRO", "NANO", "PICO", "FEMTO",
@@ -445,7 +458,8 @@ class IfcExporter():
self.ifc_parser.parse() self.ifc_parser.parse()
self.create_psets() self.create_psets()
self.create_rep_context() self.create_rep_context()
self.create_context() self.create_project()
self.create_libraries()
self.create_map_conversion() self.create_map_conversion()
self.create_representations() self.create_representations()
self.create_type_products() self.create_type_products()
@@ -510,15 +524,22 @@ class IfcExporter():
None, None, None, None, None, None, None, None,
self.ifc_rep_context, None, "MODEL_VIEW", None) self.ifc_rep_context, None, "MODEL_VIEW", None)
def create_context(self): def create_project(self):
context = self.ifc_parser.context self.ifc_parser.project['attributes'].update({
attributes = context['attributes']
attributes.update({
'GlobalId': ifcopenshell.guid.new(), 'GlobalId': ifcopenshell.guid.new(),
'RepresentationContexts': [self.ifc_rep_context], 'RepresentationContexts': [self.ifc_rep_context],
'UnitsInContext': self.file.by_type("IfcUnitAssignment")[0] 'UnitsInContext': self.file.by_type("IfcUnitAssignment")[0]
}) })
self.ifc_parser.context['ifc'] = self.file.create_entity(self.ifc_parser.context['class'], **attributes) self.ifc_parser.project['ifc'] = self.file.create_entity(
self.ifc_parser.project['class'], **self.ifc_parser.project['attributes'])
def create_libraries(self):
for library in self.ifc_parser.libraries:
library['ifc'] = self.file.create_entity(library['class'], **library['attributes'])
self.file.createIfcRelDeclares(
ifcopenshell.guid.new(), self.owner_history,
library['attributes']['Name'], None,
self.ifc_parser.project['ifc'], [l['ifc'] for l in self.ifc_parser.libraries])
def create_map_conversion(self): def create_map_conversion(self):
if not self.ifc_parser.map_conversion: if not self.ifc_parser.map_conversion:
@@ -562,7 +583,7 @@ class IfcExporter():
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.project['ifc']
placement_rel_to = None placement_rel_to = None
else: else:
placement_rel_to = relating_object.ObjectPlacement placement_rel_to = relating_object.ObjectPlacement