]> OCCT Git - occt.git/commitdiff
Fix polygon selection CR0_ALC_OCCT781
authorsshutina <svetlana.shutina@opencascade.com>
Sat, 23 Aug 2025 18:13:02 +0000 (19:13 +0100)
committersshutina <svetlana.shutina@opencascade.com>
Sat, 23 Aug 2025 18:13:02 +0000 (19:13 +0100)
src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx
src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx

index 0df5e595afbc80d37ff40ef2fd4d9f274cda8cfd..645f874b83cf560ca9adce4b129692fd15f3d534 100644 (file)
@@ -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;
+}
index 5f8c17035128125e4d0df9d105d962dd79f18666..85bb819d13fb874f53a98e0cbf482949cab0e388 100644 (file)
@@ -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