]> OCCT Git - occt.git/commitdiff
Foundation Classes - Optimize and fix Bnd package (#839)
authorPasukhin Dmitry <dpasukhi@opencascade.com>
Tue, 25 Nov 2025 19:29:53 +0000 (19:29 +0000)
committerGitHub <noreply@github.com>
Tue, 25 Nov 2025 19:29:53 +0000 (19:29 +0000)
- 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.

src/FoundationClasses/TKMath/Bnd/Bnd_Box.cxx
src/FoundationClasses/TKMath/Bnd/Bnd_Box.hxx
src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.cxx
src/FoundationClasses/TKMath/Bnd/Bnd_Box2d.hxx
src/FoundationClasses/TKMath/GTests/Bnd_Box_Test.cxx

index 48912ac8c98a61687125e02c3fff84ce68014748..b3e8929cb701d62e6e5aa671f304261bec0994fd 100644 (file)
 // commercial license or contractual agreement.
 
 #include <Bnd_Box.hxx>
+
 #include <gp_Dir.hxx>
 #include <gp_Pln.hxx>
 #include <gp_Pnt.hxx>
 #include <gp_Trsf.hxx>
 #include <Standard_ConstructionError.hxx>
 #include <Standard_Dump.hxx>
-
-// set the flag to one
-#define ClearVoidFlag() (Flags &= ~VoidMask)
-
 #include <Standard_Stream.hxx>
-// #include <Precision.hxx>
-#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);
 }
 
 //=================================================================================================
index 5dcf314682592b76c4a7920772a8102a87a60dfc..be530c57346124c0086db13cd303839520033e8e 100644 (file)
 #include <gp_Pnt.hxx>
 #include <Standard_Real.hxx>
 #include <Standard_Boolean.hxx>
+
+#include <algorithm>
+#include <cmath>
+
 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(<tol>) and maxvalues+std::abs(<tol>))
@@ -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 <Other> to <me>.
   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 <Box> intersects or is inside <me>.
-  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 <Box> intersects
   //! or is inside <me>.
-  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 <Box> intersects
   //! or is inside the transformed box <me>.
-  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 <P1>, <P2> and
   //! direction <D> 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;
index 004c3ff9e2bbb5498cd91f5e375210f973f05249..e689c06b4fc7b3c2182836672651900d7d762bb8 100644 (file)
 // commercial license or contractual agreement.
 
 #include <Bnd_Box2d.hxx>
+
 #include <gp_Dir2d.hxx>
 #include <gp_Trsf2d.hxx>
 #include <Standard_ConstructionError.hxx>
 #include <Standard_Stream.hxx>
 
-//-- #include <Precision.hxx> 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;
 }
 
 //=================================================================================================
index d21f0c148f4562f09ea84e5cec1525f2c0fa8ed1..0bdf52534b080aae0bfb9545c74c2143629d8309 100644 (file)
 #include <Standard_Real.hxx>
 #include <Standard_Integer.hxx>
 #include <Standard_Boolean.hxx>
+
+#include <algorithm>
+#include <cmath>
+
 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 <Other> to <me>.
   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 <P> is out <me>.
-  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 <Box2d> is out <me>.
-  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 <Box2d> is out <me>.
-  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 <me> and <Other>, 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;
index 3cec183244d6051fdb75e3ded17e111061b21e6a..09a86703c578b6fa4c1994c414d262eb74d5fdab 100644 (file)
@@ -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";
 }