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)
This commit is contained in:
Petru Conduraru
2026-07-17 10:01:23 +03:00
committed by Dion Moult
parent 0191ac63dc
commit da4127f33b
2 changed files with 12 additions and 8 deletions
@@ -467,7 +467,6 @@ class application(QtWidgets.QApplication):
qtViewer3d.__init__(self, widget)
self.ais_to_product = {}
self.product_to_ais = {}
self.counter = 0
self.window = widget
self.thread = None
@@ -492,11 +491,11 @@ class application(QtWidgets.QApplication):
ais = display_shape(shape, viewer_handle=v)
product = f[shape.data.id]
if USE_OCCT_HANDLE:
ais.GetObject().SetSelectionPriority(self.counter)
self.ais_to_product[self.counter] = product
# Keyed by the AIS object itself (its __eq__/__hash__ track the
# underlying OCCT instance) instead of AIS_InteractiveObject.SetSelectionPriority(),
# which no longer exists on general AIS objects in modern pythonocc-core (#1098).
self.ais_to_product[ais] = product
self.product_to_ais[product] = ais
self.counter += 1
QtWidgets.QApplication.processEvents()
@@ -577,8 +576,9 @@ class application(QtWidgets.QApplication):
v.InitSelected()
if v.MoreSelected():
ais = v.SelectedInteractive()
inst = self.ais_to_product[ais.GetObject().SelectionPriority()]
self.instanceSelected.emit(inst)
inst = self.ais_to_product.get(ais)
if inst is not None:
self.instanceSelected.emit(inst)
class window(QtWidgets.QMainWindow):
@@ -225,7 +225,11 @@ def display_shape(shape, clr=None, viewer_handle=None):
def set_shape_transparency(ais, t, update_viewer=True):
handle.Context.SetTransparency(ais, t, update_viewer)
# AIS_InteractiveContext.SetTransparency()'s argument count differs across
# pythonocc-core versions (#1037); AIS_InteractiveObject.SetTransparency() is stable.
ais.SetTransparency(t)
if update_viewer:
handle.Context.UpdateCurrentViewer()
def get_bounding_box_center(bbox):