From 16cf012413fb14f54cf71b945b2ce10a78844b60 Mon Sep 17 00:00:00 2001 From: sshutina Date: Sat, 23 Aug 2025 19:13:02 +0100 Subject: [PATCH] Fix polygon selection --- .../SelectMgr_TriangularFrustumSet.cxx | 88 ++++++++++++++----- .../SelectMgr_TriangularFrustumSet.hxx | 10 +-- 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx b/src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx index 0df5e595af..645f874b83 100644 --- a/src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx +++ b/src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx @@ -258,28 +258,9 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsBox (const SelectMgr_Ve return Standard_True; } - gp_Pnt aMinMaxPnts[2] = { gp_Pnt (theMinPnt.x(), theMinPnt.y(), theMinPnt.z()), - gp_Pnt (theMaxPnt.x(), theMaxPnt.y(), theMaxPnt.z())}; - - gp_Pnt anOffset[3] = { gp_Pnt (aMinMaxPnts[1].X() - aMinMaxPnts[0].X(), 0.0, 0.0), - gp_Pnt (0.0, aMinMaxPnts[1].Y() - aMinMaxPnts[0].Y(), 0.0), - gp_Pnt (0.0, 0.0, aMinMaxPnts[1].Z() - aMinMaxPnts[0].Z()) }; - - Standard_Integer aSign = 1; - for (Standard_Integer aPntsIdx = 0; aPntsIdx < 2; aPntsIdx++) - { - for (Standard_Integer aCoordIdx = 0; aCoordIdx < 3; aCoordIdx++) - { - gp_Pnt anOffsetPnt = aMinMaxPnts [aPntsIdx].XYZ() + aSign * anOffset [aCoordIdx].XYZ(); - if (isIntersectBoundary (aMinMaxPnts [aPntsIdx], anOffsetPnt) - || isIntersectBoundary (anOffsetPnt, anOffsetPnt.XYZ() + aSign * anOffset [(aCoordIdx + 1) % 3].XYZ())) - { + // Disable full-inside optimization for AABB nodes in polyline mode to avoid false inclusions. + // Force per-element checks downstream (elementIsInside). *theInside &= Standard_False; - return Standard_True; - } - } - aSign = -aSign; - } return Standard_True; } @@ -308,6 +289,15 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsPoint (const gp_Pnt& th return Standard_False; } +// ======================================================================= +// function : OverlapsPoint +// purpose : +// ======================================================================= +Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsPoint (const gp_Pnt& thePnt) const +{ + return IsInsideByProjection (thePnt); +} + // ======================================================================= // function : OverlapsPolygon // purpose : @@ -990,3 +980,59 @@ void SelectMgr_TriangularFrustumSet::DumpJson (Standard_OStream& theOStream, Sta OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, aFrustum.get()) } } + +// ======================================================================= +// function : IsInsideByProjection +// purpose : Robust 2D inclusion test using original polyline (fills gaps) +// ======================================================================= +Standard_Boolean SelectMgr_TriangularFrustumSet::IsInsideByProjection (const gp_Pnt& thePnt) const +{ + if (myBoundaryPoints.Size() < 6) // at least 3 near + 3 far + { + return Standard_False; + } + + // Build plane by first frustum triangle (near plane) + const gp_Pnt& p0 = myFrustums.First()->myVertices[0]; + const gp_Pnt& p1 = myFrustums.First()->myVertices[1]; + const gp_Pnt& p2 = myFrustums.First()->myVertices[2]; + gp_Pln aPln (p0, gp_Vec(p0,p1).Crossed (gp_Vec(p0,p2))); + + // Project point onto plane along plane normal + gp_Pnt aProj = thePnt; + Standard_Real aA, aB, aC, aD; aPln.Coefficients (aA, aB, aC, aD); + const Standard_Real n2 = aA*aA + aB*aB + aC*aC; + if (n2 > gp::Resolution()) + { + const Standard_Real s = (aA * aProj.X() + aB * aProj.Y() + aC * aProj.Z() + aD) / n2; + aProj.SetCoord (aProj.X() - aA * s, + aProj.Y() - aB * s, + aProj.Z() - aC * s); + } + + // Project near boundary loop and perform winding test in 2D + const Standard_Integer aFacesNb = myBoundaryPoints.Size() / 2; + const Standard_Integer aLowerIdx = myBoundaryPoints.Lower(); + + // Choose 2D axes by dominant plane normal component + int drop = 0; if (Abs(aB) > Abs(aA) && Abs(aB) >= Abs(aC)) drop = 1; else if (Abs(aC) > Abs(aA) && Abs(aC) > Abs(aB)) drop = 2; + auto proj2d = [drop](const gp_Pnt& P) { + if (drop == 0) return gp_XY (P.Y(), P.Z()); + if (drop == 1) return gp_XY (P.X(), P.Z()); + return gp_XY (P.X(), P.Y()); + }; + + gp_XY P = proj2d (aProj); + Standard_Boolean inside = Standard_False; + for (Standard_Integer i = 0, j = aFacesNb - 1; i < aFacesNb; j = i++) + { + const gp_Pnt& Pi3d = myBoundaryPoints.Value (aLowerIdx + i); + const gp_Pnt& Pj3d = myBoundaryPoints.Value (aLowerIdx + j); + const gp_XY Ai = proj2d (Pi3d); + const gp_XY Aj = proj2d (Pj3d); + const Standard_Boolean intersect = ((Ai.Y() > P.Y()) != (Aj.Y() > P.Y())) + && (P.X() < (Aj.X()-Ai.X()) * (P.Y()-Ai.Y()) / (Aj.Y()-Ai.Y() + 1e-300) + Ai.X()); + if (intersect) inside = !inside; + } + return inside; +} diff --git a/src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx b/src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx index 5f8c170351..85bb819d13 100644 --- a/src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx +++ b/src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx @@ -84,11 +84,7 @@ public: const SelectMgr_ViewClipRange& theClipRange, SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE; - //! Always returns FALSE (not applicable to this selector). - virtual Standard_Boolean OverlapsPoint (const gp_Pnt& ) const Standard_OVERRIDE - { - return Standard_False; - } + Standard_EXPORT virtual Standard_Boolean OverlapsPoint (const gp_Pnt& thePnt) const Standard_OVERRIDE; Standard_EXPORT virtual Standard_Boolean OverlapsPolygon (const TColgp_Array1OfPnt& theArrayOfPnts, Select3D_TypeOfSensitivity theSensType, @@ -170,6 +166,10 @@ public: //! Dumps the content of me into the stream Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE; +public: + //! 2D inclusion test: project 3D point onto selection plane and check inside original polyline + Standard_EXPORT Standard_Boolean IsInsideByProjection (const gp_Pnt& thePnt) const; + private: //! Checks whether the segment intersects with the boundary of the current volume selection -- 2.39.5