Improve prototype of native round-tripping by reading from original file and preserving styles

This commit is contained in:
Dion Moult
2020-09-28 22:14:03 +10:00
parent e70d08c3a1
commit b4f4d9b3c5
3 changed files with 50 additions and 35 deletions
@@ -8,8 +8,9 @@ import zipfile
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from mathutils import Vector, Matrix from mathutils import Vector, Matrix
from .helper import SIUnitHelper from .helper import SIUnitHelper, get_representation_elements
from . import schema from . import schema
from . import ifc
import ifcopenshell import ifcopenshell
import addon_utils import addon_utils
@@ -1027,7 +1028,7 @@ class IfcParser():
obj.data, obj, 'Model', 'Body', 'MODEL_VIEW') obj.data, obj, 'Model', 'Body', 'MODEL_VIEW')
if 'Model/Box/MODEL_VIEW' in self.generated_subcontexts: if 'Model/Box/MODEL_VIEW' in self.generated_subcontexts:
if self.ifc_export_settings.should_roundtrip_native \ if self.ifc_export_settings.should_roundtrip_native \
and obj.data.BIMMeshProperties.ifc_definition: and obj.data.BIMMeshProperties.ifc_definition_id:
return return
self.representations['Model/Box/MODEL_VIEW/{}'.format(obj.data.name)] = self.get_representation( self.representations['Model/Box/MODEL_VIEW/{}'.format(obj.data.name)] = self.get_representation(
obj.data, obj, 'Model', 'Box', 'MODEL_VIEW') obj.data, obj, 'Model', 'Box', 'MODEL_VIEW')
@@ -1068,7 +1069,7 @@ class IfcParser():
if 'Model/Box/MODEL_VIEW' in self.generated_subcontexts \ if 'Model/Box/MODEL_VIEW' in self.generated_subcontexts \
and context_prefix == 'Model/Body/MODEL_VIEW': and context_prefix == 'Model/Body/MODEL_VIEW':
if self.ifc_export_settings.should_roundtrip_native \ if self.ifc_export_settings.should_roundtrip_native \
and obj.data.BIMMeshProperties.ifc_definition: and obj.data.BIMMeshProperties.ifc_definition_id:
pass pass
else: else:
self.representations['Model/Box/MODEL_VIEW/{}'.format(mesh_name.split('/')[3])] = self.get_representation( self.representations['Model/Box/MODEL_VIEW/{}'.format(mesh_name.split('/')[3])] = self.get_representation(
@@ -1101,6 +1102,7 @@ class IfcParser():
'context': context, 'context': context,
'subcontext': subcontext, 'subcontext': subcontext,
'target_view': target_view, 'target_view': target_view,
'has_ifc_definition': False if not hasattr(mesh, 'BIMMeshProperties') else (mesh.BIMMeshProperties.ifc_definition or mesh.BIMMeshProperties.ifc_definition_id),
'ifc_definition': mesh.BIMMeshProperties.ifc_definition if hasattr(mesh, 'BIMMeshProperties') else None, 'ifc_definition': mesh.BIMMeshProperties.ifc_definition if hasattr(mesh, 'BIMMeshProperties') else None,
'ifc_definition_id': mesh.BIMMeshProperties.ifc_definition_id if hasattr(mesh, 'BIMMeshProperties') else None, 'ifc_definition_id': mesh.BIMMeshProperties.ifc_definition_id if hasattr(mesh, 'BIMMeshProperties') else None,
'is_parametric': mesh.BIMMeshProperties.is_parametric if hasattr(mesh, 'BIMMeshProperties') else False, 'is_parametric': mesh.BIMMeshProperties.is_parametric if hasattr(mesh, 'BIMMeshProperties') else False,
@@ -1172,7 +1174,9 @@ class IfcParser():
parsed_data_names = [] parsed_data_names = []
for product in self.selected_products + self.type_products: for product in self.selected_products + self.type_products:
obj = product['raw'] obj = product['raw']
if obj.data is None or obj.data.name in parsed_data_names: if obj.data is None \
or obj.data.name in parsed_data_names \
or obj.data.BIMMeshProperties.ifc_definition_id:
continue continue
parsed_data_names.append(obj.data.name) parsed_data_names.append(obj.data.name)
for slot in obj.material_slots: for slot in obj.material_slots:
@@ -2180,7 +2184,7 @@ class IfcExporter():
results = [] results = []
for representation_name in product['representations']: for representation_name in product['representations']:
representation = self.ifc_parser.representations[representation_name] representation = self.ifc_parser.representations[representation_name]
if self.ifc_export_settings.should_roundtrip_native and representation['ifc_definition']: if self.ifc_export_settings.should_roundtrip_native and representation['has_ifc_definition']:
results.append(representation['ifc']) results.append(representation['ifc'])
else: else:
results.append(self.get_product_mapped_geometry(product, representation)) results.append(self.get_product_mapped_geometry(product, representation))
@@ -2233,7 +2237,7 @@ class IfcExporter():
self.file.createIfcDirection((forward.x, forward.y, forward.z))) self.file.createIfcDirection((forward.x, forward.y, forward.z)))
def create_representation(self, representation): def create_representation(self, representation):
if self.ifc_export_settings.should_roundtrip_native and representation['ifc_definition']: if self.ifc_export_settings.should_roundtrip_native and representation['has_ifc_definition']:
return self.create_representation_from_definition(representation) return self.create_representation_from_definition(representation)
self.ifc_vertices = [] self.ifc_vertices = []
self.ifc_edges = [] self.ifc_edges = []
@@ -2245,28 +2249,32 @@ class IfcExporter():
return self.create_variable_representation(representation) return self.create_variable_representation(representation)
def create_representation_from_definition(self, representation): def create_representation_from_definition(self, representation):
# See bug #999 on why we don't garbage collect the temporary IFC file if representation['ifc_definition']:
representation['ifc_definition_file'] = ifcopenshell.file.from_string(representation['ifc_definition']) print('Authoring an IFC definition directly is not yet implemented')
entry = self.file.add(representation['ifc_definition_file'].by_id(representation['ifc_definition_id'])) return
substitutions = [] elif representation['ifc_definition_id']:
for element in representation['ifc_definition_file']: entry = self.file.add(ifc.IfcStore.get_file().by_id(representation['ifc_definition_id']))
added_element = self.file.add(element) substitutions = []
if added_element.is_a('IfcGeometricRepresentationContext'): for element in get_representation_elements(
substitutions.append(added_element) ifc.IfcStore.get_file(), representation['ifc_definition_id']):
for element in substitutions: added_element = self.file.add(element)
if element.is_a() == 'IfcGeometricRepresentationContext': if added_element.is_a('IfcGeometricRepresentationContext'):
new_element = [e for e in substitutions.append(added_element)
self.file.by_type('IfcGeometricRepresentationContext') for element in substitutions:
if e.ContextType == element.ContextType][0] if element.is_a() == 'IfcGeometricRepresentationContext':
elif element.is_a() == 'IfcGeometricRepresentationSubContext': new_element = [e for e in
new_element = [e for e in self.file.by_type('IfcGeometricRepresentationContext')
self.file.by_type('IfcGeometricRepresentationContext') if e.ContextType == element.ContextType][0]
if e.ContextType == element.ContextType and elif element.is_a() == 'IfcGeometricRepresentationSubContext':
e.ContextIdentifier == element.ContextIdentifier][0] new_element = [e for e in
for inverse in self.file.get_inverse(element): self.file.by_type('IfcGeometricRepresentationContext')
ifcopenshell.util.element.replace_attribute(inverse, element, new_element) if e.ContextType == element.ContextType and
self.file.remove(element) e.ContextIdentifier == element.ContextIdentifier][0]
return entry for inverse in self.file.get_inverse(element):
ifcopenshell.util.element.replace_attribute(inverse, element, new_element)
# TODO: Work out how and when to purge this
#self.file.remove(element)
return entry
def create_model_representation(self, representation): def create_model_representation(self, representation):
if representation['subcontext'] == 'Annotation': if representation['subcontext'] == 'Annotation':
@@ -1,6 +1,19 @@
import math import math
import bpy import bpy
# TODO: figure out where this should go
def get_representation_elements(ifc_file, step_id):
results = []
for child in ifc_file.traverse(ifc_file.by_id(step_id)):
if hasattr(child, 'StyledByItem') and child.StyledByItem:
for styled_by_item in child.StyledByItem:
for style in styled_by_item.Styles:
for style_child in ifc_file.traverse(style):
results.append(style_child)
results.append(child)
return results
# TODO: Deprecate this in favour of ifcopenshell.util.unit # TODO: Deprecate this in favour of ifcopenshell.util.unit
class SIUnitHelper: class SIUnitHelper:
@@ -1938,17 +1938,11 @@ class IfcImporter():
mesh.BIMMeshProperties.geometry_type = str(self.get_geometry_type(element)) mesh.BIMMeshProperties.geometry_type = str(self.get_geometry_type(element))
if not self.ifc_import_settings.should_roundtrip_native: if not self.ifc_import_settings.should_roundtrip_native:
return return
dummy = ifcopenshell.file(schema=self.file.schema)
if element.is_a('IfcRepresentation'): if element.is_a('IfcRepresentation'):
representation = element representation = element
else: else:
representation = self.get_representation_of_context(element.Representation.Representations, shape.context) representation = self.get_representation_of_context(element.Representation.Representations, shape.context)
mesh.BIMMeshProperties.ifc_definition_id = int(dummy.add(representation).id()) mesh.BIMMeshProperties.ifc_definition_id = int(representation.id())
for child in self.file.traverse(representation):
[dummy.add(inverse) for inverse in self.file.get_inverse(child)]
dummy.add(child)
mesh.BIMMeshProperties.ifc_definition = dummy.to_string()
def create_curve(self, geometry): def create_curve(self, geometry):
curve = bpy.data.curves.new(geometry.id, type='CURVE') curve = bpy.data.curves.new(geometry.id, type='CURVE')