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