Skip to content

Commit

Permalink
Fix bug where missing styles in invalid IFCs cause imports to fail
Browse files Browse the repository at this point in the history
  • Loading branch information
Moult committed Apr 2, 2020
1 parent 02e2995 commit 4c58cec
Showing 1 changed file with 35 additions and 19 deletions.
54 changes: 35 additions & 19 deletions src/ifcblenderexport/blenderbim/import_ifc.py
Expand Up @@ -26,25 +26,28 @@ def create(self, element, obj, mesh):
and self.mesh.name in self.parsed_meshes:
return
if self.parse_representations(element):
self.assign_material_slots_to_faces(obj, mesh)
self.assign_material_slots_to_faces(obj, self.mesh)
self.parsed_meshes.append(self.mesh.name)
return # styled items override material styles
self.parse_material(element)
self.parsed_meshes.append(self.mesh.name)

def parse_representations(self, element):
has_parsed = False
for representation in element.Representation.Representations:
if self.parse_representation(representation):
return True
has_parsed = True
return has_parsed

def parse_representation(self, representation):
has_parsed = False
representation = self.resolve_mapped_representation(representation)
for item in representation.Items:
if self.parse_representation_item(item):
has_parsed = True
return has_parsed

def parse_representation_item(self, item):
if item.is_a('IfcMappedItem'):
item = item.MappingSource.MappedRepresentation.Items[0]
if not item.StyledByItem:
return
styled_item = item.StyledByItem[0]
Expand All @@ -53,14 +56,14 @@ def parse_representation_item(self, item):

if material_name not in self.materials:
self.materials[material_name] = bpy.data.materials.new(material_name)
self.parse_styled_item(item.StyledByItem[0], self.materials[material_name])
self.parse_styled_item(styled_item, self.materials[material_name])

if self.ifc_import_settings.should_treat_styled_item_as_material:
# Revit workaround: since Revit exports all material
# assignments as individual object styled items. Treating
# them as reusable materials makes things much more
# efficient in Blender.
if self.mesh.name not in self.parsed_meshes:
self.assign_material_to_mesh(self.materials[material_name])
self.assign_material_to_mesh(self.materials[material_name])
else:
# Proper behaviour
self.assign_material_to_mesh(self.materials[material_name], is_styled_item=True)
Expand Down Expand Up @@ -112,23 +115,17 @@ def create_new_single(self, material):
def get_material_name(self, styled_item):
if styled_item.Name:
return styled_item.Name
# Note IfcPresentationStyleAssignment is deprecated as of IFC4,
# but we still support it as it is widely used, gee thanks Revit :(
if styled_item.Styles[0].is_a('IfcPresentationStyleAssignment'):
styled_item = styled_item.Styles[0]
styled_item = self.resolve_presentation_style_assignment(styled_item)
for style in styled_item.Styles:
if not style.is_a('IfcSurfaceStyle'):
continue
if style.Name:
return style.Name
return style.id()
return styled_item.id()
return str(style.id())
return str(styled_item.id())

def parse_styled_item(self, styled_item, material):
# Note IfcPresentationStyleAssignment is deprecated as of IFC4,
# but we still support it as it is widely used, gee thanks Revit :(
if styled_item.Styles[0].is_a('IfcPresentationStyleAssignment'):
styled_item = styled_item.Styles[0]
styled_item = self.resolve_presentation_style_assignment(styled_item)
for style in styled_item.Styles:
if not style.is_a('IfcSurfaceStyle'):
continue
Expand All @@ -153,8 +150,21 @@ def parse_styled_item(self, styled_item, material):
material.BIMMaterialProperties.identification = external_style.Identification
material.BIMMaterialProperties.name = external_style.Name

# IfcPresentationStyleAssignment is deprecated as of IFC4
# However it is still widely used thanks to Revit :(
def resolve_presentation_style_assignment(self, styled_item):
for style in styled_item.Styles:
if style.is_a('IfcPresentationStyleAssignment'):
return style
return styled_item

def resolve_mapped_representation(self, representation):
for item in representation.Items:
if item.is_a('IfcMappedItem'):
return item.MappingSource.MappedRepresentation
return representation

def assign_material_to_mesh(self, material, is_styled_item=False):
self.parsed_meshes.append(self.mesh.name)
self.mesh.materials.append(material)
if is_styled_item:
index = len(self.obj.material_slots) - 1
Expand Down Expand Up @@ -760,7 +770,13 @@ def create_mesh(self, element, shape):
edges = [[e[i], e[i + 1]]
for i in range(0, len(e), 2)]
mesh.from_pydata(vertices, edges, faces)
mesh['ios_materials'] = [m.name for m in geometry.materials]
ios_materials = []
for mat in geometry.materials:
if mat.original_name():
ios_materials.append(mat.original_name())
else:
ios_materials.append(mat.name)
mesh['ios_materials'] = ios_materials
mesh['ios_material_ids'] = geometry.material_ids
return mesh
except:
Expand Down

0 comments on commit 4c58cec

Please sign in to comment.