See #1227. Experimental support for 3D layerset slicing.

This commit is contained in:
Dion Moult
2025-02-23 17:27:32 +11:00
parent 23158b1b7e
commit a7509dbe29
2 changed files with 73 additions and 1 deletions
+5 -1
View File
@@ -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
+68
View File
@@ -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,