1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-29 14:00:49 +03:00

# build hierarchy of BVH trees

This commit is contained in:
emv
2020-05-18 11:55:47 +03:00
parent 9cc449ed6a
commit 448ecf7bd5
6 changed files with 377 additions and 271 deletions

View 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);
}
}

View 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;
}
}
// 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 (Standard_Integer i = 0; i < nbPar; i++)
theParams->SetValue (i + 1, aParams (i));
}
aParams.Append (theParMax);
Standard_Integer nbPar = aParams.Length();
//=======================================================================
//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);
}
// In case of an insufficient number of points the grid will be built later
if (nbPar < theNbSample)
return;
theParams = new TColStd_HArray1OfReal (1, nbPar);
for (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 : 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->SetSize (myNbUSamples * myNbVSamples);
myGridBoxSet = new BVH_IndexedBoxSet<Standard_Real, 3, Handle (Extrema_GenExtPS_GridCellBoxSet)> (
new BVH_LinearBuilder<Standard_Real, 3> (BVH_Constants_LeafNodeSizeSingle));
for (int iU = 1; iU <= myNbUSamples; iU++)
// 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 (aNbUT * aNbVT);
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;
Handle (Extrema_GenExtPS_GridCellBoxSet) aGridSet = myGridBoxSet->Element (iSet);
Standard_Integer aUCoeff = (iU < myNbUSamples) ? 1 : 0;
Standard_Integer aVCoeff = (iV < myNbVSamples) ? 1 : 0;
// 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());
aBox.Enlarge (Precision::Confusion());
const Extrema_POnSurf& aPMin = myPoints->Value (iU, iV);
const Extrema_POnSurf& aPMax = myPoints->Value (iU + aUCoeff, iV + aVCoeff);
Standard_Real U1, V1, U2, V2;
aPMin.Parameter (U1, V1);
aPMax.Parameter (U2, V2);
// Enlarge box to make sure the whole cell is covered
if (U1 != U2 || V1 != V2)
// Box of the set
Bnd_Box aSetBox;
const Standard_Integer aNbCells = aGridSet->Size();
for (Standard_Integer iCell = 0; iCell < aNbCells; ++iCell)
{
gp_Pnt aPMid = myS->Value ((U1 + U2) * 0.5, (V1 + V2) * 0.5);
aBox.Add (aPMid);
const GridCell& aCell = aGridSet->Element (iCell);
Standard_Integer iU = aCell.UIndex, iV = aCell.VIndex;
gp_Vec aDir(aPMin.Value(), aPMax.Value());
if (aDir.SquareMagnitude() > gp::Resolution())
Standard_Integer aUCoeff = (iU < myNbUSamples) ? 1 : 0;
Standard_Integer aVCoeff = (iV < myNbVSamples) ? 1 : 0;
// 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());
const Extrema_POnSurf& aPMin = myPoints->Value (iU, iV);
const Extrema_POnSurf& aPMax = myPoints->Value (iU + aUCoeff, iV + aVCoeff);
Standard_Real U1, V1, U2, V2;
aPMin.Parameter (U1, V1);
aPMax.Parameter (U2, V2);
// 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);
myGridBoxSet->UpdateBox (iCell, Bnd_Tools::Bnd2BVH (aBox));
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));
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;
}

View 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)

View File

@@ -1,3 +1,5 @@
GCPnts.cxx
GCPnts.hxx
GCPnts_AbscissaPoint.cxx
GCPnts_AbscissaPoint.pxx
GCPnts_AbscissaPoint.hxx

54
src/GCPnts/GCPnts.cxx Normal file
View File

@@ -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);
}

35
src/GCPnts/GCPnts.hxx Normal file
View File

@@ -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