0027190: IntPatch_ImpPrmIntersection algorithm does not split intersection curve...
authornbv <nbv@opencascade.com>
Wed, 24 Feb 2016 09:59:36 +0000 (12:59 +0300)
committerabv <abv@opencascade.com>
Fri, 18 Mar 2016 04:11:00 +0000 (07:11 +0300)
1. Processing when IntPatch_WLine/IntPatch_RLine goes through the seam edge has been improved in DecomposeResult(...) function (see IntPatch_ImpPrmIntersection.cxx).
2. Incorrect initialization of last point of IntPatch_WLine/IntPatch_RLine has been eliminated. Earlier it was the reason of exception.

Creation of test case for this issue.

Adjusting some test cases according to their new behavior. Namely:

1) tests\bugs\modalg_4\bug825 (bug825_2)
Details are described in issue #25915. In short, new intersection algorithm works better than old (WLine without "jumping"). However, Boolean operation loses degenerated edges of the sphere. Consequently, we get the result with Not-closed face.

2) tests\bugs\modalg_6\bug26684_2
TolReached of intersection curve has become smaller. Consequently, intersection algorithm works better than earlier.

src/IntPatch/IntPatch_ImpPrmIntersection.cxx
src/IntTools/IntTools_FaceFace.cxx
tests/bugs/modalg_4/bug825
tests/bugs/modalg_4/bug825_2
tests/bugs/modalg_6/bug26684_2
tests/bugs/modalg_6/bug27190 [new file with mode: 0644]

index 564725c..71377ab 100644 (file)
@@ -69,6 +69,7 @@
 #include <IntPatch_PointLine.hxx>
 
 #include <Extrema_GenLocateExtPS.hxx>
+#include <math_FunctionSetRoot.hxx>
 
 static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLine,
                                         const Standard_Boolean       IsReversed,
@@ -77,6 +78,7 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
                                         const Handle(Adaptor3d_HSurface)&  theQSurf,
                                         const Handle(Adaptor3d_HSurface)&  theOtherSurf,
                                         const Standard_Real                theArcTol,
+                                        const Standard_Real                theTolTang,
                                         IntPatch_SequenceOfLine&           theLines);
 static 
   void ComputeTangency (const IntPatch_TheSOnBounds& solrst,
@@ -106,6 +108,190 @@ static
                               const Standard_Real theToler2D,
                               const Standard_Real thePeriod);
 
+enum PrePoint_Type
+{
+  PrePoint_NONE,
+  PrePoint_SEAMU,
+  PrePoint_SEAMV,
+  PrePoint_SEAMUV,
+  PrePoint_POLESEAMU,
+  PrePoint_POLE
+};
+
+static PrePoint_Type IsSeamOrPole(const Handle(Adaptor3d_HSurface)& theQSurf,
+                                  const Handle(IntSurf_LineOn2S)& theLine,
+                                  const Standard_Boolean IsReversed,
+                                  const Standard_Integer theRefIndex,
+                                  const Standard_Real theDeltaMax)
+{
+  if((theRefIndex < 1) || (theRefIndex >= theLine->NbPoints()))
+    return PrePoint_NONE;
+
+  //Parameters on Quadric and on parametric for reference point
+  Standard_Real aUQRef, aVQRef, aUPRef, aVPRef;
+  Standard_Real aUQNext, aVQNext, aUPNext, aVPNext;
+
+  if(IsReversed)
+  {
+    theLine->Value(theRefIndex).Parameters  (aUPRef, aVPRef, aUQRef, aVQRef);
+    theLine->Value(theRefIndex+1).Parameters(aUPNext, aVPNext, aUQNext, aVQNext);
+  }
+  else
+  {
+    theLine->Value(theRefIndex).Parameters  (aUQRef, aVQRef, aUPRef, aVPRef);
+    theLine->Value(theRefIndex+1).Parameters(aUQNext, aVQNext, aUPNext, aVPNext);
+  }
+
+  const GeomAbs_SurfaceType aType = theQSurf->GetType();
+
+  const Standard_Real aDeltaU = Abs(aUQRef - aUQNext);
+
+  if((aType != GeomAbs_Torus) && (aDeltaU < theDeltaMax))
+    return PrePoint_NONE;
+
+  switch(aType)
+  {
+  case GeomAbs_Cylinder:
+    return PrePoint_SEAMU;
+
+  case GeomAbs_Torus:
+    {
+      const Standard_Real aDeltaV = Abs(aVQRef - aVQNext);
+
+      if((aDeltaU >= theDeltaMax) && (aDeltaV >= theDeltaMax))
+        return PrePoint_SEAMUV;
+
+      if(aDeltaU >= theDeltaMax)
+        return PrePoint_SEAMU;
+
+      if(aDeltaV >= theDeltaMax)
+        return PrePoint_SEAMV;
+    }
+
+    break;
+  case GeomAbs_Sphere:
+  case GeomAbs_Cone:
+    return PrePoint_POLESEAMU;
+  default:
+    break;
+  }
+
+  return PrePoint_NONE;
+}
+
+// The function for searching intersection point, which 
+// lies in the seam-edge of the quadric definetely.
+class FuncPreciseSeam: public math_FunctionSetWithDerivatives
+{
+public:
+  FuncPreciseSeam(const Handle(Adaptor3d_HSurface)& theQSurf, const Handle(Adaptor3d_HSurface)& thePSurf, const Standard_Boolean isTheUSeam): myQSurf(theQSurf), myPSurf(thePSurf), myIsUSeam(isTheUSeam) {};
+  
+  Standard_EXPORT virtual Standard_Integer NbVariables() const
+  {
+    return 3;
+  };
+
+  Standard_EXPORT virtual Standard_Integer NbEquations() const
+  {
+    return 3;
+  }
+
+  Standard_EXPORT virtual Standard_Boolean Value (const math_Vector& theX, math_Vector& theF)
+  {
+    try
+    {
+      const Standard_Integer anIndX = theX.Lower(), anIndF = theF.Lower();
+      const gp_Pnt aP1(myPSurf->Value(theX(anIndX), theX(anIndX+1)));
+      const gp_Pnt aP2(myIsUSeam? myQSurf->Value(0.0, theX(anIndX+2)) : myQSurf->Value(theX(anIndX+2), 0.0));
+
+      (aP1.XYZ()-aP2.XYZ()).Coord(theF(anIndF), theF(anIndF+1), theF(anIndF+2));
+    }
+    catch(Standard_Failure)
+    {
+      return Standard_False;
+    }
+
+    return Standard_True;
+  };
+
+  Standard_EXPORT virtual Standard_Boolean Derivatives (const math_Vector& theX, math_Matrix& theD)
+  {
+    try
+    {
+      const Standard_Integer anIndX = theX.Lower(), anIndRD = theD.LowerRow(), anIndCD = theD.LowerCol();
+      gp_Pnt aPt;
+      gp_Vec aD1u, aD1v, aD2u, aD2v;
+      myPSurf->D1(theX(anIndX), theX(anIndX+1), aPt, aD1u, aD1v);
+      if(myIsUSeam)
+        myQSurf->D1(0.0, theX(anIndX+2), aPt, aD2u, aD2v);
+      else
+        myQSurf->D1(theX(anIndX+2), 0.0, aPt, aD2u, aD2v);
+
+      // d/dX1
+      aD1u.Coord(theD(anIndRD, anIndCD), theD(anIndRD+1, anIndCD), theD(anIndRD+2, anIndCD));
+
+      // d/dX1
+      aD1v.Coord(theD(anIndRD, anIndCD+1), theD(anIndRD+1, anIndCD+1), theD(anIndRD+2, anIndCD+1));
+
+      // d/dX3
+      if(myIsUSeam)
+        aD2v.Reversed().Coord(theD(anIndRD, anIndCD+2), theD(anIndRD+1, anIndCD+2), theD(anIndRD+2, anIndCD+2));
+      else
+        aD2u.Reversed().Coord(theD(anIndRD, anIndCD+2), theD(anIndRD+1, anIndCD+2), theD(anIndRD+2, anIndCD+2));
+    }
+    catch(Standard_Failure)
+    {
+      return Standard_False;
+    }
+
+    return Standard_True;
+  };
+
+  Standard_EXPORT virtual Standard_Boolean Values (const math_Vector& theX, math_Vector& theF, math_Matrix& theD)
+  {
+    try
+    {
+      const Standard_Integer anIndX = theX.Lower(), anIndF = theF.Lower(), anIndRD = theD.LowerRow(), anIndCD = theD.LowerCol();
+      gp_Pnt aP1, aP2;
+      gp_Vec aD1u, aD1v, aD2u, aD2v;
+      myPSurf->D1(theX(anIndX), theX(anIndX+1), aP1, aD1u, aD1v);
+      if(myIsUSeam)
+        myQSurf->D1(0.0, theX(anIndX+2), aP2, aD2u, aD2v);
+      else
+        myQSurf->D1(theX(anIndX+2), 0.0, aP2, aD2u, aD2v);
+
+      //Value
+      (aP1.XYZ()-aP2.XYZ()).Coord(theF(anIndF), theF(anIndF+1), theF(anIndF+2));
+
+      // d/dX1
+      aD1u.Coord(theD(anIndRD, anIndCD), theD(anIndRD+1, anIndCD), theD(anIndRD+2, anIndCD));
+
+      // d/dX1
+      aD1v.Coord(theD(anIndRD, anIndCD+1), theD(anIndRD+1, anIndCD+1), theD(anIndRD+2, anIndCD+1));
+
+      // d/dX3
+      if(myIsUSeam)
+        aD2v.Reversed().Coord(theD(anIndRD, anIndCD+2), theD(anIndRD+1, anIndCD+2), theD(anIndRD+2, anIndCD+2));
+      else
+        aD2u.Reversed().Coord(theD(anIndRD, anIndCD+2), theD(anIndRD+1, anIndCD+2), theD(anIndRD+2, anIndCD+2));
+    }
+    catch(Standard_Failure)
+    {
+      return Standard_False;
+    }
+
+    return Standard_True;
+  }
+
+protected:
+  FuncPreciseSeam operator=(FuncPreciseSeam&);
+
+private:
+  const Handle(Adaptor3d_HSurface)& myQSurf;
+  const Handle(Adaptor3d_HSurface)& myPSurf;
+  const Standard_Boolean myIsUSeam;
+};
+
 //=======================================================================
 //function : IntPatch_ImpPrmIntersection
 //purpose  : 
@@ -1501,7 +1687,9 @@ void IntPatch_ImpPrmIntersection::Perform (const Handle(Adaptor3d_HSurface)& Sur
     return;
 
   Standard_Boolean isDecomposeRequired =  (Quad.TypeQuadric() == GeomAbs_Cone) || 
-                                          (Quad.TypeQuadric() == GeomAbs_Sphere);
+                                          (Quad.TypeQuadric() == GeomAbs_Sphere) ||
+                                          (Quad.TypeQuadric() == GeomAbs_Cylinder) ||
+                                          (Quad.TypeQuadric() == GeomAbs_Torus);
 
   if(!isDecomposeRequired)
     return;
@@ -1516,7 +1704,7 @@ void IntPatch_ImpPrmIntersection::Perform (const Handle(Adaptor3d_HSurface)& Sur
   {
     if(DecomposeResult( Handle(IntPatch_PointLine)::DownCast(slin(i)),
                                         reversed, Quad, PDomain, aQSurf,
-                                        anOtherSurf, TolArc, dslin))
+                                        anOtherSurf, TolArc, aTol3d, dslin))
     {
       isDecompose = Standard_True;
     }
@@ -2318,7 +2506,7 @@ static Handle(IntPatch_WLine) MakeSplitWLine (Handle(IntPatch_WLine)&        WLi
   TPntL.SetParameters(uu1,vv1,uu2,vv2);
   TPntL.SetParameter((Standard_Real)sline->NbPoints());
   wline->AddVertex(TPntL);
-  wline->SetLastPoint(sline->NbPoints());
+  wline->SetLastPoint(wline->NbVertex());
 
   return wline;
 }
@@ -2369,6 +2557,7 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
                                         const Handle(Adaptor3d_HSurface)&  theQSurf, //quadric
                                         const Handle(Adaptor3d_HSurface)&  thePSurf, //parametric
                                         const Standard_Real                theArcTol,
+                                        const Standard_Real                theTolTang,
                                         IntPatch_SequenceOfLine&           theLines)
 {
   if(theLine->ArcType() == IntPatch_Restriction)
@@ -2430,12 +2619,7 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
   // build WLine parts (if any)
   Standard_Boolean flNextLine = Standard_True;
   Standard_Boolean hasBeenDecomposed = Standard_False;
-  enum PrePoint_Type
-  {
-    PrePoint_NONE,
-    PrePoint_SEAM,
-    PrePoint_POLE
-  }PrePointExist = PrePoint_NONE;
+  PrePoint_Type aPrePointExist = PrePoint_NONE;
 
   IntSurf_PntOn2S PrePoint;
   while(flNextLine)
@@ -2443,22 +2627,18 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
     // reset variables
     flNextLine = Standard_False;
     Standard_Boolean isDecomposited = Standard_False;
-    Standard_Real U1 = 0., U2 = 0., V1 = 0., V2 = 0., AnU1 = 0.;
+    Standard_Real U1 = 0., U2 = 0., V1 = 0., V2 = 0.;
 
     Handle(IntSurf_LineOn2S) sline = new IntSurf_LineOn2S();
 
     //if((Lindex-Findex+1) <= 2 )
-    if((aLindex <= aFindex) && (PrePointExist != PrePoint_POLE))
+    if((aLindex <= aFindex) && !aPrePointExist)
     {
       //break of "while(flNextLine)" cycle
       break;
     }
 
-    if (PrePointExist == PrePoint_SEAM)
-    {
-      sline->Add(PrePoint);
-    }
-    else if(PrePointExist == PrePoint_POLE)
+    if(aPrePointExist)
     {
       //The last point of the line is the pole of the quadric.
       //Therefore, Walking-line has been broken in this point.
@@ -2483,12 +2663,19 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
       //Consequently, when the line goes throug the pole, @U_{q}@ can be
       //changed on @\pi /2 @ (but not less).
 
+      //Here, we forbid "jumping" between two neighbor Walking-point
+      //with step greater than pi/4
       const Standard_Real aPeriod = M_PI_2, aHalfPeriod = M_PI_4;
       const IntSurf_PntOn2S& aRefPt = aSSLine->Value(aFindex);
 
-      IntSurf_PntOn2S aFirstPoint = PrePoint;
+      const Standard_Real aURes = theQSurf->UResolution(theArcTol),
+                          aVRes = theQSurf->UResolution(theArcTol);
+
+      const Standard_Real aTol2d = (aPrePointExist == PrePoint_POLE) ? 0.0 : 
+              (aPrePointExist == PrePoint_SEAMV)? aVRes :
+              (aPrePointExist == PrePoint_SEAMUV)? Max(aURes, aVRes) : aURes;
 
-      if(!aFirstPoint.IsSame(aRefPt, Precision::Confusion()))
+      if(!PrePoint.IsSame(aRefPt, Precision::Confusion(), aTol2d))
       {
         Standard_Real aURef = 0.0, aVRef = 0.0;
         Standard_Real aUquad = 0.0, aVquad = 0.0;
@@ -2496,15 +2683,16 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
         //Take parameters on quadric
         if(IsReversed)
         {
-          aFirstPoint.ParametersOnS2(aUquad, aVquad);
+          PrePoint.ParametersOnS2(aUquad, aVquad);
           aRefPt.ParametersOnS2(aURef, aVRef);
         }
         else
         {
-          aFirstPoint.ParametersOnS1(aUquad, aVquad);
+          PrePoint.ParametersOnS1(aUquad, aVquad);
           aRefPt.ParametersOnS1(aURef, aVRef);
         }
 
+        if(theQSurf->IsUPeriodic())
         {
           Standard_Real aDeltaPar = aURef-aUquad;
           const Standard_Real anIncr = Sign(aPeriod, aDeltaPar);
@@ -2515,8 +2703,19 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
           }
         }
 
-        aFirstPoint.SetValue(!IsReversed, aUquad, aVquad);
-        sline->Add(aFirstPoint);
+        if(theQSurf->IsVPeriodic())
+        {
+          Standard_Real aDeltaPar = aVRef-aVquad;
+          const Standard_Real anIncr = Sign(aPeriod, aDeltaPar);
+          while((aDeltaPar > aHalfPeriod) || (aDeltaPar < -aHalfPeriod))
+          {
+            aVquad += anIncr;
+            aDeltaPar = aVRef-aVquad;
+          }
+        }
+
+        PrePoint.SetValue(!IsReversed, aUquad, aVquad);
+        sline->Add(PrePoint);
       }
       else
       {
@@ -2525,24 +2724,15 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
       }
     }
 
-    PrePointExist = PrePoint_NONE;
+    aPrePointExist = PrePoint_NONE;
 
     // analyze other points
     for(Standard_Integer k = aFindex; k <= aLindex; k++)
     {
       if( k == aFindex )
       {
-        if(IsReversed)
-        {
-          aSSLine->Value(k).ParametersOnS2(AnU1,V1);   // S2 - quadric, set U,V by Pnt3D
-        }
-        else
-        {
-          aSSLine->Value(k).ParametersOnS1(AnU1,V1);    // S1 - quadric, set U,V by Pnt3D
-        }
-
-        sline->Add(aSSLine->Value(k));
         PrePoint = aSSLine->Value(k);
+        sline->Add(PrePoint);
         continue;
       }
 
@@ -2555,77 +2745,172 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
         aSSLine->Value(k).ParametersOnS1(U1,V1);    // S1 - quadric, set U,V by Pnt3D
       }
 
-      if(Abs(U1-AnU1) > aDeltaUmax)
+      aPrePointExist = IsSeamOrPole(theQSurf, aSSLine, IsReversed, k-1, aDeltaUmax);
+
+      if(aPrePointExist != PrePoint_NONE)
       {
         aBindex = k;
         isDecomposited = Standard_True;
         ////
-        if (Abs(U1) <= Precision::PConfusion() ||
-            Abs(U1 - 2*M_PI) <= Precision::PConfusion())
+        const Standard_Real aPeriod = M_PI+M_PI, aHalfPeriod = M_PI;
+        const IntSurf_PntOn2S& aRefPt = aSSLine->Value(aBindex-1);
+
+        //Not quadric point
+        Standard_Real aU0 = 0.0, aV0 = 0.0;
+        //Quadric point
+        Standard_Real aUQuadRef = 0.0, aVQuadRef = 0.0;
+
+        if(IsReversed)
+        {
+          aRefPt.Parameters(aU0, aV0, aUQuadRef, aVQuadRef);
+        }
+        else
         {
-          IntSurf_PntOn2S NewPoint;
-          IntSurf_PntOn2S CurPoint = aSSLine->Value(k);
-          gp_Pnt thePnt = CurPoint.Value();
-          Standard_Real theU1, theV1, theU2, theV2;
-          theU1 = (Abs(U1) <= Precision::PConfusion())? 2*M_PI : 0.;
-          theV1 = V1;
-          NewPoint.SetValue(thePnt);
-          if (!IsReversed)
+          aRefPt.Parameters(aUQuadRef, aVQuadRef, aU0, aV0);
+        }
+
+        if(aPrePointExist == PrePoint_SEAMUV)
+        {
+          aPrePointExist = PrePoint_NONE;
+
+          gp_Pnt aPQuad;
+          Standard_Real aUquad = 0.0;
+          Standard_Real aVquad = 0.0; 
+
+          theQSurf->D0(aUquad, aVquad, aPQuad);
+
+          Extrema_GenLocateExtPS anExtr(aPQuad, thePSurf->Surface(), aU0, aV0,
+                                        Precision::PConfusion(),
+                                        Precision::PConfusion());
+
+          if(!anExtr.IsDone())
           {
-            CurPoint.ParametersOnS2(theU2, theV2);
-            NewPoint.SetValue(theU1, theV1, theU2, theV2);
+            break;
           }
-          else
+
+          if(anExtr.SquareDistance() < theTolTang*theTolTang)
           {
-            CurPoint.ParametersOnS1(theU2, theV2);
-            NewPoint.SetValue(theU2, theV2, theU1, theV1);
+            anExtr.Point().Parameter(aU0, aV0);
+            gp_Pnt aP0(anExtr.Point().Value());
+
+            IntSurf_PntOn2S aNewPoint;
+            aNewPoint.SetValue(0.5*(aP0.XYZ() + aPQuad.XYZ()), IsReversed, aU0, aV0);
+
+            if(!aNewPoint.IsSame(aRefPt, Precision::Confusion()))
+            {
+              //Adjust found U-paramter to previous point of the Walking-line
+              Standard_Real aDeltaPar = aUQuadRef-aUquad;
+              const Standard_Real anIncrU = Sign(aPeriod, aDeltaPar);
+              while((aDeltaPar > aHalfPeriod) || (aDeltaPar < -aHalfPeriod))
+              {
+                aUquad += anIncrU;
+                aDeltaPar = aUQuadRef-aUquad;
+              }
+
+              //Adjust found V-paramter to previous point of the Walking-line
+              aDeltaPar = aVQuadRef-aVquad;
+              const Standard_Real anIncrV = Sign(aPeriod, aDeltaPar);
+              while((aDeltaPar > aHalfPeriod) || (aDeltaPar < -aHalfPeriod))
+              {
+                aVquad += anIncrV;
+                aDeltaPar = aVQuadRef-aVquad;
+              }
+
+              aNewPoint.SetValue(!IsReversed, aUquad, aVquad);
+              
+              sline->Add(aNewPoint);
+              aPrePointExist = PrePoint_SEAMUV;
+              PrePoint = aNewPoint;
+            }
           }
-          sline->Add(NewPoint);
         }
-        else if (Abs(AnU1) <= Precision::PConfusion() ||
-                 Abs(AnU1 - 2*M_PI) <= Precision::PConfusion())
-        {
-          //Modify <PrePoint>
-          PrePointExist = PrePoint_SEAM;
-          Standard_Real theU1, theV1;
-          if (!IsReversed)
+        else if(aPrePointExist == PrePoint_SEAMV)
+        {//WLine goes through seam
+          aPrePointExist = PrePoint_NONE;
+
+          FuncPreciseSeam aF(theQSurf, thePSurf, Standard_False);
+          math_Vector aTol(1, 3), aStartPoint(1,3);
+          
+          //Parameters on parametric surface
+          Standard_Real aUp = 0.0, aVp = 0.0;
+          if(IsReversed)
           {
-            PrePoint.ParametersOnS1(theU1, theV1);
-            theU1 = (Abs(AnU1) <= Precision::PConfusion())? 2*M_PI : 0.;
-            PrePoint.SetValue(Standard_True, //on first
-                              theU1, theV1);
+            aSSLine->Value(k).ParametersOnS1(aUp, aVp);
           }
           else
           {
-            PrePoint.ParametersOnS2(theU1, theV1);
-            theU1 = (Abs(AnU1) <= Precision::PConfusion())? 2*M_PI : 0.;
-            PrePoint.SetValue(Standard_False, //on second
-                              theU1, theV1);
+            aSSLine->Value(k).ParametersOnS2(aUp, aVp);
           }
-        }
-        else
-        {//Check if WLine goes through pole
-          const Standard_Real aTol = Precision::Confusion();
-          const Standard_Real aPeriod = M_PI+M_PI, aHalfPeriod = M_PI;
-          const IntSurf_PntOn2S& aRefPt = aSSLine->Value(aBindex-1);
+
+          aTol(1) = thePSurf->UResolution(theArcTol);
+          aTol(2) = thePSurf->VResolution(theArcTol);
+          aTol(3) = theQSurf->UResolution(theArcTol);
+          aStartPoint(1) = 0.5*(aU0 + aUp);
+          aStartPoint(2) = 0.5*(aV0 + aVp);
+          aStartPoint(3) = 0.5*(aUQuadRef + U1);
+
+          math_FunctionSetRoot aSRF(aF, aTol);
+          aSRF.Perform(aF, aStartPoint);
+
+          if(!aSRF.IsDone())
+          {
+            break;
+          }
+
+          // Now aStartPoint is useless. Therefore, we use it for keeping
+          // new point.
+          aSRF.Root(aStartPoint);
           
-          //Not quadric point
-          Standard_Real aU0 = 0.0, aV0 = 0.0;
-          //Quadric point
-          Standard_Real aUQuadRef = 0.0, aVQuadRef = 0.0;
+          //On parametric
+          aU0 = aStartPoint(1);
+          aV0 = aStartPoint(2);
+
+          //On quadric
+          Standard_Real aUquad = aStartPoint(3);
+          Standard_Real aVquad = 0.0; 
+          const gp_Pnt aPQuad(theQSurf->Value(aUquad, aVquad));
+          const gp_Pnt aP0(thePSurf->Value(aU0, aV0));
 
-          if(IsReversed)
           {
-            aRefPt.Parameters(aU0, aV0, aUQuadRef, aVQuadRef);
+            //Adjust found U-paramter to previous point of the Walking-line
+            Standard_Real aDeltaPar = aVQuadRef-aVquad;
+            const Standard_Real anIncr = Sign(aPeriod, aDeltaPar);
+            while((aDeltaPar > aHalfPeriod) || (aDeltaPar < -aHalfPeriod))
+            {
+              aVquad += anIncr;
+              aDeltaPar = aVQuadRef-aVquad;
+            }
           }
+
+          IntSurf_PntOn2S aNewPoint;
+          if(IsReversed)
+            aNewPoint.SetValue(0.5*(aP0.XYZ() + aPQuad.XYZ()), aU0, aV0, aUquad, aVquad);
           else
+            aNewPoint.SetValue(0.5*(aP0.XYZ() + aPQuad.XYZ()), aUquad, aVquad, aU0, aV0);
+
+          if(!aNewPoint.IsSame(aRefPt, Precision::Confusion(), Precision::PConfusion()))
           {
-            aRefPt.Parameters(aUQuadRef, aVQuadRef, aU0, aV0);
+            aNewPoint.SetValue(!IsReversed, aUquad, aVquad);
+            sline->Add(aNewPoint);
+            aPrePointExist = PrePoint_SEAMV;
+            PrePoint = aNewPoint;
           }
+          else
+          {
+            if(sline->NbPoints() == 1)
+            {
+              //FIRST point of the sline is the pole of the quadric.
+              //Therefore, there is no point in decomposition.
 
-          //Transforms parametric surface in coordinate-system of the quadric
-          gp_Trsf aTr;
-          aTr.SetTransformation(theQuad.Sphere().Position());
+              PrePoint = aRefPt;
+              aPrePointExist = PrePoint_SEAMV;
+            }
+          }
+        }
+        else if(aPrePointExist == PrePoint_POLESEAMU)
+        {//Check if WLine goes through pole
+          
+          aPrePointExist = PrePoint_NONE;
 
           //aPQuad is Pole
           gp_Pnt aPQuad;
@@ -2656,9 +2941,11 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
                                         Precision::PConfusion());
 
           if(!anExtr.IsDone())
+          {
             break;
+          }
 
-          if(anExtr.SquareDistance() < aTol*aTol)
+          if(anExtr.SquareDistance() < theTolTang*theTolTang)
           { //Pole is an intersection point
             //(lies in the quadric and the parametric surface)
 
@@ -2690,6 +2977,12 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
               gp_Vec aVecDu, aVecDv;
               thePSurf->D1(aU0, aV0, aPtemp, aVecDu, aVecDv);
 
+              //Transforms parametric surface in coordinate-system of the quadric
+              gp_Trsf aTr;
+              aTr.SetTransformation((theQuad.TypeQuadric() == GeomAbs_Sphere) ?
+                                      theQuad.Sphere().Position() :
+                                      theQuad.Cone().Position());
+
               //Derivatives of transformed thePSurf
               aVecDu.Transform(aTr);
               aVecDv.Transform(aTr);
@@ -2880,22 +3173,112 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
               aNewPoint.SetValue(!IsReversed, aUquad, aVquad);
               
               sline->Add(aNewPoint);
-              PrePointExist = PrePoint_POLE;
+              aPrePointExist = PrePoint_POLE;
               PrePoint = aNewPoint;
             } // if(!aNewPoint.IsSame(aRefPt, Precision::Confusion()))
             else
             {
+              aPrePointExist = PrePoint_NONE;
+
               if(sline->NbPoints() == 1)
               {
                 //FIRST point of the sline is the pole of the quadric.
                 //Therefore, there is no point in decomposition.
 
                 PrePoint = aRefPt;
-                AnU1=U1;
-                PrePointExist = PrePoint_POLE;
+                aPrePointExist = PrePoint_POLE;
               }
             }
           } //if(anExtr.SquareDistance() < aTol*aTol)
+          else
+          {//Pole is not an intersection point
+            aPrePointExist = PrePoint_SEAMU;
+          }
+        }
+
+        if(aPrePointExist == PrePoint_SEAMU)
+        {//WLine goes through seam
+
+          aPrePointExist = PrePoint_NONE;
+
+          FuncPreciseSeam aF(theQSurf, thePSurf, Standard_True);
+          math_Vector aTol(1, 3), aStartPoint(1,3);
+          
+          //Parameters on parametric surface
+          Standard_Real aUp = 0.0, aVp = 0.0;
+          if(IsReversed)
+          {
+            aSSLine->Value(k).ParametersOnS1(aUp, aVp);
+          }
+          else
+          {
+            aSSLine->Value(k).ParametersOnS2(aUp, aVp);
+          }
+
+          aTol(1) = thePSurf->UResolution(theArcTol);
+          aTol(2) = thePSurf->VResolution(theArcTol);
+          aTol(3) = theQSurf->VResolution(theArcTol);
+          aStartPoint(1) = 0.5*(aU0 + aUp);
+          aStartPoint(2) = 0.5*(aV0 + aVp);
+          aStartPoint(3) = 0.5*(aVQuadRef + V1);
+
+          math_FunctionSetRoot aSRF(aF, aTol);
+          aSRF.Perform(aF, aStartPoint);
+
+          if(!aSRF.IsDone())
+          {
+            break;
+          }
+
+          // Now aStartPoint is useless. Therefore, we use it for keeping
+          // new point.
+          aSRF.Root(aStartPoint);
+          
+          //On parametric
+          aU0 = aStartPoint(1);
+          aV0 = aStartPoint(2);
+
+          //On quadric
+          Standard_Real aUquad = 0.0;
+          Standard_Real aVquad = aStartPoint(3); 
+          const gp_Pnt aPQuad(theQSurf->Value(aUquad, aVquad));
+          const gp_Pnt aP0(thePSurf->Value(aU0, aV0));
+
+          {
+            //Adjust found U-paramter to previous point of the Walking-line
+            Standard_Real aDeltaPar = aUQuadRef-aUquad;
+            const Standard_Real anIncr = Sign(aPeriod, aDeltaPar);
+            while((aDeltaPar > aHalfPeriod) || (aDeltaPar < -aHalfPeriod))
+            {
+              aUquad += anIncr;
+              aDeltaPar = aUQuadRef-aUquad;
+            }
+          }
+
+          IntSurf_PntOn2S aNewPoint;
+          if(IsReversed)
+            aNewPoint.SetValue(0.5*(aP0.XYZ() + aPQuad.XYZ()), aU0, aV0, aUquad, aVquad);
+          else
+            aNewPoint.SetValue(0.5*(aP0.XYZ() + aPQuad.XYZ()), aUquad, aVquad, aU0, aV0);
+
+          if(!aNewPoint.IsSame(aRefPt, Precision::Confusion(), Precision::PConfusion()))
+          {
+            aNewPoint.SetValue(!IsReversed, aUquad, aVquad);
+            sline->Add(aNewPoint);
+            aPrePointExist = PrePoint_SEAMU;
+            PrePoint = aNewPoint;
+          }
+          else
+          {
+            if(sline->NbPoints() == 1)
+            {
+              //FIRST point of the sline is the pole of the quadric.
+              //Therefore, there is no point in decomposition.
+
+              PrePoint = aRefPt;
+              aPrePointExist = PrePoint_SEAMU;
+            }
+          }
         }
 
         ////
@@ -2904,7 +3287,6 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
 
       sline->Add(aSSLine->Value(k));
       PrePoint = aSSLine->Value(k);
-      AnU1=U1;
     } //for(Standard_Integer k = aFindex; k <= aLindex; k++)
 
     //Creation of new line as part of existing theLine.
@@ -2980,7 +3362,7 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
       aTPntL.SetParameters(U1,V1,U2,V2);
       aTPntL.SetParameter(sline->NbPoints());
       wline->AddVertex(aTPntL);
-      wline->SetLastPoint(sline->NbPoints());
+      wline->SetLastPoint(wline->NbVertex());
 
       IntPatch_SequenceOfLine segm;
       Standard_Boolean isSplited = SplitOnSegments(wline,Standard_False,
@@ -3075,12 +3457,15 @@ static Standard_Boolean DecomposeResult(const Handle(IntPatch_PointLine)& theLin
         aRLine->AddVertex(aTPnt);
       }
 
-      aRLine->SetFirstPoint(1);
-      aRLine->SetLastPoint(sline->NbPoints());
+      if(aLPar - aFPar > Precision::PConfusion())
+      {
+        aRLine->SetFirstPoint(1);
+        aRLine->SetLastPoint(aRLine->NbVertex());
 
-      anArc->Trim(aFPar, aLPar, theArcTol);
+        anArc->Trim(aFPar, aLPar, theArcTol);
 
-      theLines.Append(aRLine);
+        theLines.Append(aRLine);
+      }
     }
 
     if(isDecomposited)
index a4146ae..1d1e814 100644 (file)
@@ -648,6 +648,28 @@ void IntTools_FaceFace::Perform(const TopoDS_Face& aF1,
     }
   }
 
+#ifdef INTTOOLS_FACEFACE_DEBUG
+    if(!myListOfPnts.IsEmpty()) {
+      char aBuff[10000];
+      const IntSurf_PntOn2S& aPt = myListOfPnts.First();
+      Standard_Real u1, v1, u2, v2;
+      aPt.Parameters(u1, v1, u2, v2);
+
+      Sprintf(aBuff,"bopcurves <face1 face2> -2d");
+      IntSurf_ListIteratorOfListOfPntOn2S IterLOP1(myListOfPnts);
+      for(;IterLOP1.More(); IterLOP1.Next())
+      {
+        const IntSurf_PntOn2S& aPt = IterLOP1.Value();
+        Standard_Real u1, v1, u2, v2;
+        aPt.Parameters(u1, v1, u2, v2);
+
+        Sprintf(aBuff, "%s -p %+10.20f %+10.20f %+10.20f %+10.20f", aBuff, u1, v1, u2, v2);
+      }
+
+      cout << aBuff << endl;
+    }
+#endif
+
   const Standard_Boolean isGeomInt = isTreatAnalityc(aF1, aF2);
   myIntersector.Perform(myHS1, dom1, myHS2, dom2, TolArc, TolTang, 
                                   myListOfPnts, RestrictLine, isGeomInt);
@@ -888,28 +910,6 @@ void IntTools_FaceFace::MakeCurve(const Standard_Integer Index,
     }
     L = aWLine;
 
-#ifdef INTTOOLS_FACEFACE_DEBUG
-    if(!myListOfPnts.IsEmpty()) {
-      char aBuff[10000];
-      const IntSurf_PntOn2S& aPt = myListOfPnts.First();
-      Standard_Real u1, v1, u2, v2;
-      aPt.Parameters(u1, v1, u2, v2);
-
-      Sprintf(aBuff,"bopcurves <face1 face2> -2d");
-      IntSurf_ListIteratorOfListOfPntOn2S IterLOP1(myListOfPnts);
-      for(;IterLOP1.More(); IterLOP1.Next())
-      {
-        const IntSurf_PntOn2S& aPt = IterLOP1.Value();
-        Standard_Real u1, v1, u2, v2;
-        aPt.Parameters(u1, v1, u2, v2);
-
-        Sprintf(aBuff, "%s -p %+10.20f %+10.20f %+10.20f %+10.20f", aBuff, u1, v1, u2, v2);
-      }
-
-      cout << aBuff << endl;
-    }
-#endif
-
     Standard_Integer nbp = aWLine->NbPnts();
     const IntSurf_PntOn2S& p1 = aWLine->Point(1);
     const IntSurf_PntOn2S& p2 = aWLine->Point(nbp);
index a6f14f1..4909ffe 100755 (executable)
@@ -1,5 +1,6 @@
 puts "TODO OCC25915 ALL: Faulty OCC825"
 puts "TODO OCC25915 ALL: Error : The command is not valid. The area is"
+puts "TODO OCC25915 ALL: Faulty shapes in variables faulty_1 to faulty_"
 
 pload QAcommands
 
index b3d3073..5f64c54 100755 (executable)
@@ -1,3 +1,5 @@
+puts "TODO OCC25915 ALL: Faulty shapes in variables faulty_1 to faulty_"
+
 pload QAcommands
 
 puts "========"
@@ -23,6 +25,6 @@ if { [ catch { set info_result [OCC825 a1 a2 a3 a4 a5] } ] } {
     }
 }
 
-checkprops result -s 7853.92 
+checkprops result -s 5890.48
 checkshape result
 checkview -display result -2d -path ${imagedir}/${test_image}.png
index fcf35e9..d5028b7 100644 (file)
@@ -26,6 +26,6 @@ checkreal "Reached tolerance" ${Tolerance} 1.2530391548405894e-008 1.e-7 0
 set bop_info_2d [bopcurves f1 f2 -2d]
 regexp {Tolerance Reached=([-0-9.+eE]+)} $bop_info_2d full Tolerance_2d
 
-checkreal "Reached tolerance" ${Tolerance_2d} 1.8067758590039568e-005 0 1.e-2
+checkreal "Reached tolerance" ${Tolerance_2d} 1.4134494834137484e-005 0 1.e-2
 
 checkview -screenshot -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_6/bug27190 b/tests/bugs/modalg_6/bug27190
new file mode 100644 (file)
index 0000000..cd2837c
--- /dev/null
@@ -0,0 +1,66 @@
+puts "================"
+puts "OCC27190"
+puts "================"
+puts ""
+#######################################################################
+# IntPatch_ImpPrmIntersection algorithm does not split intersection curve by the seam-edge of the quadric
+#######################################################################
+
+set MaxTol 1.e-3
+set GoodNbCurv 11
+
+restore [locate_data_file bug27167-pipe.brep] a1
+pcylinder a2 100 300
+
+explode a1 f
+explode a2 f
+
+set log [bopcurves a1_2 a2_1 -2d]
+
+regexp {Tolerance Reached=+([-0-9.+eE]+)\n+([-0-9.+eE]+)} ${log} full Toler NbCurv
+
+if {${Toler} > ${MaxTol}} {
+  puts "Error: Tolerance is too big!"
+}
+
+if {${NbCurv} != ${GoodNbCurv}} {
+  puts "Error: Curve Number is bad!"
+}
+
+set Period [dval 2*pi]
+
+for {set i 1} {$i <= ${NbCurv}} {incr i} {
+  bounds c2d2_$i u1 u2
+  
+  2dcvalue c2d2_$i u1 x1 y
+  2dcvalue c2d2_$i u2 x2 y
+  
+  set X1 [dval x1/$Period]
+  set X2 [dval x2/$Period]
+  
+  # Example: x1 = 5.3*pi, x2 = 12.8*pi ==> [x1, x2] intersects seam
+  if { [expr abs($X1 - $X2) > 1.0] } {
+    puts "Error: c2d2_$i intersects seam (0.0 or $Period): x1=[dval x1], x2=[dval x2]"
+    continue;
+  }
+
+  set iX1 [expr floor($X1)]
+  set iX2 [expr floor($X2)]
+  
+  # Examples:
+  #   1. x1 = 5*pi/2, x2 = 3*pi ==> [x1, x2] does not intersect seam and
+  #     ($iX1 == $iX2 == 0). I.e. if ($iX1 == $iX2) then seam is not intersected.
+  #   2. x1 = 3*pi, x2 = 5*pi ==> [x1, x2] intersects seam and
+  #     ($iX1 == 1, $iX2 == 2) ==> ($iX1 != $iX2).
+  #   3. x1 = pi/4, x2 = 2*pi ==> [x1, x2] does not intersect seam and
+  #     ($iX1 == 0, $iX2 == 1) ==> ($iX1 != $iX2) and ($X2 == $iX2 = 1)
+  if { ($iX1 != $iX2) && ($X2 != $iX2) } {
+    puts "Error: c2d2_$i intersects seam (0.0 or $Period): x1=[dval x1], x2=[dval x2]"
+  }
+}
+
+smallview
+don c_*
+fit
+
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png