Commit Graph

212 Commits

Author SHA1 Message Date
Petru Conduraru 66bcddc277 geom: expose a reusable kernel object to Python (prototype for #9417)
ifcopenshell.geom.create_shape constructs a geometry kernel, converter and
mapping on every call and discards them afterwards. For hybrid kernels the
construction alone rescans the plugin directory per component, which #9417
addresses on the C++ side by caching the resolved component ids. This
prototypes the alternative aothms suggested in the #9417 review: reuse the
constructed kernel itself from Python.

The wrapper gains a geometry_kernel class holding the converter (and through
it the kernel, mapping and conversion caches) built once per
(geometry_library, file, settings) triple, with create_shape(instance[,
representation]) delegating to the same helper the free create_shape uses,
now split so both paths share one body. Python gains
ifcopenshell.geom.kernel(settings, file, geometry_library) mirroring the
iterator constructor signature. The binding is fixed at construction:
settings are copied the way converter already copies them, and a guard
rejects instances from a different file because the mapping is file-bound.

On PGSuper_Import_Model.ifc (322 products, single-threaded, arm64 Linux),
hybrid-cgal-simple-opencascade drops from 71.97 ms/call with per-call
create_shape to 23.35 ms/call through the reused kernel, matching the
iterator (22.74 ms/call) without needing the #9417 cache; plain opencascade
is unaffected (23.30 vs 22.28 ms/call).
2026-09-01 19:26:35 +02:00
Andrej730 109bd58384 ruff: use readable rule names in ignores 2026-08-10 17:06:56 +05:00
Andrej730 7370d07db1 ruff: sort imports 2026-08-10 16:54:37 +05:00
Thomas Krijnen 3d15500976 run black 2026-08-09 14:17:35 +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 be3c2ee770 Expose geometry types in snake case
Generated with the assistance of an AI coding tool.
2026-08-09 04:44:18 +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
Andrej730 a655ef6cd2 Drop Python 2 workaround 2026-08-03 11:52:48 +05: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 291d7d8441 black . 2026-07-26 18:03:09 +10:00
Petru Conduraru da4127f33b Fix pythonocc-core viewer compatibility in geom.occ_utils and geom.app (#1037, #1098)
set_shape_transparency() called AIS_InteractiveContext.SetTransparency(),
whose argument count is inconsistent across pythonocc-core versions
(reported as a TypeError in #1037). Set transparency directly on the AIS
object instead, the same stable pattern already used elsewhere in this
file (display_shape() calls ais.SetTransparency() directly, never through
the Context), then call Context.UpdateCurrentViewer() to refresh.

app.py's viewer used a "SetSelectionPriority(counter)"/"SelectionPriority()"
pair as an ad hoc unique key to map a displayed AIS object back to its IFC
product. On modern pythonocc-core this crashed with AttributeError because
.GetObject() (needed to unwrap the old handle-based API) no longer exists
on AIS objects (#1098, PR #1113 partially patched one of the two call
sites but left the one in HandleSelection unguarded).

Live pythonocc-core 7.9.3 testing showed the GetObject() guard alone is
not sufficient: SetSelectionPriority/SelectionPriority themselves have
been removed from AIS_InteractiveObject entirely in modern OCCT (only
AIS_Trihedron keeps a same-named but unrelated method for datum parts),
so gating the .GetObject() call with the existing USE_OCCT_HANDLE flag
would still crash the first time a shape is selected. Verified live that
AIS objects retain correct __eq__/__hash__ (matching the underlying OCCT
instance) across separate SWIG wrapper instances, so ais_to_product is
now keyed directly by the AIS object itself, removing the dependency on
the removed OCCT API and the GetObject()/handle distinction altogether.

Verified live against pythonocc-core 7.9.3 (conda-forge) using real
AIS_Shape objects obtained from ifcopenshell.geom.occ_utils.display_shape()
and a real IFC file: reproduced both the original TypeError (#1037) and
AttributeError (#1098), confirmed both fixes resolve them, and confirmed
the ais_to_product dict lookup round trips correctly through a real
Context.Select()/SelectedInteractive() call. Could not exercise the full
Qt-embedded viewer.finished()/HandleSelection() flow end to end because
this pythonocc-core build segfaults natively when creating a second GL
context inside a Qt widget on this macOS host, a pre-existing environment
issue unrelated to this diff (reproduces identically with unpatched code,
before any touched line executes).

AI-generated, reviewed and tested by Petru Conduraru.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 6603c8459a)
2026-07-25 23:16:38 +10:00
Petru Conduraru 0191ac63dc ifcwrap: keep geometry's owning element alive to fix silent data corruption (#1124)
create_shape() returns a Python-owned Element (SWIG_POINTER_OWN in the
boost::variant out typemap). Its .geometry property calls Element::geometry(),
which returns a reference into the element's boost::shared_ptr<Representation>
_geometry member. SWIG wraps that reference as a non-owning pointer, so the
returned Triangulation/BRep/Serialization proxy does not keep the element alive.

When a caller keeps only .geometry (e.g. create_shape(s, e).geometry) and drops
the parent element, Python garbage-collects the element, destroying its
shared_ptr and freeing the underlying representation. Subsequent reads of
verts/faces then return freed memory: empty or implausible float/int garbage,
non-deterministically depending on GC and allocator timing. This is silent data
corruption, not a crash, and has bitten users since 2020.

Fix: in the TriangulationElement/SerializedElement/BRepElement pythoncode, wrap
the geometry getter so the returned geometry stores a backreference to its
owning element (result._parent = self). This makes the parent's lifetime at
least as long as the geometry's, automatically and transparently, so no caller
has to remember to hold the element. This is aothms's suggested backreference,
applied generically in the binding rather than left as a workaround.

Reproduced deterministically (washBasin fixture): before, verts len 0 vs 133500
across repeated GC-pressure runs; after, 133500 every run for all three element
types. test_create_shape passes; no regressions.

Note: tree.select_ray()'s ray_intersection_result (2024 follow-up in #1124) is a
separate ownership mechanism (std::vector element reference + std::array member
pointer) and is left as follow-up scope.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 824c1fc280)
2026-07-25 23:16:38 +10:00
Andrej730 6858cccdcc settings_mixin.build_parser: fix ty == "bool" typo, should be an assignment
(cherry picked from commit f744753726)
2026-07-25 23:16:38 +10:00
Dion Moult a341ad29f3 port: SVG edge classification (#3668) onto wgpu [worklist #114-120]
Ports the 7-commit v0.8.0 SVG edge-classification feature (f0970b90b +
6 follow-ups) onto wgpu's heavily-diverged serializer. Reconstructed
block-by-block rather than merged, because both sides rewrote
SvgSerializer (v0.8.0 +419, wgpu +778) and git's conflict alignment was
misleading.

Key wgpu adaptations reasoned per block:
- IfcUtil::IfcBaseEntity* (pointer identity) -> express::Base (value),
  incl. as a std::map key in draw_hlr (express::Base has operator<);
  nullptr fallback -> express::Base{}
- boost::optional -> std::optional (css_class, dash_array)
- hlr_calc::result_type pair -> 3-tuple (adds per-edge class label)
- draw_hlr restructured with a group_by_product map: ONE path_object per
  product so multiple class buckets share a group and per-path classes
  survive Bonsai's merge (NOT naive per-item threading, which fragments
  groups -- caught during visual verification)
- settings wired into wgpu's apply_settings() (ctor-called), NOT the
  feature's added ready() call which wgpu already solved differently
- logger_.Warning -> logger().warning in write(geometry_data)

Verified end-to-end via IfcConvert on a curved-geometry stress scene
(Suzanne/Torus/Sphere/Cube/Cone/...): edges classify into outline/sharp/
crease/boundary/flush with correct per-product grouping and CSS styling.
Requires the model's storey to carry an Elevation and --svg-project to
trigger the HLR projection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 23:16:38 +10:00
Andrej730 2f4bcc17a6 geom/main.py: fix ty complaint
(cherry picked from commit 8a00ce84cc)
2026-07-25 23:15:23 +10:00
Andrej730 298e4cfd8d instance_streamer: migrate to snake case 2026-07-22 19:01:50 +05:00
Andrej730 ab38f4f7f6 Consider new geometry settings 2026-07-22 19:01:50 +05:00
Andrej730 01cfbe6948 Consider new serializer settings 2026-07-22 19:01:50 +05:00
Andrej730 32f2dfd294 downstream: logger: reuse logger_or_root, dedupe optional-logger-arg pattern 2026-07-22 19:01:50 +05:00
Andrej730 5f0f4669f2 Fix using logger.Root instead of logger.root 2026-07-22 19:01:50 +05:00
Thomas Krijnen 7fc2d9a998 Merge remote-tracking branch 'origin/v0.8.0' into ifcviewer-wgpu 2026-07-09 13:21:39 +02:00
Thomas Krijnen 6a6756de66 Bump binary versions in makefiles; add backwards compatibility to logger usage in python #8167 2026-06-15 09:56:36 +02:00
Thomas Krijnen ca99ef3af7 More changes to pass around logger to parse-related calls 2026-06-14 14:49:14 +02:00
Thomas Krijnen a7738eeb64 Pass around non-static logger instances and programmatic access to messages in-memory 2026-06-10 18:40:17 +02:00
Thomas Krijnen 2eb2d65710 Allow passing buffer to serializers that support it 2026-05-09 21:03:15 +02:00
Thomas Krijnen 554c7174e3 Backspace everything regarding HDF5 2026-05-08 16:20:26 +02:00
Thomas Krijnen bfea57c617 Wire up serializer plug-ins in python 2026-05-08 10:58:09 +02:00
Thomas Krijnen ea4747ccb1 SIDE_MODULE=2 for plug-ins 2026-05-05 21:43:58 +02:00
Thomas Krijnen 91ae631c7d Merge remote-tracking branch 'origin/v0.8.0' into datamodel-v1.0 2026-04-18 20:15:28 +02:00
Thomas Krijnen d2cc66fdf0 tree and document plug-ins 2026-04-17 11:24:09 +02:00
Andrej730 26280d24fe Add ty to check for missing symbols and other simple errors 2026-03-20 15:36:14 +05:00
Andrej730 f2e2e324b1 Fixing stubs
- `function_item`, `tags` added in df7318973
- MakeVolume added in c385b93, ignore as all other conversion settings
- moved `SeparateZUpNode` ignore to the other geom serializer settings
2026-03-18 12:25:14 +05:00
Andrej730 eba798c544 typing 2026-03-13 20:26:22 +05:00
Andrej730 92c979fbbf black . 2026-02-27 14:52:55 +05:00
Andrej730 dfc91e6639 ifcopenshell-python - clean up unused imports 2026-01-16 17:16:24 +05:00
Thomas Krijnen cf3393b6a0 black 2026-01-14 14:09:40 +01:00
Thomas Krijnen 7e5248da29 Fix create_shape() overloads because SWIG does not map None for us anymore 2026-01-13 08:44:30 +01:00
Thomas Krijnen 0a9e29ce45 black 2026-01-10 11:52:08 +01:00
Thomas Krijnen ae79996eb6 Fix running of test/tests.py 2026-01-08 11:49:29 +01:00
Andrej730 13be6ccd45 Sort imports 2025-12-19 18:53:14 +05:00
Thomas Krijnen 487a4f345d Creoox json serializer 2025-11-17 14:06:39 +01:00
Thomas Krijnen 6df5632f91 black 2025-10-26 13:33:10 +01:00
Thomas Krijnen b10415b1b3 Rework iterator constructor #7291 2025-10-26 13:31:31 +01:00
Thomas Krijnen e82ca0e932 Less back and forths by returning semi count in page 2025-10-25 15:08:21 +02:00
Thomas Krijnen 5910b39766 geom.stats module for preemptive scanning through file 2025-10-25 13:58:32 +02:00
smr 67fb569669 style: fix formatting with black 2025-08-30 20:04:58 +02:00
smr da9be7cff0 Fix PythonOCC >=7.8.0 compatibility in serialize_shape function
Resolves issue #6099: PythonOCC >=7.8.0 changed WriteToString() method
signature, causing TypeError in ifcopenshell.geom.serialise().

This fix uses signature inspection to detect the method signature:
- For PythonOCC < 7.8.0: Use WriteToString() (no parameters)
- For PythonOCC >= 7.8.0: Fall back to Write() method
- Graceful handling of signature inspection failures

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-30 20:04:58 +02:00
Thomas Krijnen 6ffcf363a6 Fix geom literals #6974 2025-08-06 10:49:45 +02:00