]> OCCT Git - occt-copy.git/commitdiff
# Perform localized extrema search in ComputeApproxOnPolarSurface
authoremv <emv@opencascade.com>
Wed, 27 May 2020 13:42:36 +0000 (16:42 +0300)
committeremv <emv@opencascade.com>
Wed, 26 Aug 2020 13:45:17 +0000 (16:45 +0300)
src/Extrema/Extrema_ExtPS.cxx
src/Extrema/Extrema_ExtPS.hxx
src/Extrema/Extrema_GenExtPS.cxx
src/Extrema/Extrema_GenExtPS.hxx
src/ProjLib/ProjLib_ComputeApproxOnPolarSurface.cxx

index 94b486d71ac247083026c0507062340647d32146..b38ab1215de402b3b6f9f894b8a0d94a95d442dc 100644 (file)
@@ -112,25 +112,25 @@ void Extrema_ExtPS::TreatSolution (const Extrema_POnSurf& PS,
   Standard_Real U, V;
   PS.Parameter(U, V);
   if (myS->IsUPeriodic()) {
-    U = ElCLib::InPeriod(U, myuinf, myuinf + myS->UPeriod());
+    U = ElCLib::InPeriod(U, myLocUMin, myLocUMin + myS->UPeriod());
     
     // Handle trimmed surfaces.
-    if (U > myusup + mytolu)
+    if (U > myLocUMax + mytolu)
       U -= myS->UPeriod();
-    if (U < myuinf - mytolu)
+    if (U < myLocUMin - mytolu)
       U += myS->UPeriod();
   }
   if (myS->IsVPeriodic()) {
-    V = ElCLib::InPeriod(V, myvinf, myvinf + myS->VPeriod());
+    V = ElCLib::InPeriod(V, myLocVMin, myLocVMin + myS->VPeriod());
 
     // Handle trimmed surfaces.
-    if (V > myvsup + mytolv)
+    if (V > myLocVMax + mytolv)
       V -= myS->VPeriod();
-    if (V < myvinf - mytolv)
+    if (V < myLocVMin - mytolv)
       V += myS->VPeriod();
   }
-  if ((myuinf-U) <= mytolu && (U-myusup) <= mytolu &&
-      (myvinf-V) <= mytolv && (V-myvsup) <= mytolv) {
+  if ((myLocUMin-U) <= mytolu && (U-myLocUMax) <= mytolu &&
+      (myLocVMin-V) <= mytolv && (V-myLocVMax) <= mytolv) {
     myPoints.Append(Extrema_POnSurf (U, V, PS.Value()));
     mySqDist.Append(Val);
   }
@@ -237,6 +237,11 @@ void Extrema_ExtPS::Initialize (const Adaptor3d_Surface& theS,
   if (Precision::IsNegativeInfinite(myvinf)) myvinf = -1e10;
   if (Precision::IsPositiveInfinite(myvsup)) myvsup = 1e10;
 
+  myLocUMin = myuinf;
+  myLocUMax = myusup;
+  myLocVMin = myvinf;
+  myLocVMax = myvsup;
+
   mytolu = theTolU;
   mytolv = theTolV;
   mytype = myS->GetType();
@@ -272,12 +277,29 @@ void Extrema_ExtPS::Initialize (const Adaptor3d_Surface& theS,
 //function : Perform
 //purpose  : 
 //=======================================================================
+void Extrema_ExtPS::Perform (const gp_Pnt& thePoint)
+{
+  Perform (thePoint, myuinf, myusup, myvinf, myvsup);
+}
 
-void Extrema_ExtPS::Perform(const gp_Pnt& thePoint)
+//=======================================================================
+//function : Perform
+//purpose  : 
+//=======================================================================
+void Extrema_ExtPS::Perform (const gp_Pnt& thePoint,
+                             const Standard_Real theLocUMin,
+                             const Standard_Real theLocUMax,
+                             const Standard_Real theLocVMin,
+                             const Standard_Real theLocVMax)
 {
   myPoints.Clear();
   mySqDist.Clear();
 
+  myLocUMin = Max (theLocUMin, myuinf);
+  myLocUMax = Min (theLocUMax, myusup);
+  myLocVMin = Max (theLocVMin, myvinf);
+  myLocVMax = Min (theLocVMax, myvsup);
+
   switch (mytype)
   {
     case GeomAbs_Cylinder:
@@ -350,7 +372,7 @@ void Extrema_ExtPS::Perform(const gp_Pnt& thePoint)
 
     default:
     {
-      myExtPS->Perform (thePoint);
+      myExtPS->Perform (thePoint, myLocUMin, myLocUMax, myLocVMin, myLocVMax);
       myDone = myExtPS->IsDone();
       if (myDone)
       {
index 722938471c0428fa74f5a1871c347ddbc14319b1..41837021a0b0f6c43dc169d1d8625e6521d4c8c6 100644 (file)
@@ -100,6 +100,15 @@ public:
   //! initialized.
   Standard_EXPORT void Perform (const gp_Pnt& P);
   
+  //! Performs localized extrema search.
+  //! The solution to be found in the given parametric space, which
+  //! is required to be inside the initialized parametric space.
+  Standard_EXPORT void Perform (const gp_Pnt& P,
+                                const Standard_Real theLocUMin,
+                                const Standard_Real theLocUMax,
+                                const Standard_Real theLocVMin,
+                                const Standard_Real theLocVMax);
+
   //! Returns True if the distances are found.
   Standard_EXPORT Standard_Boolean IsDone() const;
   
@@ -152,6 +161,10 @@ private:
   Standard_Real myvsup;
   Standard_Real mytolu;
   Standard_Real mytolv;
+  Standard_Real myLocUMin; //!< Localized parametric space boundary (required to be inside the main parametric space)
+  Standard_Real myLocUMax; //!< Localized parametric space boundary (required to be inside the main parametric space)
+  Standard_Real myLocVMin; //!< Localized parametric space boundary (required to be inside the main parametric space)
+  Standard_Real myLocVMax; //!< Localized parametric space boundary (required to be inside the main parametric space)
   Standard_Real d11;
   Standard_Real d12;
   Standard_Real d21;
index e038d17b7a82454befa6e5c7ed1483647c07556f..15fd6153f4c21e407eca63b3dd22bc66cbf59084 100644 (file)
@@ -108,6 +108,10 @@ Extrema_GenExtPS::Extrema_GenExtPS()
   myNbVSamples (0),
   myTolU (Precision::PConfusion()),
   myTolV (Precision::PConfusion()),
+  myLocUMin (RealLast()),
+  myLocUMax (RealFirst()),
+  myLocVMin (RealLast()),
+  myLocVMax (RealFirst()),
   myTarget (Extrema_ExtFlag_MINMAX),
   mySqDistance (-1),
   myIsDone (Standard_False)
@@ -211,6 +215,11 @@ void Extrema_GenExtPS::Initialize (const Adaptor3d_Surface& theS,
   myTolU = theTolU;
   myTolV = theTolV;
 
+  myLocUMin = myUMin;
+  myLocUMax = myUMax;
+  myLocVMin = myVMin;
+  myLocVMax = myVMax;
+
   if (myNbUSamples < 2 || myNbVSamples < 2)
   {
     throw Standard_OutOfRange ("Extrema_GenExtPS::Initialize - number of samples is too small");
@@ -228,12 +237,30 @@ void Extrema_GenExtPS::Initialize (const Adaptor3d_Surface& theS,
 //purpose  : 
 //=======================================================================
 void Extrema_GenExtPS::Perform (const gp_Pnt& thePoint)
+{
+  Perform (thePoint, myUMin, myUMax, myVMin, myVMax);
+}
+
+//=======================================================================
+//function : Perform
+//purpose  : 
+//=======================================================================
+void Extrema_GenExtPS::Perform (const gp_Pnt& thePoint,
+                                const Standard_Real theUMin,
+                                const Standard_Real theUMax,
+                                const Standard_Real theVMin,
+                                const Standard_Real theVMax)
 {
   myIsDone = Standard_False;
   myPoint = BVH_Vec3d (thePoint.X(), thePoint.Y(), thePoint.Z());
   myF.SetPoint (thePoint, myTarget);
   mySolutions.clear();
 
+  myLocUMin = Max (theUMin, myUMin);
+  myLocUMax = Min (theUMax, myUMax);
+  myLocVMin = Max (theVMin, myVMin);
+  myLocVMax = Min (theVMax, myVMax);
+
   if (myUParams.IsNull() || myVParams.IsNull())
   {
     // Prepare surface sampling
@@ -318,7 +345,7 @@ void Extrema_GenExtPS::Perform (const gp_Pnt& thePoint)
     // Copy solutions
     for (Standard_Integer i = 1; i <= myF.NbExt(); ++i)
     {
-      mySolutions.push_back (Extrema_GenExtPS::ExtPSResult (myF.Point (i), myF.SquareDistance (i)));
+      mySolutions.push_back (Extrema_GenExtPS_ExtPSResult (myF.Point (i), myF.SquareDistance (i)));
     }
   }
   else
@@ -331,7 +358,7 @@ void Extrema_GenExtPS::Perform (const gp_Pnt& thePoint)
     for (Standard_Integer i = 1; i <= myF.NbExt(); ++i)
     {
       if (Abs (mySqDistance - myF.SquareDistance (i)) < Precision::SquareConfusion())
-        mySolutions.push_back (Extrema_GenExtPS::ExtPSResult (myF.Point (i), myF.SquareDistance (i)));
+        mySolutions.push_back (Extrema_GenExtPS_ExtPSResult (myF.Point (i), myF.SquareDistance (i)));
     }
   }
 
@@ -406,7 +433,7 @@ void Extrema_GenExtPS::BuildTree()
     // Builder for low-level BVH sets
     opencascade::handle<BVH_LinearBuilder<Standard_Real, 3> > aLBuilder = new BVH_LinearBuilder<Standard_Real, 3>();
 
-    myBVHBoxSet = new BVH_IndexedBoxSet<Standard_Real, 3, Handle (Extrema_GenExtPS_GridCellBoxSet)> (
+    myBVHBoxSet = new BVH_IndexedBoxSet<Standard_Real, 3, Extrema_GenExtPS_LocalizedSurf> (
       new BVH_LinearBuilder<Standard_Real, 3> (BVH_Constants_LeafNodeSizeSingle));
 
     // create hierarchy of BVH trees
@@ -433,12 +460,27 @@ void Extrema_GenExtPS::BuildTree()
         {
           for (Standard_Integer iV = V1; iV <= V2; ++iV)
           {
-            aGridSet->Add (GridCell (iU, iV), BVH_Box<Standard_Real, 3>());
+            aGridSet->Add (Extrema_GenExtPS_GridCell (iU, iV), BVH_Box<Standard_Real, 3>());
           }
         }
         V1 = V2 + 1;
 
-        myBVHBoxSet->Add (aGridSet, BVH_Box<Standard_Real, 3>());
+        Extrema_GenExtPS_GridCell aMinCell = aGridSet->Element (0);
+        Extrema_GenExtPS_GridCell aMaxCell = aGridSet->Element (aGridSet->Size() - 1);
+
+        Standard_Integer aUCoeff = (aMaxCell.UIndex < myNbUSamples) ? 1 : 0;
+        Standard_Integer aVCoeff = (aMaxCell.VIndex < myNbVSamples) ? 1 : 0;
+
+        const Extrema_POnSurf& aPMin = myPoints->Value (aMinCell.UIndex, aMinCell.VIndex);
+        const Extrema_POnSurf& aPMax = myPoints->Value (aMaxCell.UIndex + aUCoeff, aMaxCell.VIndex + aVCoeff);
+
+        Standard_Real aUMin, aUMax, aVMin, aVMax;
+        aPMin.Parameter (aUMin, aVMin);
+        aPMax.Parameter (aUMax, aVMax);
+
+        myBVHBoxSet->Add (
+          Extrema_GenExtPS_LocalizedSurf (aUMin, aUMax, aVMin, aVMax, aGridSet),
+          BVH_Box<Standard_Real, 3>());
       }
       U1 = U2 + 1;
       V1 = 1;
@@ -451,14 +493,14 @@ void Extrema_GenExtPS::BuildTree()
     const Standard_Integer aNbSets = myBVHBoxSet->Size();
     for (Standard_Integer iSet = 0; iSet < aNbSets; ++iSet)
     {
-      Handle (Extrema_GenExtPS_GridCellBoxSet) aGridSet = myBVHBoxSet->Element (iSet);
+      Extrema_GenExtPS_LocalizedSurf aGridSet = myBVHBoxSet->Element (iSet);
 
       // Box of the set
       Bnd_Box aSetBox;
-      const Standard_Integer aNbCells = aGridSet->Size();
+      const Standard_Integer aNbCells = aGridSet.CellBoxSet->Size();
       for (Standard_Integer iCell = 0; iCell < aNbCells; ++iCell)
       {
-        const GridCell& aCell = aGridSet->Element (iCell);
+        const Extrema_GenExtPS_GridCell& aCell = aGridSet.CellBoxSet->Element (iCell);
         Standard_Integer iU = aCell.UIndex, iV = aCell.VIndex;
 
         Standard_Integer aUCoeff = (iU < myNbUSamples) ? 1 : 0;
@@ -496,7 +538,7 @@ void Extrema_GenExtPS::BuildTree()
           //Standard_Real anAvSqExt = aSetBox.SquareExtent() / (aGridSet->Size() - 1);
           //aGridBox.Enlarge (Sqrt (anAvSqExt));
         }
-        aGridSet->UpdateBox (iCell, Bnd_Tools::Bnd2BVH (aGridBox));
+        aGridSet.CellBoxSet->UpdateBox (iCell, Bnd_Tools::Bnd2BVH (aGridBox));
 
         aSetBox.Add (aGridBox);
       }
@@ -653,10 +695,14 @@ Standard_Boolean Extrema_GenExtPS::Accept (const Standard_Integer theIndex,
 {
   if (myBVHSet == NULL)
   {
-    Handle (Extrema_GenExtPS_GridCellBoxSet) aGridSet = myBVHBoxSet->Element (theIndex);
-    aGridSet->Build();
+    Extrema_GenExtPS_LocalizedSurf aGridSet = myBVHBoxSet->Element (theIndex);
+    if ((aGridSet.UMax < myLocUMin || aGridSet.UMin > myLocUMax) &&
+        (aGridSet.VMax < myLocVMin || aGridSet.VMin > myLocVMax))
+      return 0;
+
+    aGridSet.CellBoxSet->Build();
     // Set low-level BVH set for inner selection
-    SetBVHSet (aGridSet.get());
+    SetBVHSet (aGridSet.CellBoxSet.get());
     Standard_Integer aNb = Select();
     // Unset the inner set and continue with high level BVH traverse
     SetBVHSet (NULL);
@@ -664,7 +710,7 @@ Standard_Boolean Extrema_GenExtPS::Accept (const Standard_Integer theIndex,
   }
   else
   {
-    GridCell aCell = myBVHSet->Element (theIndex);
+    Extrema_GenExtPS_GridCell aCell = myBVHSet->Element (theIndex);
     return FindSolution (aCell.UIndex, aCell.VIndex, myTarget);
   }
 }
@@ -677,13 +723,21 @@ Standard_Boolean Extrema_GenExtPS::FindSolution (const Standard_Integer theNU,
                                                  const Standard_Integer theNV,
                                                  const Extrema_ExtFlag theTarget)
 {
-
   // Fill corner points with square distance to myPoint
   Extrema_POnSurfParams& aParam00 = myPoints->ChangeValue (theNU, theNV);
   Extrema_POnSurfParams& aParam01 = myPoints->ChangeValue (theNU, theNV + 1);
   Extrema_POnSurfParams& aParam10 = myPoints->ChangeValue (theNU + 1, theNV);
   Extrema_POnSurfParams& aParam11 = myPoints->ChangeValue (theNU + 1, theNV + 1);
 
+  {
+    Standard_Real U1, U2, V1, V2;
+    aParam00.Parameter (U1, V1);
+    aParam11.Parameter (U2, V2);
+    if ((U2 < myLocUMin || U1 > myLocUMax) &&
+        (V2 < myLocVMin || V1 > myLocVMax))
+      return Standard_False;
+  }
+
   gp_Pnt aPoint (myPoint.x(), myPoint.y(), myPoint.z());
 
   fillSqDist (aParam00, aPoint);
index b6b49e76027f56e5eb6fee4ea45760fb265edb4d..795602c9806e2424ad2f1fca75c320d8f8fe6cae 100644 (file)
@@ -45,18 +45,18 @@ class Extrema_POnSurfParams;
 
 //! Grid cell defined by (U, V) indices of the minimal
 //! corner of the cell
-struct GridCell
+struct Extrema_GenExtPS_GridCell
 {
   Standard_Integer UIndex; //!< U index of the minimal corner
   Standard_Integer VIndex; //!< V index of the minimal corner
 
-  GridCell (Standard_Integer theUInd = -1, Standard_Integer theVInd = -1)
+  Extrema_GenExtPS_GridCell (Standard_Integer theUInd = -1, Standard_Integer theVInd = -1)
     : UIndex (theUInd), VIndex (theVInd)
   {}
 };
 
 //! typedef to BVH tree of the grid cells
-typedef BVH_BoxSet <Standard_Real, 3, GridCell> Extrema_GenExtPS_GridCellBoxSet;
+typedef BVH_BoxSet <Standard_Real, 3, Extrema_GenExtPS_GridCell> Extrema_GenExtPS_GridCellBoxSet;
 
 
 //! It calculates the extreme distances between a point and a surface.
@@ -219,7 +219,15 @@ public: //! @name Performing projection
   //! Allows multiple points be projected on the same surface.
   Standard_EXPORT void Perform (const gp_Pnt& theP);
 
-
+  //! Performs localized extrema search.
+  //! The localized boundaries are required to be inside the
+  //! main (initialized) surface parametric space.
+  Standard_EXPORT void Perform (const gp_Pnt& theP,
+                                const Standard_Real theUMin,
+                                const Standard_Real theUMax,
+                                const Standard_Real theVMin,
+                                const Standard_Real theVMax);
+  
 public: //! @name Getting the results
 
   //! Returns True if the distances are found.
@@ -308,23 +316,23 @@ protected: //! @name Rules for BVH traverse
 protected: //! @name Auxiliary types
 
   //! Structure to keep and sort the results
-  struct ExtPSResult
+  struct Extrema_GenExtPS_ExtPSResult
   {
     Extrema_POnSurf UV;       //! UV coordinates of extrema solution
     Standard_Real SqDistance; //! Square distance to target point
 
-    ExtPSResult()
+    Extrema_GenExtPS_ExtPSResult()
       : SqDistance (-1)
     {}
 
-    ExtPSResult (const Extrema_POnSurf& theUV,
-                 const Standard_Real theSqDist)
+    Extrema_GenExtPS_ExtPSResult (const Extrema_POnSurf& theUV,
+                                  const Standard_Real theSqDist)
       : UV (theUV),
         SqDistance (theSqDist)
     {}
 
     //! IsLess operator
-    Standard_Boolean operator< (const ExtPSResult& Other) const
+    Standard_Boolean operator< (const Extrema_GenExtPS_ExtPSResult& Other) const
     {
       if (SqDistance != Other.SqDistance)
         return SqDistance < Other.SqDistance;
@@ -336,6 +344,29 @@ protected: //! @name Auxiliary types
     }
   };
 
+  //! Localized parametric space of surface on which the single
+  //! BVH tree is built
+  struct Extrema_GenExtPS_LocalizedSurf
+  {
+    Standard_Real UMin;
+    Standard_Real UMax;
+    Standard_Real VMin;
+    Standard_Real VMax;
+    Handle(Extrema_GenExtPS_GridCellBoxSet) CellBoxSet;
+
+    Extrema_GenExtPS_LocalizedSurf ()
+      : UMin (0.0), UMax (0.0), VMin (0.0), VMax (0.0), CellBoxSet (NULL)
+    {}
+
+    Extrema_GenExtPS_LocalizedSurf (const Standard_Real theUMin,
+                                    const Standard_Real theUMax,
+                                    const Standard_Real theVMin,
+                                    const Standard_Real theVMax,
+                                    const Handle(Extrema_GenExtPS_GridCellBoxSet)& theCellBoxSet)
+      : UMin (theUMin), UMax (theUMax), VMin (theVMin), VMax (theVMax), CellBoxSet (theCellBoxSet)
+    {}
+  };
+
 protected: //! @name Fields
 
   // Inputs
@@ -354,6 +385,11 @@ protected: //! @name Fields
   Standard_Real myTolU;     //!< U parametric tolerance
   Standard_Real myTolV;     //!< V parametric tolerance
 
+  Standard_Real myLocUMin; //!< Localized surface parametric range: UMin
+  Standard_Real myLocUMax; //!< Localized surface parametric range: UMax
+  Standard_Real myLocVMin; //!< Localized surface parametric range: VMin
+  Standard_Real myLocVMax; //!< Localized surface parametric range: VMax
+
   Extrema_ExtFlag myTarget; //!< Extrema objective
 
   // Intermediate data
@@ -368,11 +404,11 @@ protected: //! @name Fields
 
   Standard_Real mySqDistance; //!< Min/Max found square distance used in BVH tree traverse
   opencascade::handle 
-    <BVH_IndexedBoxSet<Standard_Real, 3, Handle(Extrema_GenExtPS_GridCellBoxSet)> > myBVHBoxSet; //!< High-level BVH of BVH organized grid cells
+    <BVH_IndexedBoxSet<Standard_Real, 3, Extrema_GenExtPS_LocalizedSurf> > myBVHBoxSet; //!< High-level BVH of BVH organized grid cells
 
   // Results
-  std::vector <ExtPSResult> mySolutions; //!< Found solutions (sorted first by distance to target point,
-                                         //!  second by the ascending U,V coordinates)
+  std::vector <Extrema_GenExtPS_ExtPSResult> mySolutions; //!< Found solutions (sorted first by distance to target point,
+                                                          //!  second by the ascending U,V coordinates)
   Standard_Boolean myIsDone;             //!< Done/Not done flag
 };
 
index 491e88380ef2eae9295427c19d0c6a11fa034160..ca8d02ee3bf156ae09cee90fb90ea69cf5f68b76 100644 (file)
@@ -95,6 +95,7 @@ struct aFuncStruct
   Handle(Adaptor3d_HSurface) mySurf; // Surface where to project.
   Handle(Adaptor3d_HCurve)   myCurve; // Curve to project.
   Handle(Adaptor2d_HCurve2d) myInitCurve2d; // Initial 2dcurve projection.
+  mutable Extrema_ExtPS myGlobExtPS; // Extrema initialized on whole parameter space of the surface
   Standard_Real mySqProjOrtTol; // Used to filter non-orthogonal projected point.
   Standard_Real myTolU;
   Standard_Real myTolV;
@@ -190,6 +191,73 @@ static Standard_Real anOrthogSqValue(const gp_Pnt& aBasePnt,
   return (aFirstPart * aFirstPart + aSecondPart * aSecondPart);
 }
 
+//=======================================================================
+//function : checkSolution
+//purpose  : checks if the current solution is better than initial point
+//=======================================================================
+static Standard_Boolean checkSolution (const Extrema_POnSurf& theSol,
+                                       const Standard_Real theProjSqDist,
+                                       const Handle(Adaptor3d_HSurface)& theSurf,
+                                       const Standard_Real theUPeriod,
+                                       const Standard_Real theVPeriod,
+                                       const Standard_Integer theNbU,
+                                       const Standard_Integer theNbV,
+                                       const gp_Pnt& thePoint,
+                                       const Standard_Real theProjTol,
+                                       const Standard_Real theDist,
+                                       gp_Pnt2d& thePOnSurf)
+{
+  Standard_Real U, V;
+  theSol.Parameter (U, V);
+  Standard_Real Dist2Min = anOrthogSqValue (thePoint, theSurf, U, V);
+  if (Dist2Min < theProjTol && // Point is projection.
+      theProjSqDist < theDist + Precision::SquareConfusion()) // Point better than initial.
+  {
+    thePOnSurf.SetXY (gp_XY (U - theNbU * theUPeriod, V - theNbV * theVPeriod));
+    return Standard_True;
+  }
+  return Standard_False;
+}
+
+//=======================================================================
+//function : checkSolution
+//purpose  : checks solutions found by extrema
+//=======================================================================
+static Standard_Boolean checkSolution (const Extrema_ExtPS& theExtrema,
+                                       const Handle(Adaptor3d_HSurface)& theSurf,
+                                       const Standard_Real theUPeriod,
+                                       const Standard_Real theVPeriod,
+                                       const Standard_Integer theNbU,
+                                       const Standard_Integer theNbV,
+                                       const gp_Pnt& thePoint,
+                                       const Standard_Real theProjTol,
+                                       const Standard_Real theDist,
+                                       gp_Pnt2d& theSolution)
+{
+  if (!theExtrema.IsDone() || !theExtrema.NbExt())
+    return Standard_False;
+
+  Standard_Real aDist2Min = RealLast();
+  Standard_Integer iGoodValue = -1;
+
+  for (Standard_Integer i = 1; i <= theExtrema.NbExt(); i++)
+  {
+    if (aDist2Min > theExtrema.SquareDistance(i))
+    {
+      aDist2Min = theExtrema.SquareDistance(i);
+      iGoodValue = i;
+    }
+  }
+
+  if (iGoodValue < 1)
+    return Standard_False;
+
+  return checkSolution (theExtrema.Point (iGoodValue), theExtrema.SquareDistance (iGoodValue),
+                        theSurf, theUPeriod, theVPeriod, theNbU, theNbV,
+                        thePoint, theProjTol, theDist, theSolution);
+}
+
+
 //=======================================================================
 //function : Value
 //purpose  : (OCC217 - apo)- Compute Point2d that project on polar surface(<Surf>) 3D<Curve>
@@ -298,10 +366,8 @@ static gp_Pnt2d Function_Value(const Standard_Real theU,
   }
 
   // Non-analytical case.
-  Standard_Real Dist2Min = RealLast();
   Standard_Real uperiod = theData.myPeriod[0],
-                vperiod = theData.myPeriod[1],
-                u, v;
+                vperiod = theData.myPeriod[1];
 
   // U0 and V0 are the points within the initialized period.
   if(U0 < Uinf)
@@ -379,36 +445,31 @@ static gp_Pnt2d Function_Value(const Standard_Real theU,
   locext.Perform(p, U0, V0);
   if (locext.IsDone()) 
   {
-    locext.Point().Parameter(u, v);
-    Dist2Min = anOrthogSqValue(p, theData.mySurf, u, v);
-    if (Dist2Min < theData.mySqProjOrtTol && // Point is projection.
-        locext.SquareDistance() < aSurfPntDist + Precision::SquareConfusion()) // Point better than initial.
+    gp_Pnt2d pnt;
+    if (checkSolution (locext.Point(), locext.SquareDistance(),
+                       theData.mySurf, uperiod, vperiod, decalU, decalV,
+                       p, theData.mySqProjOrtTol, aSurfPntDist, pnt))
     {
-      gp_Pnt2d pnt(u - decalU*uperiod,v - decalV*vperiod);
       return pnt;
     }
   }
 
-  // Perform whole param space search.
-  Extrema_ExtPS  ext(p, SurfLittle, theData.myTolU, theData.myTolV);
+  // Perform search on the whole parametric space using preinitialized extrema.
+  theData.myGlobExtPS.Perform (p, uInfLi, uSupLi, vInfLi, vSupLi);
+  gp_Pnt2d pnt;
+  if (checkSolution (theData.myGlobExtPS, theData.mySurf, uperiod, vperiod, decalU, decalV,
+                     p, theData.mySqProjOrtTol, aSurfPntDist, pnt))
+  {
+    return pnt;
+  }
+
+  // Perform search on the decreased parametric space.
+  Extrema_ExtPS  ext(p, SurfLittle, theData.myTolU, theData.myTolV, Extrema_ExtFlag_MIN);
   if (ext.IsDone() && ext.NbExt() >= 1)
   {
-    Dist2Min = ext.SquareDistance(1);
-    Standard_Integer GoodValue = 1;
-    for (Standard_Integer i = 2 ; i <= ext.NbExt() ; i++ )
+    if (checkSolution (ext, theData.mySurf, uperiod, vperiod, decalU, decalV,
+                       p, theData.mySqProjOrtTol, aSurfPntDist, pnt))
     {
-      if( Dist2Min > ext.SquareDistance(i))
-      {
-        Dist2Min = ext.SquareDistance(i);
-        GoodValue = i;
-      }
-    }
-    ext.Point(GoodValue).Parameter(u, v);
-    Dist2Min = anOrthogSqValue(p, theData.mySurf, u, v);
-    if (Dist2Min < theData.mySqProjOrtTol && // Point is projection.
-        ext.SquareDistance(GoodValue) < aSurfPntDist + Precision::SquareConfusion()) // Point better than initial.
-    {
-      gp_Pnt2d pnt(u - decalU*uperiod,v - decalV*vperiod);
       return pnt;
     }
   }
@@ -445,6 +506,14 @@ class ProjLib_PolarFunction : public AppCont_Function
     myStruct.mySqProjOrtTol = 10000.0 * Tol3d * Tol3d;
     myStruct.myTolU = Surf->UResolution(Tol3d);
     myStruct.myTolV = Surf->VResolution(Tol3d);
+
+    Standard_Real Uinf, Usup, Vinf, Vsup;
+    Uinf = Surf->Surface().FirstUParameter();
+    Usup = Surf->Surface().LastUParameter();
+    Vinf = Surf->Surface().FirstVParameter();
+    Vsup = Surf->Surface().LastVParameter();
+    myStruct.myGlobExtPS.Initialize (Surf->Surface(), Uinf, Usup, Vinf, Vsup, myStruct.myTolU, myStruct.myTolV);
+    myStruct.myGlobExtPS.SetFlag (Extrema_ExtFlag_MIN);
   }
 
   ~ProjLib_PolarFunction() {}