0027299: Incorrect result of the normal projection algorithm
[occt.git] / src / Extrema / Extrema_GenExtCC.gxx
index 3d6f3cc..f3604aa 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.
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-#include <StdFail_NotDone.hxx>
-#include <math_FunctionSetRoot.hxx>
-#include <math_NewtonFunctionSetRoot.hxx>
-#include <TColStd_Array2OfInteger.hxx>
-#include <TColStd_Array2OfReal.hxx>
+#include <algorithm>
+
+#include <Extrema_GlobOptFuncCC.hxx>
+#include <math_GlobOptMin.hxx>
 #include <Standard_NullObject.hxx>
 #include <Standard_OutOfRange.hxx>
+#include <StdFail_NotDone.hxx>
+#include <TColStd_Array1OfReal.hxx>
 #include <Precision.hxx>
+#include <NCollection_Vector.hxx>
+#include <NCollection_CellFilter.hxx>
 
-Extrema_GenExtCC::Extrema_GenExtCC () : myDone (Standard_False)
+// Comparator, used in std::sort.
+static Standard_Boolean comp(const gp_XY& theA,
+                             const gp_XY& theB)
 {
+  if (theA.X() < theB.X())
+  {
+    return Standard_True;
+  }
+  else
+  {
+    if (theA.X() == theB.X())
+    {
+      if (theA.Y() < theB.Y())
+        return Standard_True;
+    }
+  }
+
+  return Standard_False;
 }
 
-Extrema_GenExtCC::Extrema_GenExtCC (const Curve1& C1,
-                             const Curve2& C2,
-                             const Standard_Integer NbU, 
-                             const Standard_Integer NbV,
-                             const Standard_Real TolU, 
-                             const Standard_Real TolV) : myF (C1,C2, Min(TolU, TolV)), myDone (Standard_False)
+class Extrema_CCPointsInspector : public NCollection_CellFilter_InspectorXY
 {
-  SetCurveCache (1, new Cache (C1, C1.FirstParameter(), C1.LastParameter(), NbU, Standard_True));
-  SetCurveCache (2, new Cache (C2, C2.FirstParameter(), C2.LastParameter(), NbV, Standard_True));
-  Perform();
-}
+public:
+  typedef gp_XY Target;
+  //! Constructor; remembers the tolerance
+  Extrema_CCPointsInspector (const Standard_Real theTol)
+  {
+    myTol = theTol * theTol;
+    myIsFind = Standard_False;
+  }
 
+  void ClearFind()
+  {
+    myIsFind = Standard_False;
+  }
+
+  Standard_Boolean isFind()
+  {
+    return myIsFind;
+  }
+
+  //! Set current point to search for coincidence
+  void SetCurrent (const gp_XY& theCurPnt) 
+  { 
+    myCurrent = theCurPnt;
+  }
+
+  //! Implementation of inspection method
+  NCollection_CellFilter_Action Inspect (const Target& theObject)
+  {
+    gp_XY aPt = myCurrent.Subtracted(theObject);
+    const Standard_Real aSQDist = aPt.SquareModulus();
+    if(aSQDist < myTol)
+    {
+      myIsFind = Standard_True;
+    }
 
-Extrema_GenExtCC::Extrema_GenExtCC (const Curve1& C1,
-                             const Curve2& C2,
-                             const Standard_Real Uinf,
-                             const Standard_Real Usup,
-                             const Standard_Real Vinf,
-                             const Standard_Real Vsup,
-                             const Standard_Integer NbU, 
-                             const Standard_Integer NbV,
-                             const Standard_Real /*TolU*/, 
-                             const Standard_Real /*TolV*/) : myF (C1,C2), myDone (Standard_False)
+    return CellFilter_Keep;
+  }
+
+private:
+  Standard_Real myTol;
+  gp_XY myCurrent;
+  Standard_Boolean myIsFind;
+};
+
+//=======================================================================
+//function : Extrema_GenExtCC
+//purpose  : 
+//=======================================================================
+Extrema_GenExtCC::Extrema_GenExtCC()
+: myIsFindSingleSolution(Standard_False),
+  myParallel(Standard_False),
+  myCurveMinTol(Precision::PConfusion()),
+  myLowBorder(1,2),
+  myUppBorder(1,2),
+  myDone(Standard_False)
+{
+  myC[0] = myC[1] = 0;
+}
+
+//=======================================================================
+//function : Extrema_GenExtCC
+//purpose  : 
+//=======================================================================
+Extrema_GenExtCC::Extrema_GenExtCC(const Curve1& C1,
+                                   const Curve2& C2)
+: myIsFindSingleSolution(Standard_False),
+  myParallel(Standard_False),
+  myCurveMinTol(Precision::PConfusion()),
+  myLowBorder(1,2),
+  myUppBorder(1,2),
+  myDone(Standard_False)
 {
-  SetCurveCache (1, new Cache (C1, Uinf, Usup, NbU, Standard_True));
-  SetCurveCache (2, new Cache (C2, Vinf, Vsup, NbV, Standard_True));
-  Perform();
+  myC[0] = (Standard_Address)&C1;
+  myC[1] = (Standard_Address)&C2;
+  myLowBorder(1) = C1.FirstParameter();
+  myLowBorder(2) = C2.FirstParameter();
+  myUppBorder(1) = C1.LastParameter();
+  myUppBorder(2) = C2.LastParameter();
 }
 
-void Extrema_GenExtCC::SetCurveCache (const Standard_Integer theRank,
-                                      const Handle(Cache)& theCache)
+//=======================================================================
+//function : Extrema_GenExtCC
+//purpose  : 
+//=======================================================================
+Extrema_GenExtCC::Extrema_GenExtCC(const Curve1& C1,
+                                   const Curve2& C2,
+                                   const Standard_Real Uinf,
+                                   const Standard_Real Usup,
+                                   const Standard_Real Vinf,
+                                   const Standard_Real Vsup)
+: myIsFindSingleSolution(Standard_False),
+  myParallel(Standard_False),
+  myCurveMinTol(Precision::PConfusion()),
+  myLowBorder(1,2),
+  myUppBorder(1,2),
+  myDone(Standard_False)
 {
-  Standard_OutOfRange_Raise_if (theRank < 1 || theRank > 2, "Extrema_GenExtCC::SetCurveCache()")
-  myF.SetCurve (theRank, *(Curve1*)theCache->CurvePtr());
-  Standard_Integer anInd = theRank - 1;
-  myCache[anInd] = theCache;
+  myC[0] = (Standard_Address)&C1;
+  myC[1] = (Standard_Address)&C2;
+  myLowBorder(1) = Uinf;
+  myLowBorder(2) = Vinf;
+  myUppBorder(1) = Usup;
+  myUppBorder(2) = Vsup;
 }
 
-void Extrema_GenExtCC::SetTolerance (const Standard_Real Tol)
+//=======================================================================
+//function : SetParams
+//purpose  : 
+//=======================================================================
+void Extrema_GenExtCC::SetParams(const Curve1& C1,
+                                 const Curve2& C2,
+                                 const Standard_Real Uinf,
+                                 const Standard_Real Usup,
+                                 const Standard_Real Vinf,
+                                 const Standard_Real Vsup)
 {
-  myF.SetTolerance (Tol);
+  myC[0] = (Standard_Address)&C1;
+  myC[1] = (Standard_Address)&C2;
+  myLowBorder(1) = Uinf;
+  myLowBorder(2) = Vinf;
+  myUppBorder(1) = Usup;
+  myUppBorder(2) = Vsup;
 }
 
+//=======================================================================
+//function : SetTolerance
+//purpose  : 
+//=======================================================================
+void Extrema_GenExtCC::SetTolerance(Standard_Real theTol)
+{
+  myCurveMinTol = theTol;
+}
 
-//=============================================================================
-void Extrema_GenExtCC::Perform ()
-/*-----------------------------------------------------------------------------
-Fonction:
-   Recherche de toutes les distances extremales entre les courbes C1 et C2.
-  a partir de 2 echantillonnages (NbU,NbV).
-
-Methode:
-   L'algorithme part de l'hypothese que les echantillonnages sont suffisamment
-  fins pour que, s'il existe N distances extremales entre les 2 courbes,
-  alors il existe aussi N extrema entre les 2 ensembles de points.
-  Ainsi, l'algorithme consiste a partir des extrema des echantillons
-  pour trouver les extrema des courbes.
-   Les extrema sont calcules par l'algorithme math_FunctionSetRoot avec les
-  arguments suivants:
-  - myF: Extrema_FuncExtCC cree a partir de C1 et C2,
-  - UV: math_Vector dont les composantes sont les parametres des points de
-    l'extremum sur les ensembles de points,
-  - Tol: Min(TolU,TolV), (Prov.:math_FunctionSetRoot n'autorise pas un vecteur)
-  - UVinf: math_Vector dont les composantes sont les bornes inferieures de u et
-    v,
-  - UVsup: math_Vector dont les composantes sont les bornes superieures de u et
-    v.
-
-Traitement:
-  a- Constitution du tableau des square distances (TbDist2(0,NbU+1,0,NbV+1)):
-      Le tableau est volontairement etendu; les lignes 0 et NbU+1 et les
-     colonnes 0 et NbV+1 seront initialisees a RealFirst() ou RealLast()
-     pour simplifier les tests effectues dans l'etape b
-     (on n'a pas besoin de tester si le point est sur une extremite).
-  b- Calcul des extrema:
-      On recherche d'abord les minima et ensuite les maxima. Ces 2 traitements
-     se passent de facon similaire:
-  b.a- Initialisations:
-      - des 'bords' du tableau TbDist2 (a RealLast() dans le cas des minima
-        et a RealLast() dans le cas des maxima),
-      - du tableau TbSel(0,NbU+1,0,NbV+1) de selection des points pour un
-        calcul d'extremum local (a 0). Lorsqu'un couple de points sera
-       selectionne, il ne sera plus selectionnable, ainsi que les couples
-       adjacents (8 au maximum).
-       Les adresses correspondantes seront mises a 1.
-  b.b- Calcul des minima (ou maxima):
-       On boucle sur toutes les square distances du tableau TbDist2:
-      - recherche d'un minimum (ou maximum) sur les echantillons,
-      - calcul de l'extremum sur les courbes,
-      - mise a jour du tableau TbSel.
------------------------------------------------------------------------------*/
+//=======================================================================
+//function : Perform
+//purpose  : 
+//=======================================================================
+void Extrema_GenExtCC::Perform()
 {
   myDone = Standard_False;
+  myParallel = Standard_False;
 
-  const Handle(Cache)& aCache1 = myCache[0];
-  const Handle(Cache)& aCache2 = myCache[1];
-  Standard_NullObject_Raise_if ((aCache1.IsNull() || aCache2.IsNull()),
-    "Extrema_GenExtCC::Perform()")
-
-  Standard_Integer aNbU = aCache1->NbSamples(), aNbV = aCache2->NbSamples();
-  Standard_OutOfRange_Raise_if ((aNbU < 2 ||aNbV < 2), "Extrema_GenExtCC::Perform()")
-
-/*
-a- Constitution du tableau des distances (TbDist2(0,NbU+1,0,NbV+1)):
-   ---------------------------------------------------------------
-*/
-
-  //ensure that caches have been calculated
-  if (!aCache1->IsValid())
-    aCache1->CalculatePoints();
-  if (!aCache2->IsValid())
-    aCache2->CalculatePoints();
-
-// Calcul des distances
-  const Handle(ArrayOfPnt)& aPntArray1 = aCache1->Points();
-  const Handle(ArrayOfPnt)& aPntArray2 = aCache2->Points();
-  Standard_Integer NoU, NoV;
-  TColStd_Array2OfReal TbDist2(0, aNbU + 1, 0, aNbV + 1);
-  for (NoU = 1; NoU <= aNbU; NoU++) {
-    const Pnt& P1 = aPntArray1->Value (NoU);
-    for (NoV = 1; NoV <= aNbV; NoV++) {
-      const Pnt& P2 = aPntArray2->Value (NoV);
-      TbDist2(NoU,NoV) = P1.SquareDistance(P2);
-    }
+  Curve1 &C1 = *(Curve1*)myC[0];
+  Curve2 &C2 = *(Curve2*)myC[1];
+
+  Standard_Integer aNbInter[2];
+  GeomAbs_Shape aContinuity = GeomAbs_C2;
+  aNbInter[0] = C1.NbIntervals(aContinuity);
+  aNbInter[1] = C2.NbIntervals(aContinuity);
+
+  if (aNbInter[0] * aNbInter[1] > 100)
+  {
+    aContinuity = GeomAbs_C1;
+    aNbInter[0] = C1.NbIntervals(aContinuity);
+    aNbInter[1] = C2.NbIntervals(aContinuity);
   }
 
-/*
-b- Calcul des minima:
-   -----------------
-   b.a) Initialisations:
-*/
-//     - generales
-  math_Vector Tol(1, 2);
-  Tol(1) = myF.Tolerance();
-  Tol(2) = myF.Tolerance();
-  math_Vector UV(1,2), UVinf(1,2), UVsup(1,2);
-  UVinf(1) = aCache1->TrimFirstParameter();
-  UVinf(2) = aCache2->TrimFirstParameter();
-  UVsup(1) = aCache1->TrimLastParameter();
-  UVsup(2) = aCache2->TrimLastParameter();
-  
-  myF.SubIntervalInitialize(UVinf,UVsup);
-
-//     - des 'bords' du tableau TbDist2
-  for (NoV = 0; NoV <= aNbV+1; NoV++) {
-    TbDist2(0,NoV) = RealLast();
-    TbDist2(aNbU+1,NoV) = RealLast();
+  TColStd_Array1OfReal anIntervals1(1, aNbInter[0] + 1);
+  TColStd_Array1OfReal anIntervals2(1, aNbInter[1] + 1);
+  C1.Intervals(anIntervals1, aContinuity);
+  C2.Intervals(anIntervals2, aContinuity);
+
+  // Lipchitz constant approximation.
+  Standard_Real aLC = 9.0; // Default value.
+  Standard_Boolean isConstLockedFlag = Standard_False;
+  if (C1.GetType() == GeomAbs_Line)
+  {
+    Standard_Real aMaxDer = 1.0 / C2.Resolution(1.0);
+    if (aLC > aMaxDer)
+    {
+      isConstLockedFlag = Standard_True;
+      aLC = aMaxDer;
+    }
   }
-  for (NoU = 1; NoU <= aNbU; NoU++) {
-    TbDist2(NoU,0) = RealLast();
-    TbDist2(NoU,aNbV+1) = RealLast();
+  if (C2.GetType() == GeomAbs_Line)
+  {
+    Standard_Real aMaxDer = 1.0 / C1.Resolution(1.0);
+    if (aLC > aMaxDer)
+    {
+      isConstLockedFlag = Standard_True;
+      aLC = aMaxDer;
+    }
+  }
+
+  Extrema_GlobOptFuncCCC2 aFunc (C1, C2);
+  math_GlobOptMin aFinder(&aFunc, myLowBorder, myUppBorder, aLC);
+  aFinder.SetLipConstState(isConstLockedFlag);
+  aFinder.SetContinuity(aContinuity == GeomAbs_C2 ? 2 : 1);
+  Standard_Real aDiscTol = 1.0e-2;
+  Standard_Real aValueTol = 1.0e-2;
+  Standard_Real aSameTol = myCurveMinTol / (aDiscTol);
+  aFinder.SetTol(aDiscTol, aSameTol);
+  aFinder.SetFunctionalMinimalValue(0.0); // Best distance cannot be lower than 0.0.
+
+  // Size computed to have cell index inside of int32 value.
+  const Standard_Real aCellSize = Max(anIntervals1.Upper() - anIntervals1.Lower(),
+                                      anIntervals2.Upper() - anIntervals2.Lower())
+                                  * Precision::PConfusion() / (2.0 * Sqrt(2.0));
+  Extrema_CCPointsInspector anInspector(Precision::PConfusion());
+  NCollection_CellFilter<Extrema_CCPointsInspector> aFilter(aCellSize);
+  NCollection_Vector<gp_XY> aPnts;
+
+  Standard_Integer i,j,k;
+  math_Vector aFirstBorderInterval(1,2);
+  math_Vector aSecondBorderInterval(1,2);
+  Standard_Real aF = RealLast(); // Best functional value.
+  Standard_Real aCurrF = RealLast(); // Current functional value computed on current interval.
+  for(i = 1; i <= aNbInter[0]; i++)
+  {
+    for(j = 1; j <= aNbInter[1]; j++)
+    {
+      aFirstBorderInterval(1) = anIntervals1(i);
+      aFirstBorderInterval(2) = anIntervals2(j); 
+      aSecondBorderInterval(1) = anIntervals1(i + 1);
+      aSecondBorderInterval(2) = anIntervals2(j + 1);
+
+      aFinder.SetLocalParams(aFirstBorderInterval, aSecondBorderInterval);
+      aFinder.Perform(GetSingleSolutionFlag());
+
+      // Check that solution found on current interval is not worse than previous.
+      aCurrF = aFinder.GetF();
+      if (aCurrF >= aF + aSameTol * aValueTol)
+      {
+        continue;
+      }
+
+      // Clean previously computed solution if current one is better.
+      if (aCurrF > aF - aSameTol * aValueTol)
+      {
+        if (aCurrF < aF)
+          aF = aCurrF;
+      }
+      else
+      {
+        aF = aCurrF;
+        aFilter.Reset(aCellSize);
+        aPnts.Clear();
+      }
+
+      // Save found solutions avoiding repetitions.
+      math_Vector sol(1,2);
+      for(k = 1; k <= aFinder.NbExtrema(); k++)
+      {
+        aFinder.Points(k, sol);
+        gp_XY aPnt2d(sol(1), sol(2));
+
+        gp_XY aXYmin = anInspector.Shift(aPnt2d, -aCellSize);
+        gp_XY aXYmax = anInspector.Shift(aPnt2d,  aCellSize);
+
+        anInspector.ClearFind();
+        anInspector.SetCurrent(aPnt2d);
+        aFilter.Inspect(aXYmin, aXYmax, anInspector);
+        if (!anInspector.isFind())
+        {
+          // Point is out of close cells, add new one.
+          aFilter.Add(aPnt2d, aPnt2d);
+          aPnts.Append(gp_XY(sol(1), sol(2)));
+        }
+      }
+    }
   }
 
-//     - du tableau TbSel(0,aNbU+1,0,aNbV+1) de selection des points
-  TColStd_Array2OfInteger TbSel(0,aNbU+1,0,aNbV+1);
-  TbSel.Init(0);
-
-/*
-   b.b) Calcul des minima:
-*/
-//     - recherche d un minimum sur la grille
-  Standard_Integer Nu, Nv;
-  Standard_Real Dist2;
-  const Handle(TColStd_HArray1OfReal)& aParamArray1 = aCache1->Parameters();
-  const Handle(TColStd_HArray1OfReal)& aParamArray2 = aCache2->Parameters();
-  for (NoU = 1; NoU <= aNbU; NoU++) {
-    for (NoV = 1; NoV <= aNbV; NoV++) {
-      if (TbSel(NoU,NoV) == 0) {
-       Dist2 = TbDist2(NoU,NoV);
-       if ((TbDist2(NoU-1,NoV-1) >= Dist2) &&
-           (TbDist2(NoU-1,NoV  ) >= Dist2) &&
-           (TbDist2(NoU-1,NoV+1) >= Dist2) &&
-           (TbDist2(NoU  ,NoV-1) >= Dist2) &&
-           (TbDist2(NoU  ,NoV+1) >= Dist2) &&
-           (TbDist2(NoU+1,NoV-1) >= Dist2) &&
-           (TbDist2(NoU+1,NoV  ) >= Dist2) &&
-           (TbDist2(NoU+1,NoV+1) >= Dist2)) {
-
-//     - calcul de l extremum sur la surface:
-          
-          UV(1) = aParamArray1->Value(NoU);
-          UV(2) = aParamArray2->Value(NoV);
-
-         math_FunctionSetRoot S (myF,UV,Tol,UVinf,UVsup);
-
-      
-//     - mise a jour du tableau TbSel    
-         for (Nu = NoU-1; Nu <= NoU+1; Nu++) {
-           for (Nv = NoV-1; Nv <= NoV+1; Nv++) {
-             TbSel(Nu,Nv) = 1;
-           }
-         }
-       }
-      } // if (TbSel(NoU,NoV)
-    } // for (NoV = 1; ...
-  } // for (NoU = 1; ...
-/*
-c- Calcul des maxima:
-   -----------------
-   c.a) Initialisations:
-*/
-//     - des 'bords' du tableau TbDist2
-  for (NoV = 0; NoV <= aNbV+1; NoV++) {
-    TbDist2(0,NoV) = RealFirst();
-    TbDist2(aNbU+1,NoV) = RealFirst();
+  if (aPnts.Size() == 0)
+  {
+    // No solutions.
+    myDone = Standard_False;
+    return;
   }
-  for (NoU = 1; NoU <= aNbU; NoU++) {
-    TbDist2(NoU,0) = RealFirst();
-    TbDist2(NoU,aNbV+1) = RealFirst();
+
+  // Check for infinity solutions case, for this:
+  // Sort points lexicographically and check midpoint between each two neighboring points.
+  // If all midpoints functional value is acceptable
+  // then set myParallel flag to true and return one solution.
+  std::sort(aPnts.begin(), aPnts.end(), comp);
+  Standard_Boolean isParallel = Standard_False;
+  Standard_Real aVal = 0.0;
+  math_Vector aVec(1,2, 0.0);
+
+  // Avoid mark parallel case when have duplicates out of tolerance.
+  // Bad conditioned task: bug25635_1, bug23706_10, bug23706_13.
+  const Standard_Integer aMinNbInfSol = 100;
+  if (aPnts.Size() >= aMinNbInfSol)
+  {
+    isParallel = Standard_True;
+    for(Standard_Integer anIdx = aPnts.Lower(); anIdx <= aPnts.Upper() - 1; anIdx++)
+    {
+      const gp_XY& aCurrent = aPnts(anIdx);
+      const gp_XY& aNext    = aPnts(anIdx + 1);
+
+      aVec(1) = (aCurrent.X() + aNext.X()) * 0.5;
+      aVec(2) = (aCurrent.Y() + aNext.Y()) * 0.5;
+
+      aFunc.Value(aVec, aVal);
+
+      if (Abs(aVal - aF) > Precision::Confusion())
+      {
+        isParallel = Standard_False;
+        break;
+      }
+    }
   }
 
-//     - du tableau TbSel(0,aNbU+1,0,aNbV+1) de selection des points
-  TbSel.Init(0);
-  /*for (NoU = 0; NoU <= aNbU+1; NoU++) {
-    for (NoV = 0; NoV <= aNbV+1; NoV++) {
-      TbSel(NoU,NoV) = 0;
+  if (isParallel)
+  {
+    const gp_XY& aCurrent = aPnts.First();
+    myPoints1.Append(aCurrent.X());
+    myPoints2.Append(aCurrent.Y());
+    myParallel = Standard_True;
+  }
+  else
+  {
+    for(Standard_Integer anIdx = aPnts.Lower(); anIdx <= aPnts.Upper(); anIdx++)
+    {
+      const gp_XY& aCurrent = aPnts(anIdx);
+      myPoints1.Append(aCurrent.X());
+      myPoints2.Append(aCurrent.Y());
     }
-  }*/
-/*
-   c.b) Calcul des maxima:
-*/
-//     - recherche d un maximum sur la grille
-  for (NoU = 1; NoU <= aNbU; NoU++) {
-    for (NoV = 1; NoV <= aNbV; NoV++) {
-      if (TbSel(NoU,NoV) == 0) {
-       Dist2 = TbDist2(NoU,NoV);
-       if ((TbDist2(NoU-1,NoV-1) <= Dist2) &&
-           (TbDist2(NoU-1,NoV  ) <= Dist2) &&
-           (TbDist2(NoU-1,NoV+1) <= Dist2) &&
-           (TbDist2(NoU  ,NoV-1) <= Dist2) &&
-           (TbDist2(NoU  ,NoV+1) <= Dist2) &&
-           (TbDist2(NoU+1,NoV-1) <= Dist2) &&
-           (TbDist2(NoU+1,NoV  ) <= Dist2) &&
-           (TbDist2(NoU+1,NoV+1) <= Dist2)) {
-
-//     - calcul de l extremum sur la surface:
-
-          UV(1) = aParamArray1->Value(NoU);
-          UV(2) = aParamArray2->Value(NoV);
-
-         math_FunctionSetRoot S (myF,UV,Tol,UVinf,UVsup);
-      
-//     - mise a jour du tableau TbSel    
-         for (Nu = NoU-1; Nu <= NoU+1; Nu++) {
-           for (Nv = NoV-1; Nv <= NoV+1; Nv++) {
-             TbSel(Nu,Nv) = 1;
-           }
-         }
-       }
-      } // if (TbSel(NoU,NoV))
-    } // for (NoV = 1; ...)
-  } // for (NoU = 1; ...)
+  }
+
   myDone = Standard_True;
 }
-//=============================================================================
 
-Standard_Boolean Extrema_GenExtCC::IsDone () const { return myDone; }
-//=============================================================================
+//=======================================================================
+//function : IsDone
+//purpose  : 
+//=======================================================================
+Standard_Boolean Extrema_GenExtCC::IsDone() const 
+{
+  return myDone; 
+}
+
+//=======================================================================
+//function : IsParallel
+//purpose  : 
+//=======================================================================
+Standard_Boolean Extrema_GenExtCC::IsParallel() const 
+{
+  return myParallel; 
+}
 
-Standard_Integer Extrema_GenExtCC::NbExt () const
+//=======================================================================
+//function : NbExt
+//purpose  : 
+//=======================================================================
+Standard_Integer Extrema_GenExtCC::NbExt() const
 {
   StdFail_NotDone_Raise_if (!myDone, "Extrema_GenExtCC::NbExt()")
-  return myF.NbExt();
+
+  return myPoints1.Length();
 }
-//=============================================================================
 
-Standard_Real Extrema_GenExtCC::SquareDistance (const Standard_Integer N) const
+//=======================================================================
+//function : SquareDistance
+//purpose  : 
+//=======================================================================
+Standard_Real Extrema_GenExtCC::SquareDistance(const Standard_Integer N) const
 {
   StdFail_NotDone_Raise_if (!myDone, "Extrema_GenExtCC::SquareDistance()")
   Standard_OutOfRange_Raise_if ((N < 1 || N > NbExt()), "Extrema_GenExtCC::SquareDistance()")
-  return myF.SquareDistance(N);
+
+  return Tool1::Value(*((Curve1*)myC[0]), myPoints1(N)).SquareDistance(Tool2::Value(*((Curve2*)myC[1]), myPoints2(N)));
 }
-//=============================================================================
 
-void Extrema_GenExtCC::Points (const Standard_Integer N,
-                           POnC& P1, POnC& P2) const
+//=======================================================================
+//function : Points
+//purpose  : 
+//=======================================================================
+void Extrema_GenExtCC::Points(const Standard_Integer N,
+                              POnC& P1,
+                              POnC& P2) const
 {
-  StdFail_NotDone_Raise_if (!myDone, "Extrema_GenExtCC::SquareDistance()")
-  Standard_OutOfRange_Raise_if ((N < 1 || N > NbExt()), "Extrema_GenExtCC::SquareDistance()")
-  myF.Points(N,P1,P2);
+  StdFail_NotDone_Raise_if (!myDone, "Extrema_GenExtCC::Points()")
+  Standard_OutOfRange_Raise_if ((N < 1 || N > NbExt()), "Extrema_GenExtCC::Points()")
+
+  P1.SetValues(myPoints1(N), Tool1::Value(*((Curve1*)myC[0]), myPoints1(N)));
+  P2.SetValues(myPoints2(N), Tool2::Value(*((Curve2*)myC[1]), myPoints2(N)));
+}
+
+//=======================================================================
+//function : SetSingleSolutionFlag
+//purpose  : 
+//=======================================================================
+void Extrema_GenExtCC::SetSingleSolutionFlag(const Standard_Boolean theFlag)
+{
+  myIsFindSingleSolution = theFlag;
+}
+
+//=======================================================================
+//function : GetSingleSolutionFlag
+//purpose  : 
+//=======================================================================
+Standard_Boolean Extrema_GenExtCC::GetSingleSolutionFlag() const
+{
+  return myIsFindSingleSolution;
 }