mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +00:00
Fix slab layer geometry for rotated and angled slabs
Three bugs fixed: 1. EditAssignedMaterial was sweeping all slabs that share a layer set when changing material properties, instead of updating only the selected element's assigned material. 2. slice_layerset_mesh (loader.py): layer bisect positions were scaled incorrectly due to a stale unit_scale and a reversed/missing DirectionSense guard. Now always recalculates unit_scale fresh and correctly applies sense_factor. 3. change_thickness (slab.py): extrusion depth was computed as `thickness / cos(obj.rotation_euler.x)`, which incorrectly scaled ObjectPlacement-rotated slabs (where the extrusion direction is local Z and no scaling is needed). The correct formula is `thickness / extrusion_vec.z`, which handles both ObjectPlacement rotation (extrusion_vec.z ≈ 1.0 → no scale) and ExtrudedDirection tilts (extrusion_vec.z < 1.0 → scale up) uniformly. The resulting slab was 1.414× too thick for 45°-rotated slabs, making both material layers appear fatter than specified. slice_layerset_mesh retains a depth_scale safety factor (extrusion_vec.z × ifc_depth / total_layer_thickness) as a robustness guard for IFC files from other authoring tools where extrusion depth may not match the sum of LayerThicknesses.
This commit is contained in:
@@ -281,8 +281,17 @@ class DumbSlabPlaner:
|
|||||||
existing_x_angle = 0 if tool.Cad.is_x(existing_x_angle, 2 * pi, tolerance=0.001) else existing_x_angle
|
existing_x_angle = 0 if tool.Cad.is_x(existing_x_angle, 2 * pi, tolerance=0.001) else existing_x_angle
|
||||||
direction_ratios = Vector(extrusion.ExtrudedDirection.DirectionRatios)
|
direction_ratios = Vector(extrusion.ExtrudedDirection.DirectionRatios)
|
||||||
offset_direction = direction_ratios.copy()
|
offset_direction = direction_ratios.copy()
|
||||||
perpendicular_depth = thickness * abs(1 / cos(existing_x_angle))
|
# The extrusion depth needed to achieve a given perpendicular thickness depends on
|
||||||
perpendicular_offset = layer_offset * abs(1 / cos(existing_x_angle)) / self.unit_scale
|
# how much the extrusion direction deviates from the slab face normal (local Z).
|
||||||
|
# For an ObjectPlacement-rotated slab, extrusion_vec.z ≈ 1.0 → no scaling.
|
||||||
|
# For an ExtrudedDirection-tilted slab, extrusion_vec.z < 1.0 → scale up.
|
||||||
|
extrusion_z = abs(direction_ratios.normalized().z)
|
||||||
|
if extrusion_z > 1e-6:
|
||||||
|
perpendicular_depth = thickness / extrusion_z
|
||||||
|
perpendicular_offset = layer_offset / extrusion_z / self.unit_scale
|
||||||
|
else:
|
||||||
|
perpendicular_depth = thickness
|
||||||
|
perpendicular_offset = layer_offset / self.unit_scale
|
||||||
|
|
||||||
ifc_position = extrusion.Position
|
ifc_position = extrusion.Position
|
||||||
|
|
||||||
|
|||||||
@@ -1086,6 +1086,7 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
bm = bmesh.new()
|
bm = bmesh.new()
|
||||||
bm.from_mesh(mesh)
|
bm.from_mesh(mesh)
|
||||||
prev_co = None
|
prev_co = None
|
||||||
|
depth_scale = 1.0
|
||||||
if not usage:
|
if not usage:
|
||||||
sense_factor = 1 # Assume the extrusion vector points in the direction sense
|
sense_factor = 1 # Assume the extrusion vector points in the direction sense
|
||||||
no = cls.get_extrusion_vector(element).normalized()
|
no = cls.get_extrusion_vector(element).normalized()
|
||||||
@@ -1095,9 +1096,26 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
no = cls.get_extrusion_vector(element).normalized()
|
no = cls.get_extrusion_vector(element).normalized()
|
||||||
no = no.cross(Vector([1.0, 0.0, 0.0]))
|
no = no.cross(Vector([1.0, 0.0, 0.0]))
|
||||||
elif usage.LayerSetDirection == "AXIS3":
|
elif usage.LayerSetDirection == "AXIS3":
|
||||||
co = Vector((0.0, 0.0, offset))
|
|
||||||
no = cls.get_extrusion_vector(element).normalized()
|
|
||||||
no = Vector([0.0, 0.0, 1.0])
|
no = Vector([0.0, 0.0, 1.0])
|
||||||
|
co = Vector((0.0, 0.0, offset))
|
||||||
|
# Bisect planes are always horizontal (world Z) for AXIS3.
|
||||||
|
# For well-formed IFC data, the mesh local Z span equals total_perp_thickness
|
||||||
|
# (extrusion.Depth is always set to thickness / extrusion_vec.z so that
|
||||||
|
# extrusion.Depth × extrusion_vec.z = thickness). depth_scale is kept as
|
||||||
|
# a safety net for IFC files from other authoring tools where the extrusion
|
||||||
|
# depth may not exactly match the sum of LayerThicknesses.
|
||||||
|
extrusion_vec = cls.get_extrusion_vector(element).normalized()
|
||||||
|
ifc_extrusion_depth = None
|
||||||
|
if body_rep := ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW"):
|
||||||
|
for item in ifcopenshell.util.representation.resolve_representation(body_rep).Items:
|
||||||
|
while item.is_a("IfcBooleanResult"):
|
||||||
|
item = item.FirstOperand
|
||||||
|
if item.is_a("IfcExtrudedAreaSolid"):
|
||||||
|
ifc_extrusion_depth = item.Depth
|
||||||
|
break
|
||||||
|
total_perp_thickness = sum(l.LayerThickness for l in layer_set.MaterialLayers)
|
||||||
|
if ifc_extrusion_depth and total_perp_thickness:
|
||||||
|
depth_scale = abs(extrusion_vec.z) * (ifc_extrusion_depth / total_perp_thickness)
|
||||||
elif usage.LayerSetDirection == "AXIS1":
|
elif usage.LayerSetDirection == "AXIS1":
|
||||||
co = Vector((0.0, 0.0, offset))
|
co = Vector((0.0, 0.0, offset))
|
||||||
no = cls.get_extrusion_vector(element).normalized()
|
no = cls.get_extrusion_vector(element).normalized()
|
||||||
@@ -1114,7 +1132,7 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
for i, layer in enumerate(layer_set.MaterialLayers):
|
for i, layer in enumerate(layer_set.MaterialLayers):
|
||||||
if i != last_i:
|
if i != last_i:
|
||||||
prev_co = co.copy()
|
prev_co = co.copy()
|
||||||
co += no * layer.LayerThickness * unit_scale
|
co += no * layer.LayerThickness * depth_scale * unit_scale
|
||||||
bisect_geom = bmesh.ops.bisect_plane(
|
bisect_geom = bmesh.ops.bisect_plane(
|
||||||
bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], dist=0.0001, plane_co=co, plane_no=no
|
bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], dist=0.0001, plane_co=co, plane_no=no
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user