mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Self-heal inconsistent slab extrusion depth on import
In slice_layerset_mesh (loader.py), detect when an AXIS3 slab's stored extrusion.Depth is inconsistent with the sum of its LayerThicknesses (i.e. depth_scale != 1.0). This was caused by old Bonsai code in change_thickness that incorrectly scaled extrusion.Depth by 1/cos(obj.rotation_euler.x) for ObjectPlacement-rotated slabs, making the mesh 1.414× too tall for 45°-rotated slabs. Two-part fix applied on first import of affected files: 1. Scale mesh vertices in Z (from the mesh bottom) by 1/depth_scale so the local Z span equals total_perp_thickness × unit_scale, giving the correct physical slab geometry immediately. 2. Write the corrected extrusion.Depth = total_perp_thickness / extrusion_vec.z back to the IFC data so future imports load the correct geometry without requiring this correction. Files saved after this fix will open correctly with depth_scale = 1.0 and no vertex adjustment needed.
This commit is contained in:
@@ -1090,11 +1090,12 @@ class Loader(bonsai.core.tool.Loader):
|
||||
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.
|
||||
# The mesh local Z span should equal total_perp_thickness × unit_scale:
|
||||
# extrusion.Depth × extrusion_vec.z = total_perp_thickness
|
||||
# If the IFC data is inconsistent (e.g. from old Bonsai code that incorrectly
|
||||
# scaled extrusion.Depth for ObjectPlacement-rotated slabs), we self-heal:
|
||||
# scale the mesh vertices to the correct Z span and fix the stored depth so
|
||||
# future imports load correctly without this correction.
|
||||
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"):
|
||||
@@ -1107,6 +1108,22 @@ class Loader(bonsai.core.tool.Loader):
|
||||
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)
|
||||
if abs(depth_scale - 1.0) > 1e-6 and ifc_extrusion_depth and body_rep:
|
||||
# Z_span / depth_scale == total_perp_thickness × unit_scale for any
|
||||
# extrusion direction, so scaling from the mesh bottom is always correct.
|
||||
min_z = min(v.co.z for v in bm.verts)
|
||||
for v in bm.verts:
|
||||
v.co.z = min_z + (v.co.z - min_z) / depth_scale
|
||||
# Fix the IFC data so future imports don't require this correction.
|
||||
extrusion_vec_z = abs(extrusion_vec.z)
|
||||
correct_depth = total_perp_thickness / extrusion_vec_z if extrusion_vec_z > 1e-6 else total_perp_thickness
|
||||
for item in ifcopenshell.util.representation.resolve_representation(body_rep).Items:
|
||||
while item.is_a("IfcBooleanResult"):
|
||||
item = item.FirstOperand
|
||||
if item.is_a("IfcExtrudedAreaSolid"):
|
||||
item.Depth = correct_depth
|
||||
break
|
||||
depth_scale = 1.0
|
||||
elif usage.LayerSetDirection == "AXIS1":
|
||||
co = Vector((0.0, 0.0, offset))
|
||||
no = cls.get_extrusion_vector(element).normalized()
|
||||
|
||||
Reference in New Issue
Block a user