Skip to content

Bonsai: set unit scale when a project is loaded from a .blend (#9490) - #9491

Open
theoryshaw wants to merge 1 commit into
IfcOpenShell:v0.9.0from
theoryshaw:fix_unit_scale_on_blend_load
Open

theoryshaw wants to merge 1 commit into
IfcOpenShell:v0.9.0from
theoryshaw:fix_unit_scale_on_blend_load

Conversation

@theoryshaw

Copy link
Copy Markdown
Member

Fixes #9490

Problem

Loader.unit_scale is a class attribute defaulting to 1, and Loader.set_unit_scale() is only called when a project is imported, created, or opened through the large-project path. Reopening a saved .blend does none of those, so the session keeps the default.

For a project measured in metres that default is accidentally correct. For any other project every consumer of Loader.unit_scale is then wrong by the unit scale factor.

The most visible victim is Loader.slice_layerset_mesh(), which places its bisect planes at layer.LayerThickness * cls.unit_scale. In a project measured in feet the planes land 1/0.3048 ≈ 3.28× too far out, so bmesh.ops.bisect_plane() never cuts and the first layer's band test claims every face — the element renders as a single layer. Because has_layer_styles is still set to True, material_creator.create() early-returns and never repairs it.

Fix

Set the unit scale in handler.loadIfcStore, the load_post handler that restores a project when a .blend is opened.

Verification

With a 3-layer wall in a project measured in feet, replaying the real bmesh algorithm on the wall's actual geometry:

unit_scale = 0.3048 -> polys=14  {0:5, 1:4, 2:5}   (correct)
unit_scale = 1.0    -> polys=6   {0:6}             (the bug)

In a live session, tool.Loader.unit_scale reads 1 after opening a .blend and 0.3048 with this change. A wall that was correct on disk and broke on regeneration now re-slices correctly.

Note for reviewers

This is the same root cause as #7169, which was fixed for the CreateProject path only in 0bb21fe. That makes this the second time unit_scale has been patched per entry point.

A more durable alternative would be to have Loader.unit_scale derive itself from tool.Ifc.get() on access, so a missed entry path cannot reintroduce this. I kept this PR narrow for reviewability — happy to switch to that approach if preferred.

🤖 Generated with Claude Code

Loader.unit_scale is a class attribute that defaults to 1 and is only
populated by set_unit_scale(), which is called when an IFC is imported
(IfcImporter.calculate_unit_scale), when a project is created
(CreateProject) and when a large project is opened. Reopening a saved
.blend does none of those, so the whole session runs with unit_scale 1.

For a project measured in metres that default is accidentally correct,
which is why this has gone unnoticed. For any other project every
consumer of Loader.unit_scale is then wrong by the unit scale factor.
The most visible victim is Loader.slice_layerset_mesh(), which places
its bisect planes at layer.LayerThickness * unit_scale: in a project
measured in feet the planes land 1/0.3048 times too far out, so
bmesh.ops.bisect_plane() never cuts and the first layer's band test
claims every face. The element then renders as a single layer, and
because has_layer_styles is still set to True the material creator
early-returns and never repairs it.

This is the same root cause as IfcOpenShell#7169, which was fixed for the
new-project path only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

Layered elements render as a single layer after reopening a .blend (unit scale not set on load)

1 participant