]> OCCT Git - occt-copy.git/commitdiff
# build hierarchy of BVH trees
authoremv <emv@opencascade.com>
Mon, 18 May 2020 08:55:47 +0000 (11:55 +0300)
committeremv <emv@opencascade.com>
Mon, 18 May 2020 20:27:31 +0000 (23:27 +0300)
src/BRepLib/BRepLib_FindSurface.cxx
src/Extrema/Extrema_GenExtPS.cxx
src/Extrema/Extrema_GenExtPS.hxx
src/GCPnts/FILES
src/GCPnts/GCPnts.cxx [new file with mode: 0644]
src/GCPnts/GCPnts.hxx [new file with mode: 0644]

index 8906a82b0885a09f3bac76a563c6ff7be3d73846..1f3c9fd5047f79b2e9896a9a8ceef92dd2352ffb 100644 (file)
@@ -23,6 +23,7 @@
 #include <BRepLib_MakeFace.hxx>
 #include <BRepTools_WireExplorer.hxx>
 #include <BRepTopAdaptor_FClass2d.hxx>
+#include <GCPnts.hxx>
 #include <Geom2d_Curve.hxx>
 #include <Geom_BezierCurve.hxx>
 #include <Geom_BSplineCurve.hxx>
@@ -178,39 +179,6 @@ BRepLib_FindSurface::BRepLib_FindSurface(const TopoDS_Shape&    S,
 
 namespace
 {
-static void fillParams (const TColStd_Array1OfReal& theKnots,
-                        Standard_Integer theDegree,
-                        Standard_Real theParMin,
-                        Standard_Real theParMax,
-                        NCollection_Vector<Standard_Real>& theParams)
-{
-  Standard_Real aPrevPar = theParMin;
-  theParams.Append (aPrevPar);
-
-  Standard_Integer aNbP = Max (theDegree, 1);
-
-  for (Standard_Integer i = 1;
-       (i < theKnots.Length()) && (theKnots (i) < (theParMax - Precision::PConfusion())); ++i)
-  {
-    if (theKnots (i + 1) < theParMin + Precision::PConfusion())
-      continue;
-
-    Standard_Real aStep = (theKnots (i + 1) - theKnots (i)) / aNbP;
-    for (Standard_Integer k = 1; k <= aNbP ; ++k)
-    {
-      Standard_Real aPar = theKnots (i) + k * aStep;
-      if (aPar > theParMax - Precision::PConfusion())
-        break;
-
-      if (aPar > aPrevPar + Precision::PConfusion())
-      {
-        theParams.Append (aPar);
-        aPrevPar = aPar;
-      }
-    }
-  }
-  theParams.Append (theParMax);
-}
 
 static void fillPoints (const BRepAdaptor_Curve& theCurve,
                         const NCollection_Vector<Standard_Real> theParams,
@@ -358,13 +326,13 @@ void BRepLib_FindSurface::Init(const TopoDS_Shape&    S,
         aKnots.SetValue (1, GC->FirstParameter());
         aKnots.SetValue (2, GC->LastParameter());
 
-        fillParams (aKnots, GC->Degree(), dfUf, dfUl, aParams);
+        GCPnts::FillParams (aKnots, GC->Degree(), dfUf, dfUl, aParams);
         break;
       }
       case GeomAbs_BSplineCurve:
       {
         Handle(Geom_BSplineCurve) GC = c.BSpline();
-        fillParams (GC->Knots(), GC->Degree(), dfUf, dfUl, aParams);
+        GCPnts::FillParams (GC->Knots(), GC->Degree(), dfUf, dfUl, aParams);
         break;
       }
       case GeomAbs_Line:
@@ -391,7 +359,7 @@ void BRepLib_FindSurface::Init(const TopoDS_Shape&    S,
         aBounds.SetValue (1, dfUf);
         aBounds.SetValue (2, dfUl);
 
-        fillParams (aBounds, iNbPoints - 1, dfUf, dfUl, aParams);
+        GCPnts::FillParams (aBounds, iNbPoints - 1, dfUf, dfUl, aParams);
       }
     }
 
index 23e381bf97a76c0b5f01895dbd40697cc62e255f..ed6fc06c80e470e9bdc97b3a87afbb1f2f2e279d 100644 (file)
@@ -23,6 +23,7 @@
 #include <BndLib_AddSurface.hxx>
 #include <BVH_LinearBuilder.hxx>
 #include <BVH_Tools.hxx>
+#include <GCPnts.hxx>
 #include <Geom_BezierCurve.hxx>
 #include <Geom_BezierSurface.hxx>
 #include <Geom_BSplineCurve.hxx>
@@ -37,83 +38,59 @@ IMPLEMENT_STANDARD_RTTIEXT (Extrema_GenExtPS, Standard_Transient)
 // Static methods definition
 namespace
 {
-//=======================================================================
-//function : fillParams
-//purpose  : 
-//=======================================================================
-static void fillParams (const TColStd_Array1OfReal& theKnots,
-                        Standard_Integer theDegree,
-                        Standard_Real theParMin,
-                        Standard_Real theParMax,
-                        Handle (TColStd_HArray1OfReal)& theParams,
-                        Standard_Integer theNbSample)
-{
-  NCollection_Vector<Standard_Real> aParams;
-  Standard_Integer i = 1;
-  Standard_Real aPrevPar = theParMin;
-  aParams.Append (aPrevPar);
-  // Calculation the array of parametric points depending on the knots array variation and degree of given surface
-  for (; i < theKnots.Length() && theKnots (i) < (theParMax - Precision::PConfusion()); i++)
+  //=======================================================================
+  //function : fillParams
+  //purpose  : 
+  //=======================================================================
+  static void fillParams (const TColStd_Array1OfReal& theKnots,
+                          const Standard_Integer theDegree,
+                          const Standard_Real theParMin,
+                          const Standard_Real theParMax,
+                          Standard_Integer theNbSamples,
+                          Handle (TColStd_HArray1OfReal)& theParams)
   {
-    if (theKnots (i + 1) < theParMin + Precision::PConfusion())
-      continue;
+    NCollection_Vector<Standard_Real> aParams;
+    GCPnts::FillParams (theKnots, theDegree, theParMin, theParMax, aParams);
+    Standard_Integer nbPar = aParams.Length();
 
-    Standard_Real aStep = (theKnots (i + 1) - theKnots (i)) / Max (theDegree, 2);
-    Standard_Integer k = 1;
-    for (; k <= theDegree; k++)
-    {
-      Standard_Real aPar = theKnots (i) + k * aStep;
-      if (aPar > theParMax - Precision::PConfusion())
-        break;
-      if (aPar > aPrevPar + Precision::PConfusion())
-      {
-        aParams.Append (aPar);
-        aPrevPar = aPar;
-      }
-    }
-  }
-
-  aParams.Append (theParMax);
-  Standard_Integer nbPar = aParams.Length();
-
-  // In case of an insufficient number of points the grid will be built later 
-  if (nbPar < theNbSample)
-    return;
+    // In case of an insufficient number of points the grid will be built later 
+    if (nbPar < theNbSamples)
+      return;
 
-  theParams = new TColStd_HArray1OfReal (1, nbPar);
-  for (i = 0; i < nbPar; i++)
-    theParams->SetValue (i + 1, aParams (i));
-}
+    theParams = new TColStd_HArray1OfReal (1, nbPar);
+    for (Standard_Integer i = 0; i < nbPar; i++)
+      theParams->SetValue (i + 1, aParams (i));
+  }
 
-//=======================================================================
-//function : fillParams
-//purpose  : 
-//=======================================================================
-static void fillParams (Standard_Real theParMin,
-                        Standard_Real theParMax,
-                        Handle (TColStd_HArray1OfReal)& theParams,
-                        Standard_Integer theNbSamples)
-{
-  Standard_Real PasU = theParMax - theParMin;
-  Standard_Real U0 = PasU / theNbSamples / 100.;
-  PasU = (PasU - U0) / (theNbSamples - 1);
-  U0 = U0 / 2. + theParMin;
-  theParams = new TColStd_HArray1OfReal (1, theNbSamples);
-  Standard_Real U = U0;
-  for (int NoU = 1; NoU <= theNbSamples; NoU++, U += PasU)
-    theParams->SetValue (NoU, U);
-}
+  //=======================================================================
+  //function : fillParams
+  //purpose  : 
+  //=======================================================================
+  static void fillParams (Standard_Real theParMin,
+                          Standard_Real theParMax,
+                          Handle (TColStd_HArray1OfReal)& theParams,
+                          Standard_Integer theNbSamples)
+  {
+    Standard_Real PasU = theParMax - theParMin;
+    Standard_Real U0 = PasU / theNbSamples / 100.;
+    PasU = (PasU - U0) / (theNbSamples - 1);
+    U0 = U0 / 2. + theParMin;
+    theParams = new TColStd_HArray1OfReal (1, theNbSamples);
+    Standard_Real U = U0;
+    for (int NoU = 1; NoU <= theNbSamples; NoU++, U += PasU)
+      theParams->SetValue (NoU, U);
+  }
 
-//=======================================================================
-//function : fillSqDist
-//purpose  : 
-//=======================================================================
-static void fillSqDist (Extrema_POnSurfParams& theParams,
-                        const gp_Pnt& thePoint)
-{
-  if (theParams.GetSqrDistance() < -0.5)
-    theParams.SetSqrDistance (theParams.Value().SquareDistance (thePoint));
-}
+  //=======================================================================
+  //function : fillSqDist
+  //purpose  : 
+  //=======================================================================
+  static void fillSqDist (Extrema_POnSurfParams& theParams,
+                          const gp_Pnt& thePoint)
+  {
+    if (theParams.GetSqrDistance() < -0.5)
+      theParams.SetSqrDistance (theParams.Value().SquareDistance (thePoint));
+  }
 
 }
 
@@ -316,7 +293,7 @@ void Extrema_GenExtPS::Perform (const gp_Pnt& thePoint)
       myFacePntParams->ChangeValue (0, iV).SetSqrDistance (RealLast());
       myFacePntParams->ChangeValue (myNbUSamples, iV).SetSqrDistance (RealLast());
     }
-  
+
     for (int iU = 1; iU < myNbUSamples; ++iU)
     {
       myFacePntParams->ChangeValue (iU, 0).SetSqrDistance (RealLast());
@@ -327,18 +304,20 @@ void Extrema_GenExtPS::Perform (const gp_Pnt& thePoint)
   if (myTarget == Extrema_ExtFlag_MINMAX)
   {
     // Perform standard solution search (no tree)
-    const Standard_Integer aNbCells = myGridBoxSet->Size();
-    for (Standard_Integer i = 0; i < aNbCells; ++i)
+    for (Standard_Integer iTarget = 0; iTarget < 2; ++iTarget)
     {
-      FindSolution (i, 0.0, Extrema_ExtFlag_MIN);
-    }
-    for (Standard_Integer i = 0; i < aNbCells; ++i)
-    {
-      FindSolution (i, 0.0, Extrema_ExtFlag_MAX);
+      const Extrema_ExtFlag aTarget = static_cast<Extrema_ExtFlag> (iTarget);
+      for (int iU = 1; iU <= myNbUSamples; iU++)
+      {
+        for (int iV = 1; iV <= myNbVSamples; iV++)
+        {
+          FindSolution (iU, iV, aTarget);
+        }
+      }
     }
 
     // Copy solutions
-    for (Standard_Integer i = 1; i <= myF.NbExt (); ++i)
+    for (Standard_Integer i = 1; i <= myF.NbExt(); ++i)
     {
       mySolutions.push_back (Extrema_GenExtPS::ExtPSResult (myF.Point (i), myF.SquareDistance (i)));
     }
@@ -404,62 +383,102 @@ void Extrema_GenExtPS::BuildTree()
   // so fill the tree with elements with empty boxes
   if (myGridBoxSet.IsNull())
   {
-    myGridBoxSet = new BVH_BoxSet<Standard_Real, 3, GridCell>(new BVH_LinearBuilder<Standard_Real, 3>());
+    // Builder for low-level BVH sets
+    opencascade::handle<BVH_LinearBuilder<Standard_Real, 3> > aLBuilder = new BVH_LinearBuilder<Standard_Real, 3>();
+
+    myGridBoxSet = new BVH_IndexedBoxSet<Standard_Real, 3, Handle (Extrema_GenExtPS_GridCellBoxSet)> (
+      new BVH_LinearBuilder<Standard_Real, 3> (BVH_Constants_LeafNodeSizeSingle));
+
+    // create hierarchy of BVH trees
+    const Standard_Integer aCoeff = static_cast<Standard_Integer> (Sqrt (Min (myNbUSamples, myNbVSamples)));
+    const Standard_Integer aNbUT = myNbUSamples / aCoeff;
+    const Standard_Integer aNbVT = myNbVSamples / aCoeff;
+    const Standard_Integer aNbU = myNbUSamples / aNbUT;
+    const Standard_Integer aNbV = myNbVSamples / aNbVT;
+    const Standard_Integer aSize = aNbU * aNbV;
 
-    myGridBoxSet->SetSize (myNbUSamples * myNbVSamples);
+    myGridBoxSet->SetSize (aNbUT * aNbVT);
 
-    for (int iU = 1; iU <= myNbUSamples; iU++)
+    Standard_Integer U1 = 1, V1 = 1, U2 = 1, V2 = 1;
+    for (Standard_Integer iUT = 1; iUT <= aNbUT; ++iUT)
     {
-      for (int iV = 1; iV <= myNbVSamples; iV++)
+      U2 = (iUT == aNbUT) ? myNbUSamples : iUT * aNbU;
+      for (Standard_Integer iVT = 1; iVT <= aNbVT; ++iVT)
       {
-        myGridBoxSet->Add (GridCell (iU, iV), BVH_Box<Standard_Real, 3>());
+        Handle (Extrema_GenExtPS_GridCellBoxSet) aGridSet = new Extrema_GenExtPS_GridCellBoxSet (aLBuilder);
+        aGridSet->SetSize (aSize);
+
+        V2 = (iVT == aNbVT) ? myNbVSamples : iVT * aNbV;
+        for (Standard_Integer iU = U1; iU <= U2; ++iU)
+        {
+          for (Standard_Integer iV = V1; iV <= V2; ++iV)
+          {
+            aGridSet->Add (GridCell (iU, iV), BVH_Box<Standard_Real, 3>());
+          }
+        }
+        V1 = V2 + 1;
+
+        myGridBoxSet->Add (aGridSet, BVH_Box<Standard_Real, 3>());
       }
+      U1 = U2 + 1;
+      V1 = 1;
     }
   }
 
   if (myGridBoxSet->IsDirty() && myTarget != Extrema_ExtFlag_MINMAX)
   {
     // Fill the tree with the real boxes
-    const Standard_Integer aNbCells = myGridBoxSet->Size();
-    for (Standard_Integer iCell = 0; iCell < aNbCells; ++iCell)
+    const Standard_Integer aNbSets = myGridBoxSet->Size();
+    for (Standard_Integer iSet = 0; iSet < aNbSets; ++iSet)
     {
-      const GridCell& aCell = myGridBoxSet->Element (iCell);
-      Standard_Integer iU = aCell.myUInd, iV = aCell.myVInd;
-
-      Standard_Integer aUCoeff = (iU < myNbUSamples) ? 1 : 0;
-      Standard_Integer aVCoeff = (iV < myNbVSamples) ? 1 : 0;
+      Handle (Extrema_GenExtPS_GridCellBoxSet) aGridSet = myGridBoxSet->Element (iSet);
 
-      // Build box for the cell
-      Bnd_Box aBox;
-
-      for (int i = 0; i < 2; ++i)
-        for (int j = 0; j < 2; ++j)
-          aBox.Add (myPoints->Value (iU + i * aUCoeff, iV + j * aVCoeff).Value());
+      // Box of the set
+      Bnd_Box aSetBox;
+      const Standard_Integer aNbCells = aGridSet->Size();
+      for (Standard_Integer iCell = 0; iCell < aNbCells; ++iCell)
+      {
+        const GridCell& aCell = aGridSet->Element (iCell);
+        Standard_Integer iU = aCell.UIndex, iV = aCell.VIndex;
 
-      aBox.Enlarge (Precision::Confusion());
+        Standard_Integer aUCoeff = (iU < myNbUSamples) ? 1 : 0;
+        Standard_Integer aVCoeff = (iV < myNbVSamples) ? 1 : 0;
 
-      const Extrema_POnSurf& aPMin = myPoints->Value (iU, iV);
-      const Extrema_POnSurf& aPMax = myPoints->Value (iU + aUCoeff, iV + aVCoeff);
+        // Build box for the cell
+        Bnd_Box aGridBox;
+        aGridBox.Add (myPoints->Value (iU, iV).Value());
+        aGridBox.Add (myPoints->Value (iU + 1, iV).Value());
+        aGridBox.Add (myPoints->Value (iU, iV + 1).Value());
+        aGridBox.Add (myPoints->Value (iU + 1, iV + 1).Value());
+        aGridBox.Enlarge (Precision::Confusion());
 
-      Standard_Real U1, V1, U2, V2;
-      aPMin.Parameter (U1, V1);
-      aPMax.Parameter (U2, V2);
+        const Extrema_POnSurf& aPMin = myPoints->Value (iU, iV);
+        const Extrema_POnSurf& aPMax = myPoints->Value (iU + aUCoeff, iV + aVCoeff);
 
-      // Enlarge box to make sure the whole cell is covered
-      if (U1 != U2 || V1 != V2)
-      {
-        gp_Pnt aPMid = myS->Value ((U1 + U2) * 0.5, (V1 + V2) * 0.5);
-        aBox.Add (aPMid);
+        Standard_Real U1, V1, U2, V2;
+        aPMin.Parameter (U1, V1);
+        aPMax.Parameter (U2, V2);
 
-        gp_Vec aDir(aPMin.Value(), aPMax.Value());
-        if (aDir.SquareMagnitude() > gp::Resolution())
+        // Enlarge box to make sure the whole cell is covered
+        if (U1 != U2 || V1 != V2)
         {
-          aBox.Enlarge (gp_Lin (aPMin.Value(), aDir).Distance (aPMid));
+          gp_Pnt aPMid = myS->Value ((U1 + U2) * 0.5, (V1 + V2) * 0.5);
+          aGridBox.Add (aPMid);
+
+          gp_Vec aDir (aPMin.Value(), aPMax.Value());
+          if (aDir.SquareMagnitude() > gp::Resolution())
+          {
+            aGridBox.Enlarge (gp_Lin (aPMin.Value(), aDir).Distance (aPMid));
+          }
         }
-      }
+        aGridSet->UpdateBox (iCell, Bnd_Tools::Bnd2BVH (aGridBox));
 
-      myGridBoxSet->UpdateBox (iCell, Bnd_Tools::Bnd2BVH (aBox));
+        aSetBox.Add (aGridBox);
+      }
+      myGridBoxSet->UpdateBox (iSet, Bnd_Tools::Bnd2BVH (aSetBox));
     }
+
+    // Build only high level BVH tree
     myGridBoxSet->Build();
   }
 }
@@ -485,8 +504,8 @@ void Extrema_GenExtPS::GetGridPoints (const Adaptor3d_Surface& theSurf)
       aBspl->UKnots (aUKnots);
       TColStd_Array1OfReal aVKnots (1, aBspl->NbVKnots());
       aBspl->VKnots (aVKnots);
-      fillParams (aUKnots, aBspl->UDegree(), myUMin, myUMax, myUParams, myNbUSamples);
-      fillParams (aVKnots, aBspl->VDegree(), myVMin, myVMax, myVParams, myNbVSamples);
+      fillParams (aUKnots, aBspl->UDegree(), myUMin, myUMax, myNbUSamples, myUParams);
+      fillParams (aVKnots, aBspl->VDegree(), myVMin, myVMax, myNbVSamples, myVParams);
     }
   }
 
@@ -499,8 +518,8 @@ void Extrema_GenExtPS::GetGridPoints (const Adaptor3d_Surface& theSurf)
       TColStd_Array1OfReal aUKnots (1, 2);
       TColStd_Array1OfReal aVKnots (1, 2);
       aBezier->Bounds (aUKnots (1), aUKnots (2), aVKnots (1), aVKnots (2));
-      fillParams (aUKnots, aBezier->UDegree(), myUMin, myUMax, myUParams, myNbUSamples);
-      fillParams (aVKnots, aBezier->VDegree(), myVMin, myVMax, myVParams, myNbVSamples);
+      fillParams (aUKnots, aBezier->UDegree(), myUMin, myUMax, myNbUSamples, myUParams);
+      fillParams (aVKnots, aBezier->VDegree(), myVMin, myVMax, myNbVSamples, myVParams);
     }
   }
 
@@ -535,9 +554,9 @@ void Extrema_GenExtPS::GetGridPoints (const Adaptor3d_Surface& theSurf)
     if (anArrKnots.IsNull())
       return;
     if (theSurf.GetType() == GeomAbs_SurfaceOfRevolution)
-      fillParams (anArrKnots->Array1(), aDegree, myVMin, myVMax, myVParams, myNbVSamples);
+      fillParams (anArrKnots->Array1(), aDegree, myVMin, myVMax, myNbVSamples, myVParams);
     else
-      fillParams (anArrKnots->Array1(), aDegree, myUMin, myUMax, myUParams, myNbUSamples);
+      fillParams (anArrKnots->Array1(), aDegree, myUMin, myUMax, myNbUSamples, myUParams);
   }
 
   // Update the number of points in sample
@@ -605,27 +624,40 @@ Standard_Boolean Extrema_GenExtPS::IsMetricBetter (const Standard_Real& theLeft,
 //purpose  : 
 //=======================================================================
 Standard_Boolean Extrema_GenExtPS::Accept (const Standard_Integer theIndex,
-                                           const Standard_Real& theMetric)
+                                           const Standard_Real&)
 {
-  return FindSolution (theIndex, theMetric, myTarget);
+  if (myBVHSet == NULL)
+  {
+    Handle (Extrema_GenExtPS_GridCellBoxSet) aGridSet = myGridBoxSet->Element (theIndex);
+    aGridSet->Build();
+    // Set low-level BVH set for inner selection
+    SetBVHSet (aGridSet.get());
+    Standard_Integer aNb = Select();
+    // Unset the inner set and continue with high level BVH traverse
+    SetBVHSet (NULL);
+    return aNb > 0;
+  }
+  else
+  {
+    GridCell aCell = myBVHSet->Element (theIndex);
+    return FindSolution (aCell.UIndex, aCell.VIndex, myTarget);
+  }
 }
 
 //=======================================================================
 //function : Accept
 //purpose  : 
 //=======================================================================
-Standard_Boolean Extrema_GenExtPS::FindSolution (const Standard_Integer theIndex,
-                                                 const Standard_Real&,
+Standard_Boolean Extrema_GenExtPS::FindSolution (const Standard_Integer theNU,
+                                                 const Standard_Integer theNV,
                                                  const Extrema_ExtFlag theTarget)
 {
-  const GridCell& aCell = myGridBoxSet->Element (theIndex);
 
   // Fill corner points with square distance to myPoint
-  Standard_Integer nU = aCell.myUInd, nV = aCell.myVInd;
-  Extrema_POnSurfParams& aParam00 = myPoints->ChangeValue (nU, nV);
-  Extrema_POnSurfParams& aParam01 = myPoints->ChangeValue (nU, nV + 1);
-  Extrema_POnSurfParams& aParam10 = myPoints->ChangeValue (nU + 1, nV);
-  Extrema_POnSurfParams& aParam11 = myPoints->ChangeValue (nU + 1, nV + 1);
+  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);
 
   gp_Pnt aPoint (myPoint.x(), myPoint.y(), myPoint.z());
 
@@ -634,15 +666,15 @@ Standard_Boolean Extrema_GenExtPS::FindSolution (const Standard_Integer theIndex
   fillSqDist (aParam10, aPoint);
   fillSqDist (aParam11, aPoint);
 
-  if (nU != myNbUSamples && nV != myNbVSamples &&
-     (theTarget == Extrema_ExtFlag_MIN || theTarget == Extrema_ExtFlag_MINMAX))
+  if (theNU != myNbUSamples && theNV != myNbVSamples &&
+    (theTarget == Extrema_ExtFlag_MIN || theTarget == Extrema_ExtFlag_MINMAX))
   {
     // Find minimum
 
-    const Extrema_POnSurfParams& aParam = ComputeFaceParameters (nU, nV, aPoint);
+    const Extrema_POnSurfParams& aParam = ComputeFaceParameters (theNU, theNV, aPoint);
 
     Standard_Boolean isMin = Standard_False;
-    Extrema_ElementType anElemType = aParam.GetElementType ();
+    Extrema_ElementType anElemType = aParam.GetElementType();
 
     if (anElemType == Extrema_Face)
     {
@@ -665,19 +697,19 @@ Standard_Boolean Extrema_GenExtPS::FindSolution (const Standard_Integer theIndex
       else if (anElemType == Extrema_Node)
       {
         isMin = (iU == 1 || iU == myNbUSamples) &&
-                (iV == 1 || iV == myNbVSamples);
+          (iV == 1 || iV == myNbVSamples);
       }
 
       if (!isMin)
       {
         // This is a middle element.
         if (anElemType == Extrema_UIsoEdge ||
-           (anElemType == Extrema_Node && (iU == 1 || iU == myNbUSamples)))
+          (anElemType == Extrema_Node && (iU == 1 || iU == myNbUSamples)))
         {
           // Check the down face.
-          const Extrema_POnSurfParams &aDownParam = ComputeFaceParameters (nU, nV - 1, aPoint);
+          const Extrema_POnSurfParams &aDownParam = ComputeFaceParameters (theNU, theNV - 1, aPoint);
 
-          if (aDownParam.GetElementType () == anElemType)
+          if (aDownParam.GetElementType() == anElemType)
           {
             Standard_Integer iU2, iV2;
             aDownParam.GetIndices (iU2, iV2);
@@ -685,32 +717,32 @@ Standard_Boolean Extrema_GenExtPS::FindSolution (const Standard_Integer theIndex
           }
         }
         else if (anElemType == Extrema_VIsoEdge ||
-                (anElemType == Extrema_Node && (iV == 1 || iV == myNbVSamples)))
+          (anElemType == Extrema_Node && (iV == 1 || iV == myNbVSamples)))
         {
           // Check the right face.
-          const Extrema_POnSurfParams &aRightParam = ComputeFaceParameters (nU - 1, nV, aPoint);
+          const Extrema_POnSurfParams &aRightParam = ComputeFaceParameters (theNU - 1, theNV, aPoint);
 
-          if (aRightParam.GetElementType () == anElemType)
+          if (aRightParam.GetElementType() == anElemType)
           {
             Standard_Integer iU2, iV2;
             aRightParam.GetIndices (iU2, iV2);
             isMin = (iU == iU2 && iV == iV2);
           }
         }
-        else if (iU == nU && iV == nV)
+        else if (iU == theNU && iV == theNV)
         {
           // Check the lower-left node. For this purpose it is necessary
           // to check lower-left, lower and left faces.
           isMin = Standard_True;
 
           const Extrema_POnSurfParams *anOtherParam[3] = {
-            &ComputeFaceParameters (nU,     nV - 1, aPoint),     // Down
-            &ComputeFaceParameters (nU - 1, nV - 1, aPoint),     // Lower-left
-            &ComputeFaceParameters (nU - 1, nV,     aPoint) };   // Left
+            &ComputeFaceParameters (theNU,     theNV - 1, aPoint),     // Down
+            &ComputeFaceParameters (theNU - 1, theNV - 1, aPoint),     // Lower-left
+            &ComputeFaceParameters (theNU - 1, theNV,     aPoint) };   // Left
 
           for (int i = 0; i < 3 && isMin; i++)
           {
-            if (anOtherParam[i]->GetElementType () == Extrema_Node)
+            if (anOtherParam[i]->GetElementType() == Extrema_Node)
             {
               Standard_Integer iU2, iV2;
               anOtherParam[i]->GetIndices (iU2, iV2);
@@ -734,14 +766,14 @@ Standard_Boolean Extrema_GenExtPS::FindSolution (const Standard_Integer theIndex
   if (theTarget == Extrema_ExtFlag_MAX || theTarget == Extrema_ExtFlag_MINMAX)
   {
     // Find maximum
-    Extrema_POnSurfParams &aParam1 = myPoints->ChangeValue (nU - 1, nV - 1);
-    Extrema_POnSurfParams &aParam2 = myPoints->ChangeValue (nU - 1, nV);
-    Extrema_POnSurfParams &aParam3 = myPoints->ChangeValue (nU - 1, nV + 1);
-    Extrema_POnSurfParams &aParam4 = myPoints->ChangeValue (nU, nV - 1);
-    Extrema_POnSurfParams &aParam5 = myPoints->ChangeValue (nU, nV + 1);
-    Extrema_POnSurfParams &aParam6 = myPoints->ChangeValue (nU + 1, nV - 1);
-    Extrema_POnSurfParams &aParam7 = myPoints->ChangeValue (nU + 1, nV);
-    Extrema_POnSurfParams &aParam8 = myPoints->ChangeValue (nU + 1, nV + 1);
+    Extrema_POnSurfParams &aParam1 = myPoints->ChangeValue (theNU - 1, theNV - 1);
+    Extrema_POnSurfParams &aParam2 = myPoints->ChangeValue (theNU - 1, theNV);
+    Extrema_POnSurfParams &aParam3 = myPoints->ChangeValue (theNU - 1, theNV + 1);
+    Extrema_POnSurfParams &aParam4 = myPoints->ChangeValue (theNU, theNV - 1);
+    Extrema_POnSurfParams &aParam5 = myPoints->ChangeValue (theNU, theNV + 1);
+    Extrema_POnSurfParams &aParam6 = myPoints->ChangeValue (theNU + 1, theNV - 1);
+    Extrema_POnSurfParams &aParam7 = myPoints->ChangeValue (theNU + 1, theNV);
+    Extrema_POnSurfParams &aParam8 = myPoints->ChangeValue (theNU + 1, theNV + 1);
 
     fillSqDist (aParam1, aPoint);
     fillSqDist (aParam2, aPoint);
@@ -752,7 +784,7 @@ Standard_Boolean Extrema_GenExtPS::FindSolution (const Standard_Integer theIndex
     Standard_Real aDist = aParam00.GetSqrDistance();
 
     if ((aParam1.GetSqrDistance() <= aDist) &&
-        (aParam2.GetSqrDistance() <= aDist) &&
+      (aParam2.GetSqrDistance() <= aDist) &&
         (aParam3.GetSqrDistance() <= aDist) &&
         (aParam4.GetSqrDistance() <= aDist) &&
         (aParam5.GetSqrDistance() <= aDist) &&
@@ -798,13 +830,13 @@ void Extrema_GenExtPS::FindSolution (const Extrema_POnSurfParams &theParams)
   {
     for (Standard_Integer i = aNbFuncSol + 1; i <= myF.NbExt(); ++i)
     {
-      Standard_Real aDist = myF.SquareDistance(i);
+      Standard_Real aDist = myF.SquareDistance (i);
       if ((myTarget == Extrema_ExtFlag_MIN && aDist <= mySqDistance) ||
-          (myTarget == Extrema_ExtFlag_MAX && aDist >= mySqDistance))
+        (myTarget == Extrema_ExtFlag_MAX && aDist >= mySqDistance))
       {
         if (aDist != mySqDistance)
           mySolutions.clear();
-        mySolutions.push_back (Extrema_GenExtPS::ExtPSResult (myF.Point(i), aDist));
+        mySolutions.push_back (Extrema_GenExtPS::ExtPSResult (myF.Point (i), aDist));
         mySqDistance = aDist;
       }
     }
@@ -823,7 +855,7 @@ const Extrema_POnSurfParams& Extrema_GenExtPS::
                          const gp_Pnt          &thePoint,
                          const Standard_Real    theDiffTol)
 {
-  const Handle(Extrema_HArray2OfPOnSurfParams)& anEdgeParams = IsUEdge ? myUEdgePntParams : myVEdgePntParams;
+  const Handle (Extrema_HArray2OfPOnSurfParams)& anEdgeParams = IsUEdge ? myUEdgePntParams : myVEdgePntParams;
   Standard_Integer iU, iV;
   theParam0.GetIndices (iU, iV);
   if (anEdgeParams->Value (iU, iV).GetSqrDistance() < 0)
@@ -985,14 +1017,14 @@ const Extrema_POnSurfParams& Extrema_GenExtPS::
     }
   }
 
-  return myFacePntParams->Value(theU, theV);
+  return myFacePntParams->Value (theU, theV);
 }
 
 //=======================================================================
 //function : NbExt
 //purpose  : 
 //=======================================================================
-Standard_Integer Extrema_GenExtPS::NbExt () const
+Standard_Integer Extrema_GenExtPS::NbExt() const
 {
   if (!IsDone())
   {
@@ -1012,7 +1044,7 @@ Standard_Real Extrema_GenExtPS::SquareDistance (const Standard_Integer N) const
     throw Standard_OutOfRange();
   }
 
-  return mySolutions[N - 1].mySqDistance;
+  return mySolutions[N - 1].SqDistance;
 }
 
 //=======================================================================
@@ -1026,5 +1058,5 @@ const Extrema_POnSurf& Extrema_GenExtPS::Point (const Standard_Integer N) const
     throw Standard_OutOfRange();
   }
 
-  return mySolutions[N - 1].myUV;
+  return mySolutions[N - 1].UV;
 }
index f47c45d5a89276dc6c5ed6c992848f35e5f45130..833d88b6723fdaca9910aad0923468f4fcbbae07 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <Adaptor3d_SurfacePtr.hxx>
 #include <BVH_BoxSet.hxx>
+#include <BVH_IndexedBoxSet.hxx>
 #include <BVH_Traverse.hxx>
 #include <Extrema_HArray2OfPOnSurfParams.hxx>
 #include <Extrema_FuncPSNorm.hxx>
@@ -42,6 +43,22 @@ class Extrema_POnSurf;
 class Extrema_POnSurfParams;
 
 
+//! Grid cell defined by (U, V) indices of the minimal
+//! corner of the cell
+struct 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)
+    : UIndex (theUInd), VIndex (theVInd)
+  {}
+};
+
+//! typedef to BVH tree of the grid cells
+typedef BVH_BoxSet <Standard_Real, 3, GridCell> Extrema_GenExtPS_GridCellBoxSet;
+
+
 //! It calculates the extreme distances between a point and a surface.
 //! These distances can be minimum or maximum.
 //! 
@@ -68,28 +85,14 @@ class Extrema_POnSurfParams;
 //! The class is BVH enhanced - the grid cells are stored into BVH-organized
 //! structure. Depending on the Extrema target the traverse of the BVH tree
 //! is different.
-class Extrema_GenExtPS: protected BVH_Traverse <Standard_Real, 3>,
-                        public Standard_Transient
+class Extrema_GenExtPS:
+  protected BVH_Traverse <Standard_Real, 3, Extrema_GenExtPS_GridCellBoxSet>,
+  public Standard_Transient
 {
 public:
 
   DEFINE_STANDARD_RTTIEXT (Extrema_GenExtPS, Standard_Transient)
 
-public: //! @name public types
-
-  //! Grid cell is defined just by (U, V) indices of the minimal
-  //! corner of the cell.
-  struct GridCell
-  {
-    GridCell (Standard_Integer theUInd = -1, Standard_Integer theVInd = -1)
-      : myUInd (theUInd), myVInd (theVInd)
-    {}
-
-    Standard_Integer myUInd; //!< U index of the minimal corner
-    Standard_Integer myVInd; //!< V index of the minimal corner
-  };
-
-
 public: //! @name Constructors computing the distances
   
   //! Constructor for computation of the distances between specified point and surface.
@@ -188,7 +191,7 @@ public: //! @name Specifying the search options
   //! Specifies what solutions are necessary:
   //! - *Extrema_ExtFlag_MIN* - only minimal solutions
   //! - *Extrema_ExtFlag_MAX* - only maximal solutions
-  //! - *Extrema_ExtFlag_MINMAX - all solutions.
+  //! - *Extrema_ExtFlag_MINMAX - all solutions (default value).
   void SetTarget (const Extrema_ExtFlag theTarget)
   {
     myTarget = theTarget;
@@ -217,52 +220,29 @@ public: //! @name Performing projection
   Standard_EXPORT void Perform (const gp_Pnt& theP);
 
 
-public: //! @name Rules for BVH traverse
-
-  //! Rejection of the node by bounding box.
-  //! Metric is computed to choose the best branch.
-  //! Returns true if the node should be rejected, false otherwise.
-  Standard_EXPORT virtual Standard_Boolean
-    RejectNode (const BVH_Vec3d& theCornerMin,
-                const BVH_Vec3d& theCornerMax,
-                Standard_Real& theMetric) const Standard_OVERRIDE;
-
-  //! Rejects the node by the metric
-  Standard_EXPORT virtual Standard_Boolean
-    RejectMetric (const Standard_Real& theMetric) const Standard_OVERRIDE;
-
-  //! Compares the two metrics and chooses the best one.
-  //! Returns true if the first metric is better than the second,
-  //! false otherwise.
-  Standard_EXPORT virtual Standard_Boolean
-    IsMetricBetter (const Standard_Real& theLeft,
-                    const Standard_Real& theRight) const Standard_OVERRIDE;
-
-  //! Leaf element acceptance.
-  //! Metric of the parent leaf-node is passed to avoid the check on the
-  //! element and accept it unconditionally.
-  //! Returns true if the element has been accepted, false otherwise.
-  Standard_EXPORT virtual Standard_Boolean
-    Accept (const Standard_Integer theIndex,
-            const Standard_Real& theMetric) Standard_OVERRIDE;
-
-
 public: //! @name Getting the results
 
   //! Returns True if the distances are found.
   Standard_Boolean IsDone() const { return myIsDone; }
 
   //! Returns the number of extrema distances found.
+  //! @throws StdFail_NotDone if extrema search has failed.
   Standard_EXPORT Standard_Integer NbExt() const;
 
   //! Returns the value of the Nth resulting square distance.
+  //! @throws StdFail_NotDone if extrema search has failed.
+  //! @throws Standard_OutOfRange if given index is out of range of found
+  //!                             solutions ((N < 1) || (N > NbExt()).
   Standard_EXPORT Standard_Real SquareDistance (const Standard_Integer theN) const;
 
   //! Returns the point of the Nth resulting distance.
+  //! @throws StdFail_NotDone if extrema search has failed.
+  //! @throws Standard_OutOfRange if given index is out of range of found
+  //!                             solutions ((N < 1) || (N > NbExt()).
   Standard_EXPORT const Extrema_POnSurf& Point (const Standard_Integer theN) const;
 
 
-private: //! @name Private methods performing the job
+protected: //! @name Protected methods performing the job
 
   //! Creation of grid of parametric points (sampling of the surface)
   Standard_EXPORT void BuildGrid();
@@ -291,39 +271,72 @@ private: //! @name Private methods performing the job
                            const Standard_Real theDiffTol);
 
   //! Looks for the Min or Max Solution (depending on the given target).
-  Standard_EXPORT Standard_Boolean FindSolution (const Standard_Integer theIndex,
-                                                 const Standard_Real& theMetric,
+  Standard_EXPORT Standard_Boolean FindSolution (const Standard_Integer theUIndex,
+                                                 const Standard_Integer theVIndex,
                                                  const Extrema_ExtFlag theTarget);
 
-  //! structure to keep the results
+
+protected: //! @name Rules for BVH traverse
+
+  //! Rejection of the node by bounding box.
+  //! Metric is computed to choose the best branch.
+  //! Returns true if the node should be rejected, false otherwise.
+  Standard_EXPORT virtual Standard_Boolean
+    RejectNode (const BVH_Vec3d& theCornerMin,
+                const BVH_Vec3d& theCornerMax,
+                Standard_Real& theMetric) const Standard_OVERRIDE;
+
+  //! Rejects the node by the metric
+  Standard_EXPORT virtual Standard_Boolean
+    RejectMetric (const Standard_Real& theMetric) const Standard_OVERRIDE;
+
+  //! Compares the two metrics and chooses the best one.
+  //! Returns true if the first metric is better than the second,
+  //! false otherwise.
+  Standard_EXPORT virtual Standard_Boolean
+    IsMetricBetter (const Standard_Real& theLeft,
+                    const Standard_Real& theRight) const Standard_OVERRIDE;
+
+  //! Leaf element acceptance.
+  //! Metric of the parent leaf-node is passed to avoid the check on the
+  //! element and accept it unconditionally.
+  //! Returns true if the element has been accepted, false otherwise.
+  Standard_EXPORT virtual Standard_Boolean
+    Accept (const Standard_Integer theIndex,
+            const Standard_Real& theMetric) Standard_OVERRIDE;
+
+protected: //! @name Auxiliary types
+
+  //! Structure to keep and sort the results
   struct ExtPSResult
   {
-    ExtPSResult ()
-      : mySqDistance (-1)
+    Extrema_POnSurf UV;       //! UV coordinates of extrema solution
+    Standard_Real SqDistance; //! Square distance to target point
+
+    ExtPSResult()
+      : SqDistance (-1)
     {}
 
     ExtPSResult (const Extrema_POnSurf& theUV,
                  const Standard_Real theSqDist)
-      : myUV (theUV),
-        mySqDistance (theSqDist)
+      : UV (theUV),
+        SqDistance (theSqDist)
     {}
 
+    //! IsLess operator
     Standard_Boolean operator< (const ExtPSResult& Other) const
     {
-      if (mySqDistance != Other.mySqDistance)
-        return mySqDistance < Other.mySqDistance;
+      if (SqDistance != Other.SqDistance)
+        return SqDistance < Other.SqDistance;
 
       Standard_Real U1, U2, V1, V2;
-      myUV.Parameter (U1, V1);
-      Other.myUV.Parameter (U2, V2);
+      UV.Parameter (U1, V1);
+      Other.UV.Parameter (U2, V2);
       return (U1 < U2 || (U1 == U2 && V1 < V2));
     }
-
-    Extrema_POnSurf myUV;
-    Standard_Real mySqDistance;
   };
 
-private: //! @name Fields
+protected: //! @name Fields
 
   // Inputs
   NCollection_Vec3<Standard_Real> myPoint; //!< Point
@@ -354,11 +367,13 @@ private: //! @name Fields
   Handle(Extrema_HArray2OfPOnSurfParams) myVEdgePntParams;
 
   Standard_Real mySqDistance; //!< Min/Max found square distance used in BVH tree traverse
-  opencascade::handle <BVH_BoxSet <Standard_Real, 3, GridCell>> myGridBoxSet; //!< BVH-organized grid
+  opencascade::handle 
+    <BVH_IndexedBoxSet<Standard_Real, 3, Handle(Extrema_GenExtPS_GridCellBoxSet)> > myGridBoxSet; //!< High-level BVH of BVH organized grid cells
 
   // Results
-  std::vector <ExtPSResult> mySolutions;
-  Standard_Boolean myIsDone; //!< IsDone flag
+  std::vector <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
 };
 
 DEFINE_STANDARD_HANDLE (Extrema_GenExtPS, Standard_Transient)
index 29ead1dda0c87c962acfad19ef0892dd390a8443..c2364c641edd5b7344a5cabeb5e2bc8dc07c5085 100755 (executable)
@@ -1,3 +1,5 @@
+GCPnts.cxx
+GCPnts.hxx
 GCPnts_AbscissaPoint.cxx
 GCPnts_AbscissaPoint.pxx
 GCPnts_AbscissaPoint.hxx
diff --git a/src/GCPnts/GCPnts.cxx b/src/GCPnts/GCPnts.cxx
new file mode 100644 (file)
index 0000000..de7fe42
--- /dev/null
@@ -0,0 +1,54 @@
+// Created on: 2020-05-18
+// Copyright (c) 1999-2020 OPEN CASCADE SAS
+//
+// 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 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 <GCPnts.hxx>
+
+#include <Precision.hxx>
+//=======================================================================
+//function : FillParams
+//purpose  : 
+//=======================================================================
+void GCPnts::FillParams (const TColStd_Array1OfReal& theKnots,
+                         const Standard_Integer theDegree,
+                         const Standard_Real theParMin,
+                         const Standard_Real theParMax,
+                         NCollection_Vector<Standard_Real>& theParams)
+{
+  Standard_Real aPrevPar = theParMin;
+  theParams.Append (aPrevPar);
+
+  Standard_Integer aNbP = Max (theDegree, 1);
+
+  for (Standard_Integer i = 1;
+    (i < theKnots.Length()) && (theKnots (i) < (theParMax - Precision::PConfusion())); ++i)
+  {
+    if (theKnots (i + 1) < theParMin + Precision::PConfusion())
+      continue;
+
+    Standard_Real aStep = (theKnots (i + 1) - theKnots (i)) / aNbP;
+    for (Standard_Integer k = 1; k <= aNbP ; ++k)
+    {
+      Standard_Real aPar = theKnots (i) + k * aStep;
+      if (aPar > theParMax - Precision::PConfusion())
+        break;
+
+      if (aPar > aPrevPar + Precision::PConfusion())
+      {
+        theParams.Append (aPar);
+        aPrevPar = aPar;
+      }
+    }
+  }
+  theParams.Append (theParMax);
+}
diff --git a/src/GCPnts/GCPnts.hxx b/src/GCPnts/GCPnts.hxx
new file mode 100644 (file)
index 0000000..dbaf585
--- /dev/null
@@ -0,0 +1,35 @@
+// Created on: 2020-05-18
+// Copyright (c) 1999-2020 OPEN CASCADE SAS
+//
+// 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 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.
+
+#ifndef _GCPnts_HeaderFile
+#define _GCPnts_HeaderFile
+
+#include <TColStd_Array1OfReal.hxx>
+#include <NCollection_Vector.hxx>
+
+//! The GCPnts package provides general utilities for
+//! Curves analysis.
+class GCPnts
+{
+public:
+
+  //! Fills <theParams> vector with sampling parameters on the curve
+  Standard_EXPORT static void FillParams (const TColStd_Array1OfReal& theKnots,
+                                          const Standard_Integer theDegree,
+                                          const Standard_Real theParMin,
+                                          const Standard_Real theParMax,
+                                          NCollection_Vector<Standard_Real>& theParams);
+};
+
+#endif