0026627: [Regression] Shape Healing hangs as of OCC 6.8.0
[occt.git] / src / BRepClass3d / BRepClass3d_SClassifier.cxx
index 5d2e594..07833c1 100644 (file)
@@ -5,8 +5,8 @@
 //
 // This file is part of Open CASCADE Technology software library.
 //
-// This library is free software; you can redistribute it and / or modify it
-// under the terms of the GNU Lesser General Public version 2.1 as published
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
 // by the Free Software Foundation, with special exception defined in the file
 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
 // distribution for complete text of the license and disclaimer of any warranty.
 
 //  Modified by skv - Thu Sep  4 11:22:05 2003 OCC578
 
-#include <BRepClass3d_SClassifier.ixx>
-
-#include <gp_Pnt.hxx>
+#include <BRep_Tool.hxx>
+#include <BRepClass3d_Intersector3d.hxx>
+#include <BRepClass3d_SClassifier.hxx>
+#include <BRepClass3d_SolidExplorer.hxx>
+#include <BRepTopAdaptor_FClass2d.hxx>
+#include <ElCLib.hxx>
+#include <Geom_Surface.hxx>
 #include <gp_Lin.hxx>
+#include <gp_Pnt.hxx>
 #include <gp_Vec.hxx>
-#include <BRepClass3d_Intersector3d.hxx>
-#include <TopoDS.hxx>
-
 #include <IntCurvesFace_Intersector.hxx>
-// modified by NIZHNY-MKK  Mon Jun 21 15:13:40 2004
+#include <math_BullardGenerator.hxx>
 #include <Precision.hxx>
-#include <ElCLib.hxx>
-#include <Geom_Surface.hxx>
-#include <BRep_Tool.hxx>
+#include <Standard_DomainError.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Face.hxx>
+
+#include <vector>
 
+// modified by NIZHNY-MKK  Mon Jun 21 15:13:40 2004
 static
-  void FaceNormal (const TopoDS_Face& aF,
-                  const Standard_Real U,
-                  const Standard_Real V,
-                  gp_Dir& aDN);
+  Standard_Boolean FaceNormal (const TopoDS_Face& aF,
+                               const Standard_Real U,
+                               const Standard_Real V,
+                               gp_Dir& aDN);
 
 static 
   Standard_Real GetAddToParam(const gp_Lin& L,const Standard_Real P,const Bnd_Box& B);
@@ -73,13 +78,17 @@ BRepClass3d_SClassifier::BRepClass3d_SClassifier(BRepClass3d_SolidExplorer& S,
 //=======================================================================
 void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aSE,
                                                   const Standard_Real /*Tol*/) {
-  //-- Idea : Take point A in face1 and point B in face B 
-  //-- (if there is only one face, take 2 points in the same face.)
-  //-- 
-  //-- Intersect straight line AB with the solid and produce transition of the 
-  //-- first point. If the solid has only one face and the straight line AB does not cut it 
-  //-- it is not possible to decide.
 
+  //Take a normal to the first extracted face in its random inner point
+  //and intersect this reversed normal with the faces of the solid.
+  //If the min.par.-intersection point is
+  // a) inner point of a face
+  // b) transition is not TANGENT
+  //    (the line does not touch the face but pierces it)
+  //then set <myState> to IN or OUT according to transition
+  //else take the next random point inside the min.par.-intersected face
+  //and continue
+  
   if(aSE.Reject(gp_Pnt(0,0,0))) { 
     myState=3; //-- in ds solid case without face 
     return;
@@ -87,150 +96,87 @@ void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aS
   //
   //------------------------------------------------------------
   // 1
-  Standard_Boolean bFound, bFlag;
-  Standard_Integer nump;
-  Standard_Real aParam, aU1 = 0., aV1 = 0., aU2 = 0., aV2 = 0.;
-  gp_Pnt A,B;
-  gp_Dir aDN1, aDN2;
-  TopoDS_Face aF1, aF2;
-  //
-  nump = 0;
-  aParam = 0.5;
+  Standard_Boolean bFound;
+  Standard_Real aParam, aU = 0., aV = 0.;
+  gp_Pnt aPoint;
+  gp_Dir aDN;
+
+  math_BullardGenerator aRandomGenerator;
   myFace.Nullify();
-  myState=2; 
-  for(aSE.InitShell(); aSE.MoreShell() && nump<2;  aSE.NextShell()) { 
-    for(aSE.InitFace();        aSE.MoreFace()  && nump<2; ) {
-      TopoDS_Face aF = aSE.CurrentFace();
-      aSE.NextFace();
-      if(!nump) { 
-       nump++;
-       bFound=aSE.FindAPointInTheFace(aF, A, aU1, aV1, aParam);
-       if (!bFound) {
-         return;
-       }
-       aF1=aF;
-       if(!aSE.MoreFace()) { 
-         nump++;
-         bFound=aSE.FindAPointInTheFace(aF, B, aU2, aV2, aParam);
-         if (!bFound) {
-           return;
-         }
-         aF2=aF;
-       }
-      }// if(nump==0) {    
-      else if(nump==1) { 
-       bFound=aSE.FindAPointInTheFace(aF, B, aU2, aV2, aParam);
-       if(!bFound) { 
-         return;
-       } 
-       aF2=aF;
-       nump++;
-      }
-    }// for(aSE.InitFace();    aSE.MoreFace()  && nump<2; ) {
-  }// for(aSE.InitShell(); aSE.MoreShell() && nump<2;  aSE.NextShell()) { 
-  //
-  //------------------------------------------------------------
-  // 2
-  Standard_Integer cpasbon;
-  Standard_Real parmin, aD2, aSP;
-  IntCurveSurface_TransitionOnCurve aTC;    
-  TopAbs_State aState;
-  //
-  parmin = RealLast();
-  //
-  bFlag=Standard_False;
-  if (aF1!=aF2) {
-    FaceNormal(aF1, aU1, aV1, aDN1);
-    FaceNormal(aF2, aU2, aV2, aDN2);
-    aSP=1.-aDN1*aDN2;
-    if (aSP < 1.e-5) {
-      bFlag=!bFlag;
+  myState=2;
+
+  // Collect faces in sequence to iterate
+  std::vector<TopoDS_Face> aFaces;
+  for (aSE.InitShell(); aSE.MoreShell(); aSE.NextShell())
+  {
+    for (aSE.InitFace(); aSE.MoreFace(); aSE.NextFace())
+    {
+      aFaces.push_back (aSE.CurrentFace());
     }
   }
-  //
-  aD2=A.SquareDistance(B);
-  if(aD2<0.000001 || bFlag) { 
-    B.SetCoord(A.X()+1,A.Y()+1,A.Z()+1);
-  }
-  //
-  cpasbon = 0;
-  gp_Vec AB(A,B);
-  //
-  do { 
-    switch (cpasbon) 
+
+  // iteratively try up to 10 probing points from each face
+  const int NB_MAX_POINTS_PER_FACE = 10;
+  for (int itry = 0; itry < NB_MAX_POINTS_PER_FACE; itry++)
+  {
+    for (std::vector<TopoDS_Face>::iterator iFace = aFaces.begin(); iFace != aFaces.end(); ++iFace)
+    {
+      TopoDS_Face aF = *iFace;
+
+      TopAbs_State aState = TopAbs_OUT;
+      IntCurveSurface_TransitionOnCurve aTransition = IntCurveSurface_Tangent;
+
+      aParam = 0.1 + 0.8 * aRandomGenerator.NextReal(); // random number in range [0.1, 0.9]
+      bFound = aSE.FindAPointInTheFace(aF, aPoint, aU, aV, aParam);
+      if (!bFound || !FaceNormal(aF, aU, aV, aDN))
+        continue;
+
+      gp_Lin aLin(aPoint, -aDN);
+      Standard_Real parmin = RealLast();
+      for (aSE.InitShell();aSE.MoreShell();aSE.NextShell()) { 
+        if (aSE.RejectShell(aLin) == Standard_False) { 
+          for (aSE.InitFace();aSE.MoreFace(); aSE.NextFace()) {
+            if (aSE.RejectFace(aLin) == Standard_False) { 
+              TopoDS_Shape aLocalShape = aSE.CurrentFace();
+              TopoDS_Face CurFace = TopoDS::Face(aLocalShape);
+              IntCurvesFace_Intersector& Intersector3d = aSE.Intersector(CurFace);
+              Intersector3d.Perform(aLin,-RealLast(),parmin); 
+
+              if(Intersector3d.IsDone()) {
+                if(Intersector3d.NbPnt()) { 
+                  Standard_Integer imin = 1;
+                  for (Standard_Integer i = 2; i <= Intersector3d.NbPnt(); i++)
+                    if (Intersector3d.WParameter(i) < Intersector3d.WParameter(imin))
+                      imin = i;
+                  parmin = Intersector3d.WParameter(imin);
+                  aState = Intersector3d.State(imin);
+                  aTransition = Intersector3d.Transition(imin);
+                }
+              }
+            }
+          }
+        }
+        else
+          myState = 1;
+      } //end of loop on the whole solid
+        
+      if (aState == TopAbs_IN)
       {
-      case 1 : AB.SetX(-AB.X());break;
-      case 2 : AB.SetY(-AB.Y());break;
-      case 3 : AB.SetZ(-AB.Z());break;
-      case 4 : AB.SetY(-AB.Y());break;
-      case 5 : AB.SetX(-AB.X());break;
-      }
-    gp_Lin L(A,gp_Dir(AB));    
-    //-- cout<<"\npoint A "<<A.X()<<" "<<A.Y()<<" "<<A.Z()<<endl;
-    //-- cout<<"\npoint B "<<B.X()<<" "<<B.Y()<<" "<<B.Z()<<endl;
-    for(aSE.InitShell();aSE.MoreShell();aSE.NextShell()) { 
-      if(aSE.RejectShell(L) == Standard_False) { 
-       for(aSE.InitFace();aSE.MoreFace(); aSE.NextFace()) {
-         if(aSE.RejectFace(L) == Standard_False) { 
-           TopoDS_Shape aLocalShape = aSE.CurrentFace();
-           TopoDS_Face f = TopoDS::Face(aLocalShape);
-           IntCurvesFace_Intersector& Intersector3d = aSE.Intersector(f);
-           Intersector3d.Perform(L,-RealLast(),parmin); 
-
-           if(Intersector3d.IsDone()) { 
-             if(Intersector3d.NbPnt()) { 
-               if(Intersector3d.WParameter(1) < parmin) {
-                 aState=Intersector3d.State(1);
-                 parmin = Intersector3d.WParameter(1);
-                 if(aState==TopAbs_IN || aState==TopAbs_ON) { 
-                   aTC=Intersector3d.Transition(1);
-                   //-- The intersection point between the line and a face F 
-                   // -- of the solid is in the face F 
-                   if(aTC == IntCurveSurface_Out) { 
-                     //-- The line is going from inside the solid to outside 
-                     //-- the solid.
-                     myState = 3; //-- IN --
-                   }
-                   else if(aTC == IntCurveSurface_In) { 
-                     myState = 4; //-- OUT --
-                   }
-                   myFace  = f;
-                 }
-                 /*
-                 else if(Intersector3d.State(1)==TopAbs_ON)  {
-                   //-- The intersection point between the line and a face F 
-                   //-- of the solid is in the face F 
-                   if(Intersector3d.Transition(1) == IntCurveSurface_Out) { 
-                     //-- The line is going from inside the solid to outside 
-                     //-- the solid.
-                     myState = 3; //-- IN --
-                   }
-                   else if(Intersector3d.Transition(1) == IntCurveSurface_In) { 
-                     myState = 4; //-- OUT --
-                   }
-                   //-- myState = 2;
-                   myFace  = f;
-                 }
-                 */
-               }
-               
-               else { 
-                 //-- No point has been found by the Intersector3d.
-                 //-- Or a Point has been found with a greater parameter.
-               }
-             }
-           }
-         }
-       } //-- Exploration of the faces
-      } //-- Shell has not been rejected
-      else { 
-       myState=1; 
+        if (aTransition == IntCurveSurface_Out) { 
+          //-- The line is going from inside the solid to outside 
+          //-- the solid.
+          myState = 3; //-- IN --
+          return;
+        }
+        else if (aTransition == IntCurveSurface_In) { 
+          myState = 4; //-- OUT --
+          return;
+        }
       }
-    } //-- Exploration of the shells
-    cpasbon++;
-  }
-  while(cpasbon!=0 && cpasbon<5);
+    } // iteration by faces
+  } // iteration by points
 }
+
 //=======================================================================
 //function : Perform
 //purpose  : 
@@ -370,7 +316,7 @@ void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer,
              if(Intersector3d.IsDone()) { 
                Standard_Integer i;
                for (i=1; i <= Intersector3d.NbPnt(); i++) { 
-                 if(Abs(Intersector3d.WParameter(i)) < Abs(parmin)) {
+                 if(Abs(Intersector3d.WParameter(i)) < Abs(parmin) - Precision::PConfusion()) {
  
                    parmin = Intersector3d.WParameter(i);
                    //  Modified by skv - Thu Sep  4 12:46:32 2003 OCC578 Begin
@@ -391,7 +337,7 @@ void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer,
 
                      IntCurveSurface_TransitionOnCurve tran = Intersector3d.Transition(i);
                      if (tran == IntCurveSurface_Tangent) {
-#ifdef DEB
+#ifdef OCCT_DEBUG
                        cout<<"*Problem ds BRepClass3d_SClassifier.cxx"<<endl;
 #endif
                        continue; // ignore this point
@@ -442,7 +388,7 @@ void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer,
     }
     //  Modified by skv - Thu Sep  4 11:42:03 2003 OCC578 End
 
-#ifdef DEB
+#ifdef OCCT_DEBUG
     //#################################################
     SolidExplorer.DumpSegment(P,L,parmin,State());
     //#################################################
@@ -516,10 +462,10 @@ Standard_Real GetAddToParam(const gp_Lin&       L,
 //function : FaceNormal
 //purpose  : 
 //=======================================================================
-void FaceNormal (const TopoDS_Face& aF,
-                const Standard_Real U,
-                const Standard_Real V,
-                gp_Dir& aDN)
+Standard_Boolean FaceNormal (const TopoDS_Face& aF,
+                             const Standard_Real U,
+                             const Standard_Real V,
+                             gp_Dir& aDN)
 {
   gp_Pnt aPnt ;
   gp_Vec aD1U, aD1V, aN;
@@ -528,10 +474,13 @@ void FaceNormal (const TopoDS_Face& aF,
   aS=BRep_Tool::Surface(aF);
   aS->D1 (U, V, aPnt, aD1U, aD1V);
   aN=aD1U.Crossed(aD1V);
+  if (aN.Magnitude() <= gp::Resolution())
+    return Standard_False;
+  
   aN.Normalize();  
   aDN.SetXYZ(aN.XYZ());
   if (aF.Orientation() == TopAbs_REVERSED){
     aDN.Reverse();
   }
-  return;
+  return Standard_True;
 }