Commit Graph

20080 Commits

Author SHA1 Message Date
CyrilWaechter 7b324e7016 Use space's own container for regeneration instead of requiring default
When regenerating an existing IfcSpace, the default container is no longer required. Instead, the space's container is found via get_parent(element), which walks the full spatial hierarchy (aggregation, containment, nesting). For new space creation, the default container is still required.

Add optional container parameter to get_space_polygon_from_context_visible_objects so regeneration can pass the resolved container directly.

Generated with the assistance of an AI coding tool.
2026-08-02 03:38:42 +02:00
CyrilWaechter 61a0baf571 Optimize coplanar face reconstruction and add tests
Vectorize the coplanarity prefilter in _union_coplanar_face_polygon and
compute per-triangle normals once instead of per space face. Add
regression tests for the SmallHouse and Triangle boundary test models.

Generated with the assistance of an AI coding tool.
2026-08-02 00:57:38 +02:00
CyrilWaechter cb925e0259 Keep shaft holes in generated space boundaries
dissolve_faces with merge_coplanar drops interior rings, so the shaft
opening in a ceiling was lost and replaced by spurious wall-cap
boundaries. Reconstruct the space face from its raw coplanar triangles,
preserve interior rings in the assigned boundary, absorb redundant
candidates by plane offset, and raise the full-face tolerance so walls
offset by their half thickness get a single boundary.

Generated with the assistance of an AI coding tool.
2026-08-02 00:57:38 +02:00
CyrilWaechter ff89bf66bc Fix space boundary generation regressions
When several elements match the same space face, offset matches that only
duplicate coplanar coverage are now skipped, and a single bounding element
within a small plane offset gets the full space face instead of a clipped
polygon. Existing boundaries are removed before regeneration so stale 2nd
level boundaries are not left behind, and the Bonsai operator delegates
element filtering to auto_generate_boundaries.

Regenerates SmallHouse boundaries to match the reference output and keeps
the ExternalEarth opening unioning intact.

Generated with the assistance of an AI coding tool.
2026-08-02 00:57:38 +02:00
CyrilWaechter 373079f2d4 Deduplicate opening boundaries in auto_generate_boundaries
When a building element has multiple ngons matching the same space face,
_process_openings was called multiple times for the same opening/filling,
producing duplicate boundaries (e.g. two boundaries for the same door).

Fix: pass a set of processed filling IDs to _process_openings and skip
already-processed openings.

Generated with the assistance of an AI coding tool.
2026-08-02 00:57:38 +02:00
CyrilWaechter 3abb46eefa Fix dissolve_faces polygon reconstruction with merge_coplanar
When merge_coplanar merges two sub-faces that share an edge from the
original BRep (e.g. two rectangles forming an L-shape cap), that shared
edge remained in boundary_edges via original_edges filtering, causing
the edge_adjacency walk to produce wrong polygons.

Fix: after coplanar merging, use edge frequency (edges used by exactly
1 triangle = boundary) instead of original_edges filtering, which
correctly identifies only outer boundary edges.

Also add safety checks: edge_adjacency emptiness guard, infinite loop
protection, and minimum polygon length check.

Generated with the assistance of an AI coding tool.
2026-08-02 00:57:38 +02:00
CyrilWaechter d88b201d5f Fix axis/ref_direction swap in connection geometry
The a2p placement matrix stores col[0]=X (edge direction) and
col[2]=Z (face normal), but assign_connection_geometry expects
axis=Z (normal) and ref_direction=X (edge).

Generated with the assistance of an AI coding tool.
2026-08-02 00:57:38 +02:00
CyrilWaechter ac23a67e72 Extract boundary generation to ifcopenshell.util.boundary
Move Blender-independent boundary generation algorithm from Bonsai
(GPL) to ifcopenshell.util.boundary (LGPL):

- ifcopenshell.util.shape.dissolve_faces: reconstruct polygonal faces
  from triangulated mesh using original edges from get_edges() + Union-Find
- ifcopenshell.util.boundary.auto_generate_boundaries: full boundary
  generation algorithm using IFC geometry (numpy, shapely) without
  Blender — replaces bmesh, matrix_world, tool.Cad.is_x, mathutils with
  numpy equivalents
- Uses existing ifcopenshell.api.boundary.assign_connection_geometry
  for connection geometry creation
- Uses existing ifcopenshell.util.placement.a2p + np_normal for face
  matrix construction
- BOUNDARY_ELEMENT_CLASSES expanded to include IfcColumn and
  IfcCurtainWall

Bonsai's boundary/operator.py auto_generate_boundaries is now a thin
adapter handling Blender-specific preprocessing (flushing moved
objects, building iterator + tree) then delegating to the util module.

Added 12 tests: 3 for dissolve_faces, 3 for auto_generate_boundaries.

Generated with the assistance of an AI coding tool.
2026-08-02 00:57:38 +02:00
CyrilWaechter 8b73de5d42 Fix shapely topology crash in boundary generation
Add buffer(0) validation for space_face_polygon and face_polygon
before intersection, following the same pattern as tool/cad.py.

Wrap the intersection in try/except for shapely.errors.GEOSException
to catch remaining topology errors. On exception, set
bonsai.last_error (so the 'Copy Error Message To Clipboard' button
appears in the UI), report an ERROR to the operator, and continue
processing other face pairs instead of crashing.

Generated with the assistance of an AI coding tool.
2026-08-02 00:57:38 +02:00
CyrilWaechter 2ad4ae8de5 Fix pyright possibly-missing-submodule in covering test
Add explicit import bonsai.core.tool to satisfy pyright's type checker,
which requires submodules to be explicitly imported rather than relying
on transitive imports from import bonsai.
2026-08-02 00:56:27 +02:00
CyrilWaechter 888595b142 Fix ruff import-ordering in covering and spatial tests
ruff check flagged unsorted imports in test/core/test_covering.py
and test/tool/test_spatial.py. Fix by reorganising import blocks.
2026-08-02 00:56:27 +02:00
CyrilWaechter ebad18d0b3 Rework TestGenerateSpace to use IFC representations instead of Blender cubes
All 8 space-generation tests now create IFC walls/slabs with real
solid-block representations using IfcExtrudedAreaSolid, instead of
relying on the old Blender-mesh bisection path (broken since 79ee88da5
switched to IFC-geometry-only for boundary detection).

- _BlockHelper provides create_wall (10x10xheight block) and create_slab
  (12x12x1.0 block) helpers using standard IfcOpenShell API calls.
- The wall block bisects to a 10x10 polygon at the cutting plane
  (matching the old cube-behaviour), and auto-height detects wall_top_z.
- Pre-existing height assertions (z=10) now pass correctly because
  auto-height = wall_top_z - base_z = 10 - 0 = 10 (the old values were
  wrong for the Blender path where h defaulted to 3).
- test_regenerate_after_wall_height_change modifies the IFC extrusion
  depth directly and bumps the geom cache token via
  _bump_geom_cache_token() instead of relying on Blender depsgraph.
- No Blender cubes are created except when absolutely needed for
  selection/active-object flow (regeneration, apply-height).
- Added ifcopenshell.util.representation to imports.
- Import _bump_geom_cache_token from bonsai.tool.spatial.

Generated with the assistance of an AI coding tool.
2026-08-02 00:56:27 +02:00
CyrilWaechter 0808bcd9c9 Add covering core tests verifying tuple-unpack fix
Covers all three covering operators with success and error-path tests
using the Prophecy mocking framework. The key assertion verifies that
get_space_polygon_from_context_visible_objects' return value is unpacked
so the polygon (not the tuple of polygon+bounding_elements) reaches
set_covering_representation_from_polygon.

Shapely geometry objects are not JSON-serialisable (Prophecy call
serialisation), so we use the plain integer 42 as a stand-in for the
polygon value.

Generated with the assistance of an AI coding tool.
2026-08-02 00:56:27 +02:00
CyrilWaechter 53084ca94c Fix covering operators to unpack tuple return from get_space_polygon_from_context_visible_objects
Three covering core functions (add_instance_flooring_covering_from_cursor,
add_instance_ceiling_covering_from_cursor, regen_selected_covering_object)
used the old single-value assignment from
get_space_polygon_from_context_visible_objects, which now returns a
(polygon, bounding_walls) tuple. The isinstance(str) guard never fired,
causing the tuple to flow into set_covering_representation_from_polygon
and raise a shapely error.

Fix by unpacking space_polygon, _ at all three call sites.

Generated with the assistance of an AI coding tool.
2026-08-02 00:56:27 +02:00
CyrilWaechter 3e6460eceb Extract space generation algorithms to ifcopenshell.util
Move Blender-independent space generation algorithms from Bonsai
(GPL) to ifcopenshell.util (LGPL):

- ifcopenshell.util.shape.bisect_mesh_plane_vf: vectorized numpy
  triangle/plane intersection for mesh bisection
- ifcopenshell.util.element.iter_top_connections: walker for
  IfcRelConnectsElements(TOP) relationships
- ifcopenshell.util.space: new module with get_boundary_lines,
  get_space_polygon, get_auto_space_height and height detection
  helpers — all operating on IFC geometry without Blender

Bonsai's tool/spatial.py now delegates to these utilities via
thin wrappers, keeping only Blender-specific concerns (cache
management with depsgraph invalidation, UI property reads).

tool/wall.py iter_wall_slab_connections delegates to
ifcopenshell.util.element.iter_top_connections.

Added 22 tests: 6 for bisect_mesh_plane_vf, 10 for space
generation algorithms, 4 for iter_top_connections, 2 Bonsai
integration tests for cache behavior.

Generated with the assistance of an AI coding tool.
2026-08-02 00:56:27 +02:00
CyrilWaechter 2f7af12734 Add auto-detect space height from elements above
Space height is now auto-detected using IFC geometry directly
(ifcopenshell.geom.create_shape + get_shape_bottom/top_elevation)
instead of Blender object bounding boxes. This fixes height detection
when the slab above is not loaded in Blender.

Detection priority:
1. IfcRelConnectsElements(TOP) connections on bounding walls
2. IfcSlab / IfcRoof elements above with XY overlap to space polygon
3. Minimum wall top Z of bounding walls
4. Fallback to space_height property (default 3m)

Added space_height and force_space_height properties to
BIMSpatialDecompositionProperties. The height field is synced to
the active space's height via active_object_callback (msgbus), not
in draw().

Added ApplySpaceHeightToSelection operator to modify
IfcExtrudedAreaSolid.Depth in place without regenerating footprint.

bounding_walls changed from list[tuple[element, obj]] to
list[entity_instance] since Blender objects are no longer needed.

Generated with the assistance of an AI coding tool.
2026-08-02 00:56:26 +02:00
CyrilWaechter d5e6c19f2b Add copy attribute to selection for boundaries
Add a paste button to IfcRelSpaceBoundary specific attributes
(RelatingSpace, RelatedBuildingElement, ParentBoundary,
CorrespondingBoundary, PhysicalOrVirtualBoundary,
InternalOrExternalBoundary) reusing the existing
copy_attribute_to_selection core function.

The core function value type hint is broadened from Union[str, None]
to Any since boundary relation attributes pass IFC entity instances.

Generated with the assistance of an AI coding tool.
2026-08-02 00:55:26 +02:00
Thomas Krijnen 064ce00826 import Any 2026-08-01 14:16:12 +02:00
Thomas Krijnen 98ce2a1b46 Move __eq__ impl back to the mixin and fix test_rules.py test 2026-08-01 13:16:51 +02:00
Bartok 4ea05f79c3 docs: add Eigen to Linux install deps
Linux "basic dependencies" omitted libeigen3-dev even though
ifcgeom requires Eigen3 (find_package Eigen3 REQUIRED) and the
cmake snippet already passes -DEIGEN_DIR=/usr/include/eigen3.
macOS Homebrew line already installs eigen.

Closes #6903

Generated with the assistance of an AI coding tool.
2026-08-01 10:50:34 +02:00
Petru Conduraru 6b917ba36d Fix test_rules.py filtering by sys.argv, which empties the corpus under pytest
test_file's parametrize list was filtered with `sys.argv[1] in
os.path.basename(fn)`, reading the raw process argv instead of a
pytest-native option. Under a bare `pytest` invocation sys.argv[1] is
pytest's own first CLI token, never a match, so the 138-fixture EXPRESS
rule corpus in test/fixtures/rules collapses to an empty parametrize and
pytest reports it as a single skipped test rather than an error. Under
CI's actual invocation (pytest -p no:pytest-blender -n $NPROCS test ...)
sys.argv[1] is "-p", which happens to substring-match 47 of the 138
fixtures, so CI has been silently running a coincidental 34% slice of
the corpus with no signal anything was wrong.

Replaced the module-level list comprehension with a pytest_generate_tests
hook plus a --rule CLI option (added via a new test/conftest.py). This
runs the full corpus by default under any pytest invocation, still
allows filtering to one rule for local debugging via --rule, and no
longer collides with pytest's own argv.

Verified all 138 fixtures collect and pass under the fixed harness
(63 fail- fixtures each raise a violation, 75 pass- fixtures raise none).

Generated with the assistance of an AI coding tool.
2026-08-01 10:50:30 +02:00
Petru Conduraru fa1b70883f ifcmcp: pin mcp below 2.0 to fix broken FastMCP import
mcp 2.0.0 (unpinned in CI and in the ifcmcp[mcp] extra) renamed
mcp.server.fastmcp.FastMCP to mcp.server.mcpserver.MCPServer, which
ifcmcp does not support yet. server.py caught the resulting
ModuleNotFoundError with a bare except Exception and silently
reported it as FastMCP not installed, masking the real breakage
until the ifcmcp test suite failed in CI.

Pinned mcp to >=1.0,<2 in both ci.yml and ifcmcp's pyproject.toml
mcp extra, confirmed the full ifcmcp test suite (70 tests) passes
against mcp 1.29.0, and confirmed the genuinely-not-installed path
still raises the expected ImportError. Also narrowed the except
clause to ImportError only so an unrelated future bug in that
import block surfaces instead of being swallowed as "not installed".

Generated with the assistance of an AI coding tool.
2026-08-01 10:49:17 +02:00
Petru Conduraru 913f9f2262 ifcopenshell.template: fix timestring ignoring an explicit timestamp of 0
create(timestamp=0) computed the FILE_NAME timestring with
`d.get("timestamp") or time.time()`, which treats 0 (a legitimate
epoch timestamp) as unset because 0 is falsy. The header ended up
with the current wall-clock time in FILE_NAME while IFCOWNERHISTORY
correctly stored CreationDate=0, an inconsistent pair of dates in
the same file. Switched to an explicit None check so an explicit
timestamp of 0 is honoured the same way any other explicit
timestamp is.

Generated with the assistance of an AI coding tool.
2026-08-01 10:49:17 +02:00
yekose 34da3950e3 ifcgeom: add a profile_point overload taking a plain double
The profile mapping builds its points as

    profile_helper(m4, {
        {{-x, -y}, {f2}},
        ...

where `f2` is a `double` and profile_point's second member is a
`boost::optional<double>`. In recent Boost (somewhere between 1.85 and 1.91)
optional's converting constructor became explicit, and an explicit constructor
cannot be used in copy-initialization — which is what a braced element is. So
every one of these call sites stops compiling:

  MSVC 19.4x:  error C2664: cannot convert argument 2 from
               'initializer list' to 'const std::vector<profile_point>&'
  clang-cl 22: error: chosen constructor is explicit in copy-initialization

Twelve translation units are affected (IfcCShapeProfileDef,
IfcIShapeProfileDef, IfcLShapeProfileDef, IfcTShapeProfileDef,
IfcUShapeProfileDef, IfcZShapeProfileDef, IfcAsymmetricIShapeProfileDef,
IfcCraneRailAShapeProfileDef, IfcRectangleProfileDef,
IfcRectangleHollowProfileDef, IfcRoundedRectangleProfileDef,
IfcTrapeziumProfileDef), roughly 100 call sites in total.

Adding one overload that takes the double directly fixes all of them without
touching a single call site, and changes nothing for existing code: the
optional overload still wins wherever an optional is passed.

Verified by building schemas 2x3;4;4x3_add2 with MSVC 2022 against Boost
1.91 and OCCT 7.9.3 — IfcParse, IfcGeom, the schema mappings and
geometry_kernel_opencascade all archive cleanly. Without this, the same build
against Boost 1.85 succeeds, which is what identified Boost as the variable.
2026-08-01 10:49:17 +02:00
CyrilWaechter 24f7629fad Fix space regen doubling Z location
Removing translate_obj_to_z_location from the existing-IfcSpace
regeneration branch. The ShapeBuilder rewrite (d8de62308) builds
geometry in local space preserving obj.matrix_world, making the
translate call redundant — it adds z on top of the already-correct
location.z, producing 2*z.

Add test_regenerate_space_preserves_z_location to cover the
regeneration path with a non-zero Z elevation.

Generated with the assistance of an AI coding tool.
2026-08-01 10:49:17 +02:00
Thomas Krijnen d3ca116534 Even more plug-in workarounds 2026-07-31 07:47:34 +02:00
Thomas Krijnen 3d1e157ff1 Even more plug-in workarounds 2026-07-31 07:17:36 +02:00
Thomas Krijnen 8d5cedd152 Remove duplicate install 2026-07-31 07:17:07 +02:00
Thomas Krijnen fb17c66bf4 cmake rpath and interface fixes 2026-07-31 05:55:20 +02:00
Thomas Krijnen 008ac8a354 Discard old examples - modernize others 2026-07-31 03:58:50 +02:00
Dion Moult 3fc83847dd Get SQL is_a() working again 2026-07-30 21:56:33 +10:00
Dion Moult ea5c8343c2 If we have a global git push setting, then config_push won't be setup for our IFC repo 2026-07-30 21:43:18 +10:00
Dion Moult e033a4471a Fix typo and scale setting is std::string 2026-07-30 21:19:28 +10:00
Thomas Krijnen 41308cf122 Cmake install config fixes 2026-07-30 08:54:08 +02:00
Thomas Krijnen 6d7aa3c48c translate ../bin -> ../lib search path for plug-ins for installed execs 2026-07-30 03:35:21 +02:00
Thomas Krijnen 4b14c21963 schema nullptr dereference 2026-07-30 03:34:46 +02:00
Thomas Krijnen d472814e2a Don't try and set empty aggregates (todo: see if they are still needed with the type-aware upgrade-based parse mode) 2026-07-30 03:16:39 +02:00
Thomas Krijnen e033729233 Try rpath fix for shared build 2026-07-30 02:42:54 +02:00
Dion Moult a4f2075c3d ifcviewer: x-ray marquee selects through occluders
Box select resolved hits by reading the depth-tested object_id MRT, so only
the front-most surface in each pixel could ever come back. In x-ray that is
wrong twice over: you can see the geometry behind, and you still cannot
select it.

Add a second box-pick path used only while x-ray is active. It runs the same
vs_pick geometry through fs_boxpick with depth compare Always, no depth write
and no colour targets, scissored to the marquee — so nothing culls a fragment
behind another and the pass's only output is an atomicOr of one bit per
object into a hit bitmask. Reading that back gives every object with geometry
inside the box, occluded or not.

The bitmask rides alongside sel_flags at group(0) binding 2, allocated and
bound by ensureSelectionFlagsBuffer so the two can never disagree about how
many object ids exist. The layout entry is FRAGMENT-visible only: WebGPU
forbids a read_write storage buffer in the vertex stage, and every pipeline
shares this layout. Back-face culling is off for the pass — a box landing
inside a closed solid would otherwise see none of its faces and miss it.

Outside x-ray the depth-tested read stands, so a plain marquee still takes
only what is visible. A failure to build the pipeline falls back to that path
rather than breaking box select.

Tests cover the three properties worth having: x-ray selects strictly more,
its result is a superset of the plain one (a bare count would wave through a
wrong scissor or an off-by-one in the bit decode), and turning x-ray off
restores front-most-only. They need a model with real self-occlusion, which
sidecar_bake cannot currently produce — it segfaults on any input, including
the pristine sample.ifc — so they skip with an explanation until a fixture is
supplied. See the note at the top of the spec.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 07:46:22 +10:00
Dion Moult 8cc96127ce ifcviewer-web: let host pages choose the mouse nav preset
ViewportCore has had a preset table (blender / rhino / revit / web) since the
nav bindings were shared with the desktop, and the web input handlers already
classify presses against it — but main() hard-coded "web" and nothing could
reach setNavPreset from JS, so every page was stuck on LMB-orbit.

Export ifcv_set_nav_preset_c and wrap it as IfcViewer.create's `navPreset`
option plus a setNavPreset() method. The preset is only the button/modifier
table, so it needs no GPU state: it applies as soon as the module resolves,
which means the first drag already uses the host's scheme rather than
flipping after a frame or two.

Names are validated in JS against the four the core knows. The core silently
falls back to blender for anything unrecognised, which would turn a typo into
a mystery change of scheme rather than an error.

The default stays "web", so existing pages and the smoke tests are unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 07:46:22 +10:00
Thomas Krijnen 6bcfb175a3 Bring back create_entity() based on global file dict 2026-07-29 13:48:18 +02:00
Thomas Krijnen ba8dc53718 Fix streamer header ownership
Create file-owned headers after storage is selected but before streaming starts. Let owner-backed streamers use that header directly, and keep owned_header_ exclusively for ownerless streamers.

Generated with the assistance of an AI coding tool.
2026-07-28 04:19:28 +02:00
Thomas Krijnen 02bc09029e spf_header::assign() cfr a9d67768 2026-07-28 04:19:01 +02:00
Thomas Krijnen 9c965e9f08 Set IfcConvert install RPATH
Configure the executable to find installed shared libraries without relying on the build-tree runtime paths.
2026-07-28 04:19:01 +02:00
Thomas Krijnen e122f2cec3 Defer header initialization to aafter storage is set - cfr dcebf23a 2026-07-28 04:18:52 +02:00
Dion Moult 0aef201d50 bonsaiviewer-autodesk: satisfy cargo fmt and clippy
The crate had never been run through rustfmt, so the CI job's first step
(`cargo fmt --all -- --check`) failed and masked 12 clippy errors behind
it. Fix both.

Beyond the mechanical reformat and the redundant-closure/div_ceil/Default
lints, two changes carry meaning:

- SettingsDialog::on_reload is UI-thread only, so it becomes an Rc. The
  Arc was never shared across threads and clippy rightly flagged it as
  an Arc over a non-Send/Sync closure.
- WorkerMsg variants lose their shared `Loaded` postfix; the enum's doc
  comment already says these are worker completions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 20:39:21 +10:00
Dion Moult a84957fd45 Fix Wrong number or type of arguments for overloaded function 'new_file
I got this error, so I used the same pattern I saw in the generated wrapper py:

                            |   File "/home/dion/.config/blender/5.2/extensions/.local/lib/python3.13/site-packages/ifcopenshell/api/project/create_file.py", line 54, in create_file
                            |     file = ifcopenshell.file(schema=version)
                            |   File "/home/dion/.config/blender/5.2/extensions/.local/lib/python3.13/site-packages/ifcopenshell/ifcopenshell_wrapper.py", line 5242, in __init__
                            |     _ifcopenshell_wrapper.new_file(self, identifier)
                            |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
                            | TypeError: Wrong number or type of arguments for overloaded function 'new_file'.
                            |   Possible C/C++ prototypes are:
                            |     ifcopenshell::file::file(std::string const &,ifcopenshell::filetype,bool,::logger &)
                            |     ifcopenshell::file::file(std::string const &,ifcopenshell::filetype,bool)
                            |     ifcopenshell::file::file(std::string const &,ifcopenshell::filetype)
                            |     ifcopenshell::file::file(std::istream &,int,::logger &)
                            |     ifcopenshell::file::file(std::istream &,int)
                            |     ifcopenshell::file::file(void *,int,::logger &)
                            |     ifcopenshell::file::file(void *,int)
                            |     ifcopenshell::file::file(ifcopenshell::schema_definition const *,ifcopenshell::filetype,std::string const &,::logger &)
                            |     ifcopenshell::file::file(ifcopenshell::schema_definition const *,ifcopenshell::filetype,std::string const &)
                            |     ifcopenshell::file::file(ifcopenshell::schema_definition const *,ifcopenshell::filetype)
                            |     ifcopenshell::file::file(ifcopenshell::schema_definition const *)
                            |     ifcopenshell::file::file()
                            |     ifcopenshell::file::file(ifcopenshell::uninitialized_tag const &,::logger &)
                            |     ifcopenshell::file::file(ifcopenshell::uninitialized_tag const &)
                            |     ifcopenshell::file::file(std::string const &)
2026-07-27 19:22:15 +10:00
Dion Moult 19a1d88970 Fix all ty diagnostics on ifcviewer-wgpu (ci-lint ty-ios + ty-bonsai)
This branch carried v0.8.0's strict `[tool.ty.rules] all = "error"` config but
not the source fixes that were made upstream to satisfy it, so both ci-lint ty
gates were failing: `poe ty-ios` reported 256 diagnostics and `poe ty-bonsai`
258. Both are now clean.

Most fixes are ported from v0.8.0 and follow two idioms: initialise a name
before a conditional that may not bind it (plus an `assert` where the invariant
is real but not provable), and close an exhaustive `if`/`elif` chain with
`else: assert False, <discriminant>`.

The branch's own newer accessors are preserved throughout - `.file`,
`.declaration`, `file.types()`, `get_max_id()` are kept rather than reverted to
`wrapped_data.*`, and non-ty upstream changes (notably the in-progress geometry
cache removal) are deliberately not pulled in.

Notable fixes that are not straight ports:

* ifcopenshell_wrapper.pyi: `entity_instance.file` was declared as
  `def file(self) -> file`, where the property name shadows the `class file`
  below it, so the annotation resolved to `Unknown`. Every `element.file` in
  the codebase was therefore unchecked. Qualifying it to `ifcopenshell.file`
  restores `.schema` to its Literal union and surfaces no new diagnostics.

* model/wall.py: a duplicated merge fragment in the void-straddle path ran an
  always-true `if void_straddles:` that read `new_opening` from the mutually
  exclusive branch (stale value, or NameError on the first iteration), followed
  by an unreachable duplicate `elif`. Removing it makes the file match v0.8.0.

* light/operator.py: upstream's own fix unpacks three targets from two values
  and raises ValueError unconditionally; corrected to `None, None, None`.

* assign_system.py, validate.py, geom/main.py: walrus-in-genexp is valid at
  runtime (PEP 572 binds in the containing scope) but ty does not model it;
  rewritten as explicit loops, matching upstream.

Verified: poe ty-ios, poe ty-bonsai, ruff check src/ nix/, black --check .,
and compileall -W error at py3.10 (ifcopenshell-python) and py3.11 (bonsai).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 19:14:39 +10:00
Dion Moult f0c0312e8d Fix Windows (MSVC) and WASM (Emscripten) build failures
Both surfaced on the first Windows/WASM CI run of this branch:

- XmlSerializer.cpp: the IfcPropertySetDefinitionSet block used a C-style
  cast to convert the set to std::vector<IfcPropertySetDefinition>. GCC
  invokes the non-explicit conversion operator; MSVC rejects the cast to a
  template type (C2440/C3536/C2661). Use copy-initialisation instead, which
  invokes the same implicit conversion portably. (This block was dead until
  the SCHEMAS_->SCHEMA_HAS_ typo fix enabled it, so it had never hit MSVC.)

- parse.cpp: the floating-point parse path falls back to strtod_l because
  libc++ =deletes the float from_chars overload. That fallback was guarded
  for __APPLE__ only; Emscripten uses the same libc++, so WASM hit the
  deleted from_chars. Extend the guard to __EMSCRIPTEN__ (its musl provides
  strtod_l/newlocale, treating all locales as C).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 19:37:11 +10:00
Dion Moult c9c3beb139 poe ruff 2026-07-26 18:05:39 +10:00