From: Pasukhin Dmitry Date: Tue, 25 Nov 2025 19:29:53 +0000 (+0000) Subject: Foundation Classes - Optimize and fix Bnd package (#839) X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=c5120a28c80ea00da2fd1c621e8b95981c0eb22f;p=occt.git Foundation Classes - Optimize and fix Bnd package (#839) - Fixed multiple bugs including uninitialized variables (zmin/zmax in IsOut(gp_Lin)), incorrect type usage (Standard_Integer → Standard_Boolean), and improper gap handling - Optimized performance-critical methods through branchless operations, early exits, and cached computations - Modernized codebase with C++17 features including constexpr constructors, noexcept specifications, and [[nodiscard]] attributes - Refactor Bnd_Box and Bnd_Box2d classes to introduce GetXMin, GetXMax, GetYMin, GetYMax, and GetZMin, GetZMax methods for improved clarity and encapsulation. - Add Limits struct to represent box limits in both classes. --- diff --git a/src/FoundationClasses/TKMath/Bnd/Bnd_Box.cxx b/src/FoundationClasses/TKMath/Bnd/Bnd_Box.cxx index 48912ac8c9..b3e8929cb7 100644 --- a/src/FoundationClasses/TKMath/Bnd/Bnd_Box.cxx +++ b/src/FoundationClasses/TKMath/Bnd/Bnd_Box.cxx @@ -15,49 +15,106 @@ // commercial license or contractual agreement. #include + #include #include #include #include #include #include - -// set the flag to one -#define ClearVoidFlag() (Flags &= ~VoidMask) - #include -// #include -#define Bnd_Precision_Infinite 1e+100 - -//================================================================================================= -Bnd_Box::Bnd_Box() - // Equal to SetVoid(); - : Xmin(RealLast()), - Xmax(-RealLast()), - Ymin(RealLast()), - Ymax(-RealLast()), - Zmin(RealLast()), - Zmax(-RealLast()), - Gap(0.0), - Flags(VoidMask) +namespace { +// Precision constant for infinite bounds +constexpr Standard_Real THE_BND_PRECISION_INFINITE = 1e+100; + +// Precomputed unit direction vectors for bounding box transformations +constexpr gp_Dir THE_DIR_XMIN{gp_Dir::D::NX}; +constexpr gp_Dir THE_DIR_XMAX{gp_Dir::D::X}; +constexpr gp_Dir THE_DIR_YMIN{gp_Dir::D::NY}; +constexpr gp_Dir THE_DIR_YMAX{gp_Dir::D::Y}; +constexpr gp_Dir THE_DIR_ZMIN{gp_Dir::D::NZ}; +constexpr gp_Dir THE_DIR_ZMAX{gp_Dir::D::Z}; + +// Computes minimum squared distance between two 1D intervals +inline Standard_Real DistMini2Box(const Standard_Real theR1Min, + const Standard_Real theR1Max, + const Standard_Real theR2Min, + const Standard_Real theR2Max) noexcept +{ + const Standard_Real aR1 = Square(theR1Min - theR2Max); + const Standard_Real aR2 = Square(theR1Max - theR2Min); + return std::min(aR1, aR2); } -//================================================================================================= +// Computes squared distance in one dimension, returns 0 if intervals overlap +inline Standard_Real DistanceInDimension(const Standard_Real theMin1, + const Standard_Real theMax1, + const Standard_Real theMin2, + const Standard_Real theMax2) noexcept +{ + // Check if intervals overlap + if ((theMin1 <= theMin2 && theMin2 <= theMax1) || (theMin2 <= theMin1 && theMin1 <= theMax2)) + return 0.0; + return DistMini2Box(theMin1, theMax1, theMin2, theMax2); +} -Bnd_Box::Bnd_Box(const gp_Pnt& theMin, const gp_Pnt& theMax) - // Equal to Update(theMin.X(), theMin.Y(), theMin.Z(), theMax.X(), theMax.Y(), theMax.Z()); - : Xmin(theMin.X()), - Xmax(theMax.X()), - Ymin(theMin.Y()), - Ymax(theMax.Y()), - Zmin(theMin.Z()), - Zmax(theMax.Z()), - Gap(0.0), - Flags(0) +// Tests if a 2D segment is outside a 2D box +Standard_Boolean IsSegmentOut(const Standard_Real theX1, + const Standard_Real theY1, + const Standard_Real theX2, + const Standard_Real theY2, + const Standard_Real theXs1, + const Standard_Real theYs1, + const Standard_Real theXs2, + const Standard_Real theYs2) noexcept { + constexpr Standard_Real anEps = RealSmall(); + const Standard_Real aXsMin = std::min(theXs1, theXs2); + const Standard_Real aXsMax = std::max(theXs1, theXs2); + const Standard_Real aYsMin = std::min(theYs1, theYs2); + const Standard_Real aYsMax = std::max(theYs1, theYs2); + + if (aYsMax - aYsMin < anEps && (theY1 - theYs1 < anEps && theYs1 - theY2 < anEps) + && ((aXsMin - theX1 < anEps && theX1 - aXsMax < anEps) + || (aXsMin - theX2 < anEps && theX2 - aXsMax < anEps) + || (theX1 - theXs1 < anEps && theXs1 - theX2 < anEps))) + return Standard_False; + if (aXsMax - aXsMin < anEps && (theX1 - theXs1 < anEps && theXs1 - theX2 < anEps) + && ((aYsMin - theY1 < anEps && theY1 - aYsMax < anEps) + || (aYsMin - theY2 < anEps && theY2 - aYsMax < anEps) + || (theY1 - theYs1 < anEps && theYs1 - theY2 < anEps))) + return Standard_False; + + if ((theXs1 < theX1 && theXs2 < theX1) || (theXs1 > theX2 && theXs2 > theX2) + || (theYs1 < theY1 && theYs2 < theY1) || (theYs1 > theY2 && theYs2 > theY2)) + return Standard_True; + + if (std::abs(theXs2 - theXs1) > anEps) + { + const Standard_Real aYa = + (std::min(theX1, theX2) - theXs1) * (theYs2 - theYs1) / (theXs2 - theXs1) + theYs1; + const Standard_Real aYb = + (std::max(theX1, theX2) - theXs1) * (theYs2 - theYs1) / (theXs2 - theXs1) + theYs1; + if ((aYa < theY1 && aYb < theY1) || (aYa > theY2 && aYb > theY2)) + return Standard_True; + } + else if (std::abs(theYs2 - theYs1) > anEps) + { + const Standard_Real aXa = + (std::min(theY1, theY2) - theYs1) * (theXs2 - theXs1) / (theYs2 - theYs1) + theXs1; + const Standard_Real aXb = + (std::max(theY1, theY2) - theYs1) * (theXs2 - theXs1) / (theYs2 - theYs1) + theXs1; + if ((aXa < theX1 && aXb < theX1) || (aXa > theX2 && aXb > theX2)) + return Standard_True; + } + else + return Standard_True; + + return Standard_False; } +} // anonymous namespace //================================================================================================= @@ -92,22 +149,16 @@ void Bnd_Box::Update(const Standard_Real x, Xmax = X; Ymax = Y; Zmax = Z; - ClearVoidFlag(); + Flags &= ~VoidMask; } else { - if (x < Xmin) - Xmin = x; - if (X > Xmax) - Xmax = X; - if (y < Ymin) - Ymin = y; - if (Y > Ymax) - Ymax = Y; - if (z < Zmin) - Zmin = z; - if (Z > Zmax) - Zmax = Z; + Xmin = std::min(Xmin, x); + Xmax = std::max(Xmax, X); + Ymin = std::min(Ymin, y); + Ymax = std::max(Ymax, Y); + Zmin = std::min(Zmin, z); + Zmax = std::max(Zmax, Z); } } @@ -123,132 +174,114 @@ void Bnd_Box::Update(const Standard_Real X, const Standard_Real Y, const Standar Xmax = X; Ymax = Y; Zmax = Z; - ClearVoidFlag(); + Flags &= ~VoidMask; } else { - if (X < Xmin) - Xmin = X; - else if (X > Xmax) - Xmax = X; - if (Y < Ymin) - Ymin = Y; - else if (Y > Ymax) - Ymax = Y; - if (Z < Zmin) - Zmin = Z; - else if (Z > Zmax) - Zmax = Z; + Xmin = std::min(Xmin, X); + Xmax = std::max(Xmax, X); + Ymin = std::min(Ymin, Y); + Ymax = std::max(Ymax, Y); + Zmin = std::min(Zmin, Z); + Zmax = std::max(Zmax, Z); } } //================================================================================================= -Standard_Real Bnd_Box::GetGap() const +void Bnd_Box::Get(Standard_Real& theXmin, + Standard_Real& theYmin, + Standard_Real& theZmin, + Standard_Real& theXmax, + Standard_Real& theYmax, + Standard_Real& theZmax) const { - return Gap; + if (IsVoid()) + { + throw Standard_ConstructionError("Bnd_Box is void"); + } + + theXmin = GetXMin(); + theXmax = GetXMax(); + theYmin = GetYMin(); + theYmax = GetYMax(); + theZmin = GetZMin(); + theZmax = GetZMax(); } //================================================================================================= -void Bnd_Box::SetGap(const Standard_Real Tol) +Bnd_Box::Limits Bnd_Box::Get() const { - Gap = Tol; + return {GetXMin(), GetXMax(), GetYMin(), GetYMax(), GetZMin(), GetZMax()}; } //================================================================================================= -void Bnd_Box::Enlarge(const Standard_Real Tol) +Standard_Real Bnd_Box::GetXMin() const { - Gap = std::max(Gap, std::abs(Tol)); + return IsOpenXmin() ? -THE_BND_PRECISION_INFINITE : Xmin - Gap; } //================================================================================================= -void Bnd_Box::Get(Standard_Real& theXmin, - Standard_Real& theYmin, - Standard_Real& theZmin, - Standard_Real& theXmax, - Standard_Real& theYmax, - Standard_Real& theZmax) const +Standard_Real Bnd_Box::GetXMax() const { - if (IsVoid()) - { - throw Standard_ConstructionError("Bnd_Box is void"); - } + return IsOpenXmax() ? THE_BND_PRECISION_INFINITE : Xmax + Gap; +} - if (IsOpenXmin()) - theXmin = -Bnd_Precision_Infinite; - else - theXmin = Xmin - Gap; - if (IsOpenXmax()) - theXmax = Bnd_Precision_Infinite; - else - theXmax = Xmax + Gap; - if (IsOpenYmin()) - theYmin = -Bnd_Precision_Infinite; - else - theYmin = Ymin - Gap; - if (IsOpenYmax()) - theYmax = Bnd_Precision_Infinite; - else - theYmax = Ymax + Gap; - if (IsOpenZmin()) - theZmin = -Bnd_Precision_Infinite; - else - theZmin = Zmin - Gap; - if (IsOpenZmax()) - theZmax = Bnd_Precision_Infinite; - else - theZmax = Zmax + Gap; +//================================================================================================= + +Standard_Real Bnd_Box::GetYMin() const +{ + return IsOpenYmin() ? -THE_BND_PRECISION_INFINITE : Ymin - Gap; +} + +//================================================================================================= + +Standard_Real Bnd_Box::GetYMax() const +{ + return IsOpenYmax() ? THE_BND_PRECISION_INFINITE : Ymax + Gap; +} + +//================================================================================================= + +Standard_Real Bnd_Box::GetZMin() const +{ + return IsOpenZmin() ? -THE_BND_PRECISION_INFINITE : Zmin - Gap; +} + +//================================================================================================= + +Standard_Real Bnd_Box::GetZMax() const +{ + return IsOpenZmax() ? THE_BND_PRECISION_INFINITE : Zmax + Gap; } //================================================================================================= gp_Pnt Bnd_Box::CornerMin() const { - gp_Pnt aCornerMin; if (IsVoid()) { throw Standard_ConstructionError("Bnd_Box is void"); } - if (IsOpenXmin()) - aCornerMin.SetX(-Bnd_Precision_Infinite); - else - aCornerMin.SetX(Xmin - Gap); - if (IsOpenYmin()) - aCornerMin.SetY(-Bnd_Precision_Infinite); - else - aCornerMin.SetY(Ymin - Gap); - if (IsOpenZmin()) - aCornerMin.SetZ(-Bnd_Precision_Infinite); - else - aCornerMin.SetZ(Zmin - Gap); - return aCornerMin; + return gp_Pnt(IsOpenXmin() ? -THE_BND_PRECISION_INFINITE : Xmin - Gap, + IsOpenYmin() ? -THE_BND_PRECISION_INFINITE : Ymin - Gap, + IsOpenZmin() ? -THE_BND_PRECISION_INFINITE : Zmin - Gap); } //================================================================================================= gp_Pnt Bnd_Box::CornerMax() const { - gp_Pnt aCornerMax; if (IsVoid()) { throw Standard_ConstructionError("Bnd_Box is void"); } - if (IsOpenXmax()) - aCornerMax.SetX(Bnd_Precision_Infinite); - else - aCornerMax.SetX(Xmax + Gap); - if (IsOpenYmax()) - aCornerMax.SetY(Bnd_Precision_Infinite); - else - aCornerMax.SetY(Ymax + Gap); - if (IsOpenZmax()) - aCornerMax.SetZ(Bnd_Precision_Infinite); - else - aCornerMax.SetZ(Zmax + Gap); - return aCornerMax; + return gp_Pnt(IsOpenXmax() ? THE_BND_PRECISION_INFINITE : Xmax + Gap, + IsOpenYmax() ? THE_BND_PRECISION_INFINITE : Ymax + Gap, + IsOpenZmax() ? THE_BND_PRECISION_INFINITE : Zmax + Gap); } //================================================================================================= @@ -306,11 +339,15 @@ Standard_Boolean Bnd_Box::IsZThin(const Standard_Real tol) const Standard_Boolean Bnd_Box::IsThin(const Standard_Real tol) const { - if (!IsXThin(tol)) + if (IsWhole()) return Standard_False; - if (!IsYThin(tol)) + if (IsVoid()) + return Standard_True; + if (IsOpenXmin() || IsOpenXmax() || Xmax - Xmin >= tol) return Standard_False; - if (!IsZThin(tol)) + if (IsOpenYmin() || IsOpenYmax() || Ymax - Ymin >= tol) + return Standard_False; + if (IsOpenZmin() || IsOpenZmax() || Zmax - Zmin >= tol) return Standard_False; return Standard_True; } @@ -374,27 +411,27 @@ Bnd_Box Bnd_Box::Transformed(const gp_Trsf& T) const Standard_Integer aNbDirs = 0; if (IsOpenXmin()) { - aDirs[aNbDirs++].SetCoord(-1., 0., 0.); + aDirs[aNbDirs++] = THE_DIR_XMIN; } if (IsOpenXmax()) { - aDirs[aNbDirs++].SetCoord(1., 0., 0.); + aDirs[aNbDirs++] = THE_DIR_XMAX; } if (IsOpenYmin()) { - aDirs[aNbDirs++].SetCoord(0., -1., 0.); + aDirs[aNbDirs++] = THE_DIR_YMIN; } if (IsOpenYmax()) { - aDirs[aNbDirs++].SetCoord(0., 1., 0.); + aDirs[aNbDirs++] = THE_DIR_YMAX; } if (IsOpenZmin()) { - aDirs[aNbDirs++].SetCoord(0., 0., -1.); + aDirs[aNbDirs++] = THE_DIR_ZMIN; } if (IsOpenZmax()) { - aDirs[aNbDirs++].SetCoord(0., 0., 1.); + aDirs[aNbDirs++] = THE_DIR_ZMAX; } for (Standard_Integer aDirIter = 0; aDirIter < aNbDirs; ++aDirIter) @@ -539,9 +576,8 @@ Standard_Boolean Bnd_Box::IsOut(const gp_Pln& P) const { Standard_Real A, B, C, D; P.Coefficients(A, B, C, D); - Standard_Real d = A * (Xmin - Gap) + B * (Ymin - Gap) + C * (Zmin - Gap) + D; - // Standard_Boolean plus = d > 0; - Standard_Integer plus = d > 0; + Standard_Real d = A * (Xmin - Gap) + B * (Ymin - Gap) + C * (Zmin - Gap) + D; + Standard_Boolean plus = d > 0; if (plus != ((A * (Xmin - Gap) + B * (Ymin - Gap) + C * (Zmax + Gap) + D) > 0)) return Standard_False; if (plus != ((A * (Xmin - Gap) + B * (Ymax + Gap) + C * (Zmin - Gap) + D) > 0)) @@ -571,13 +607,17 @@ Standard_Boolean Bnd_Box::IsOut(const gp_Lin& L) const return Standard_True; else { - Standard_Real xmin = 0, xmax = 0, ymin = 0, ymax = 0, zmin, zmax; + Standard_Real xmin = 0, xmax = 0, ymin = 0, ymax = 0, zmin = 0, zmax = 0; Standard_Real parmin, parmax, par1, par2; Standard_Boolean xToSet, yToSet; Standard_Real myXmin, myYmin, myZmin, myXmax, myYmax, myZmax; Get(myXmin, myYmin, myZmin, myXmax, myYmax, myZmax); - if (std::abs(L.Direction().XYZ().X()) > 0.) + const Standard_Real aDirX = std::abs(L.Direction().XYZ().X()); + const Standard_Real aDirY = std::abs(L.Direction().XYZ().Y()); + const Standard_Real aDirZ = std::abs(L.Direction().XYZ().Z()); + + if (aDirX > 0.) { par1 = (myXmin - L.Location().XYZ().X()) / L.Direction().XYZ().X(); par2 = (myXmax - L.Location().XYZ().X()) / L.Direction().XYZ().X(); @@ -593,12 +633,12 @@ Standard_Boolean Bnd_Box::IsOut(const gp_Lin& L) const } xmin = L.Location().XYZ().X(); xmax = L.Location().XYZ().X(); - parmin = -Bnd_Precision_Infinite; - parmax = Bnd_Precision_Infinite; + parmin = -THE_BND_PRECISION_INFINITE; + parmax = THE_BND_PRECISION_INFINITE; xToSet = Standard_False; } - if (std::abs(L.Direction().XYZ().Y()) > 0.) + if (aDirY > 0.) { par1 = (myYmin - L.Location().XYZ().Y()) / L.Direction().XYZ().Y(); par2 = (myYmax - L.Location().XYZ().Y()) / L.Direction().XYZ().Y(); @@ -621,7 +661,7 @@ Standard_Boolean Bnd_Box::IsOut(const gp_Lin& L) const yToSet = Standard_False; } - if (std::abs(L.Direction().XYZ().Z()) > 0.) + if (aDirZ > 0.) { par1 = (myZmin - L.Location().XYZ().Z()) / L.Direction().XYZ().Z(); par2 = (myZmax - L.Location().XYZ().Z()) / L.Direction().XYZ().Z(); @@ -673,50 +713,49 @@ Standard_Boolean Bnd_Box::IsOut(const gp_Lin& L) const Standard_Boolean Bnd_Box::IsOut(const Bnd_Box& Other) const { - // modified by NIZNHY-PKV Fri Jul 08 11:03:43 2011f + // Fast path for non-open boxes with early exit if (!Flags && !Other.Flags) { - Standard_Boolean bRet; - Standard_Real delta; - // - delta = Other.Gap + Gap; - bRet = ((Xmin - Other.Xmax > delta) || (Other.Xmin - Xmax > delta) - || (Ymin - Other.Ymax > delta) || (Other.Ymin - Ymax > delta) - || (Zmin - Other.Zmax > delta) || (Other.Zmin - Zmax > delta)); - return bRet; + const Standard_Real aDelta = Other.Gap + Gap; + // Early exit on first separating axis found + if (Xmin - Other.Xmax > aDelta) + return Standard_True; + if (Other.Xmin - Xmax > aDelta) + return Standard_True; + if (Ymin - Other.Ymax > aDelta) + return Standard_True; + if (Other.Ymin - Ymax > aDelta) + return Standard_True; + if (Zmin - Other.Zmax > aDelta) + return Standard_True; + if (Other.Zmin - Zmax > aDelta) + return Standard_True; + return Standard_False; } - // modified by NIZNHY-PKV Fri Jul 08 11:03:46 2011t - if (IsVoid()) - return Standard_True; - if (Other.IsVoid()) + + // Handle special cases + if (IsVoid() || Other.IsVoid()) return Standard_True; - if (IsWhole()) - return Standard_False; - if (Other.IsWhole()) + if (IsWhole() || Other.IsWhole()) return Standard_False; - Standard_Real delta = Other.Gap + Gap; + const Standard_Real aDelta = Other.Gap + Gap; - if (!IsOpenXmin() && !Other.IsOpenXmax()) - if (Xmin - Other.Xmax > delta) - return Standard_True; - if (!IsOpenXmax() && !Other.IsOpenXmin()) - if (Other.Xmin - Xmax > delta) - return Standard_True; + // Check each axis with early exit + if (!IsOpenXmin() && !Other.IsOpenXmax() && Xmin - Other.Xmax > aDelta) + return Standard_True; + if (!IsOpenXmax() && !Other.IsOpenXmin() && Other.Xmin - Xmax > aDelta) + return Standard_True; - if (!IsOpenYmin() && !Other.IsOpenYmax()) - if (Ymin - Other.Ymax > delta) - return Standard_True; - if (!IsOpenYmax() && !Other.IsOpenYmin()) - if (Other.Ymin - Ymax > delta) - return Standard_True; + if (!IsOpenYmin() && !Other.IsOpenYmax() && Ymin - Other.Ymax > aDelta) + return Standard_True; + if (!IsOpenYmax() && !Other.IsOpenYmin() && Other.Ymin - Ymax > aDelta) + return Standard_True; - if (!IsOpenZmin() && !Other.IsOpenZmax()) - if (Zmin - Other.Zmax > delta) - return Standard_True; - if (!IsOpenZmax() && !Other.IsOpenZmin()) - if (Other.Zmin - Zmax > delta) - return Standard_True; + if (!IsOpenZmin() && !Other.IsOpenZmax() && Zmin - Other.Zmax > aDelta) + return Standard_True; + if (!IsOpenZmax() && !Other.IsOpenZmin() && Other.Zmin - Zmax > aDelta) + return Standard_True; return Standard_False; } @@ -737,54 +776,6 @@ Standard_Boolean Bnd_Box::IsOut(const gp_Trsf& T1, const Bnd_Box& Other, const g //================================================================================================= -static Standard_Boolean IsSegmentOut(Standard_Real x1, - Standard_Real y1, - Standard_Real x2, - Standard_Real y2, - Standard_Real xs1, - Standard_Real ys1, - Standard_Real xs2, - Standard_Real ys2) -{ - constexpr Standard_Real eps = RealSmall(); - Standard_Real xsmin = std::min(xs1, xs2); - Standard_Real xsmax = std::max(xs1, xs2); - Standard_Real ysmin = std::min(ys1, ys2); - Standard_Real ysmax = std::max(ys1, ys2); - - if (ysmax - ysmin < eps && (y1 - ys1 < eps && ys1 - y2 < eps) - && ((xsmin - x1 < eps && x1 - xsmax < eps) || (xsmin - x2 < eps && x2 - xsmax < eps) - || (x1 - xs1 < eps && xs1 - x2 < eps))) - return Standard_False; - if (xsmax - xsmin < eps && (x1 - xs1 < eps && xs1 - x2 < eps) - && ((ysmin - y1 < eps && y1 - ysmax < eps) || (ysmin - y2 < eps && y2 - ysmax < eps) - || (y1 - ys1 < eps && ys1 - y2 < eps))) - return Standard_False; - - if ((xs1 < x1 && xs2 < x1) || (xs1 > x2 && xs2 > x2) || (ys1 < y1 && ys2 < y1) - || (ys1 > y2 && ys2 > y2)) - return Standard_True; - - if (std::abs(xs2 - xs1) > eps) - { - Standard_Real ya = (std::min(x1, x2) - xs1) * (ys2 - ys1) / (xs2 - xs1) + ys1; - Standard_Real yb = (std::max(x1, x2) - xs1) * (ys2 - ys1) / (xs2 - xs1) + ys1; - if ((ya < y1 && yb < y1) || (ya > y2 && yb > y2)) - return Standard_True; - } - else if (std::abs(ys2 - ys1) > eps) - { - Standard_Real xa = (std::min(y1, y2) - ys1) * (xs2 - xs1) / (ys2 - ys1) + xs1; - Standard_Real xb = (std::max(y1, y2) - ys1) * (xs2 - xs1) / (ys2 - ys1) + xs1; - if ((xa < x1 && xb < x1) || (xa > x2 && xb > x2)) - return Standard_True; - } - else - return Standard_True; - - return Standard_False; -} - Standard_Boolean Bnd_Box::IsOut(const gp_Pnt& P1, const gp_Pnt& P2, const gp_Dir& D) const { @@ -1009,53 +1000,19 @@ Standard_Boolean Bnd_Box::IsOut(const gp_Pnt& P1, const gp_Pnt& P2, const gp_Dir // purpose : computes the minimum distance between two boxes //======================================================================= -static Standard_Real DistMini2Box(const Standard_Real r1min, - const Standard_Real r1max, - const Standard_Real r2min, - const Standard_Real r2max) -{ - Standard_Real r1, r2; - - r1 = Square(r1min - r2max); - r2 = Square(r1max - r2min); - return std::min(r1, r2); -} - Standard_Real Bnd_Box::Distance(const Bnd_Box& Other) const { - Standard_Real xminB1, yminB1, zminB1, xmaxB1, ymaxB1, zmaxB1; - Standard_Real xminB2, yminB2, zminB2, xmaxB2, ymaxB2, zmaxB2; - Standard_Real dist_x, dist_y, dist_z, dist_t; + Standard_Real aXMinB1, aYMinB1, aZMinB1, aXMaxB1, aYMaxB1, aZMaxB1; + Standard_Real aXMinB2, aYMinB2, aZMinB2, aXMaxB2, aYMaxB2, aZMaxB2; - Get(xminB1, yminB1, zminB1, xmaxB1, ymaxB1, zmaxB1); - Other.Get(xminB2, yminB2, zminB2, xmaxB2, ymaxB2, zmaxB2); + Get(aXMinB1, aYMinB1, aZMinB1, aXMaxB1, aYMaxB1, aZMaxB1); + Other.Get(aXMinB2, aYMinB2, aZMinB2, aXMaxB2, aYMaxB2, aZMaxB2); - if (((xminB1 <= xminB2) && (xminB2 <= xmaxB1)) || ((xminB2 <= xminB1) && (xminB1 <= xmaxB2))) - { - dist_x = 0; - } - else - { - dist_x = DistMini2Box(xminB1, xmaxB1, xminB2, xmaxB2); - } - if (((yminB1 <= yminB2) && (yminB2 <= ymaxB1)) || ((yminB2 <= yminB1) && (yminB1 <= ymaxB2))) - { - dist_y = 0; - } - else - { - dist_y = DistMini2Box(yminB1, ymaxB1, yminB2, ymaxB2); - } - if (((zminB1 <= zminB2) && (zminB2 <= zmaxB1)) || ((zminB2 <= zminB1) && (zminB1 <= zmaxB2))) - { - dist_z = 0; - } - else - { - dist_z = DistMini2Box(zminB1, zmaxB1, zminB2, zmaxB2); - } - dist_t = dist_x + dist_y + dist_z; - return (std::sqrt(dist_t)); + const Standard_Real aDistX = DistanceInDimension(aXMinB1, aXMaxB1, aXMinB2, aXMaxB2); + const Standard_Real aDistY = DistanceInDimension(aYMinB1, aYMaxB1, aYMinB2, aYMaxB2); + const Standard_Real aDistZ = DistanceInDimension(aZMinB1, aZMaxB1, aZMinB2, aZMaxB2); + + return std::sqrt(aDistX + aDistY + aDistZ); } //================================================================================================= diff --git a/src/FoundationClasses/TKMath/Bnd/Bnd_Box.hxx b/src/FoundationClasses/TKMath/Bnd/Bnd_Box.hxx index 5dcf314682..be530c5734 100644 --- a/src/FoundationClasses/TKMath/Bnd/Bnd_Box.hxx +++ b/src/FoundationClasses/TKMath/Bnd/Bnd_Box.hxx @@ -24,6 +24,10 @@ #include #include #include + +#include +#include + class gp_Pnt; class gp_Dir; class gp_Trsf; @@ -61,21 +65,53 @@ class Bnd_Box public: DEFINE_STANDARD_ALLOC + //! Structure containing the box limits (Xmin, Xmax, Ymin, Ymax, Zmin, Zmax). + //! The values include the gap and account for open directions. + struct Limits + { + double Xmin; //!< Minimum X coordinate + double Xmax; //!< Maximum X coordinate + double Ymin; //!< Minimum Y coordinate + double Ymax; //!< Maximum Y coordinate + double Zmin; //!< Minimum Z coordinate + double Zmax; //!< Maximum Z coordinate + }; + //! Creates an empty Box. //! The constructed box is qualified Void. Its gap is null. - Standard_EXPORT Bnd_Box(); + constexpr Bnd_Box() + : Xmin(RealLast()), + Xmax(-RealLast()), + Ymin(RealLast()), + Ymax(-RealLast()), + Zmin(RealLast()), + Zmax(-RealLast()), + Gap(0.0), + Flags(VoidMask) + { + } //! Creates a bounding box, it contains: //! - minimum/maximum point of bounding box, //! The constructed box is qualified Void. Its gap is null. - Standard_EXPORT Bnd_Box(const gp_Pnt& theMin, const gp_Pnt& theMax); + constexpr Bnd_Box(const gp_Pnt& theMin, const gp_Pnt& theMax) + : Xmin(theMin.X()), + Xmax(theMax.X()), + Ymin(theMin.Y()), + Ymax(theMax.Y()), + Zmin(theMin.Z()), + Zmax(theMax.Z()), + Gap(0.0), + Flags(0) + { + } //! Sets this bounding box so that it covers the whole of 3D space. //! It is infinitely long in all directions. - void SetWhole() { Flags = WholeMask; } + void SetWhole() noexcept { Flags = WholeMask; } //! Sets this bounding box so that it is empty. All points are outside a void box. - void SetVoid() + void SetVoid() noexcept { Xmin = RealLast(); Xmax = -RealLast(); @@ -115,10 +151,10 @@ public: Standard_EXPORT void Update(const Standard_Real X, const Standard_Real Y, const Standard_Real Z); //! Returns the gap of this bounding box. - Standard_EXPORT Standard_Real GetGap() const; + [[nodiscard]] constexpr Standard_Real GetGap() const noexcept { return Gap; } //! Set the gap of this bounding box to abs(Tol). - Standard_EXPORT void SetGap(const Standard_Real Tol); + void SetGap(const Standard_Real Tol) noexcept { Gap = std::abs(Tol); } //! Enlarges the box with a tolerance value. //! (minvalues-std::abs() and maxvalues+std::abs()) @@ -126,7 +162,7 @@ public: //! intervals of definition, when they are finite, are reduced by //! the absolute value of Tol, while the maximum values are //! increased by the same amount. - Standard_EXPORT void Enlarge(const Standard_Real Tol); + void Enlarge(const Standard_Real Tol) noexcept { Gap = std::max(Gap, std::abs(Tol)); } //! Returns the bounds of this bounding box. The gap is included. //! If this bounding box is infinite (i.e. "open"), returned values @@ -140,83 +176,114 @@ public: Standard_Real& theYmax, Standard_Real& theZmax) const; + //! Returns the bounds of this bounding box as a Limits structure. + //! The gap is included. If this bounding box is infinite (i.e. "open"), + //! returned values may be equal to +/- Precision::Infinite(). + //! If the box is void, returns raw internal values. + //! Can be used with C++17 structured bindings: + //! @code + //! auto [xmin, xmax, ymin, ymax, zmin, zmax] = aBox.Get(); + //! @endcode + [[nodiscard]] Standard_EXPORT Limits Get() const; + + //! Returns the Xmin value (IsOpenXmin() ? -Precision::Infinite() : Xmin - GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetXMin() const; + + //! Returns the Xmax value (IsOpenXmax() ? Precision::Infinite() : Xmax + GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetXMax() const; + + //! Returns the Ymin value (IsOpenYmin() ? -Precision::Infinite() : Ymin - GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetYMin() const; + + //! Returns the Ymax value (IsOpenYmax() ? Precision::Infinite() : Ymax + GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetYMax() const; + + //! Returns the Zmin value (IsOpenZmin() ? -Precision::Infinite() : Zmin - GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetZMin() const; + + //! Returns the Zmax value (IsOpenZmax() ? Precision::Infinite() : Zmax + GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetZMax() const; + //! Returns the lower corner of this bounding box. The gap is included. //! If this bounding box is infinite (i.e. "open"), returned values //! may be equal to +/- Precision::Infinite(). //! Standard_ConstructionError exception will be thrown if the box is void. //! if IsVoid() - Standard_EXPORT gp_Pnt CornerMin() const; + [[nodiscard]] Standard_EXPORT gp_Pnt CornerMin() const; //! Returns the upper corner of this bounding box. The gap is included. //! If this bounding box is infinite (i.e. "open"), returned values //! may be equal to +/- Precision::Infinite(). //! Standard_ConstructionError exception will be thrown if the box is void. //! if IsVoid() - Standard_EXPORT gp_Pnt CornerMax() const; + [[nodiscard]] Standard_EXPORT gp_Pnt CornerMax() const; //! The Box will be infinitely long in the Xmin //! direction. - void OpenXmin() { Flags |= XminMask; } + void OpenXmin() noexcept { Flags |= XminMask; } //! The Box will be infinitely long in the Xmax //! direction. - void OpenXmax() { Flags |= XmaxMask; } + void OpenXmax() noexcept { Flags |= XmaxMask; } //! The Box will be infinitely long in the Ymin //! direction. - void OpenYmin() { Flags |= YminMask; } + void OpenYmin() noexcept { Flags |= YminMask; } //! The Box will be infinitely long in the Ymax //! direction. - void OpenYmax() { Flags |= YmaxMask; } + void OpenYmax() noexcept { Flags |= YmaxMask; } //! The Box will be infinitely long in the Zmin //! direction. - void OpenZmin() { Flags |= ZminMask; } + void OpenZmin() noexcept { Flags |= ZminMask; } //! The Box will be infinitely long in the Zmax //! direction. - void OpenZmax() { Flags |= ZmaxMask; } + void OpenZmax() noexcept { Flags |= ZmaxMask; } //! Returns true if this bounding box has at least one open direction. - Standard_Boolean IsOpen() const { return (Flags & WholeMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpen() const noexcept { return (Flags & WholeMask) != 0; } //! Returns true if this bounding box is open in the Xmin direction. - Standard_Boolean IsOpenXmin() const { return (Flags & XminMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenXmin() const noexcept { return (Flags & XminMask) != 0; } //! Returns true if this bounding box is open in the Xmax direction. - Standard_Boolean IsOpenXmax() const { return (Flags & XmaxMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenXmax() const noexcept { return (Flags & XmaxMask) != 0; } //! Returns true if this bounding box is open in the Ymix direction. - Standard_Boolean IsOpenYmin() const { return (Flags & YminMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenYmin() const noexcept { return (Flags & YminMask) != 0; } //! Returns true if this bounding box is open in the Ymax direction. - Standard_Boolean IsOpenYmax() const { return (Flags & YmaxMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenYmax() const noexcept { return (Flags & YmaxMask) != 0; } //! Returns true if this bounding box is open in the Zmin direction. - Standard_Boolean IsOpenZmin() const { return (Flags & ZminMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenZmin() const noexcept { return (Flags & ZminMask) != 0; } //! Returns true if this bounding box is open in the Zmax direction. - Standard_Boolean IsOpenZmax() const { return (Flags & ZmaxMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenZmax() const noexcept { return (Flags & ZmaxMask) != 0; } //! Returns true if this bounding box is infinite in all 6 directions (WholeSpace flag). - Standard_Boolean IsWhole() const { return (Flags & WholeMask) == WholeMask; } + [[nodiscard]] Standard_Boolean IsWhole() const noexcept + { + return (Flags & WholeMask) == WholeMask; + } //! Returns true if this bounding box is empty (Void flag). - Standard_Boolean IsVoid() const { return (Flags & VoidMask) != 0; } + [[nodiscard]] Standard_Boolean IsVoid() const noexcept { return (Flags & VoidMask) != 0; } //! true if xmax-xmin < tol. - Standard_EXPORT Standard_Boolean IsXThin(const Standard_Real tol) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsXThin(const Standard_Real tol) const; //! true if ymax-ymin < tol. - Standard_EXPORT Standard_Boolean IsYThin(const Standard_Real tol) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsYThin(const Standard_Real tol) const; //! true if zmax-zmin < tol. - Standard_EXPORT Standard_Boolean IsZThin(const Standard_Real tol) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsZThin(const Standard_Real tol) const; //! Returns true if IsXThin, IsYThin and IsZThin are all true, //! i.e. if the box is thin in all three dimensions. - Standard_EXPORT Standard_Boolean IsThin(const Standard_Real tol) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsThin(const Standard_Real tol) const; //! Returns a bounding box which is the result of applying the //! transformation T to this bounding box. @@ -224,7 +291,7 @@ public: //! Applying a geometric transformation (for example, a //! rotation) to a bounding box generally increases its //! dimensions. This is not optimal for algorithms which use it. - Standard_NODISCARD Standard_EXPORT Bnd_Box Transformed(const gp_Trsf& T) const; + [[nodiscard]] Standard_EXPORT Bnd_Box Transformed(const gp_Trsf& T) const; //! Adds the box to . Standard_EXPORT void Add(const Bnd_Box& Other); @@ -241,39 +308,42 @@ public: Standard_EXPORT void Add(const gp_Dir& D); //! Returns True if the Pnt is out the box. - Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt& P) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt& P) const; //! Returns False if the line intersects the box. - Standard_EXPORT Standard_Boolean IsOut(const gp_Lin& L) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const gp_Lin& L) const; //! Returns False if the plane intersects the box. - Standard_EXPORT Standard_Boolean IsOut(const gp_Pln& P) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const gp_Pln& P) const; //! Returns False if the intersects or is inside . - Standard_EXPORT Standard_Boolean IsOut(const Bnd_Box& Other) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const Bnd_Box& Other) const; //! Returns False if the transformed intersects //! or is inside . - Standard_EXPORT Standard_Boolean IsOut(const Bnd_Box& Other, const gp_Trsf& T) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const Bnd_Box& Other, + const gp_Trsf& T) const; //! Returns False if the transformed intersects //! or is inside the transformed box . - Standard_EXPORT Standard_Boolean IsOut(const gp_Trsf& T1, - const Bnd_Box& Other, - const gp_Trsf& T2) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const gp_Trsf& T1, + const Bnd_Box& Other, + const gp_Trsf& T2) const; //! Returns False if the flat band lying between two parallel //! lines represented by their reference points , and //! direction intersects the box. - Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt& P1, const gp_Pnt& P2, const gp_Dir& D) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt& P1, + const gp_Pnt& P2, + const gp_Dir& D) const; //! Computes the minimum distance between two boxes. - Standard_EXPORT Standard_Real Distance(const Bnd_Box& Other) const; + [[nodiscard]] Standard_EXPORT Standard_Real Distance(const Bnd_Box& Other) const; Standard_EXPORT void Dump() const; //! Computes the squared diagonal of me. - Standard_Real SquareExtent() const + [[nodiscard]] Standard_Real SquareExtent() const noexcept { if (IsVoid()) { @@ -290,7 +360,7 @@ public: //! box). This can be a Void box in case if its sides has been defined as infinite (Open) without //! adding any finite points. WARNING! This method relies on Open flags, the infinite points added //! using Add() method will be returned as is. - Bnd_Box FinitePart() const + [[nodiscard]] Bnd_Box FinitePart() const noexcept { if (!HasFinitePart()) { @@ -304,7 +374,10 @@ public: } //! Returns TRUE if this box has finite part. - Standard_Boolean HasFinitePart() const { return !IsVoid() && Xmax >= Xmin; } + [[nodiscard]] Standard_Boolean HasFinitePart() const noexcept + { + return !IsVoid() && Xmax >= Xmin; + } //! Dumps the content of me into the stream Standard_EXPORT void DumpJson(Standard_OStream& theOStream, Standard_Integer theDepth = -1) const; diff --git a/src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.cxx b/src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.cxx index 004c3ff9e2..e689c06b4f 100644 --- a/src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.cxx +++ b/src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.cxx @@ -15,12 +15,24 @@ // commercial license or contractual agreement. #include + #include #include #include #include -//-- #include Precision::Infinite() -> 1e+100 +namespace +{ +// Precision constant for infinite bounds +constexpr Standard_Real THE_BND_PRECISION_INFINITE = 1e+100; + +// Precomputed unit direction vectors for bounding box transformations +constexpr gp_Dir2d THE_DIR_XMIN{gp_Dir2d::D::NX}; +constexpr gp_Dir2d THE_DIR_XMAX{gp_Dir2d::D::X}; +constexpr gp_Dir2d THE_DIR_YMIN{gp_Dir2d::D::NY}; +constexpr gp_Dir2d THE_DIR_YMAX{gp_Dir2d::D::Y}; +} // anonymous namespace + //================================================================================================= void Bnd_Box2d::Update(const Standard_Real x, @@ -38,14 +50,14 @@ void Bnd_Box2d::Update(const Standard_Real x, } else { - if (!(Flags & XminMask) && (x < Xmin)) - Xmin = x; - if (!(Flags & XmaxMask) && (X > Xmax)) - Xmax = X; - if (!(Flags & YminMask) && (y < Ymin)) - Ymin = y; - if (!(Flags & YmaxMask) && (Y > Ymax)) - Ymax = Y; + if (!(Flags & XminMask)) + Xmin = std::min(Xmin, x); + if (!(Flags & XmaxMask)) + Xmax = std::max(Xmax, X); + if (!(Flags & YminMask)) + Ymin = std::min(Ymin, y); + if (!(Flags & YmaxMask)) + Ymax = std::max(Ymax, Y); } } @@ -63,14 +75,14 @@ void Bnd_Box2d::Update(const Standard_Real X, const Standard_Real Y) } else { - if (!(Flags & XminMask) && (X < Xmin)) - Xmin = X; - else if (!(Flags & XmaxMask) && (X > Xmax)) - Xmax = X; - if (!(Flags & YminMask) && (Y < Ymin)) - Ymin = Y; - else if (!(Flags & YmaxMask) && (Y > Ymax)) - Ymax = Y; + if (!(Flags & XminMask)) + Xmin = std::min(Xmin, X); + if (!(Flags & XmaxMask)) + Xmax = std::max(Xmax, X); + if (!(Flags & YminMask)) + Ymin = std::min(Ymin, Y); + if (!(Flags & YmaxMask)) + Ymax = std::max(Ymax, Y); } } @@ -80,122 +92,139 @@ void Bnd_Box2d::Get(Standard_Real& x, Standard_Real& y, Standard_Real& Xm, Stand { if (Flags & VoidMask) throw Standard_ConstructionError("Bnd_Box is void"); - Standard_Real pinf = 1e+100; //-- Precision::Infinite(); - if (Flags & XminMask) - x = -pinf; - else - x = Xmin - Gap; - if (Flags & XmaxMask) - Xm = pinf; - else - Xm = Xmax + Gap; - if (Flags & YminMask) - y = -pinf; - else - y = Ymin - Gap; - if (Flags & YmaxMask) - Ym = pinf; - else - Ym = Ymax + Gap; + + x = GetXMin(); + Xm = GetXMax(); + y = GetYMin(); + Ym = GetYMax(); +} + +//================================================================================================= + +Bnd_Box2d::Limits Bnd_Box2d::Get() const +{ + return {GetXMin(), GetXMax(), GetYMin(), GetYMax()}; +} + +//================================================================================================= + +Standard_Real Bnd_Box2d::GetXMin() const +{ + return (Flags & XminMask) ? -THE_BND_PRECISION_INFINITE : Xmin - Gap; +} + +//================================================================================================= + +Standard_Real Bnd_Box2d::GetXMax() const +{ + return (Flags & XmaxMask) ? THE_BND_PRECISION_INFINITE : Xmax + Gap; +} + +//================================================================================================= + +Standard_Real Bnd_Box2d::GetYMin() const +{ + return (Flags & YminMask) ? -THE_BND_PRECISION_INFINITE : Ymin - Gap; +} + +//================================================================================================= + +Standard_Real Bnd_Box2d::GetYMax() const +{ + return (Flags & YmaxMask) ? THE_BND_PRECISION_INFINITE : Ymax + Gap; } //================================================================================================= Bnd_Box2d Bnd_Box2d::Transformed(const gp_Trsf2d& T) const { - gp_TrsfForm F = T.Form(); - Bnd_Box2d newb(*this); + const gp_TrsfForm aF = T.Form(); + Bnd_Box2d aNewBox(*this); if (IsVoid()) - return newb; + return aNewBox; - if (F == gp_Identity) + if (aF == gp_Identity) { } - else if (F == gp_Translation) + else if (aF == gp_Translation) { - Standard_Real DX, DY; - (T.TranslationPart()).Coord(DX, DY); + Standard_Real aDX, aDY; + (T.TranslationPart()).Coord(aDX, aDY); if (!(Flags & XminMask)) - newb.Xmin += DX; + aNewBox.Xmin += aDX; if (!(Flags & XmaxMask)) - newb.Xmax += DX; + aNewBox.Xmax += aDX; if (!(Flags & YminMask)) - newb.Ymin += DY; + aNewBox.Ymin += aDY; if (!(Flags & YmaxMask)) - newb.Ymax += DY; + aNewBox.Ymax += aDY; } else { - gp_Pnt2d P[4]; - Standard_Boolean Vertex[4]; - Standard_Integer i; - Vertex[0] = Standard_True; - Vertex[1] = Standard_True; - Vertex[2] = Standard_True; - Vertex[3] = Standard_True; - gp_Dir2d D[6]; - // Standard_Integer vertices = 0; - Standard_Integer directions = 0; + gp_Pnt2d aP[4]; + Standard_Boolean aVertex[4]; + aVertex[0] = Standard_True; + aVertex[1] = Standard_True; + aVertex[2] = Standard_True; + aVertex[3] = Standard_True; + gp_Dir2d aD[6]; + Standard_Integer aNbDirs = 0; if (Flags & XminMask) { - D[directions].SetCoord(-1., 0.); - directions++; - Vertex[0] = Vertex[2] = Standard_False; + aD[aNbDirs++] = THE_DIR_XMIN; + aVertex[0] = aVertex[2] = Standard_False; } if (Flags & XmaxMask) { - D[directions].SetCoord(1., 0.); - directions++; - Vertex[1] = Vertex[3] = Standard_False; + aD[aNbDirs++] = THE_DIR_XMAX; + aVertex[1] = aVertex[3] = Standard_False; } if (Flags & YminMask) { - D[directions].SetCoord(0., -1.); - directions++; - Vertex[0] = Vertex[1] = Standard_False; + aD[aNbDirs++] = THE_DIR_YMIN; + aVertex[0] = aVertex[1] = Standard_False; } if (Flags & YmaxMask) { - D[directions].SetCoord(0., 1.); - directions++; - Vertex[2] = Vertex[3] = Standard_False; + aD[aNbDirs++] = THE_DIR_YMAX; + aVertex[2] = aVertex[3] = Standard_False; } - newb.SetVoid(); + aNewBox.SetVoid(); - for (i = 0; i < directions; i++) + for (Standard_Integer i = 0; i < aNbDirs; i++) { - D[i].Transform(T); - newb.Add(D[i]); + aD[i].Transform(T); + aNewBox.Add(aD[i]); } - P[0].SetCoord(Xmin, Ymin); - P[1].SetCoord(Xmax, Ymin); - P[2].SetCoord(Xmin, Ymax); - P[3].SetCoord(Xmax, Ymax); - if (Vertex[0]) + aP[0].SetCoord(Xmin, Ymin); + aP[1].SetCoord(Xmax, Ymin); + aP[2].SetCoord(Xmin, Ymax); + aP[3].SetCoord(Xmax, Ymax); + if (aVertex[0]) { - P[0].Transform(T); - newb.Add(P[0]); + aP[0].Transform(T); + aNewBox.Add(aP[0]); } - if (Vertex[1]) + if (aVertex[1]) { - P[1].Transform(T); - newb.Add(P[1]); + aP[1].Transform(T); + aNewBox.Add(aP[1]); } - if (Vertex[2]) + if (aVertex[2]) { - P[2].Transform(T); - newb.Add(P[2]); + aP[2].Transform(T); + aNewBox.Add(aP[2]); } - if (Vertex[3]) + if (aVertex[3]) { - P[3].Transform(T); - newb.Add(P[3]); + aP[3].Transform(T); + aNewBox.Add(aP[3]); } - newb.Gap = Gap; + aNewBox.Gap = Gap; } - return newb; + return aNewBox; } //================================================================================================= diff --git a/src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.hxx b/src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.hxx index d21f0c148f..0bdf52534b 100644 --- a/src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.hxx +++ b/src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.hxx @@ -26,6 +26,10 @@ #include #include #include + +#include +#include + class gp_Dir2d; class gp_Trsf2d; @@ -53,13 +57,23 @@ class Bnd_Box2d public: DEFINE_STANDARD_ALLOC + //! Structure containing the 2D box limits (Xmin, Xmax, Ymin, Ymax). + //! The values include the gap and account for open directions. + struct Limits + { + double Xmin; //!< Minimum X coordinate + double Xmax; //!< Maximum X coordinate + double Ymin; //!< Minimum Y coordinate + double Ymax; //!< Maximum Y coordinate + }; + //! Creates an empty 2D bounding box. //! The constructed box is qualified Void. Its gap is null. - Bnd_Box2d() - : Xmin(0.), - Xmax(0.), - Ymin(0.), - Ymax(0.), + constexpr Bnd_Box2d() + : Xmin(RealLast()), + Xmax(-RealLast()), + Ymin(RealLast()), + Ymax(-RealLast()), Gap(0.), Flags(VoidMask) { @@ -67,13 +81,17 @@ public: //! Sets this bounding box so that it covers the whole 2D //! space, i.e. it is infinite in all directions. - void SetWhole() { Flags = WholeMask; } + void SetWhole() noexcept { Flags = WholeMask; } //! Sets this 2D bounding box so that it is empty. All points are outside a void box. - void SetVoid() + void SetVoid() noexcept { - Flags = VoidMask; + Xmin = RealLast(); + Xmax = -RealLast(); + Ymin = RealLast(); + Ymax = -RealLast(); Gap = 0.0; + Flags = VoidMask; } //! Sets this 2D bounding box so that it bounds @@ -111,22 +129,17 @@ public: Standard_EXPORT void Update(const Standard_Real X, const Standard_Real Y); //! Returns the gap of this 2D bounding box. - Standard_Real GetGap() const { return Gap; } + [[nodiscard]] constexpr Standard_Real GetGap() const noexcept { return Gap; } //! Set the gap of this 2D bounding box to abs(Tol). - void SetGap(const Standard_Real Tol) { Gap = Tol; } + void SetGap(const Standard_Real Tol) noexcept { Gap = std::abs(Tol); } //! Enlarges the box with a tolerance value. //! This means that the minimum values of its X and Y //! intervals of definition, when they are finite, are reduced by //! the absolute value of Tol, while the maximum values are //! increased by the same amount. - void Enlarge(const Standard_Real theTol) - { - Standard_Real aTol = theTol < 0.0 ? -theTol : theTol; - if (Gap < aTol) - Gap = aTol; - } + void Enlarge(const Standard_Real theTol) noexcept { Gap = std::max(Gap, std::abs(theTol)); } //! Returns the bounds of this 2D bounding box. //! The gap is included. If this bounding box is infinite (i.e. "open"), returned values @@ -137,36 +150,61 @@ public: Standard_Real& aXmax, Standard_Real& aYmax) const; + //! Returns the bounds of this 2D bounding box as a Limits structure. + //! The gap is included. If this bounding box is infinite (i.e. "open"), + //! returned values may be equal to +/- Precision::Infinite(). + //! If the box is void, returns raw internal values. + //! Can be used with C++17 structured bindings: + //! @code + //! auto [xmin, xmax, ymin, ymax] = aBox.Get(); + //! @endcode + [[nodiscard]] Standard_EXPORT Limits Get() const; + + //! Returns the Xmin value (IsOpenXmin() ? -Precision::Infinite() : Xmin - GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetXMin() const; + + //! Returns the Xmax value (IsOpenXmax() ? Precision::Infinite() : Xmax + GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetXMax() const; + + //! Returns the Ymin value (IsOpenYmin() ? -Precision::Infinite() : Ymin - GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetYMin() const; + + //! Returns the Ymax value (IsOpenYmax() ? Precision::Infinite() : Ymax + GetGap()). + [[nodiscard]] Standard_EXPORT Standard_Real GetYMax() const; + //! The Box will be infinitely long in the Xmin direction. - void OpenXmin() { Flags |= XminMask; } + void OpenXmin() noexcept { Flags |= XminMask; } //! The Box will be infinitely long in the Xmax direction. - void OpenXmax() { Flags |= XmaxMask; } + void OpenXmax() noexcept { Flags |= XmaxMask; } //! The Box will be infinitely long in the Ymin direction. - void OpenYmin() { Flags |= YminMask; } + void OpenYmin() noexcept { Flags |= YminMask; } //! The Box will be infinitely long in the Ymax direction. - void OpenYmax() { Flags |= YmaxMask; } + void OpenYmax() noexcept { Flags |= YmaxMask; } //! Returns true if this bounding box is open in the Xmin direction. - Standard_Boolean IsOpenXmin() const { return (Flags & XminMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenXmin() const noexcept { return (Flags & XminMask) != 0; } //! Returns true if this bounding box is open in the Xmax direction. - Standard_Boolean IsOpenXmax() const { return (Flags & XmaxMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenXmax() const noexcept { return (Flags & XmaxMask) != 0; } //! Returns true if this bounding box is open in the Ymin direction. - Standard_Boolean IsOpenYmin() const { return (Flags & YminMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenYmin() const noexcept { return (Flags & YminMask) != 0; } //! Returns true if this bounding box is open in the Ymax direction. - Standard_Boolean IsOpenYmax() const { return (Flags & YmaxMask) != 0; } + [[nodiscard]] Standard_Boolean IsOpenYmax() const noexcept { return (Flags & YmaxMask) != 0; } //! Returns true if this bounding box is infinite in all 4 //! directions (Whole Space flag). - Standard_Boolean IsWhole() const { return (Flags & WholeMask) == WholeMask; } + [[nodiscard]] Standard_Boolean IsWhole() const noexcept + { + return (Flags & WholeMask) == WholeMask; + } //! Returns true if this 2D bounding box is empty (Void flag). - Standard_Boolean IsVoid() const { return (Flags & VoidMask) != 0; } + [[nodiscard]] Standard_Boolean IsVoid() const noexcept { return (Flags & VoidMask) != 0; } //! Returns a bounding box which is the result of applying the //! transformation T to this bounding box. @@ -174,16 +212,16 @@ public: //! Applying a geometric transformation (for example, a //! rotation) to a bounding box generally increases its //! dimensions. This is not optimal for algorithms which use it. - Standard_NODISCARD Standard_EXPORT Bnd_Box2d Transformed(const gp_Trsf2d& T) const; + [[nodiscard]] Standard_EXPORT Bnd_Box2d Transformed(const gp_Trsf2d& T) const; //! Adds the 2d box to . Standard_EXPORT void Add(const Bnd_Box2d& Other); //! Adds the 2d point. - void Add(const gp_Pnt2d& thePnt) { Update(thePnt.X(), thePnt.Y()); } + void Add(const gp_Pnt2d& thePnt) noexcept { Update(thePnt.X(), thePnt.Y()); } //! Extends bounding box from thePnt in the direction theDir. - void Add(const gp_Pnt2d& thePnt, const gp_Dir2d& theDir) + void Add(const gp_Pnt2d& thePnt, const gp_Dir2d& theDir) noexcept { Add(thePnt); Add(theDir); @@ -195,19 +233,21 @@ public: Standard_EXPORT void Add(const gp_Dir2d& D); //! Returns True if the 2d pnt

is out . - Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt2d& P) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt2d& P) const; //! Returns True if the line doesn't intersect the box. - Standard_EXPORT Standard_Boolean IsOut(const gp_Lin2d& theL) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const gp_Lin2d& theL) const; //! Returns True if the segment doesn't intersect the box. - Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt2d& theP0, const gp_Pnt2d& theP1) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt2d& theP0, + const gp_Pnt2d& theP1) const; //! Returns True if is out . - Standard_EXPORT Standard_Boolean IsOut(const Bnd_Box2d& Other) const; + [[nodiscard]] Standard_EXPORT Standard_Boolean IsOut(const Bnd_Box2d& Other) const; //! Returns True if transformed is out . - Standard_Boolean IsOut(const Bnd_Box2d& theOther, const gp_Trsf2d& theTrsf) const + [[nodiscard]] Standard_Boolean IsOut(const Bnd_Box2d& theOther, + const gp_Trsf2d& theTrsf) const noexcept { return IsOut(theOther.Transformed(theTrsf)); } @@ -215,7 +255,9 @@ public: //! Compares a transformed bounding with a transformed //! bounding. The default implementation is to make a copy //! of and , to transform them and to test. - Standard_Boolean IsOut(const gp_Trsf2d& T1, const Bnd_Box2d& Other, const gp_Trsf2d& T2) const + [[nodiscard]] Standard_Boolean IsOut(const gp_Trsf2d& T1, + const Bnd_Box2d& Other, + const gp_Trsf2d& T2) const noexcept { return Transformed(T1).IsOut(Other.Transformed(T2)); } @@ -223,7 +265,7 @@ public: Standard_EXPORT void Dump() const; //! Computes the squared diagonal of me. - Standard_Real SquareExtent() const + [[nodiscard]] Standard_Real SquareExtent() const noexcept { if (IsVoid()) return 0.0; diff --git a/src/FoundationClasses/TKMath/GTests/Bnd_Box_Test.cxx b/src/FoundationClasses/TKMath/GTests/Bnd_Box_Test.cxx index 3cec183244..09a86703c5 100644 --- a/src/FoundationClasses/TKMath/GTests/Bnd_Box_Test.cxx +++ b/src/FoundationClasses/TKMath/GTests/Bnd_Box_Test.cxx @@ -205,9 +205,9 @@ TEST(Bnd_BoxTest, CornerMethodsVoidBox) { Bnd_Box aBox; // void box - EXPECT_THROW(aBox.CornerMin(), Standard_ConstructionError) + EXPECT_THROW((void)aBox.CornerMin(), Standard_ConstructionError) << "CornerMin should throw for void box"; - EXPECT_THROW(aBox.CornerMax(), Standard_ConstructionError) + EXPECT_THROW((void)aBox.CornerMax(), Standard_ConstructionError) << "CornerMax should throw for void box"; }