From a7509dbe292f00a1fb6662cee404da2edabe45c6 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 23 Feb 2025 17:27:32 +1100 Subject: [PATCH] See #1227. Experimental support for 3D layerset slicing. --- src/bonsai/bonsai/bim/import_ifc.py | 6 ++- src/bonsai/bonsai/tool/loader.py | 68 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py index 318f4834e2..b159020d43 100644 --- a/src/bonsai/bonsai/bim/import_ifc.py +++ b/src/bonsai/bonsai/bim/import_ifc.py @@ -69,6 +69,9 @@ class MaterialCreator: if isinstance(mesh, bpy.types.Curve): return + if mesh.get("has_layer_styles", None) == True: + return + self.mesh = mesh self.obj = obj if element.is_a("IfcTypeProduct"): @@ -1059,12 +1062,13 @@ class IfcImporter: else: mesh["has_cartesian_point_offset"] = False - return tool.Loader.convert_geometry_to_mesh( + mesh = tool.Loader.convert_geometry_to_mesh( geometry, mesh, verts=verts, load_indexed_maps=self.ifc_import_settings.load_indexed_maps, ) + return tool.Loader.slice_layerset_mesh(element, mesh) except: self.ifc_import_settings.logger.error("Could not create mesh for %s", element) import traceback diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 17e8764fbf..7fb5fc4788 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -1018,6 +1018,74 @@ class Loader(bonsai.core.tool.Loader): mesh["ios_material_ids"] = ifcopenshell.util.shape.get_faces_material_style_ids(geometry).tolist() return mesh + @classmethod + def slice_layerset_mesh(cls, element: ifcopenshell.entity_instance, mesh: bpy.types.Mesh) -> bpy.types.Mesh: + if True: # This feature is still experimental + return mesh + if not (material := ifcopenshell.util.element.get_material(element)): + return mesh + elif material.is_a("IfcMaterialLayerSetUsage"): + usage = material + layer_set = material.ForLayerSet + offset = usage.OffsetFromReferenceLine * cls.unit_scale + sense_factor = 1 if usage.DirectionSense == "POSITIVE" else -1 + elif material.is_a("IfcMaterialLayerSet"): + usage = None + layer_set = material + offset = 0 + sense_factor = 1 + else: + return mesh + if len(layer_set.MaterialLayers) == 1: + return mesh + bm = bmesh.new() + bm.from_mesh(mesh) + prev_co = None + co = Vector((0.0, offset, 0.0)) + no = Vector((0.0, 1.0, 0.0)) + # Cache this + body = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") + styles = {} + has_layer_styles = False + for i, material in mesh.materials: + if style := tool.Ifc.get_entity(material): + styles[style] = i + for layer in layer_set.MaterialLayers[:-1]: + prev_co = co.copy() + co.y = layer.LayerThickness * cls.unit_scale * sense_factor + bisect_geom = bmesh.ops.bisect_plane( + bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], dist=0.0001, plane_co=co, plane_no=no + ) + bmesh.ops.duplicate(bm, geom=bisect_geom["geom_cut"]) + if style := ifcopenshell.util.representation.get_material_style(layer.Material, body): + if (material_index := styles.get(style, None)) is None: + material_index = len(mesh.materials) + mesh.materials.append(tool.Ifc.get_object(style)) + for face in bisect_geom["geom"]: + if isinstance(face, bmesh.types.BMFace): + center = face.calc_center_bounds() * sense_factor + if center.y < co.y and center.y > prev_co.y: + face.material_index = material_index + has_layer_styles = True + + # Last layer + layer = layer_set.MaterialLayers[-1] + if style := ifcopenshell.util.representation.get_material_style(layer.Material, body): + if (material_index := styles.get(style, None)) is None: + material_index = len(mesh.materials) + mesh.materials.append(tool.Ifc.get_object(style)) + for face in bisect_geom["geom"]: + if isinstance(face, bmesh.types.BMFace): + center = face.calc_center_bounds() * sense_factor + if center.y > co.y: + face.material_index = material_index + has_layer_styles = True + + bm.to_mesh(mesh) + bm.free() + mesh["has_layer_styles"] = has_layer_styles + return mesh + @classmethod def create_mesh_from_shape( cls,