0031499: Boolean Operations - Custom fuzzy value corrupts the result of CUT
[occt.git] / src / IntPatch / IntPatch_ImpImpIntersection_4.gxx
index cbd5928..8fe2d21 100644 (file)
@@ -29,12 +29,10 @@ static void ShortCosForm( const Standard_Real theCosFactor,
                           Standard_Real& theCoeff,
                           Standard_Real& theAngle);
 //
-static 
-  Standard_Boolean ExploreCurve(const gp_Cylinder& aCy,
-                               const gp_Cone& aCo,
-                               IntAna_Curve& aC,
-                               const Standard_Real aTol,
-                               IntAna_ListOfCurve& aLC);
+static Standard_Boolean ExploreCurve(const gp_Cone& theCo,
+                                     IntAna_Curve& aC,
+                                     const Standard_Real aTol,
+                                     IntAna_ListOfCurve& aLC);
 
 static Standard_Boolean InscribePoint(const Standard_Real theUfTarget,
                                       const Standard_Real theUlTarget,
@@ -511,13 +509,6 @@ private:
   const Standard_Boolean myIsReverse;
 };
 
-static 
-  Standard_Boolean ExploreCurve(const gp_Cylinder& aCy,
-                               const gp_Cone& aCo,
-                               IntAna_Curve& aC,
-                               const Standard_Real aTol,
-                               IntAna_ListOfCurve& aLC);
-
 static void SeekAdditionalPoints( const IntSurf_Quadric& theQuad1,
                                   const IntSurf_Quadric& theQuad2,
                                   const Handle(IntSurf_LineOn2S)& theLine,
@@ -840,6 +831,7 @@ void ProcessBounds(const Handle(IntPatch_ALine)& alig,          //-- ligne coura
        if (!procf) {
          d=ptf.Distance(ptsol.Value());
          if (d <= Tol) {
+            ptsol.SetTolerance(Tol);
            if (!ptsol.IsMultiple()) {
              //-- le point ptsol (de aligold) est declare multiple sur aligold
              Multpoint = Standard_True;
@@ -858,6 +850,7 @@ void ProcessBounds(const Handle(IntPatch_ALine)& alig,          //-- ligne coura
        }
        if (!procl) {
          if (ptl.Distance(ptsol.Value()) <= Tol) {
+            ptsol.SetTolerance(Tol);
            if (!ptsol.IsMultiple()) {
              Multpoint = Standard_True;
              ptsol.SetMultiple(Standard_True);
@@ -888,6 +881,8 @@ void ProcessBounds(const Handle(IntPatch_ALine)& alig,          //-- ligne coura
       }
     }
   }
+  
+  ptsol.SetTolerance(Tol);
   if (!procf && !procl) {
     Quad1.Parameters(ptf,U1,V1);
     Quad2.Parameters(ptf,U2,V2);
@@ -2815,6 +2810,7 @@ static IntPatch_ImpImpIntersection::IntStatus
       {
         aL2S[i] = new IntSurf_LineOn2S();
         aWLine[i] = new IntPatch_WLine(aL2S[i], Standard_False);
+        aWLine[i]->SetCreatingWayInfo(IntPatch_WLine::IntPatch_WLImpImp);
         aWLFindStatus[i] = WLFStatus_Absent;
         isAddingWLEnabled[i] = Standard_True;
         aU2[i] = aV1[i] = aV2[i] = 0.0;
@@ -3367,7 +3363,13 @@ static IntPatch_ImpImpIntersection::IntStatus
           aP.SetTolerance(aTol3D);
           aP.SetValue(aWLine[i]->Point(1).Value());
 
-          theSPnt.Append(aP);
+          //Check whether the added point exists.
+          //It is enough to check the last point.
+          if (theSPnt.IsEmpty() ||
+              !theSPnt.Last().PntOn2S().IsSame(aP.PntOn2S(), Precision::Confusion()))
+          {
+            theSPnt.Append(aP);
+          }
         }
         else if (aWLine[i]->NbPnts() > 1)
         {
@@ -3381,6 +3383,90 @@ static IntPatch_ImpImpIntersection::IntStatus
             if (aPf.IsSame(aPl, Precision::Confusion()))
               isGood = Standard_False;
           }
+          else if (aWLine[i]->NbPnts() > 2)
+          {
+            // Sometimes points of the WLine are distributed
+            // linearly and uniformly. However, such position
+            // of the points does not always describe the real intersection
+            // curve. I.e. real tangents at the ends of the intersection
+            // curve can significantly deviate from this "line" direction.
+            // Here we are processing this case by inserting additional points
+            // to the beginning/end of the WLine to make it more precise.
+            // See description to the issue #30082.
+
+            const Standard_Real aSqTol3D = aTol3D*aTol3D;
+            for (Standard_Integer j = 0; j < 2; j++)
+            {
+              // If j == 0 ==> add point at begin of WLine.
+              // If j == 1 ==> add point at end of WLine.
+
+              for (;;)
+              {
+                if (aWLine[i]->NbPnts() >= aNbMaxPoints)
+                {
+                  break;
+                }
+
+                // Take 1st and 2nd point to compute the "line" direction.
+                // For our convenience, we make 2nd point be the ends of the WLine
+                // because it will be used for computation of the normals 
+                // to the surfaces.
+                const Standard_Integer anIdx1 = j ? aWLine[i]->NbPnts() - 1 : 2;
+                const Standard_Integer anIdx2 = j ? aWLine[i]->NbPnts() : 1;
+
+                const gp_Pnt &aP1 = aWLine[i]->Point(anIdx1).Value();
+                const gp_Pnt &aP2 = aWLine[i]->Point(anIdx2).Value();
+
+                const gp_Vec aDir(aP1, aP2);
+
+                if (aDir.SquareMagnitude() < aSqTol3D)
+                {
+                  break;
+                }
+
+                // Compute tangent in first/last point of the WLine.
+                // We do not take into account the flag "isReversed"
+                // because strict direction of the tangent is not
+                // important here (we are interested in the tangent
+                // line itself and nothing to fear if its direction
+                // is reversed).
+                const gp_Vec aN1 = aQuad1.Normale(aP2);
+                const gp_Vec aN2 = aQuad2.Normale(aP2);
+                const gp_Vec aTg(aN1.Crossed(aN2));
+
+                if (aTg.SquareMagnitude() < Precision::SquareConfusion())
+                {
+                  // Tangent zone
+                  break;
+                }
+
+                // Check of the bending
+                Standard_Real anAngle = aDir.Angle(aTg);
+
+                if (anAngle > M_PI_2)
+                  anAngle -= M_PI;
+
+                if (Abs(anAngle) > 0.25) // ~ 14deg.
+                {
+                  const Standard_Integer aNbPntsPrev = aWLine[i]->NbPnts();
+                  SeekAdditionalPoints(aQuad1, aQuad2, aWLine[i]->Curve(),
+                                       anEquationCoeffs, i, 3, anIdx1, anIdx2,
+                                       aTol2D, aPeriod, isReversed);
+
+                  if (aWLine[i]->NbPnts() == aNbPntsPrev)
+                  {
+                    // No points have been added. ==> Exit from a loop.
+                    break;
+                  }
+                }
+                else
+                {
+                  // Good result has been achieved. ==> Exit from a loop.
+                  break;
+                }
+              } // for (;;)
+            }
+          }
 
           if (isGood)
           {
@@ -3388,8 +3474,8 @@ static IntPatch_ImpImpIntersection::IntStatus
             isAddedIntoWL[i] = Standard_True;
             SeekAdditionalPoints(aQuad1, aQuad2, aWLine[i]->Curve(),
                                  anEquationCoeffs, i, aNbPoints, 1,
-              aWLine[i]->NbPnts(), aTol2D, aPeriod,
-              isReversed);
+                                 aWLine[i]->NbPnts(), aTol2D, aPeriod,
+                                 isReversed);
 
             aWLine[i]->ComputeVertexParameters(aTol3D);
             theSlin.Append(aWLine[i]);
@@ -3421,8 +3507,8 @@ static IntPatch_ImpImpIntersection::IntStatus
       const IntSurf_PntOn2S& aPntLWL1 = aWLine1->Point(aWLine1->NbPnts());
 
       const IntSurf_PntOn2S aPntCur = theSPnt.Value(aNbPnt).PntOn2S();
-      if (aPntCur.IsSame(aPntFWL1, Precision::Confusion()) ||
-        aPntCur.IsSame(aPntLWL1, Precision::Confusion()))
+      if (aPntCur.IsSame(aPntFWL1, aTol3D) ||
+        aPntCur.IsSame(aPntLWL1, aTol3D))
       {
         theSPnt.Remove(aNbPnt);
         aNbPnt--;
@@ -3452,6 +3538,7 @@ static IntPatch_ImpImpIntersection::IntStatus
 
     Handle(IntSurf_LineOn2S) aL2S = new IntSurf_LineOn2S();
     Handle(IntPatch_WLine) aWLine = new IntPatch_WLine(aL2S, Standard_False);
+    aWLine->SetCreatingWayInfo(IntPatch_WLine::IntPatch_WLImpImp);
 
     //Define the index of WLine, which lies the point aPnt2S in.
     Standard_Integer anIndex = 0;
@@ -3501,7 +3588,7 @@ static IntPatch_ImpImpIntersection::IntStatus
     // another point in the interval [anUC, anUsup] if anUC is intersection point and
     // in the interval [anUmid, anUC], otherwise.
 
-    Standard_Real anAddedPar[2] = { anUmid, anUmid };
+    Standard_Real anAddedPar[2] = {isReversed ? u2 : u1, isReversed ? u2 : u1};
 
     for (Standard_Integer aParID = 0; aParID < 2; aParID++)
     {
@@ -4136,7 +4223,7 @@ Standard_Boolean IntCyCo(const IntSurf_Quadric& Quad1,
        //curvsol = anaint.Curve(i);
        aC=anaint.Curve(i);
        aLC.Clear();
-       ExploreCurve(Cy, Co, aC, 10.*Tol, aLC);
+       ExploreCurve(Co, aC, 10.*Tol, aLC);
        //
        aIt.Initialize(aLC);
        for (; aIt.More(); aIt.Next()) {
@@ -4209,61 +4296,69 @@ Standard_Boolean IntCyCo(const IntSurf_Quadric& Quad1,
 }
 //=======================================================================
 //function : ExploreCurve
-//purpose  : 
+//purpose  : Splits aC on several curves in the cone apex points.
 //=======================================================================
-Standard_Boolean ExploreCurve(const gp_Cylinder& ,//aCy,
-                             const gp_Cone& aCo,
-                             IntAna_Curve& aC,
-                             const Standard_Real aTol,
-                             IntAna_ListOfCurve& aLC)
-                             
+Standard_Boolean ExploreCurve(const gp_Cone& theCo,
+                              IntAna_Curve& theCrv,
+                              const Standard_Real theTol,
+                              IntAna_ListOfCurve& theLC)
 {
-  Standard_Boolean bFind=Standard_False;
-  Standard_Real aTheta, aT1, aT2, aDst;
-  gp_Pnt aPapx, aPx;
-  //
-  //aC.Dump();
-  //
-  aLC.Clear();
-  aLC.Append(aC);
-  //
-  aPapx=aCo.Apex();
-  //
-  aC.Domain(aT1, aT2);
+  const Standard_Real aSqTol = theTol*theTol;
+  const gp_Pnt aPapx(theCo.Apex());
+
+  Standard_Real aT1, aT2;
+  theCrv.Domain(aT1, aT2);
+
+  theLC.Clear();
   //
-  aPx=aC.Value(aT1);
-  aDst=aPx.Distance(aPapx);
-  if (aDst<aTol) {
-    return bFind;
+  TColStd_ListOfReal aLParams;
+  theCrv.FindParameter(aPapx, aLParams);
+  if (aLParams.IsEmpty())
+  {
+    theLC.Append(theCrv);
+    return Standard_False;
   }
-  aPx=aC.Value(aT2);
-  aDst=aPx.Distance(aPapx);
-  if (aDst<aTol) {
-    return bFind;
+
+  for (TColStd_ListIteratorOfListOfReal anItr(aLParams); anItr.More(); anItr.Next())
+  {
+    Standard_Real aPrm = anItr.Value();
+
+    if ((aPrm - aT1) < Precision::PConfusion())
+      continue;
+
+    Standard_Boolean isLast = Standard_False;
+    if ((aT2 - aPrm) < Precision::PConfusion())
+    {
+      aPrm = aT2;
+      isLast = Standard_True;
+    }
+
+    const gp_Pnt aP = theCrv.Value(aPrm);
+    const Standard_Real aSqD = aP.SquareDistance(aPapx);
+    if (aSqD < aSqTol)
+    {
+      IntAna_Curve aC1 = theCrv;
+      aC1.SetDomain(aT1, aPrm);
+      aT1 = aPrm;
+      theLC.Append(aC1);
+    }
+
+    if (isLast)
+      break;
   }
-  //
-  bFind=aC.FindParameter(aPapx, aTheta);
-  if (!bFind){
-    return bFind;
+
+  if (theLC.IsEmpty())
+  {
+    theLC.Append(theCrv);
+    return Standard_False;
   }
-  //
-  aPx=aC.Value(aTheta);
-  aDst=aPx.Distance(aPapx);
-  if (aDst>aTol) {
-    return !bFind;
+
+  if ((aT2 - aT1) > Precision::PConfusion())
+  {
+    IntAna_Curve aC1 = theCrv;
+    aC1.SetDomain(aT1, aT2);
+    theLC.Append(aC1);
   }
-  //
-  // need to be splitted at aTheta
-  IntAna_Curve aC1, aC2;
-  //
-  aC1=aC;
-  aC1.SetDomain(aT1, aTheta);
-  aC2=aC;
-  aC2.SetDomain(aTheta, aT2);
-  //
-  aLC.Clear();
-  aLC.Append(aC1);
-  aLC.Append(aC2);
-  //
-  return bFind;
+
+  return Standard_True;
 }