Files
OCCT/tests
Pasukhin Dmitry 98ca3a5a32 Visualization - Fix selection for objects with group-level flipping (#1219)
Selection was broken for presentations that used Graphic3d_Group::SetFlippingOptions
(AIS_TextLabel, PrsDim_Dimension): OpenGl_Flipper mirrors the geometry at draw time
to keep labels upright relative to the camera, but the selection pipeline computed
BVH boxes and sensitive frustums in the unflipped local coordinates. When the camera
was rotated past the flipping threshold, clicks on the on-screen label missed.

- Add Graphic3d_Flipper: a CPU-side analogue of OpenGl_Flipper carrying the reference
  plane and templated Compute()/Apply() that reproduces the render-time flip matrix.
  Each flip branch is a 180 deg rotation (involution), so the matrix is self-inverse.
- Extend Graphic3d_CStructure with HasGroupFlipping()/SetGroupFlipping() alongside
  the existing transform-persistence flag; reset it in Graphic3d_Structure::clear().
- Add Graphic3d_Group::Flipper() and a myFlipper member populated from
  OpenGl_Group::SetFlippingOptions(true,...). The render-side OpenGl_Flipper element
  is still emitted for the push/pop bracket; myFlipper persists across the matching
  SetFlippingOptions(false,...) call so the selection side can see that the group
  contains flipped geometry.
- Add Select3D_SensitiveEntity::Flipper() / SetFlippingOptions() so sensitive
  entities can carry the same flipping metadata used by the selection traversal;
  include the handle in DumpJson.
- SelectMgr_SensitiveEntitySet tracks myNbEntityWithFlipping in Append()/Remove();
  HasEntityWithFlipping() exposes it to the viewer selector.
- SelectMgr_SelectableObjectSet::appropriateSubset() routes presentations with
  HasGroupFlipping() to the 3d-persistent BVH subset (same as transform persistence).
- BVHBuilderAdaptorPersistent merges the flipping and transform-persistence loops
  into a single pass: for each group with a Flipper or TransformPersistence, build
  its local bbox, apply the flip (if any), then apply the TransformPersistence
  (if any), then add the resulting box to the object bbox; object-level
  TransformPersistence is applied once to the merged box. Note: for the rare case
  of object-level + group-level TransformPersistence the application order differs
  from the prior code (object-TP now runs after group-TP contributions are added).
  Common cases (only one or the other) are behavior-preserving.
- SelectMgr_ViewerSelector::traverseObject() bypasses the root/per-node overlap
  early-outs when the entity set contains flipped sensitives, and folds the flip
  matrix into aInvFlippingAndPers = T_flip * aInvSensTrsf before computeFrustum()
  and checkOverlap(). Using T_flip directly is valid because it is self-inverse.
  Before Compute(), the object's Transformation() is folded into aMVForFlip via
  Graphic3d_TransformUtils::Convert<double> so the isReversedX/Y/Z decision
  agrees with OpenGl_Flipper::Render() which uses WorldView * ModelWorld.
- SelectMgr_SelectableObjectSet::BVHBuilderAdaptorPersistent computes the same
  aMVForFlip once per object (hoisted outside the group loop) and passes it to
  Graphic3d_Flipper::Apply, so BVH bounds and per-sensitive overlap testing use
  the same flip matrix.
- SelectMgr::ComputeSensitivePrs() forwards the flipper to the debug presentation's
  current group so selection-mode visualization reflects the flip.

Known limitation (narrowed): the selection pipeline now folds the object's
Transformation() into the MV passed to Graphic3d_Flipper::Compute, covering the
common case of a flipping label on a rotated assembly. Group-level
Graphic3d_Group::Transformation() is still not folded in on the selection side
because the sensitive entity does not carry a reference to its host group; this
only affects consumers that give the flipping group its own non-identity gp_Trsf
(uncommon in stock OCCT). A TODO in Graphic3d_Flipper::Compute and
SelectMgr_ViewerSelector marks the deferred follow-up.
2026-04-21 21:38:38 +01:00
..