Commit Graph

4221 Commits

Author SHA1 Message Date
CyrilWaechter dd5bd58916 Add footprint corner sampling for roof detection
get_vertical_bounding_planes now also casts rays from the footprint
polygon's corner vertices, offset slightly inward toward the centroid.
This catches bounding elements (e.g. sloped roofs) that only cover a
corner of the space.

Generated with the assistance of an AI coding tool.
2026-08-18 00:11:00 +02:00
CyrilWaechter fb3cd09d6d Fix space generation location and IFC2X3 B-rep
Two fixes for space generation:

1. IFC2X3 schema: build_brep_space now falls back to plain
   IfcRelSpaceBoundary because IfcRelSpaceBoundary1stLevel does not exist in
   IFC2X3.

2. Geometry location: set_space_representation_from_polygon now aligns the
   IFC ObjectPlacement with the Blender object, converts base_z/planes and
   the footprint polygon to the object's local coordinate system before
   building, and fixes the base_z unit scale. The centred-cube regeneration
   test was updated to check world bounds because the mesh is now placed
   relative to the object placement.

Generated with the assistance of an AI coding tool.
2026-08-18 00:11:00 +02:00
CyrilWaechter 332435416a Fix clipped space top reaching sloped planes
The extrusion height was capped at the top/bottom plane anchor z (the mean
of the ray-cast hits, near the footprint centre), so a sloped ceiling's
high side stopped short of the plane (e.g. 5.5 m instead of 6.88 m for the
shed roof test). Extend the extrusion to the plane's z at every footprint
vertex before clipping, falling back to the base z as before. Also correct
the mirrored profile-to-world mapping comment in the shed roof test helper
(the ridge is at world y=-5, not y=+5).

Generated with the assistance of an AI coding tool.
2026-08-18 00:11:00 +02:00
CyrilWaechter f0c6de4bdf Add regression tests for sloped slab, curved wall
Cover a curved vertical wall (EXTRUDE_CLIP strategy) in test_space.py and a
sloped slab (clipped extrusion) in test_spatial.py.

Generated with the assistance of an AI coding tool.
2026-08-18 00:11:00 +02:00
CyrilWaechter 3b16356181 Add B-rep fallback space builder
Build a faceted B-rep space from auto-generated boundary faces when
sloped or curved bounding elements make a clipped extrusion
unsuitable.

Generated with the assistance of an AI coding tool.
2026-08-18 00:06:27 +02:00
CyrilWaechter 44860cd615 Match sloped faces in boundary generation
Allow sloped roof/slab/wall faces to bound space faces when the
strict anti-parallel rule leaves a face uncovered, using a
footprint-scaled distance tolerance. Existing matching behaviour
is preserved (fallback-only).

Generated with the assistance of an AI coding tool.
2026-08-18 00:06:27 +02:00
CyrilWaechter 5651cd6494 Add clipped extrusion space builder
Build IfcExtrudedAreaSolid clipped by top/bottom half-space planes.

Generated with the assistance of an AI coding tool.
2026-08-18 00:06:27 +02:00
CyrilWaechter 29b9d8807e Add space volume strategy detection
Detect whether a space can be built as a clipped extrusion or needs
a B-rep fallback, based on wall face orientation and top/bottom
bounding planes.

Generated with the assistance of an AI coding tool.
2026-08-18 00:06:27 +02:00
CyrilWaechter 37f557b4b5 Align vertical bounding plane strategy contract with caller
get_vertical_bounding_planes always returns EXTRUDE_CLIP; the
EXTRUDE_CLIP-vs-BREP decision belongs to the calling layer.

Generated with the assistance of an AI coding tool.
2026-08-18 00:06:27 +02:00
CyrilWaechter 881fb10fe6 Add vertical bounding plane detection for space generation
Implement get_vertical_bounding_planes using ray-casting from the RL
cut elevation with nearest-hit and coplanar grouping.

Generated with the assistance of an AI coding tool.
2026-08-18 00:06:27 +02:00
CyrilWaechter adf01be1d0 ifcopenshell.util.boundary: make face matrix robust against collinear first vertices
_face_matrix_from_verts used only the first 3 vertices and sb.np_normal, which divides by zero when they are collinear. Triangulated meshes from generated spaces often start with collinear boundary vertices, producing NaN matrices and a shapely LinearRing error. Walk the polygon to find a non-degenerate normal and edge.

Generated with the assistance of an AI coding tool.
2026-08-18 00:06:27 +02:00
CyrilWaechter 243f13de09 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-18 00:06:27 +02:00
CyrilWaechter 0d5c9a0ce2 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-18 00:06:27 +02:00
CyrilWaechter ea6f03409f 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-18 00:06:27 +02:00
CyrilWaechter 21b4cd2403 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-18 00:06:27 +02:00
CyrilWaechter a543022bba 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-18 00:06:27 +02:00
CyrilWaechter 6f9d5c4005 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-18 00:06:27 +02:00
CyrilWaechter a7b6c66f77 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-18 00:06:27 +02:00
CyrilWaechter 6715e684a8 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-17 23:03:42 +02:00
Richard Brice 511584b36f Allows key point referents to be nested to the parent alignment in the reusing horizontal scenario 2026-08-17 08:03:00 +10:00
Richard Brice f65de78c46 Strengthens implementation of station_to_string. Adds alignment name to stationing referent. 2026-08-17 08:03:00 +10:00
myoualid 59b957daff fixes to sequence.create_baseline:
- assert isinstance(res, list) was wrong because duplicate_task returns a tuple not a list
- removed overkill assertion anyway as the usecase is already typed.
- setting optional name or reuse planned schedule name
- usecase now returns created baseline work schedule
2026-08-17 08:03:00 +10:00
Thomas Krijnen 81a0941d5a Apply suggestion from @aothms 2026-08-17 08:03:00 +10:00
BelGraDev dba735f1ee Fixed error when accessing the UnitType attribute in convert_file_length_units 2026-08-17 08:03:00 +10:00
Dion Moult 6bab0603e6 by_type now returns tuple - update annotations and fix failing tests 2026-08-11 17:06:37 +10:00
Andrej730 77dc679a6e pytest: fix warnings from using non-collections 2026-08-10 18:39:07 +05:00
Andrej730 109bd58384 ruff: use readable rule names in ignores 2026-08-10 17:06:56 +05:00
Andrej730 b6dccce12a ruff: use readable rule names in selectors 2026-08-10 17:06:56 +05:00
Andrej730 daa7d98b3f ruff: remove unused noqa
Most of them are actually correct, but they're not enforced in general on the repo, so using them blocks us from flagging `unused-noqa` for rules that we actually do use.
2026-08-10 17:06:56 +05:00
Andrej730 7b9615f4e5 ruff: fix unsorted-dunder-all 2026-08-10 16:54:37 +05:00
Andrej730 ff22a9d1f3 ruff: fix deprecated-import 2026-08-10 16:54:37 +05:00
Andrej730 055f64fa9b ruff: fix quoted-annotation 2026-08-10 16:54:37 +05:00
Andrej730 7370d07db1 ruff: sort imports 2026-08-10 16:54:37 +05:00
Andrej730 717d6aa2af ruff: fix pyprojects using select instead of extend-select by mistake 2026-08-10 16:33:01 +05:00
Thomas Krijnen 7a1dcd07c8 Handle version postfixes 2026-08-10 05:19:17 +02:00
Thomas Krijnen b63137e859 Merge remote-tracking branch 'origin/v0.8.0' into ifcviewer-wgpu 2026-08-10 03:31:02 +02:00
Thomas Krijnen 3d15500976 run black 2026-08-09 14:17:35 +02:00
Thomas Krijnen 64aed6a766 try fix stub 2026-08-09 14:11:49 +02:00
Thomas Krijnen a353edb9e0 check_call() so that init errors surface earlier 2026-08-09 13:59:44 +02:00
Thomas Krijnen 30fb379e32 Remove cwd from import in case you're running tests like I do 2026-08-09 13:16:24 +02:00
Thomas Krijnen 17c4d8faff Skip unavailable shape-stat kernels
Generated with the assistance of an AI coding tool.
2026-08-09 11:51:06 +02:00
Thomas Krijnen c818f48a47 Own completed iterator results uniquely
Generated with the assistance of an AI coding tool.
2026-08-09 09:14:41 +02:00
Robert Sigmundsson f05dd4aea5 Fix #9278. calculate_unit_scale raises the SI prefix to the length exponent for prefixed SQUARE_METRE/CUBIC_METRE units.
An SI prefix attaches to the base unit symbol and the prefixed symbol is
raised to the power as a whole: DECI CUBIC_METRE is dm3 = a litre = 1e-3 m3,
not 0.1 m3. The scale factor previously applied the prefix multiplier
linearly for all IfcSIUnits, inflating volumes x100 and areas x10 for such
declarations (produced e.g. by MagiCAD for Revit MEP exports).

Following the reviewer note in #9278, the exponent is taken from the
derived attribute IfcSIUnit.Dimensions rather than from substring matching
on the unit name: the multiplier is raised to LengthExponent only when the
unit's dimensions are a pure power of length, so prefixed derived units
(KILO PASCAL, MEGA NEWTON) and non-length units (KILO GRAM) correctly keep
the linear multiplier. This matches the exponent handling already present
in convert() and named_dimensions in the same module.

Adds regression tests for prefixed AREAUNIT/VOLUMEUNIT and for the
linear-prefix behaviour of PRESSUREUNIT/MASSUNIT.
2026-08-09 08:41:15 +02:00
Thomas Krijnen dcfc22e29e Transfer iterator result ownership
Generated with the assistance of an AI coding tool.
2026-08-09 04:54:51 +02:00
Thomas Krijnen be3c2ee770 Expose geometry types in snake case
Generated with the assistance of an AI coding tool.
2026-08-09 04:44:18 +02:00
Richard Brice 7ed8584edc Revised update_alignment_parameter_segment_tags to make EndTag optional 2026-08-08 10:35:20 -07:00
Thomas Krijnen 99a09a2a3c Use snake case conversion result APIs
Generated with the assistance of an AI coding tool.
2026-08-08 16:09:30 +02:00
Thomas Krijnen 7ae6bf4374 Rename geometry and serializer files
Apply the rename manifest, normalize serializer filenames to the classes they define, and update includes and CMake source lists.

Generated with the assistance of an AI coding tool.
2026-08-08 14:20:05 +02:00
Thomas Krijnen 6fea72b045 Run black 2026-08-08 12:42:25 +02:00
Thomas Krijnen af58eaf79f Last minute refactoring 2026-08-08 07:42:45 +02:00