Modeling - Revert changes to original version (#1187)

Refactor GeomBndLib classes for old version of bounding box calculations
Can be fixed later.
- Added new test case for BSplineCurve trimmed range comparison with BndLib.
- Enhanced GeomBndLib_BSplineCurve to handle parameter adjustments for periodic curves.
- Updated GeomBndLib_BSplineCurve2d to improve bounding box calculations.
- Refined GeomBndLib_BSplineSurface to use grid sampling for bounding box determination.
- Optimized GeomBndLib_BezierCurve and GeomBndLib_BezierCurve2d for bounding box calculations.
- Simplified GeomBndLib_SurfaceOfExtrusion and GeomBndLib_SurfaceOfRevolution by leveraging GeomBndLib_OtherSurface for bounding box computations.
- Improved GeomBndLib_Torus to utilize BndLib for bounding box calculations, including handling degenerate cases.
This commit is contained in:
Pasukhin Dmitry
2026-04-05 14:57:53 +01:00
committed by GitHub
parent edcb315000
commit a56f2394ce
16 changed files with 398 additions and 270 deletions
@@ -1505,13 +1505,13 @@ void BndLib::Add(const gp_Torus& S,
int Fi2;
if (VMax < VMin)
{
Fi1 = static_cast<int>(VMax / (M_PI / 4.));
Fi2 = static_cast<int>(VMin / (M_PI / 4.));
Fi1 = static_cast<int>(std::floor(VMax / (M_PI / 4.)));
Fi2 = static_cast<int>(std::floor(VMin / (M_PI / 4.)));
}
else
{
Fi1 = static_cast<int>(VMin / (M_PI / 4.));
Fi2 = static_cast<int>(VMax / (M_PI / 4.));
Fi1 = static_cast<int>(std::floor(VMin / (M_PI / 4.)));
Fi2 = static_cast<int>(std::floor(VMax / (M_PI / 4.)));
}
Fi2++;
@@ -432,6 +432,46 @@ TEST(GeomBndLib_CurveTest, BSplineCurve_CompareWithBndLib)
CompareBoxes(aNewBox, anOldBox, Precision::Confusion());
}
TEST(GeomBndLib_CurveTest, BSplineCurve_TrimmedRange_CompareWithBndLib)
{
NCollection_Array1<gp_Pnt> aPoles(1, 7);
aPoles.SetValue(1, gp_Pnt(0.0, 0.0, 0.0));
aPoles.SetValue(2, gp_Pnt(10.0, 20.0, 0.0));
aPoles.SetValue(3, gp_Pnt(20.0, -10.0, 5.0));
aPoles.SetValue(4, gp_Pnt(30.0, 40.0, 0.0));
aPoles.SetValue(5, gp_Pnt(40.0, 5.0, -5.0));
aPoles.SetValue(6, gp_Pnt(50.0, 15.0, 0.0));
aPoles.SetValue(7, gp_Pnt(60.0, 0.0, 0.0));
NCollection_Array1<double> aKnots(1, 5);
aKnots.SetValue(1, 0.0);
aKnots.SetValue(2, 1.0);
aKnots.SetValue(3, 2.0);
aKnots.SetValue(4, 3.0);
aKnots.SetValue(5, 4.0);
NCollection_Array1<int> aMults(1, 5);
aMults.SetValue(1, 4);
aMults.SetValue(2, 1);
aMults.SetValue(3, 1);
aMults.SetValue(4, 1);
aMults.SetValue(5, 4);
occ::handle<Geom_BSplineCurve> aBSpl = new Geom_BSplineCurve(aPoles, aKnots, aMults, 3);
GeomAdaptor_Curve anAdaptor(aBSpl);
constexpr double aU1 = 1.82;
constexpr double aU2 = 2.04;
Bnd_Box aNewBox;
GeomBndLib_Curve(aBSpl).Add(aU1, aU2, Precision::Confusion(), aNewBox);
Bnd_Box anOldBox;
BndLib_Add3dCurve::Add(anAdaptor, aU1, aU2, Precision::Confusion(), anOldBox);
CompareBoxes(aNewBox, anOldBox, Precision::Confusion());
}
// =========================================================================
// Adaptor constructor
// =========================================================================
@@ -13,8 +13,10 @@
#include <GeomBndLib_BSplineCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <ElCLib.hxx>
#include <Geom_Geometry.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <Precision.hxx>
#include "GeomBndLib_SplineHelpers.pxx"
//=================================================================================================
@@ -28,11 +30,87 @@ Bnd_Box GeomBndLib_BSplineCurve::Box(double theTol) const
Bnd_Box GeomBndLib_BSplineCurve::Box(double theU1, double theU2, double theTol) const
{
return GeomBndLib_SplineHelpers::
BSplineCurveBox<Geom_BSplineCurve, GeomAdaptor_Curve, Bnd_Box, gp_Pnt>(myGeom,
theU1,
theU2,
theTol);
constexpr double aWeakness = 1.5;
occ::handle<Geom_BSplineCurve> aCurve = myGeom;
double aU1 = theU1;
double aU2 = theU2;
if (std::abs(aCurve->FirstParameter() - aU1) > Precision::Parametric(theTol)
|| std::abs(aCurve->LastParameter() - aU2) > Precision::Parametric(theTol))
{
occ::handle<Geom_Geometry> aGeometry = aCurve->Copy();
occ::handle<Geom_BSplineCurve> aSegmentedCurve = occ::down_cast<Geom_BSplineCurve>(aGeometry);
if (aSegmentedCurve->IsPeriodic())
{
ElCLib::AdjustPeriodic(aSegmentedCurve->FirstParameter(),
aSegmentedCurve->LastParameter(),
Precision::PConfusion(),
aU1,
aU2);
}
else
{
if (aSegmentedCurve->FirstParameter() > aU1)
{
aU1 = aSegmentedCurve->FirstParameter();
}
if (aSegmentedCurve->LastParameter() < aU2)
{
aU2 = aSegmentedCurve->LastParameter();
}
}
double aSegmentTol = 2.0 * Precision::PConfusion();
if (aSegmentedCurve->IsPeriodic())
{
const double aPeriod = aSegmentedCurve->LastParameter() - aSegmentedCurve->FirstParameter();
const double aDirectDiff = std::abs(aU2 - aU1);
const double aCrossPeriodDiff1 = std::abs(aU2 - aPeriod - aU1);
const double aCrossPeriodDiff2 = std::abs(aU1 - aPeriod - aU2);
const double aMinDiff = std::min(aDirectDiff, std::min(aCrossPeriodDiff1, aCrossPeriodDiff2));
if (aMinDiff < aSegmentTol)
{
aSegmentTol = aMinDiff * 0.01;
}
}
else if (std::abs(aU2 - aU1) < aSegmentTol)
{
aSegmentTol = std::abs(aU2 - aU1) * 0.01;
}
aSegmentedCurve->Segment(aU1, aU2, aSegmentTol);
aCurve = aSegmentedCurve;
}
Bnd_Box aSampledBox;
const int aKnotFirst = aCurve->FirstUKnotIndex();
const int aKnotLast = aCurve->LastUKnotIndex();
const int aDegree = aCurve->Degree();
const NCollection_Array1<double>& aKnots = aCurve->Knots();
GeomAdaptor_Curve aGACurve(aCurve);
double aMaxDeflection = 0.0;
double aFirst = aKnots(aKnotFirst);
for (int aKnot = aKnotFirst + 1; aKnot <= aKnotLast; ++aKnot)
{
const double aLast = aKnots(aKnot);
aMaxDeflection =
std::max(GeomBndLib_SplineHelpers::FillBox<Bnd_Box, GeomAdaptor_Curve, gp_Pnt>(aSampledBox,
aGACurve,
aFirst,
aLast,
aDegree),
aMaxDeflection);
aFirst = aLast;
}
Bnd_Box aBox;
if (!aSampledBox.IsVoid())
{
aSampledBox.Enlarge(aWeakness * aMaxDeflection);
GeomBndLib_SplineHelpers::ReduceSplineBox(myGeom->Poles(), aSampledBox, aBox);
aBox.Enlarge(theTol);
}
return aBox;
}
//=================================================================================================
@@ -14,7 +14,9 @@
#include <GeomBndLib_BSplineCurve2d.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Geometry.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Precision.hxx>
#include "GeomBndLib_SplineHelpers.pxx"
//=================================================================================================
@@ -28,11 +30,32 @@ Bnd_Box2d GeomBndLib_BSplineCurve2d::Box(double theTol) const
Bnd_Box2d GeomBndLib_BSplineCurve2d::Box(double theU1, double theU2, double theTol) const
{
return GeomBndLib_SplineHelpers::
BSplineCurveBox<Geom2d_BSplineCurve, Geom2dAdaptor_Curve, Bnd_Box2d, gp_Pnt2d>(myGeom,
theU1,
theU2,
theTol);
occ::handle<Geom2d_BSplineCurve> aCurve = myGeom;
const double aU1 = aCurve->FirstParameter();
const double aU2 = aCurve->LastParameter();
double aTrim1 = std::max(theU1, aU1);
double aTrim2 = std::min(theU2, aU2);
if (aTrim2 < aTrim1)
{
aTrim1 = aU1;
aTrim2 = aU2;
}
constexpr double anEps = Precision::PConfusion();
if (std::abs(aU1 - aTrim1) > anEps || std::abs(aU2 - aTrim2) > anEps)
{
const occ::handle<Geom2d_Geometry> aCopy = aCurve->Copy();
aCurve = occ::down_cast<Geom2d_BSplineCurve>(aCopy);
aCurve->Segment(aTrim1, aTrim2);
}
Bnd_Box2d aBox;
for (int anIdx = 1; anIdx <= aCurve->NbPoles(); ++anIdx)
{
aBox.Add(aCurve->Pole(anIdx));
}
aBox.Enlarge(theTol);
return aBox;
}
//=================================================================================================
@@ -147,8 +147,8 @@ Bnd_Box GeomBndLib_BSplineSurface::Box(double theUMin,
// Out of geometry bounds: fall back to grid sampling.
GeomAdaptor_Surface aGASurf(myGeom);
const int aNbUSamples = GeomBndLib_SamplingHelpers::ComputeNbUSamples(aGASurf, theUMin, theUMax);
const int aNbVSamples = GeomBndLib_SamplingHelpers::ComputeNbVSamples(aGASurf, theVMin, theVMax);
const int aNbUSamples = GeomBndLib_SamplingHelpers::ComputeNbUSamples(aGASurf);
const int aNbVSamples = GeomBndLib_SamplingHelpers::ComputeNbVSamples(aGASurf);
NCollection_Array1<double> aUParams(1, aNbUSamples);
NCollection_Array1<double> aVParams(1, aNbVSamples);
@@ -14,6 +14,7 @@
#include <GeomBndLib_BezierCurve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <Precision.hxx>
#include "GeomBndLib_SplineHelpers.pxx"
//=================================================================================================
@@ -27,11 +28,21 @@ Bnd_Box GeomBndLib_BezierCurve::Box(double theTol) const
Bnd_Box GeomBndLib_BezierCurve::Box(double theU1, double theU2, double theTol) const
{
return GeomBndLib_SplineHelpers::
BezierCurveBox<Geom_BezierCurve, GeomAdaptor_Curve, Bnd_Box, gp_Pnt>(myGeom,
theU1,
theU2,
theTol);
constexpr double aWeakness = 1.5;
GeomAdaptor_Curve aGACurve(myGeom);
Bnd_Box aSampledBox;
const double aDeflection =
GeomBndLib_SplineHelpers::FillBox<Bnd_Box, GeomAdaptor_Curve, gp_Pnt>(aSampledBox,
aGACurve,
theU1,
theU2,
myGeom->Degree());
aSampledBox.Enlarge(aWeakness * aDeflection);
Bnd_Box aBox;
GeomBndLib_SplineHelpers::ReduceSplineBox(myGeom->Poles(), aSampledBox, aBox);
aBox.Enlarge(theTol);
return aBox;
}
//=================================================================================================
@@ -13,7 +13,9 @@
#include <GeomBndLib_BezierCurve2d.hxx>
#include <Geom2d_Geometry.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Precision.hxx>
#include "GeomBndLib_SplineHelpers.pxx"
//=================================================================================================
@@ -27,11 +29,26 @@ Bnd_Box2d GeomBndLib_BezierCurve2d::Box(double theTol) const
Bnd_Box2d GeomBndLib_BezierCurve2d::Box(double theU1, double theU2, double theTol) const
{
return GeomBndLib_SplineHelpers::
BezierCurveBox<Geom2d_BezierCurve, Geom2dAdaptor_Curve, Bnd_Box2d, gp_Pnt2d>(myGeom,
theU1,
theU2,
theTol);
occ::handle<Geom2d_BezierCurve> aCurve = myGeom;
const double aU1 = aCurve->FirstParameter();
const double aU2 = aCurve->LastParameter();
const double aTrim1 = std::max(theU1, aU1);
const double aTrim2 = std::min(theU2, aU2);
constexpr double anEps = Precision::PConfusion();
if (std::abs(aU1 - aTrim1) > anEps || std::abs(aU2 - aTrim2) > anEps)
{
const occ::handle<Geom2d_Geometry> aCopy = aCurve->Copy();
aCurve = occ::down_cast<Geom2d_BezierCurve>(aCopy);
aCurve->Segment(aTrim1, aTrim2);
}
Bnd_Box2d aBox;
for (int anIdx = 1; anIdx <= aCurve->NbPoles(); ++anIdx)
{
aBox.Add(aCurve->Pole(anIdx));
}
aBox.Enlarge(theTol);
return aBox;
}
//=================================================================================================
@@ -62,8 +62,8 @@ Bnd_Box GeomBndLib_BezierSurface::Box(double theUMin,
// Trimmed Bezier: fall back to grid sampling.
GeomAdaptor_Surface aGASurf(myGeom);
const int aNbUSamples = GeomBndLib_SamplingHelpers::ComputeNbUSamples(aGASurf, theUMin, theUMax);
const int aNbVSamples = GeomBndLib_SamplingHelpers::ComputeNbVSamples(aGASurf, theVMin, theVMax);
const int aNbUSamples = GeomBndLib_SamplingHelpers::ComputeNbUSamples(aGASurf);
const int aNbVSamples = GeomBndLib_SamplingHelpers::ComputeNbVSamples(aGASurf);
NCollection_Array1<double> aUParams(1, aNbUSamples);
NCollection_Array1<double> aVParams(1, aNbVSamples);
@@ -13,12 +13,15 @@
#include <GeomBndLib_SurfaceOfExtrusion.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomBndLib_Curve.hxx>
#include <GeomBndLib_InfiniteHelpers.pxx>
#include <GeomBndLib_OtherSurface.hxx>
#include <Geom_Curve.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
#include <Precision.hxx>
#include <Standard_Failure.hxx>
namespace
{
@@ -141,14 +144,52 @@ Bnd_Box GeomBndLib_SurfaceOfExtrusion::Box(double theUMin,
double theVMax,
double theTol) const
{
// P(U, V) = BasisCurve(U) + V * Direction
const occ::handle<Geom_Curve>& aBasisCurve = myGeom->BasisCurve();
const gp_Dir& aDir = myGeom->Direction();
const gp_XYZ& aDirXYZ = aDir.XYZ();
try
{
// P(U, V) = BasisCurve(U) + V * Direction
const occ::handle<Geom_Curve>& aBasisCurve = myGeom->BasisCurve();
const gp_Dir& aDir = myGeom->Direction();
const gp_XYZ& aDirXYZ = aDir.XYZ();
GeomBndLib_Curve aCurveEval(aBasisCurve);
const Bnd_Box aCurveBox = aCurveEval.Box(theUMin, theUMax, 0.);
return buildExtrusionBox(aCurveBox, aDir, aDirXYZ, theVMin, theVMax, theTol);
double aCurveU1 = theUMin;
double aCurveU2 = theUMax;
if (!aBasisCurve->IsPeriodic())
{
const double aFirst = aBasisCurve->FirstParameter();
const double aLast = aBasisCurve->LastParameter();
if (aCurveU1 < aFirst)
aCurveU1 = aFirst;
else if (aCurveU1 > aLast)
aCurveU1 = aLast;
if (aCurveU2 < aFirst)
aCurveU2 = aFirst;
else if (aCurveU2 > aLast)
aCurveU2 = aLast;
if (aCurveU1 > aCurveU2)
{
const double aTmp = aCurveU1;
aCurveU1 = aCurveU2;
aCurveU2 = aTmp;
}
}
GeomBndLib_Curve aCurveEval(aBasisCurve);
const Bnd_Box aCurveBox = aCurveEval.Box(aCurveU1, aCurveU2, 0.);
if (aCurveBox.IsVoid())
{
GeomAdaptor_Surface anAdaptor(myGeom);
GeomBndLib_OtherSurface anOther(anAdaptor);
return anOther.Box(theUMin, theUMax, theVMin, theVMax, theTol);
}
return buildExtrusionBox(aCurveBox, aDir, aDirXYZ, theVMin, theVMax, theTol);
}
catch (Standard_Failure const&)
{
// Fall back to robust generic sampling if basis-curve segmentation fails.
GeomAdaptor_Surface anAdaptor(myGeom);
GeomBndLib_OtherSurface anOther(anAdaptor);
return anOther.Box(theUMin, theUMax, theVMin, theVMax, theTol);
}
}
//=================================================================================================
@@ -159,12 +200,50 @@ Bnd_Box GeomBndLib_SurfaceOfExtrusion::BoxOptimal(double theUMin,
double theVMax,
double theTol) const
{
// Use the tight basis curve box for a more precise result.
const occ::handle<Geom_Curve>& aBasisCurve = myGeom->BasisCurve();
const gp_Dir& aDir = myGeom->Direction();
const gp_XYZ& aDirXYZ = aDir.XYZ();
try
{
// Use the tight basis curve box for a more precise result.
const occ::handle<Geom_Curve>& aBasisCurve = myGeom->BasisCurve();
const gp_Dir& aDir = myGeom->Direction();
const gp_XYZ& aDirXYZ = aDir.XYZ();
GeomBndLib_Curve aCurveEval(aBasisCurve);
const Bnd_Box aCurveBox = aCurveEval.BoxOptimal(theUMin, theUMax, 0.);
return buildExtrusionBox(aCurveBox, aDir, aDirXYZ, theVMin, theVMax, theTol);
double aCurveU1 = theUMin;
double aCurveU2 = theUMax;
if (!aBasisCurve->IsPeriodic())
{
const double aFirst = aBasisCurve->FirstParameter();
const double aLast = aBasisCurve->LastParameter();
if (aCurveU1 < aFirst)
aCurveU1 = aFirst;
else if (aCurveU1 > aLast)
aCurveU1 = aLast;
if (aCurveU2 < aFirst)
aCurveU2 = aFirst;
else if (aCurveU2 > aLast)
aCurveU2 = aLast;
if (aCurveU1 > aCurveU2)
{
const double aTmp = aCurveU1;
aCurveU1 = aCurveU2;
aCurveU2 = aTmp;
}
}
GeomBndLib_Curve aCurveEval(aBasisCurve);
const Bnd_Box aCurveBox = aCurveEval.BoxOptimal(aCurveU1, aCurveU2, 0.);
if (aCurveBox.IsVoid())
{
GeomAdaptor_Surface anAdaptor(myGeom);
GeomBndLib_OtherSurface anOther(anAdaptor);
return anOther.BoxOptimal(theUMin, theUMax, theVMin, theVMax, theTol);
}
return buildExtrusionBox(aCurveBox, aDir, aDirXYZ, theVMin, theVMax, theTol);
}
catch (Standard_Failure const&)
{
// Fall back to robust generic sampling if basis-curve segmentation fails.
GeomAdaptor_Surface anAdaptor(myGeom);
GeomBndLib_OtherSurface anOther(anAdaptor);
return anOther.BoxOptimal(theUMin, theUMax, theVMin, theVMax, theTol);
}
}
@@ -13,15 +13,18 @@
#include <GeomBndLib_SurfaceOfRevolution.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomBndLib_Circle.hxx>
#include <GeomBndLib_Curve.hxx>
#include <GeomBndLib_InfiniteHelpers.pxx>
#include <GeomBndLib_OtherSurface.hxx>
#include <Geom_Curve.hxx>
#include <gp_Ax1.hxx>
#include <gp_Circ.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
#include <Precision.hxx>
#include <Standard_Failure.hxx>
namespace
{
@@ -156,21 +159,54 @@ Bnd_Box GeomBndLib_SurfaceOfRevolution::Box(double theUMin,
double theVMax,
double theTol) const
{
const occ::handle<Geom_Curve>& aBasisCurve = myGeom->BasisCurve();
const gp_Ax1 anAxis = myGeom->Axis();
const gp_Pnt& anOrigin = anAxis.Location();
const gp_Dir& anAxisDir = anAxis.Direction();
try
{
const occ::handle<Geom_Curve>& aBasisCurve = myGeom->BasisCurve();
const gp_Ax1 anAxis = myGeom->Axis();
const gp_Pnt& anOrigin = anAxis.Location();
const gp_Dir& anAxisDir = anAxis.Direction();
// Clamp V range to basis curve bounds.
const double aVFirst = aBasisCurve->FirstParameter();
const double aVLast = aBasisCurve->LastParameter();
const double aVMin = Precision::IsNegativeInfinite(theVMin) ? aVFirst : theVMin;
const double aVMax = Precision::IsPositiveInfinite(theVMax) ? aVLast : theVMax;
// Clamp V range to basis curve bounds.
const double aVFirst = aBasisCurve->FirstParameter();
const double aVLast = aBasisCurve->LastParameter();
double aVMin = Precision::IsNegativeInfinite(theVMin) ? aVFirst : theVMin;
double aVMax = Precision::IsPositiveInfinite(theVMax) ? aVLast : theVMax;
if (!aBasisCurve->IsPeriodic())
{
if (aVMin < aVFirst)
aVMin = aVFirst;
else if (aVMin > aVLast)
aVMin = aVLast;
if (aVMax < aVFirst)
aVMax = aVFirst;
else if (aVMax > aVLast)
aVMax = aVLast;
if (aVMin > aVMax)
{
const double aTmp = aVMin;
aVMin = aVMax;
aVMax = aTmp;
}
}
// Compute the basis curve bounding box, then revolve all 8 corners around the axis.
GeomBndLib_Curve aCurveEval(aBasisCurve);
const Bnd_Box aCurveBox = aCurveEval.Box(aVMin, aVMax, 0.);
return buildRevolutionBox(aCurveBox, anOrigin, anAxisDir, theUMin, theUMax, theTol);
// Compute the basis curve bounding box, then revolve all 8 corners around the axis.
GeomBndLib_Curve aCurveEval(aBasisCurve);
const Bnd_Box aCurveBox = aCurveEval.Box(aVMin, aVMax, 0.);
if (aCurveBox.IsVoid())
{
GeomAdaptor_Surface anAdaptor(myGeom);
GeomBndLib_OtherSurface anOther(anAdaptor);
return anOther.Box(theUMin, theUMax, theVMin, theVMax, theTol);
}
return buildRevolutionBox(aCurveBox, anOrigin, anAxisDir, theUMin, theUMax, theTol);
}
catch (Standard_Failure const&)
{
// Fall back to robust generic sampling if basis-curve segmentation fails.
GeomAdaptor_Surface anAdaptor(myGeom);
GeomBndLib_OtherSurface anOther(anAdaptor);
return anOther.Box(theUMin, theUMax, theVMin, theVMax, theTol);
}
}
//=================================================================================================
@@ -181,19 +217,52 @@ Bnd_Box GeomBndLib_SurfaceOfRevolution::BoxOptimal(double theUMin,
double theVMax,
double theTol) const
{
const occ::handle<Geom_Curve>& aBasisCurve = myGeom->BasisCurve();
const gp_Ax1 anAxis = myGeom->Axis();
const gp_Pnt& anOrigin = anAxis.Location();
const gp_Dir& anAxisDir = anAxis.Direction();
try
{
const occ::handle<Geom_Curve>& aBasisCurve = myGeom->BasisCurve();
const gp_Ax1 anAxis = myGeom->Axis();
const gp_Pnt& anOrigin = anAxis.Location();
const gp_Dir& anAxisDir = anAxis.Direction();
// Clamp V range to basis curve bounds.
const double aVFirst = aBasisCurve->FirstParameter();
const double aVLast = aBasisCurve->LastParameter();
const double aVMin = Precision::IsNegativeInfinite(theVMin) ? aVFirst : theVMin;
const double aVMax = Precision::IsPositiveInfinite(theVMax) ? aVLast : theVMax;
// Clamp V range to basis curve bounds.
const double aVFirst = aBasisCurve->FirstParameter();
const double aVLast = aBasisCurve->LastParameter();
double aVMin = Precision::IsNegativeInfinite(theVMin) ? aVFirst : theVMin;
double aVMax = Precision::IsPositiveInfinite(theVMax) ? aVLast : theVMax;
if (!aBasisCurve->IsPeriodic())
{
if (aVMin < aVFirst)
aVMin = aVFirst;
else if (aVMin > aVLast)
aVMin = aVLast;
if (aVMax < aVFirst)
aVMax = aVFirst;
else if (aVMax > aVLast)
aVMax = aVLast;
if (aVMin > aVMax)
{
const double aTmp = aVMin;
aVMin = aVMax;
aVMax = aTmp;
}
}
// Use the tight basis curve box for a more precise result.
GeomBndLib_Curve aCurveEval(aBasisCurve);
const Bnd_Box aCurveBox = aCurveEval.BoxOptimal(aVMin, aVMax, 0.);
return buildRevolutionBox(aCurveBox, anOrigin, anAxisDir, theUMin, theUMax, theTol);
// Use the tight basis curve box for a more precise result.
GeomBndLib_Curve aCurveEval(aBasisCurve);
const Bnd_Box aCurveBox = aCurveEval.BoxOptimal(aVMin, aVMax, 0.);
if (aCurveBox.IsVoid())
{
GeomAdaptor_Surface anAdaptor(myGeom);
GeomBndLib_OtherSurface anOther(anAdaptor);
return anOther.BoxOptimal(theUMin, theUMax, theVMin, theVMax, theTol);
}
return buildRevolutionBox(aCurveBox, anOrigin, anAxisDir, theUMin, theUMax, theTol);
}
catch (Standard_Failure const&)
{
// Fall back to robust generic sampling if basis-curve segmentation fails.
GeomAdaptor_Surface anAdaptor(myGeom);
GeomBndLib_OtherSurface anOther(anAdaptor);
return anOther.BoxOptimal(theUMin, theUMax, theVMin, theVMax, theTol);
}
}
@@ -13,140 +13,16 @@
#include <GeomBndLib_Torus.hxx>
#include <ElCLib.hxx>
#include <ElSLib.hxx>
#include <BndLib.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomBndLib_Circle.hxx>
#include <GeomBndLib_OtherSurface.hxx>
#include <gp_Circ.hxx>
#include <gp_Torus.hxx>
#include <Precision.hxx>
#include <cmath>
//=================================================================================================
//! Compute bounding box for a degenerate torus (Ra < Ri) patch
//! using the extremal-point algorithm.
static void computeDegeneratedTorus(const gp_Torus& theTorus,
const double theUMin,
const double theUMax,
const double theVMin,
const double theVMax,
Bnd_Box& theBox)
{
const gp_Pnt aP = theTorus.Location();
const double aRa = theTorus.MajorRadius();
const double aRi = theTorus.MinorRadius();
const double aXmin = aP.X() - aRa - aRi;
const double aXmax = aP.X() + aRa + aRi;
const double aYmin = aP.Y() - aRa - aRi;
const double aYmax = aP.Y() + aRa + aRi;
const double aZmin = aP.Z() - aRi;
const double aZmax = aP.Z() + aRi;
const double aPhi = std::acos(-aRa / aRi);
constexpr double anUper = 2. * M_PI - Precision::PConfusion();
const double aVper = 2. * aPhi - Precision::PConfusion();
if (theUMax - theUMin >= anUper && theVMax - theVMin >= aVper)
{
// Whole degenerate torus.
theBox.Update(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
return;
}
// Check 6 extremal points.
double anU, aV;
const double anUmax = theUMin + 2. * M_PI;
const gp_Ax3& aPos = theTorus.Position();
gp_Pnt aPExt = aP;
aPExt.SetX(aXmin);
ElSLib::TorusParameters(aPos, aRa, aRi, aPExt, anU, aV);
anU = ElCLib::InPeriod(anU, theUMin, anUmax);
if (anU >= theUMin && anU <= theUMax && aV >= theVMin && aV <= theVMax)
{
theBox.Add(aPExt);
}
aPExt.SetX(aXmax);
ElSLib::TorusParameters(aPos, aRa, aRi, aPExt, anU, aV);
anU = ElCLib::InPeriod(anU, theUMin, anUmax);
if (anU >= theUMin && anU <= theUMax && aV >= theVMin && aV <= theVMax)
{
theBox.Add(aPExt);
}
aPExt.SetX(aP.X());
aPExt.SetY(aYmin);
ElSLib::TorusParameters(aPos, aRa, aRi, aPExt, anU, aV);
anU = ElCLib::InPeriod(anU, theUMin, anUmax);
if (anU >= theUMin && anU <= theUMax && aV >= theVMin && aV <= theVMax)
{
theBox.Add(aPExt);
}
aPExt.SetY(aYmax);
ElSLib::TorusParameters(aPos, aRa, aRi, aPExt, anU, aV);
anU = ElCLib::InPeriod(anU, theUMin, anUmax);
if (anU >= theUMin && anU <= theUMax && aV >= theVMin && aV <= theVMax)
{
theBox.Add(aPExt);
}
aPExt.SetY(aP.Y());
aPExt.SetZ(aZmin);
ElSLib::TorusParameters(aPos, aRa, aRi, aPExt, anU, aV);
anU = ElCLib::InPeriod(anU, theUMin, anUmax);
if (anU >= theUMin && anU <= theUMax && aV >= theVMin && aV <= theVMax)
{
theBox.Add(aPExt);
}
aPExt.SetZ(aZmax);
ElSLib::TorusParameters(aPos, aRa, aRi, aPExt, anU, aV);
anU = ElCLib::InPeriod(anU, theUMin, anUmax);
if (anU >= theUMin && anU <= theUMax && aV >= theVMin && aV <= theVMax)
{
theBox.Add(aPExt);
}
// Add boundary iso-curves of the patch.
gp_Circ aC = ElSLib::TorusUIso(aPos, aRa, aRi, theUMin);
theBox.Add(GeomBndLib_Circle::Box(aC, theVMin, theVMax, 0.));
aC = ElSLib::TorusUIso(aPos, aRa, aRi, theUMax);
theBox.Add(GeomBndLib_Circle::Box(aC, theVMin, theVMax, 0.));
aC = ElSLib::TorusVIso(aPos, aRa, aRi, theVMin);
theBox.Add(GeomBndLib_Circle::Box(aC, theUMin, theUMax, 0.));
aC = ElSLib::TorusVIso(aPos, aRa, aRi, theVMax);
theBox.Add(GeomBndLib_Circle::Box(aC, theUMin, theUMax, 0.));
}
//=================================================================================================
Bnd_Box GeomBndLib_Torus::Box(double theTol) const
{
Bnd_Box aBox;
const gp_Torus aTorus = myGeom->Torus();
const double aRMa = aTorus.MajorRadius();
const double aRmi = aTorus.MinorRadius();
const double aR = aRMa + aRmi;
const gp_XYZ aO = aTorus.Location().XYZ();
const gp_XYZ aXd = aTorus.XAxis().Direction().XYZ();
const gp_XYZ aYd = aTorus.YAxis().Direction().XYZ();
const gp_XYZ aZd = aTorus.Axis().Direction().XYZ();
// Precompute scaled direction vectors.
const gp_XYZ aRXd = aR * aXd;
const gp_XYZ aRYd = aR * aYd;
const gp_XYZ aRiZd = aRmi * aZd;
// Add 8 corner points of torus bounding box.
aBox.Add(gp_Pnt(aO - aRXd - aRYd + aRiZd));
aBox.Add(gp_Pnt(aO - aRXd - aRYd - aRiZd));
aBox.Add(gp_Pnt(aO + aRXd - aRYd + aRiZd));
aBox.Add(gp_Pnt(aO + aRXd - aRYd - aRiZd));
aBox.Add(gp_Pnt(aO - aRXd + aRYd + aRiZd));
aBox.Add(gp_Pnt(aO - aRXd + aRYd - aRiZd));
aBox.Add(gp_Pnt(aO + aRXd + aRYd + aRiZd));
aBox.Add(gp_Pnt(aO + aRXd + aRYd - aRiZd));
aBox.Enlarge(theTol);
Bnd_Box aBox;
BndLib::Add(myGeom->Torus(), theTol, aBox);
return aBox;
}
@@ -158,71 +34,8 @@ Bnd_Box GeomBndLib_Torus::Box(double theUMin,
double theVMax,
double theTol) const
{
Bnd_Box aBox;
const gp_Torus aTorus = myGeom->Torus();
const double aRa = aTorus.MajorRadius();
const double aRi = aTorus.MinorRadius();
if (aRa < aRi)
{
computeDegeneratedTorus(aTorus, theUMin, theUMax, theVMin, theVMax, aBox);
aBox.Enlarge(theTol);
return aBox;
}
// Compute cross-section V parameter range as integer multiples of PI/4.
int aFi1, aFi2;
if (theVMax < theVMin)
{
aFi1 = static_cast<int>(std::floor(theVMax / (M_PI / 4.)));
aFi2 = static_cast<int>(std::floor(theVMin / (M_PI / 4.)));
}
else
{
aFi1 = static_cast<int>(std::floor(theVMin / (M_PI / 4.)));
aFi2 = static_cast<int>(std::floor(theVMax / (M_PI / 4.)));
}
aFi2++;
if (aFi2 < aFi1)
{
return aBox;
}
constexpr double THE_COS_PI4 = 0.70710678118654746;
// Cache direction vectors.
const gp_XYZ aZDir = aTorus.Axis().Direction().XYZ();
const gp_XYZ aLocXYZ = aTorus.Location().XYZ();
const gp_Dir aNorm = aTorus.Axis().Direction();
const gp_Dir aXDir = aTorus.XAxis().Direction();
// Multipliers for torus cross-section points at 45-degree intervals.
constexpr double aRadiusMult[8] =
{1., THE_COS_PI4, 0., -THE_COS_PI4, -1., -THE_COS_PI4, 0., THE_COS_PI4};
constexpr double aZMult[8] =
{0., THE_COS_PI4, 1., THE_COS_PI4, 0., -THE_COS_PI4, -1., -THE_COS_PI4};
// For each cross-section sample, construct the circle in the U-direction
// and compute its analytical arc bounding box.
const auto addTorusPoint = [&](int theIdx) {
const double aRadius = aRa + aRi * aRadiusMult[theIdx];
const gp_Pnt aCenter(aLocXYZ + (aRi * aZMult[theIdx]) * aZDir);
if (aRadius < Precision::Confusion())
{
aBox.Add(aCenter);
return;
}
gp_Circ aC(gp_Ax2(aCenter, aNorm, aXDir), aRadius);
aBox.Add(GeomBndLib_Circle::Box(aC, theUMin, theUMax, 0.));
};
for (int i = aFi1; i <= aFi2; ++i)
{
addTorusPoint(((i % 8) + 8) % 8);
}
aBox.Enlarge(theTol);
Bnd_Box aBox;
BndLib::Add(myGeom->Torus(), theUMin, theUMax, theVMin, theVMax, theTol, aBox);
return aBox;
}
+1 -1
View File
@@ -7,5 +7,5 @@ restore [locate_data_file pro14928b.rle] aface
prism b aface 0 500 0
explode b
bcut result a b_1
checkprops result -s 520000
checkprops result -s 562034
checkview -display result -2d -s -otherwise { a b_1 } -path ${imagedir}/${test_image}.png
-2
View File
@@ -1,5 +1,3 @@
puts "TODO OCC23612 ALL: Faulty shapes in variables faulty_1"
puts "========"
puts "OCC23612"
puts "========"
+1 -1
View File
@@ -21,7 +21,7 @@ checkprops ra -v $VaExp
puts "OBB"
bounding result -shape ro -dump -obb
checkprops ro -v 25000
checkprops ro -v 28694.7
smallview
fit
+4 -4
View File
@@ -28,8 +28,8 @@ if {$index > -1} {
bounding e1 -save e1_x1 e1_y1 e1_z1 e1_x2 e1_y2 e1_z2
set e1_good_x1 -17.610622244944413
set e1_good_y1 -3.8835885277044451e-05
set e1_good_z1 -3.0000388358852792
set e1_good_y1 -0.010622244944396092
set e1_good_z1 -3.0106222449443982
set e1_good_x2 -17.589377755055537
set e1_good_y2 5.700038816113608
set e1_good_z2 -1.6251884728673096
@@ -51,8 +51,8 @@ set res [bounding result -save x1 y1 z1 x2 y2 z2 ]
fit
set good_x1 -17.6105835090592
set good_y1 -4.7027736569526475
set good_z1 -4.3573266042834353
set good_y1 -4.7133570660117918
set good_z1 -4.3679100133425806
set good_x2 -17.589416490940806
set good_y2 5.7000000802283299
set good_z2 -1.6252272087525899
+1 -1
View File
@@ -7,7 +7,7 @@ puts ""
puts "TODO ?OCC30012 Linux: Error: 10 curves are expected but 9 ones are found."
puts "TODO ?OCC30012 Linux: Error: 10 curves are expected but 8 ones are found."
puts "TODO ?OCC29910 Windows: Error: 10 curves are expected but 11 ones are found."
puts "TODO ?OCC29910 Windows: Error : is WRONG because number of EDGE entities in shape \"rs\" is 16"
puts "TODO ?OCC29910 Windows: Error : is WRONG because number of EDGE entities in shape \"rs\" is 15"
puts "TODO ?OCC29910 Linux: Error : is WRONG because number of EDGE entities in shape \"rs\" is 8"
puts "TODO ?OCC29910 Windows: Error: 0 vertices are expected but 2 are found"