mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-12 14:33:28 +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])
|
no = Vector([0.0, 0.0, 1.0])
|
||||||
co = Vector((0.0, 0.0, offset))
|
co = Vector((0.0, 0.0, offset))
|
||||||
# Bisect planes are always horizontal (world Z) for AXIS3.
|
# Bisect planes are always horizontal (world Z) for AXIS3.
|
||||||
# For well-formed IFC data, the mesh local Z span equals total_perp_thickness
|
# The mesh local Z span should equal total_perp_thickness × unit_scale:
|
||||||
# (extrusion.Depth is always set to thickness / extrusion_vec.z so that
|
# extrusion.Depth × extrusion_vec.z = total_perp_thickness
|
||||||
# extrusion.Depth × extrusion_vec.z = thickness). depth_scale is kept as
|
# If the IFC data is inconsistent (e.g. from old Bonsai code that incorrectly
|
||||||
# a safety net for IFC files from other authoring tools where the extrusion
|
# scaled extrusion.Depth for ObjectPlacement-rotated slabs), we self-heal:
|
||||||
# depth may not exactly match the sum of LayerThicknesses.
|
# 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()
|
extrusion_vec = cls.get_extrusion_vector(element).normalized()
|
||||||
ifc_extrusion_depth = None
|
ifc_extrusion_depth = None
|
||||||
if body_rep := ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW"):
|
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)
|
total_perp_thickness = sum(l.LayerThickness for l in layer_set.MaterialLayers)
|
||||||
if ifc_extrusion_depth and total_perp_thickness:
|
if ifc_extrusion_depth and total_perp_thickness:
|
||||||
depth_scale = abs(extrusion_vec.z) * (ifc_extrusion_depth / 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":
|
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()
|
||||||
|
|||||||
Reference in New Issue
Block a user