Skip to content

fix for #7537: When you rotate a slab, it makes one of the material layers fatter than the designated thickness.#7705

Closed
theoryshaw wants to merge 2 commits into
v0.8.0from
rotated_slab
Closed

fix for #7537: When you rotate a slab, it makes one of the material layers fatter than the designated thickness.#7705
theoryshaw wants to merge 2 commits into
v0.8.0from
rotated_slab

Conversation

@theoryshaw

@theoryshaw theoryshaw commented Feb 22, 2026

Copy link
Copy Markdown
Member

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.

@theoryshaw theoryshaw requested a review from Moult February 22, 2026 03:13
@theoryshaw

Copy link
Copy Markdown
Member Author

possible fix for #7537

@brunoperdigao brunoperdigao self-assigned this Feb 24, 2026
…er ordering

Three related bugs fixed in the slab material layer set workflow:

1. EditAssignedMaterial (operator.py): Applying a custom offset to one slab
   instance incorrectly regenerated geometry for ALL slabs sharing the same
   IfcMaterialLayerSet. Replaced regenerate_from_layer_set (sweeps all users)
   with per-element regenerate_from_occurence for AXIS3 slabs and targeted
   recalculate_walls for AXIS2 walls. Each element's IfcMaterialLayerSetUsage
   attributes are now updated individually before regeneration.

2. slice_layerset_mesh (loader.py): Loader.unit_scale is a class variable only
   set during full file import, so it was stale (= 1) during live geometry
   updates on foot-based IFC files. Layer bisect planes were being computed in
   IFC feet while the mesh was in Blender metres, placing all cuts completely
   outside the mesh. Fixed by computing unit_scale fresh from the IFC file on
   each call via ifcopenshell.util.unit.calculate_unit_scale.

3. OffsetFromReferenceLine stale / layer order reversed (slab.py, loader.py):
   A guard (and custom_offset is None) in change_thickness prevented writing
   the correct OffsetFromReferenceLine (position.z) to the usage when a custom
   offset was active. This left the value at 0.0 instead of the actual slab
   bottom (e.g. -1.0 IFC units for a TOP-reference slab), so the bisect
   starting point co was at the reference plane rather than the slab bottom,
   reversing layer assignments or missing layers entirely. Removed the guard —
   safe because each element has its own IfcMaterialLayerSetUsage instance.
   Reverted the AXIS3 bisect normal back to (0,0,1) (upward from co at slab
   bottom) which is correct once OffsetFromReferenceLine is properly set.
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.
@brunoperdigao

Copy link
Copy Markdown
Contributor

@theoryshaw Is this PR still relavant? I wasn't able to reproduce #7537

@brunoperdigao

Copy link
Copy Markdown
Contributor

@theoryshaw I see what is going on. See this commit for the explanation. That's why x angle is locked in Blender.
I'll have to revisit this. I'll take a look at the PR, but slabs have been really tricky. One change can affect multiple parts of the code.

@theoryshaw

Copy link
Copy Markdown
Member Author

Yes it's still relevant from my perspective. If you open the test file slab slope - Copy.ifc.txt shared here, #7537 (comment) you'll see the different layer thicknesses. I believe this PR addresses that condition.

@brunoperdigao

Copy link
Copy Markdown
Contributor

@theoryshaw Just a heads up that I'm going to start working on this.

@theoryshaw

Copy link
Copy Markdown
Member Author

Sounds good. Were you just going to review this pr, or come up with something from scratch?

@brunoperdigao

Copy link
Copy Markdown
Contributor

@theoryshaw A bit of both, I guess. I'm just trying to figure out the best approach since this part of the code is very prone to unintended consequences.

@brunoperdigao

Copy link
Copy Markdown
Contributor

@theoryshaw Could you test now after the latest commits?

There are a few things about the PR that I didn't fully comprehend. I'm not sure if it is necessary to change loader.py and the way the layer set is regenerated. Maybe I missed something. Let me know what you think.

@theoryshaw

Copy link
Copy Markdown
Member Author

@brunoperdigao cool, it seems to work. I'm going to close this PR, so it doesn't build to BonsaiPR then. Will keep testing via that build.

@theoryshaw theoryshaw closed this Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants