mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 19:07:57 +00:00
Roundtripping geometry now works for one to many styled item relationships
This commit is contained in:
@@ -269,6 +269,7 @@ if bpy is not None:
|
||||
prop.BIMObjectProperties,
|
||||
prop.BIMMaterialProperties,
|
||||
prop.SweptSolid,
|
||||
prop.ItemSlotMap,
|
||||
prop.BIMMeshProperties,
|
||||
prop.BIMCameraProperties,
|
||||
prop.BIMTextProperties,
|
||||
|
||||
@@ -1323,6 +1323,7 @@ class IfcExporter:
|
||||
self.template_file = "{}template.ifc".format(ifc_export_settings.schema_dir)
|
||||
self.ifc_export_settings = ifc_export_settings
|
||||
self.ifc_parser = ifc_parser
|
||||
self.roundtrip_id_map = {}
|
||||
|
||||
def export(self, selected_objects):
|
||||
self.schema_version = self.ifc_export_settings.schema
|
||||
@@ -2002,27 +2003,41 @@ class IfcExporter:
|
||||
|
||||
def create_styled_items(self):
|
||||
for styled_item in self.ifc_parser.styled_items:
|
||||
product = self.ifc_parser.products[
|
||||
self.ifc_parser.get_product_index_from_raw_name(styled_item["related_product_name"])
|
||||
]
|
||||
material_slots = {}
|
||||
if product["ifc"].Representation:
|
||||
# This is a simplification, which works since we are currently in a controlled environment where the
|
||||
# BlenderBIM Add-on controls how data is structured during export. When we implement full IFC
|
||||
# round-tripping, this simplification can no longer apply.
|
||||
for representation in product["ifc"].Representation.Representations:
|
||||
# At the moment, until we implement full support for round-tripping contexts, we assume that styled
|
||||
# items only apply to the body context. This is therefore an incomplete implementation and may break
|
||||
# in edge cases.
|
||||
if representation.RepresentationIdentifier != "Body":
|
||||
continue
|
||||
for i, item in enumerate(self.get_geometric_representation_items(representation)):
|
||||
if i >= len(product["raw"].material_slots):
|
||||
i = 0
|
||||
material_slots[product["raw"].material_slots[i].name] = item
|
||||
for styled_item_name, representation_item in material_slots.items():
|
||||
if styled_item_name == styled_item["attributes"]["Name"]:
|
||||
styled_item["ifc"] = self.create_styled_item(styled_item, representation_item)
|
||||
self.process_styled_item(styled_item)
|
||||
|
||||
def process_styled_item(self, styled_item):
|
||||
product = self.ifc_parser.products[
|
||||
self.ifc_parser.get_product_index_from_raw_name(styled_item["related_product_name"])
|
||||
]
|
||||
|
||||
if not product["ifc"].Representation:
|
||||
return
|
||||
|
||||
material_slots = []
|
||||
# This is a simplification, which works since we are currently in a controlled environment where the
|
||||
# BlenderBIM Add-on controls how data is structured during export. When we implement full IFC
|
||||
# round-tripping, this simplification can no longer apply.
|
||||
for representation in product["ifc"].Representation.Representations:
|
||||
# At the moment, until we implement full support for round-tripping contexts, we assume that styled
|
||||
# items only apply to the body context. This is therefore an incomplete implementation and may break
|
||||
# in edge cases.
|
||||
if representation.RepresentationIdentifier != "Body":
|
||||
continue
|
||||
if product["raw"].data.BIMMeshProperties.ifc_definition_id:
|
||||
# For native roundtripping, each slot could be a one to many relationship to items
|
||||
for item in self.get_geometric_representation_items(representation):
|
||||
original_id = self.roundtrip_id_map[item.id()]
|
||||
i = product["raw"].data.BIMMeshProperties.ifc_item_ids.get(str(original_id)).slot_index
|
||||
material_slots.append((product["raw"].material_slots[i].name, item))
|
||||
else:
|
||||
# For Blender, each slot represents a geometric representation item
|
||||
for i, item in enumerate(self.get_geometric_representation_items(representation)):
|
||||
if i >= len(product["raw"].material_slots):
|
||||
i = 0
|
||||
material_slots.append((product["raw"].material_slots[i].name, item))
|
||||
for styled_item_name, representation_item in material_slots:
|
||||
if styled_item_name == styled_item["attributes"]["Name"]:
|
||||
styled_item["ifc"] = self.create_styled_item(styled_item, representation_item)
|
||||
|
||||
def get_geometric_representation_items(self, representation):
|
||||
results = []
|
||||
@@ -2389,6 +2404,8 @@ class IfcExporter:
|
||||
added_element = migrator.migrate(element, self.file)
|
||||
if added_element.is_a("IfcGeometricRepresentationContext"):
|
||||
substitutions["contexts"].append(added_element)
|
||||
elif added_element.is_a("IfcGeometricRepresentationItem"):
|
||||
self.roundtrip_id_map[added_element.id()] = element.id()
|
||||
|
||||
for element in substitutions["contexts"]:
|
||||
new_element = self.ifc_rep_context[representation["context"]][representation["subcontext"]][
|
||||
|
||||
@@ -38,13 +38,11 @@ class MaterialCreator:
|
||||
def __init__(self, ifc_import_settings, ifc_importer):
|
||||
self.mesh = None
|
||||
self.materials = {}
|
||||
self.current_object_styles = []
|
||||
self.parsed_meshes = []
|
||||
self.ifc_import_settings = ifc_import_settings
|
||||
self.ifc_importer = ifc_importer
|
||||
|
||||
def create(self, element, obj, mesh):
|
||||
self.current_object_styles = []
|
||||
self.obj = obj
|
||||
self.mesh = mesh
|
||||
if (hasattr(element, "Representation") and not element.Representation) or (
|
||||
@@ -84,10 +82,14 @@ class MaterialCreator:
|
||||
if not item.StyledByItem:
|
||||
return
|
||||
|
||||
item_id = self.mesh.BIMMeshProperties.ifc_item_ids.add()
|
||||
item_id.name = str(item.id())
|
||||
|
||||
styled_item = item.StyledByItem[0]
|
||||
style_name = self.get_style_name(styled_item)
|
||||
|
||||
if style_name in self.current_object_styles:
|
||||
if self.mesh.materials.get(style_name):
|
||||
item_id.slot_index = self.mesh.materials.find(style_name)
|
||||
return True
|
||||
|
||||
style = bpy.data.materials.get(style_name)
|
||||
@@ -97,8 +99,7 @@ class MaterialCreator:
|
||||
self.parse_styled_item(styled_item, style)
|
||||
|
||||
self.assign_style_to_mesh(style)
|
||||
item_id = self.mesh.BIMMeshProperties.ifc_item_ids.add()
|
||||
item_id.name = str(item.id())
|
||||
item_id.slot_index = len(self.mesh.materials) - 1
|
||||
return True
|
||||
|
||||
def assign_material_slots_to_faces(self, obj):
|
||||
@@ -327,7 +328,6 @@ class MaterialCreator:
|
||||
if not self.mesh:
|
||||
return
|
||||
self.mesh.materials.append(material)
|
||||
self.current_object_styles.append(material.name)
|
||||
|
||||
|
||||
class IfcImporter:
|
||||
|
||||
@@ -1716,6 +1716,11 @@ class RepresentationItem(PropertyGroup):
|
||||
vgroup: StringProperty(name="Vertex Group")
|
||||
|
||||
|
||||
class ItemSlotMap(PropertyGroup):
|
||||
name: StringProperty(name="Item Element ID")
|
||||
slot_index: IntProperty(name="Material Slot Index")
|
||||
|
||||
|
||||
class BIMMeshProperties(PropertyGroup):
|
||||
is_native: BoolProperty(name="Is Native", default=False)
|
||||
is_swept_solid: BoolProperty(name="Is Swept Solid")
|
||||
@@ -1727,4 +1732,4 @@ class BIMMeshProperties(PropertyGroup):
|
||||
ifc_parameters: CollectionProperty(name="IFC Parameters", type=IfcParameter)
|
||||
active_representation_item_index: IntProperty(name="Active Representation Item Index")
|
||||
presentation_layer_index: IntProperty(name="Presentation Layer Index", default=-1)
|
||||
ifc_item_ids: CollectionProperty(name="IFC Definition ID", type=StrProperty)
|
||||
ifc_item_ids: CollectionProperty(name="IFC Definition ID", type=ItemSlotMap)
|
||||
|
||||
Reference in New Issue
Block a user