Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/opencascade/Extrema_GenExtCC.gxx is written in an unsupported language. File is not indexed.

0001 // Created on: 1995-07-18
0002 // Created by: Modelistation
0003 // Copyright (c) 1995-1999 Matra Datavision
0004 // Copyright (c) 1999-2014 OPEN CASCADE SAS
0005 //
0006 // This file is part of Open CASCADE Technology software library.
0007 //
0008 // This library is free software; you can redistribute it and/or modify it under
0009 // the terms of the GNU Lesser General Public License version 2.1 as published
0010 // by the Free Software Foundation, with special exception defined in the file
0011 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0012 // distribution for complete text of the license and disclaimer of any warranty.
0013 //
0014 // Alternatively, this file may be used under the terms of Open CASCADE
0015 // commercial license or contractual agreement.
0016 
0017 #include <algorithm>
0018 
0019 #include <Extrema_GlobOptFuncCC.hxx>
0020 #include <math_GlobOptMin.hxx>
0021 #include <Standard_NullObject.hxx>
0022 #include <Standard_OutOfRange.hxx>
0023 #include <StdFail_NotDone.hxx>
0024 #include <TColStd_Array1OfReal.hxx>
0025 #include <TColStd_ListOfInteger.hxx>
0026 #include <Precision.hxx>
0027 #include <NCollection_Vector.hxx>
0028 #include <NCollection_CellFilter.hxx>
0029 #include <GCPnts_AbscissaPoint.hxx>
0030 
0031 // Comparator, used in std::sort.
0032 static Standard_Boolean comp(const gp_XY& theA,
0033                              const gp_XY& theB)
0034 {
0035   if (theA.X() < theB.X())
0036   {
0037     return Standard_True;
0038   }
0039   else
0040   {
0041     if (theA.X() == theB.X())
0042     {
0043       if (theA.Y() < theB.Y())
0044         return Standard_True;
0045     }
0046   }
0047 
0048   return Standard_False;
0049 }
0050 
0051 static void ChangeIntervals(Handle(TColStd_HArray1OfReal)& theInts, const Standard_Integer theNbInts)
0052 {
0053   Standard_Integer aNbInts = theInts->Length() - 1;
0054   Standard_Integer aNbAdd = theNbInts - aNbInts;
0055   Handle(TColStd_HArray1OfReal) aNewInts = new TColStd_HArray1OfReal(1, theNbInts + 1);
0056   Standard_Integer aNbLast = theInts->Length();
0057   Standard_Integer i;
0058   if (aNbInts == 1)
0059   {
0060     aNewInts->SetValue(1, theInts->First());
0061     aNewInts->SetValue(theNbInts + 1, theInts->Last());
0062     Standard_Real dt = (theInts->Last() - theInts->First()) / theNbInts;
0063     Standard_Real t = theInts->First() + dt;
0064     for (i = 2; i <= theNbInts; ++i, t += dt)
0065     {
0066       aNewInts->SetValue(i, t);
0067     }
0068     theInts = aNewInts;
0069     return;
0070   }
0071   //
0072   for (i = 1; i <= aNbLast; ++i)
0073   {
0074     aNewInts->SetValue(i, theInts->Value(i));
0075   }
0076   //
0077   while (aNbAdd > 0)
0078   {
0079     Standard_Real anLIntMax = -1.;
0080     Standard_Integer aMaxInd = -1;
0081     for (i = 1; i < aNbLast; ++i)
0082     {
0083       Standard_Real anL = aNewInts->Value(i + 1) - aNewInts->Value(i);
0084       if (anL > anLIntMax)
0085       {
0086         anLIntMax = anL;
0087         aMaxInd = i;
0088       }
0089     }
0090 
0091     Standard_Real t = (aNewInts->Value(aMaxInd + 1) + aNewInts->Value(aMaxInd)) / 2.;
0092     for (i = aNbLast; i > aMaxInd; --i)
0093     {
0094       aNewInts->SetValue(i + 1, aNewInts->Value(i));
0095     }
0096     aNbLast++;
0097     aNbAdd--;
0098     aNewInts->SetValue(aMaxInd + 1, t);
0099   }
0100   theInts = aNewInts;
0101 }
0102 class Extrema_CCPointsInspector : public NCollection_CellFilter_InspectorXY
0103 {
0104 public:
0105   typedef gp_XY Target;
0106   //! Constructor; remembers the tolerance
0107   Extrema_CCPointsInspector (const Standard_Real theTol)
0108   {
0109     myTol = theTol * theTol;
0110     myIsFind = Standard_False;
0111   }
0112 
0113   void ClearFind()
0114   {
0115     myIsFind = Standard_False;
0116   }
0117 
0118   Standard_Boolean isFind()
0119   {
0120     return myIsFind;
0121   }
0122 
0123   //! Set current point to search for coincidence
0124   void SetCurrent (const gp_XY& theCurPnt) 
0125   { 
0126     myCurrent = theCurPnt;
0127   }
0128 
0129   //! Implementation of inspection method
0130   NCollection_CellFilter_Action Inspect (const Target& theObject)
0131   {
0132     gp_XY aPt = myCurrent.Subtracted(theObject);
0133     const Standard_Real aSQDist = aPt.SquareModulus();
0134     if(aSQDist < myTol)
0135     {
0136       myIsFind = Standard_True;
0137     }
0138 
0139     return CellFilter_Keep;
0140   }
0141 
0142 private:
0143   Standard_Real myTol;
0144   gp_XY myCurrent;
0145   Standard_Boolean myIsFind;
0146 };
0147 
0148 //=======================================================================
0149 //function : ProjPOnC
0150 //purpose  : Projects the point on the curve and returns the minimal
0151 //           projection distance
0152 //=======================================================================
0153 static Standard_Real ProjPOnC(const Pnt& theP,
0154                               Extrema_GExtPC& theProjTool)
0155 {
0156   Standard_Real aDist = ::RealLast();
0157   theProjTool.Perform(theP);
0158   if (theProjTool.IsDone() && theProjTool.NbExt())
0159   {
0160     for (Standard_Integer i = 1; i <= theProjTool.NbExt(); ++i)
0161     {
0162       Standard_Real aD = theProjTool.SquareDistance(i);
0163       if (aD < aDist)
0164         aDist = aD;
0165     }
0166   }
0167   return aDist;
0168 }
0169 
0170 //=======================================================================
0171 //function : Extrema_GenExtCC
0172 //purpose  : 
0173 //=======================================================================
0174 Extrema_GenExtCC::Extrema_GenExtCC()
0175 : myIsFindSingleSolution(Standard_False),
0176   myParallel(Standard_False),
0177   myCurveMinTol(Precision::PConfusion()),
0178   myLowBorder(1,2),
0179   myUppBorder(1,2),
0180   myDone(Standard_False)
0181 {
0182   myC[0] = myC[1] = 0;
0183 }
0184 
0185 //=======================================================================
0186 //function : Extrema_GenExtCC
0187 //purpose  : 
0188 //=======================================================================
0189 Extrema_GenExtCC::Extrema_GenExtCC(const Curve1& C1,
0190                                    const Curve2& C2)
0191 : myIsFindSingleSolution(Standard_False),
0192   myParallel(Standard_False),
0193   myCurveMinTol(Precision::PConfusion()),
0194   myLowBorder(1,2),
0195   myUppBorder(1,2),
0196   myDone(Standard_False)
0197 {
0198   myC[0] = (Standard_Address)&C1;
0199   myC[1] = (Standard_Address)&C2;
0200   myLowBorder(1) = C1.FirstParameter();
0201   myLowBorder(2) = C2.FirstParameter();
0202   myUppBorder(1) = C1.LastParameter();
0203   myUppBorder(2) = C2.LastParameter();
0204 }
0205 
0206 //=======================================================================
0207 //function : Extrema_GenExtCC
0208 //purpose  : 
0209 //=======================================================================
0210 Extrema_GenExtCC::Extrema_GenExtCC(const Curve1& C1,
0211                                    const Curve2& C2,
0212                                    const Standard_Real Uinf,
0213                                    const Standard_Real Usup,
0214                                    const Standard_Real Vinf,
0215                                    const Standard_Real Vsup)
0216 : myIsFindSingleSolution(Standard_False),
0217   myParallel(Standard_False),
0218   myCurveMinTol(Precision::PConfusion()),
0219   myLowBorder(1,2),
0220   myUppBorder(1,2),
0221   myDone(Standard_False)
0222 {
0223   myC[0] = (Standard_Address)&C1;
0224   myC[1] = (Standard_Address)&C2;
0225   myLowBorder(1) = Uinf;
0226   myLowBorder(2) = Vinf;
0227   myUppBorder(1) = Usup;
0228   myUppBorder(2) = Vsup;
0229 }
0230 
0231 //=======================================================================
0232 //function : SetParams
0233 //purpose  : 
0234 //=======================================================================
0235 void Extrema_GenExtCC::SetParams(const Curve1& C1,
0236                                  const Curve2& C2,
0237                                  const Standard_Real Uinf,
0238                                  const Standard_Real Usup,
0239                                  const Standard_Real Vinf,
0240                                  const Standard_Real Vsup)
0241 {
0242   myC[0] = (Standard_Address)&C1;
0243   myC[1] = (Standard_Address)&C2;
0244   myLowBorder(1) = Uinf;
0245   myLowBorder(2) = Vinf;
0246   myUppBorder(1) = Usup;
0247   myUppBorder(2) = Vsup;
0248 }
0249 
0250 //=======================================================================
0251 //function : SetTolerance
0252 //purpose  : 
0253 //=======================================================================
0254 void Extrema_GenExtCC::SetTolerance(Standard_Real theTol)
0255 {
0256   myCurveMinTol = theTol;
0257 }
0258 
0259 //=======================================================================
0260 //function : Perform
0261 //purpose  : 
0262 //=======================================================================
0263 void Extrema_GenExtCC::Perform()
0264 {
0265   myDone = Standard_False;
0266   myParallel = Standard_False;
0267 
0268   Curve1 &C1 = *(Curve1*)myC[0];
0269   Curve2 &C2 = *(Curve2*)myC[1];
0270 
0271   Standard_Integer aNbInter[2];
0272   GeomAbs_Shape aContinuity = GeomAbs_C2;
0273   aNbInter[0] = C1.NbIntervals(aContinuity);
0274   aNbInter[1] = C2.NbIntervals(aContinuity);
0275 
0276   if (aNbInter[0] * aNbInter[1] > 100)
0277   {
0278     aContinuity = GeomAbs_C1;
0279     aNbInter[0] = C1.NbIntervals(aContinuity);
0280     aNbInter[1] = C2.NbIntervals(aContinuity);
0281   }
0282 
0283   Standard_Real anL[2];
0284   Standard_Integer indmax = -1, indmin = -1;
0285   const Standard_Real mult = 20.;
0286   if (!(Precision::IsInfinite(C1.FirstParameter()) || Precision::IsInfinite(C1.LastParameter()) ||
0287         Precision::IsInfinite(C2.FirstParameter()) || Precision::IsInfinite(C2.LastParameter())))
0288   {
0289     anL[0] = GCPnts_AbscissaPoint::Length(C1);
0290     anL[1] = GCPnts_AbscissaPoint::Length(C2);
0291     if (anL[0] / aNbInter[0] > mult * anL[1] / aNbInter[1])
0292     {
0293       indmax = 0;
0294       indmin = 1;
0295     }
0296     else if (anL[1] / aNbInter[1] > mult * anL[0] / aNbInter[0])
0297     {
0298       indmax = 1;
0299       indmin = 0;
0300     }
0301   }
0302   Standard_Integer aNbIntOpt = 0;
0303   if (indmax >= 0)
0304   {
0305     aNbIntOpt = RealToInt(anL[indmax] * aNbInter[indmin] / anL[indmin] / (mult / 4.))  + 1;
0306     if (aNbIntOpt > 100 || aNbIntOpt < aNbInter[indmax])
0307     {
0308       indmax = -1;
0309     }
0310     else
0311     {
0312       if (aNbIntOpt * aNbInter[indmin] > 100)
0313       {
0314         aNbIntOpt = 100 / aNbInter[indmin];
0315         if (aNbIntOpt < aNbInter[indmax])
0316         {
0317           indmax = -1;
0318         }
0319       }
0320     }
0321   }
0322 
0323   Handle(TColStd_HArray1OfReal) anIntervals1 = new TColStd_HArray1OfReal(1, aNbInter[0] + 1);
0324   Handle(TColStd_HArray1OfReal) anIntervals2 = new TColStd_HArray1OfReal(1, aNbInter[1] + 1);
0325   C1.Intervals(anIntervals1->ChangeArray1(), aContinuity);
0326   C2.Intervals(anIntervals2->ChangeArray1(), aContinuity);
0327   if (indmax >= 0)
0328   {
0329     if (indmax == 0)
0330     {
0331       //Change anIntervals1
0332       ChangeIntervals(anIntervals1, aNbIntOpt);
0333       aNbInter[0] = anIntervals1->Length() - 1;
0334     }
0335     else
0336     {
0337       //Change anIntervals2;
0338       ChangeIntervals(anIntervals2, aNbIntOpt);
0339       aNbInter[1] = anIntervals2->Length() - 1;
0340     }
0341   }
0342   if (C1.IsClosed() && aNbInter[0] == 1)
0343   {
0344     ChangeIntervals(anIntervals1, 3);
0345     aNbInter[0] = anIntervals1->Length() - 1;
0346   }
0347   if (C2.IsClosed() && aNbInter[1] == 1)
0348   {
0349     ChangeIntervals(anIntervals2, 3);
0350     aNbInter[1] = anIntervals2->Length() - 1;
0351   }
0352 
0353   // Lipchitz constant computation.
0354   const Standard_Real aMaxLC = 10000.;
0355   Standard_Real aLC = 100.0; // Default value.
0356   const Standard_Real aMaxDer1 = 1.0 / C1.Resolution(1.0);
0357   const Standard_Real aMaxDer2 = 1.0 / C2.Resolution(1.0);
0358   Standard_Real aMaxDer = Max(aMaxDer1, aMaxDer2) * Sqrt(2.0);
0359   if (aLC > aMaxDer)
0360     aLC = aMaxDer;
0361 
0362   // Change constant value according to the concrete curve types.
0363   Standard_Boolean isConstLockedFlag = Standard_False;
0364   //To prevent LipConst to became too small
0365   const Standard_Real aCR = 0.001;
0366   if (aMaxDer1 / aMaxDer < aCR || aMaxDer2 / aMaxDer < aCR)
0367   {
0368     isConstLockedFlag = Standard_True;
0369   }
0370   if (aMaxDer > aMaxLC)
0371   {
0372     aLC = aMaxLC;
0373     isConstLockedFlag = Standard_True;
0374   }
0375   if (C1.GetType() == GeomAbs_Line)
0376   {
0377     aMaxDer = 1.0 / C2.Resolution(1.0);
0378     if (aLC > aMaxDer)
0379     {
0380       isConstLockedFlag = Standard_True;
0381       aLC = aMaxDer;
0382     }
0383   }
0384   if (C2.GetType() == GeomAbs_Line)
0385   {
0386     aMaxDer = 1.0 / C1.Resolution(1.0);
0387     if (aLC > aMaxDer)
0388     {
0389       isConstLockedFlag = Standard_True;
0390       aLC = aMaxDer;
0391     }
0392   }
0393 
0394   Extrema_GlobOptFuncCCC2 aFunc (C1, C2);
0395   if (aLC < aMaxLC || aMaxDer > aMaxLC)
0396   {
0397     //Estimation of Lipschitz constant by gradient of optimization function 
0398     //using sampling in parameter space.
0399     math_Vector aT(1, 2), aG(1, 2);
0400     Standard_Real aF, aMaxG = 0.;
0401     Standard_Real t1, t2, dt1, dt2;
0402     Standard_Integer n1 = 21, n2 = 21, i1, i2;
0403     dt1 = (C1.LastParameter() - C1.FirstParameter()) / (n1 - 1);
0404     dt2 = (C2.LastParameter() - C2.FirstParameter()) / (n2 - 1);
0405     for (i1 = 1, t1 = C1.FirstParameter(); i1 <= n1; ++i1, t1 += dt1)
0406     {
0407       aT(1) = t1;
0408       for (i2 = 1, t2 = C2.FirstParameter(); i2 <= n2; ++i2, t2 += dt2)
0409       {
0410         aT(2) = t2;
0411         aFunc.Values(aT, aF, aG);
0412         Standard_Real aMod = aG(1)*aG(1) + aG(2)*aG(2);
0413         aMaxG = Max(aMaxG, aMod);
0414       }
0415     }
0416     aMaxG = Sqrt(aMaxG);
0417     if (aMaxG > aMaxDer)
0418     {
0419       aLC = Min(aMaxG, aMaxLC);
0420       isConstLockedFlag = Standard_True;
0421     }
0422     if (aMaxG > 100. * aMaxLC)
0423     {
0424       aLC = 100. * aMaxLC;
0425       isConstLockedFlag = Standard_True;
0426     }
0427     else if (aMaxG < 0.1 * aMaxDer)
0428     {
0429       isConstLockedFlag = Standard_True;
0430     }
0431   }
0432   math_GlobOptMin aFinder(&aFunc, myLowBorder, myUppBorder, aLC);
0433   aFinder.SetLipConstState(isConstLockedFlag);
0434   aFinder.SetContinuity(aContinuity == GeomAbs_C2 ? 2 : 1);
0435   Standard_Real aDiscTol = 1.0e-2;
0436   Standard_Real aValueTol = 1.0e-2;
0437   Standard_Real aSameTol = myCurveMinTol / (aDiscTol);
0438   aFinder.SetTol(aDiscTol, aSameTol);
0439   aFinder.SetFunctionalMinimalValue(0.0); // Best distance cannot be lower than 0.0.
0440 
0441   // Size computed to have cell index inside of int32 value.
0442   const Standard_Real aCellSize = Max(Max(anIntervals1->Last() - anIntervals1->First(),
0443                                       anIntervals2->Last() - anIntervals2->First())
0444                                       * Precision::PConfusion() / (2.0 * Sqrt(2.0)),
0445                                       Precision::PConfusion());
0446   Extrema_CCPointsInspector anInspector(aCellSize);
0447   NCollection_CellFilter<Extrema_CCPointsInspector> aFilter(aCellSize);
0448   NCollection_Vector<gp_XY> aPnts;
0449 
0450   Standard_Integer i,j,k;
0451   math_Vector aFirstBorderInterval(1,2);
0452   math_Vector aSecondBorderInterval(1,2);
0453   Standard_Real aF = RealLast(); // Best functional value.
0454   Standard_Real aCurrF = RealLast(); // Current functional value computed on current interval.
0455   for(i = 1; i <= aNbInter[0]; i++)
0456   {
0457     for(j = 1; j <= aNbInter[1]; j++)
0458     {
0459       aFirstBorderInterval(1) = anIntervals1->Value(i);
0460       aFirstBorderInterval(2) = anIntervals2->Value(j); 
0461       aSecondBorderInterval(1) = anIntervals1->Value(i + 1);
0462       aSecondBorderInterval(2) = anIntervals2->Value(j + 1);
0463 
0464       aFinder.SetLocalParams(aFirstBorderInterval, aSecondBorderInterval);
0465       aFinder.Perform(GetSingleSolutionFlag());
0466 
0467       // Check that solution found on current interval is not worse than previous.
0468       aCurrF = aFinder.GetF();
0469       if (aCurrF >= aF + aSameTol * aValueTol)
0470       {
0471         continue;
0472       }
0473 
0474       // Clean previously computed solution if current one is better.
0475       if (aCurrF > aF - aSameTol * aValueTol)
0476       {
0477         if (aCurrF < aF)
0478           aF = aCurrF;
0479       }
0480       else
0481       {
0482         aF = aCurrF;
0483         aFilter.Reset(aCellSize);
0484         aPnts.Clear();
0485       }
0486 
0487       // Save found solutions avoiding repetitions.
0488       math_Vector sol(1,2);
0489       for(k = 1; k <= aFinder.NbExtrema(); k++)
0490       {
0491         aFinder.Points(k, sol);
0492         gp_XY aPnt2d(sol(1), sol(2));
0493 
0494         gp_XY aXYmin = anInspector.Shift(aPnt2d, -aCellSize);
0495         gp_XY aXYmax = anInspector.Shift(aPnt2d,  aCellSize);
0496 
0497         anInspector.ClearFind();
0498         anInspector.SetCurrent(aPnt2d);
0499         aFilter.Inspect(aXYmin, aXYmax, anInspector);
0500         if (!anInspector.isFind())
0501         {
0502           // Point is out of close cells, add new one.
0503           aFilter.Add(aPnt2d, aPnt2d);
0504           aPnts.Append(gp_XY(sol(1), sol(2)));
0505         }
0506       }
0507     }
0508   }
0509 
0510   const Standard_Integer aNbSol = aPnts.Length();
0511   if (aNbSol == 0)
0512   {
0513     // No solutions.
0514     myDone = Standard_False;
0515     return;
0516   }
0517 
0518   myDone = Standard_True;
0519 
0520   if (aNbSol == 1)
0521   {
0522     // Single solution
0523     const gp_XY& aSol = aPnts.First();
0524     myPoints1.Append(aSol.X());
0525     myPoints2.Append(aSol.Y());
0526     return;
0527   }
0528 
0529   // More than one solution is found.
0530   // Check for infinity solutions case, for this:
0531   // Sort points lexicographically and check midpoint between each two neighboring points.
0532   // If all midpoints functional value is acceptable then check the projection distances
0533   // of the bounding points of the curves onto the opposite curves.
0534   // If these distances are also acceptable set myParallel flag to true and return one solution.
0535   std::sort(aPnts.begin(), aPnts.end(), comp);
0536 
0537   // Solutions to pass into result.
0538   // If the parallel segment is found, save only extreme solutions on that segment.
0539   // The first and last solutions will always be the extreme ones, thus save them unconditionally.
0540   TColStd_ListOfInteger aSolutions;
0541 
0542   // Manages the addition of the solution into result.
0543   // Set it to TRUE to add the first solution.
0544   Standard_Boolean bSaveSolution = Standard_True;
0545 
0546   // Define direction of the second curve relatively the first one
0547   // (it will be needed for projection).
0548   Standard_Boolean bDirsCoinside = Standard_True;
0549   // Check also if the found solutions are not concentrated in one point
0550   // on any of the curves. And if they are, avoid marking the curves as parallel.
0551   Standard_Boolean bDifferentSolutions = Standard_False;
0552 
0553   Standard_Boolean isParallel = Standard_True;
0554   Standard_Real aVal = 0.0;
0555   math_Vector aVec(1, 2, 0.0);
0556 
0557   // Iterate on all solutions and collect the extreme solutions on all parallel segments.
0558   for (Standard_Integer anIdx = 0; anIdx < aNbSol - 1; anIdx++)
0559   {
0560     const gp_XY& aCurrent = aPnts(anIdx);
0561     const gp_XY& aNext    = aPnts(anIdx + 1);
0562 
0563     aVec(1) = (aCurrent.X() + aNext.X()) * 0.5;
0564     aVec(2) = (aCurrent.Y() + aNext.Y()) * 0.5;
0565 
0566     aFunc.Value(aVec, aVal);
0567     if (Abs(aVal - aF) < Precision::Confusion())
0568     {
0569       // It seems the parallel segment is found.
0570       // Save only extreme solutions on that segment.
0571       if (bSaveSolution)
0572       {
0573         // Add current solution as the beginning of the parallel segment.
0574         aSolutions.Append(anIdx);
0575         // Do not keep the next solution in current parallel segment.
0576         bSaveSolution = Standard_False;
0577       }
0578     }
0579     else
0580     {
0581       // Mid point does not satisfy the tolerance criteria, curves are not parallel.
0582       isParallel = Standard_False;
0583       // Add current solution as the last one in previous parallel segment.
0584       aSolutions.Append(anIdx);
0585       // Save also the next solution as the first one in next parallel segment.
0586       bSaveSolution = Standard_True;
0587     }
0588 
0589     if (!bDifferentSolutions)
0590     {
0591       if (aNext.X() > aCurrent.X())
0592       {
0593         if (aNext.Y() > aCurrent.Y())
0594         {
0595           bDifferentSolutions = Standard_True;
0596           bDirsCoinside = Standard_True;
0597         }
0598         else if (aNext.Y() < aCurrent.Y())
0599         {
0600           bDifferentSolutions = Standard_True;
0601           bDirsCoinside = Standard_False;
0602         }
0603       }
0604     }
0605   }
0606   // Save the last solution
0607   aSolutions.Append(aNbSol - 1);
0608 
0609   if (!bDifferentSolutions)
0610     isParallel = Standard_False;
0611 
0612   if (isParallel)
0613   {
0614     // For the check on parallel case it is also necessary to check additionally
0615     // if the ends of the curves do not diverge. For this, project the bounding
0616     // points of the curves on the opposite curves and check the distances.
0617 
0618     Standard_Real aT1[2] = {myLowBorder(1), myUppBorder(1)};
0619     Standard_Real aT2[2] = {bDirsCoinside ? myLowBorder(2) : myUppBorder(2),
0620                             bDirsCoinside ? myUppBorder(2) : myLowBorder(2)};
0621 
0622     Extrema_GExtPC anExtPC1, anExtPC2;
0623     anExtPC1.Initialize(C1, myLowBorder(1), myUppBorder(1));
0624     anExtPC2.Initialize(C2, myLowBorder(2), myUppBorder(2));
0625 
0626     for (Standard_Integer iT = 0; isParallel && (iT < 2); ++iT)
0627     {
0628       Standard_Real aDist1 = ProjPOnC(C1.Value(aT1[iT]), anExtPC2);
0629       Standard_Real aDist2 = ProjPOnC(C2.Value(aT2[iT]), anExtPC1);
0630       isParallel = (Abs(Min(aDist1, aDist2) - aF * aF) < Precision::Confusion());
0631     }
0632   }
0633 
0634   if (isParallel)
0635   {
0636     // Keep only one solution
0637     const gp_XY& aSol = aPnts.First();
0638     myPoints1.Append(aSol.X());
0639     myPoints2.Append(aSol.Y());
0640     myParallel = Standard_True;
0641   }
0642   else
0643   {
0644     // Keep all saved solutions
0645     TColStd_ListIteratorOfListOfInteger aItSol(aSolutions);
0646     for (; aItSol.More(); aItSol.Next())
0647     {
0648       const gp_XY& aSol = aPnts(aItSol.Value());
0649       myPoints1.Append(aSol.X());
0650       myPoints2.Append(aSol.Y());
0651     }
0652   }
0653 }
0654 
0655 //=======================================================================
0656 //function : IsDone
0657 //purpose  : 
0658 //=======================================================================
0659 Standard_Boolean Extrema_GenExtCC::IsDone() const 
0660 {
0661   return myDone; 
0662 }
0663 
0664 //=======================================================================
0665 //function : IsParallel
0666 //purpose  : 
0667 //=======================================================================
0668 Standard_Boolean Extrema_GenExtCC::IsParallel() const 
0669 {
0670   if (!IsDone()) throw StdFail_NotDone();
0671   return myParallel;
0672 }
0673 
0674 //=======================================================================
0675 //function : NbExt
0676 //purpose  : 
0677 //=======================================================================
0678 Standard_Integer Extrema_GenExtCC::NbExt() const
0679 {
0680   if (!IsDone()) throw StdFail_NotDone();
0681   return myPoints1.Length();
0682 }
0683 
0684 //=======================================================================
0685 //function : SquareDistance
0686 //purpose  : 
0687 //=======================================================================
0688 Standard_Real Extrema_GenExtCC::SquareDistance(const Standard_Integer N) const
0689 {
0690   if (N < 1 || N > NbExt())
0691   {
0692     throw Standard_OutOfRange();
0693   }
0694 
0695   return Tool1::Value(*((Curve1*)myC[0]), myPoints1(N)).SquareDistance(Tool2::Value(*((Curve2*)myC[1]), myPoints2(N)));
0696 }
0697 
0698 //=======================================================================
0699 //function : Points
0700 //purpose  : 
0701 //=======================================================================
0702 void Extrema_GenExtCC::Points(const Standard_Integer N,
0703                               POnC& P1,
0704                               POnC& P2) const
0705 {
0706   if (N < 1 || N > NbExt())
0707   {
0708     throw Standard_OutOfRange();
0709   }
0710 
0711   P1.SetValues(myPoints1(N), Tool1::Value(*((Curve1*)myC[0]), myPoints1(N)));
0712   P2.SetValues(myPoints2(N), Tool2::Value(*((Curve2*)myC[1]), myPoints2(N)));
0713 }
0714 
0715 //=======================================================================
0716 //function : SetSingleSolutionFlag
0717 //purpose  : 
0718 //=======================================================================
0719 void Extrema_GenExtCC::SetSingleSolutionFlag(const Standard_Boolean theFlag)
0720 {
0721   myIsFindSingleSolution = theFlag;
0722 }
0723 
0724 //=======================================================================
0725 //function : GetSingleSolutionFlag
0726 //purpose  : 
0727 //=======================================================================
0728 Standard_Boolean Extrema_GenExtCC::GetSingleSolutionFlag() const
0729 {
0730   return myIsFindSingleSolution;
0731 }