mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-06-24 21:25:38 +08:00
Foundation Classes - Bnd package improvements (#1051)
Bug fixes: - Bnd_Box::Add(Bnd_Box) - fix unconditional bounds merge before open direction check - Bnd_Box::IsOut(gp_Pln) - use GetXMin()/GetXMax() accessors (include Gap) instead of raw fields - Bnd_Box::Distance() - add void box check to avoid invalid results - Bnd_Range::Common() - add missing return statement - Bnd_Sphere::SquareDistances() - fix radius comparison (was comparing distance vs radius instead of squared values) - Bnd_OBB: OBBTool::ProcessTriangle - add safety check for degenerate cross products before normalization - Bnd_OBB: OBBTool::ProcessDiTetrahedron - fix off-by-one in bounds check (use < instead of <=) Performance optimizations: - Bnd_Box::IsOut(Bnd_Box) - add early return fast path for non-open boxes - Bnd_Box2d::IsOut(Bnd_Box2d) - add early return fast path for non-open boxes API improvements: - Add Contains()/Intersects() semantic wrappers (inverse of IsOut) to Bnd_Box, Bnd_Box2d, Bnd_OBB, Bnd_Range - Add Center() returning std::optional to Bnd_Box, Bnd_Box2d, Bnd_Range - Add Min()/Max()/Get() returning std::optional to Bnd_Range - Add Bnd_Range::Bounds struct for C++17 structured bindings via Get() - Add Bnd_OBB::HalfSizes struct and GetHalfSizes() for structured bindings - Add Bnd_Box2d::Distance() method - Replace Bnd_Range::IsIntersected magic int returns with IntersectStatus enum Code modernization: - Add [[nodiscard]] and noexcept annotations across all Bnd classes - Migrate Bnd_Sphere inline methods from .lxx to header, delete Bnd_Sphere.lxx - Remove unused includes (iomanip, fstream, legacy Standard_*.hxx headers) - Fix Bnd_Box.hxx "Ymix" typo in IsOpenYmin() comment - Clean up DET-style comments in Bnd_Box.cxx - Update IntPatch_WLineTool.cxx to use IntersectStatus enum
This commit is contained in:
@@ -24,8 +24,6 @@
|
||||
#include <Standard_Dump.hxx>
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -289,6 +287,19 @@ gp_Pnt Bnd_Box::CornerMax() const
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
std::optional<gp_Pnt> Bnd_Box::Center() const
|
||||
{
|
||||
if (IsVoid())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return gp_Pnt(0.5 * (GetXMin() + GetXMax()),
|
||||
0.5 * (GetYMin() + GetYMax()),
|
||||
0.5 * (GetZMin() + GetZMax()));
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
bool Bnd_Box::IsXThin(const double tol) const
|
||||
{
|
||||
if (IsWhole())
|
||||
@@ -460,18 +471,6 @@ void Bnd_Box::Add(const Bnd_Box& Other)
|
||||
return;
|
||||
}
|
||||
|
||||
if (Xmin > Other.Xmin)
|
||||
Xmin = Other.Xmin;
|
||||
if (Xmax < Other.Xmax)
|
||||
Xmax = Other.Xmax;
|
||||
if (Ymin > Other.Ymin)
|
||||
Ymin = Other.Ymin;
|
||||
if (Ymax < Other.Ymax)
|
||||
Ymax = Other.Ymax;
|
||||
if (Zmin > Other.Zmin)
|
||||
Zmin = Other.Zmin;
|
||||
if (Zmax < Other.Zmax)
|
||||
Zmax = Other.Zmax;
|
||||
Gap = std::max(Gap, Other.Gap);
|
||||
|
||||
if (IsWhole())
|
||||
@@ -484,18 +483,48 @@ void Bnd_Box::Add(const Bnd_Box& Other)
|
||||
return;
|
||||
}
|
||||
|
||||
if (Other.IsOpenXmin())
|
||||
OpenXmin();
|
||||
if (Other.IsOpenXmax())
|
||||
OpenXmax();
|
||||
if (Other.IsOpenYmin())
|
||||
OpenYmin();
|
||||
if (Other.IsOpenYmax())
|
||||
OpenYmax();
|
||||
if (Other.IsOpenZmin())
|
||||
OpenZmin();
|
||||
if (Other.IsOpenZmax())
|
||||
OpenZmax();
|
||||
if (!IsOpenXmin())
|
||||
{
|
||||
if (Other.IsOpenXmin())
|
||||
OpenXmin();
|
||||
else if (Xmin > Other.Xmin)
|
||||
Xmin = Other.Xmin;
|
||||
}
|
||||
if (!IsOpenXmax())
|
||||
{
|
||||
if (Other.IsOpenXmax())
|
||||
OpenXmax();
|
||||
else if (Xmax < Other.Xmax)
|
||||
Xmax = Other.Xmax;
|
||||
}
|
||||
if (!IsOpenYmin())
|
||||
{
|
||||
if (Other.IsOpenYmin())
|
||||
OpenYmin();
|
||||
else if (Ymin > Other.Ymin)
|
||||
Ymin = Other.Ymin;
|
||||
}
|
||||
if (!IsOpenYmax())
|
||||
{
|
||||
if (Other.IsOpenYmax())
|
||||
OpenYmax();
|
||||
else if (Ymax < Other.Ymax)
|
||||
Ymax = Other.Ymax;
|
||||
}
|
||||
if (!IsOpenZmin())
|
||||
{
|
||||
if (Other.IsOpenZmin())
|
||||
OpenZmin();
|
||||
else if (Zmin > Other.Zmin)
|
||||
Zmin = Other.Zmin;
|
||||
}
|
||||
if (!IsOpenZmax())
|
||||
{
|
||||
if (Other.IsOpenZmax())
|
||||
OpenZmax();
|
||||
else if (Zmax < Other.Zmax)
|
||||
Zmax = Other.Zmax;
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
@@ -579,21 +608,27 @@ bool Bnd_Box::IsOut(const gp_Pln& P) const
|
||||
{
|
||||
double A, B, C, D;
|
||||
P.Coefficients(A, B, C, D);
|
||||
double d = A * (Xmin - Gap) + B * (Ymin - Gap) + C * (Zmin - Gap) + D;
|
||||
bool plus = d > 0;
|
||||
if (plus != ((A * (Xmin - Gap) + B * (Ymin - Gap) + C * (Zmax + Gap) + D) > 0))
|
||||
const double aXmin = GetXMin();
|
||||
const double aXmax = GetXMax();
|
||||
const double aYmin = GetYMin();
|
||||
const double aYmax = GetYMax();
|
||||
const double aZmin = GetZMin();
|
||||
const double aZmax = GetZMax();
|
||||
double d = A * aXmin + B * aYmin + C * aZmin + D;
|
||||
bool plus = d > 0;
|
||||
if (plus != ((A * aXmin + B * aYmin + C * aZmax + D) > 0))
|
||||
return false;
|
||||
if (plus != ((A * (Xmin - Gap) + B * (Ymax + Gap) + C * (Zmin - Gap) + D) > 0))
|
||||
if (plus != ((A * aXmin + B * aYmax + C * aZmin + D) > 0))
|
||||
return false;
|
||||
if (plus != ((A * (Xmin - Gap) + B * (Ymax + Gap) + C * (Zmax + Gap) + D) > 0))
|
||||
if (plus != ((A * aXmin + B * aYmax + C * aZmax + D) > 0))
|
||||
return false;
|
||||
if (plus != ((A * (Xmax + Gap) + B * (Ymin - Gap) + C * (Zmin - Gap) + D) > 0))
|
||||
if (plus != ((A * aXmax + B * aYmin + C * aZmin + D) > 0))
|
||||
return false;
|
||||
if (plus != ((A * (Xmax + Gap) + B * (Ymin - Gap) + C * (Zmax + Gap) + D) > 0))
|
||||
if (plus != ((A * aXmax + B * aYmin + C * aZmax + D) > 0))
|
||||
return false;
|
||||
if (plus != ((A * (Xmax + Gap) + B * (Ymax + Gap) + C * (Zmin - Gap) + D) > 0))
|
||||
if (plus != ((A * aXmax + B * aYmax + C * aZmin + D) > 0))
|
||||
return false;
|
||||
return plus == ((A * (Xmax + Gap) + B * (Ymax + Gap) + C * (Zmax + Gap) + D) > 0);
|
||||
return plus == ((A * aXmax + B * aYmax + C * aZmax + D) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,10 +677,10 @@ bool Bnd_Box::IsOut(const gp_Lin& L) const
|
||||
{
|
||||
par1 = (myYmin - L.Location().XYZ().Y()) / L.Direction().XYZ().Y();
|
||||
par2 = (myYmax - L.Location().XYZ().Y()) / L.Direction().XYZ().Y();
|
||||
//=================DET change 06/03/01====================
|
||||
// Check if parameter ranges from this axis are disjoint (early exit)
|
||||
if (parmax < std::min(par1, par2) || parmin > std::max(par1, par2))
|
||||
return true;
|
||||
//========================================================
|
||||
|
||||
parmin = std::max(parmin, std::min(par1, par2));
|
||||
parmax = std::min(parmax, std::max(par1, par2));
|
||||
yToSet = true;
|
||||
@@ -665,10 +700,10 @@ bool Bnd_Box::IsOut(const gp_Lin& L) const
|
||||
{
|
||||
par1 = (myZmin - L.Location().XYZ().Z()) / L.Direction().XYZ().Z();
|
||||
par2 = (myZmax - L.Location().XYZ().Z()) / L.Direction().XYZ().Z();
|
||||
//=================DET change 06/03/01====================
|
||||
// Check if parameter ranges from this axis are disjoint (early exit)
|
||||
if (parmax < std::min(par1, par2) || parmin > std::max(par1, par2))
|
||||
return true;
|
||||
//========================================================
|
||||
|
||||
parmin = std::max(parmin, std::min(par1, par2));
|
||||
parmax = std::min(parmax, std::max(par1, par2));
|
||||
par1 = L.Location().XYZ().Z() + parmin * L.Direction().XYZ().Z();
|
||||
@@ -995,13 +1030,15 @@ bool Bnd_Box::IsOut(const gp_Pnt& P1, const gp_Pnt& P2, const gp_Dir& D) const
|
||||
return true;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : Distance
|
||||
// purpose : computes the minimum distance between two boxes
|
||||
//=======================================================================
|
||||
//=================================================================================================
|
||||
|
||||
double Bnd_Box::Distance(const Bnd_Box& Other) const
|
||||
{
|
||||
if (IsVoid() || Other.IsVoid())
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double aXMinB1, aYMinB1, aZMinB1, aXMaxB1, aYMaxB1, aZMaxB1;
|
||||
double aXMinB2, aYMinB2, aZMinB2, aXMaxB2, aYMaxB2, aZMaxB2;
|
||||
|
||||
|
||||
@@ -22,11 +22,10 @@
|
||||
#include <Standard_Handle.hxx>
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <Standard_Real.hxx>
|
||||
#include <Standard_Boolean.hxx>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
class gp_Pnt;
|
||||
class gp_Dir;
|
||||
@@ -218,6 +217,12 @@ public:
|
||||
//! if IsVoid()
|
||||
[[nodiscard]] Standard_EXPORT gp_Pnt CornerMax() const;
|
||||
|
||||
//! Returns the center 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().
|
||||
//! Returns std::nullopt if the box is void.
|
||||
[[nodiscard]] Standard_EXPORT std::optional<gp_Pnt> Center() const;
|
||||
|
||||
//! The Box will be infinitely long in the Xmin
|
||||
//! direction.
|
||||
void OpenXmin() noexcept { Flags |= XminMask; }
|
||||
@@ -251,7 +256,7 @@ public:
|
||||
//! Returns true if this bounding box is open in the Xmax direction.
|
||||
[[nodiscard]] bool IsOpenXmax() const noexcept { return (Flags & XmaxMask) != 0; }
|
||||
|
||||
//! Returns true if this bounding box is open in the Ymix direction.
|
||||
//! Returns true if this bounding box is open in the Ymin direction.
|
||||
[[nodiscard]] bool IsOpenYmin() const noexcept { return (Flags & YminMask) != 0; }
|
||||
|
||||
//! Returns true if this bounding box is open in the Ymax direction.
|
||||
@@ -333,6 +338,12 @@ public:
|
||||
const gp_Pnt& P2,
|
||||
const gp_Dir& D) const;
|
||||
|
||||
//! Returns True if the point is inside or on the boundary of this box.
|
||||
[[nodiscard]] bool Contains(const gp_Pnt& theP) const { return !IsOut(theP); }
|
||||
|
||||
//! Returns True if the other box intersects or is inside this box.
|
||||
[[nodiscard]] bool Intersects(const Bnd_Box& theOther) const { return !IsOut(theOther); }
|
||||
|
||||
//! Computes the minimum distance between two boxes.
|
||||
[[nodiscard]] Standard_EXPORT double Distance(const Bnd_Box& Other) const;
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <Standard_ConstructionError.hxx>
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -383,32 +381,92 @@ bool Bnd_Box2d::IsOut(const gp_Pnt2d& theP0, const gp_Pnt2d& theP1) const
|
||||
|
||||
bool Bnd_Box2d::IsOut(const Bnd_Box2d& Other) const
|
||||
{
|
||||
if (IsWhole())
|
||||
return false;
|
||||
else if (IsVoid())
|
||||
return true;
|
||||
else if (Other.IsWhole())
|
||||
return false;
|
||||
else if (Other.IsVoid())
|
||||
return true;
|
||||
else
|
||||
// Fast path for non-open, non-void, non-whole boxes (most common case)
|
||||
if (!Flags && !Other.Flags)
|
||||
{
|
||||
double OXmin, OXmax, OYmin, OYmax;
|
||||
Other.Get(OXmin, OYmin, OXmax, OYmax);
|
||||
if (!(Flags & XminMask) && (OXmax < (Xmin - Gap)))
|
||||
const double aDelta = Other.Gap + Gap;
|
||||
if (Xmin - Other.Xmax > aDelta)
|
||||
return true;
|
||||
else if (!(Flags & XmaxMask) && (OXmin > (Xmax + Gap)))
|
||||
if (Other.Xmin - Xmax > aDelta)
|
||||
return true;
|
||||
else if (!(Flags & YminMask) && (OYmax < (Ymin - Gap)))
|
||||
if (Ymin - Other.Ymax > aDelta)
|
||||
return true;
|
||||
else if (!(Flags & YmaxMask) && (OYmin > (Ymax + Gap)))
|
||||
if (Other.Ymin - Ymax > aDelta)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle special cases
|
||||
if (IsVoid() || Other.IsVoid())
|
||||
return true;
|
||||
if (IsWhole() || Other.IsWhole())
|
||||
return false;
|
||||
|
||||
double OXmin, OXmax, OYmin, OYmax;
|
||||
Other.Get(OXmin, OYmin, OXmax, OYmax);
|
||||
if (!(Flags & XminMask) && (OXmax < (Xmin - Gap)))
|
||||
return true;
|
||||
if (!(Flags & XmaxMask) && (OXmin > (Xmax + Gap)))
|
||||
return true;
|
||||
if (!(Flags & YminMask) && (OYmax < (Ymin - Gap)))
|
||||
return true;
|
||||
if (!(Flags & YmaxMask) && (OYmin > (Ymax + Gap)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
std::optional<gp_Pnt2d> Bnd_Box2d::Center() const
|
||||
{
|
||||
if (IsVoid())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return gp_Pnt2d(0.5 * (GetXMin() + GetXMax()), 0.5 * (GetYMin() + GetYMax()));
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
double Bnd_Box2d::Distance(const Bnd_Box2d& theOther) const
|
||||
{
|
||||
if (IsVoid() || theOther.IsVoid())
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double aXMin1, aYMin1, aXMax1, aYMax1;
|
||||
double aXMin2, aYMin2, aXMax2, aYMax2;
|
||||
|
||||
Get(aXMin1, aYMin1, aXMax1, aYMax1);
|
||||
theOther.Get(aXMin2, aYMin2, aXMax2, aYMax2);
|
||||
|
||||
// Compute squared distance per axis
|
||||
auto distAxis = [](const double theMin1,
|
||||
const double theMax1,
|
||||
const double theMin2,
|
||||
const double theMax2) -> double {
|
||||
if (theMin1 > theMax2)
|
||||
{
|
||||
const double aD = theMin1 - theMax2;
|
||||
return aD * aD;
|
||||
}
|
||||
if (theMin2 > theMax1)
|
||||
{
|
||||
const double aD = theMin2 - theMax1;
|
||||
return aD * aD;
|
||||
}
|
||||
return 0.0;
|
||||
};
|
||||
|
||||
const double aDx = distAxis(aXMin1, aXMax1, aXMin2, aXMax2);
|
||||
const double aDy = distAxis(aYMin1, aYMax1, aYMin2, aYMax2);
|
||||
|
||||
return std::sqrt(aDx + aDy);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
void Bnd_Box2d::Dump() const
|
||||
{
|
||||
std::cout << "Box2d : ";
|
||||
|
||||
@@ -23,12 +23,9 @@
|
||||
#include <Standard_DefineAlloc.hxx>
|
||||
#include <Standard_Handle.hxx>
|
||||
|
||||
#include <Standard_Real.hxx>
|
||||
#include <Standard_Integer.hxx>
|
||||
#include <Standard_Boolean.hxx>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
class gp_Dir2d;
|
||||
class gp_Trsf2d;
|
||||
@@ -169,6 +166,12 @@ public:
|
||||
//! Returns the Ymax value (IsOpenYmax() ? Precision::Infinite() : Ymax + GetGap()).
|
||||
[[nodiscard]] Standard_EXPORT double GetYMax() const;
|
||||
|
||||
//! Returns the center of this 2D bounding box. The gap is included.
|
||||
//! If this bounding box is infinite (i.e. "open"), returned values
|
||||
//! may be equal to +/- Precision::Infinite().
|
||||
//! Returns std::nullopt if the box is void.
|
||||
[[nodiscard]] Standard_EXPORT std::optional<gp_Pnt2d> Center() const;
|
||||
|
||||
//! The Box will be infinitely long in the Xmin direction.
|
||||
void OpenXmin() noexcept { Flags |= XminMask; }
|
||||
|
||||
@@ -238,6 +241,15 @@ public:
|
||||
//! Returns True if <Box2d> is out <me>.
|
||||
[[nodiscard]] Standard_EXPORT bool IsOut(const Bnd_Box2d& Other) const;
|
||||
|
||||
//! Returns True if the 2d point is inside or on the boundary of this box.
|
||||
[[nodiscard]] bool Contains(const gp_Pnt2d& theP) const { return !IsOut(theP); }
|
||||
|
||||
//! Returns True if the other 2d box intersects or is inside this box.
|
||||
[[nodiscard]] bool Intersects(const Bnd_Box2d& theOther) const { return !IsOut(theOther); }
|
||||
|
||||
//! Computes the minimum distance between two 2D boxes.
|
||||
[[nodiscard]] Standard_EXPORT double Distance(const Bnd_Box2d& theOther) const;
|
||||
|
||||
//! Returns True if transformed <Box2d> is out <me>.
|
||||
[[nodiscard]] bool IsOut(const Bnd_Box2d& theOther, const gp_Trsf2d& theTrsf) const noexcept
|
||||
{
|
||||
|
||||
@@ -596,8 +596,19 @@ void OBBTool::ProcessTriangle(const int theIdx1,
|
||||
aZAxis /= std::sqrt(aSqMod);
|
||||
|
||||
gp_XYZ aXAxis[aNbAxes];
|
||||
bool aXAxisValid[aNbAxes];
|
||||
for (int i = 0; i < aNbAxes; i++)
|
||||
aXAxis[i] = aYAxis[i].Crossed(aZAxis).Normalized();
|
||||
{
|
||||
const gp_XYZ aCross = aYAxis[i].Crossed(aZAxis);
|
||||
const double aCrossSqMod = aCross.SquareModulus();
|
||||
if (aCrossSqMod < Precision::SquareConfusion())
|
||||
{
|
||||
aXAxisValid[i] = false;
|
||||
continue;
|
||||
}
|
||||
aXAxis[i] = aCross / std::sqrt(aCrossSqMod);
|
||||
aXAxisValid[i] = true;
|
||||
}
|
||||
|
||||
if (theIsBuiltTrg)
|
||||
FillToTriangle5(aZAxis, myLExtremalPoints[theIdx1]);
|
||||
@@ -612,6 +623,9 @@ void OBBTool::ProcessTriangle(const int theIdx1,
|
||||
int aMinIdx = -1;
|
||||
for (int anAxeInd = 0; anAxeInd < aNbAxes; anAxeInd++)
|
||||
{
|
||||
if (!aXAxisValid[anAxeInd])
|
||||
continue;
|
||||
|
||||
const gp_XYZ& aAX = aXAxis[anAxeInd];
|
||||
// Compute params on XAxis
|
||||
FindMinMax(aAX, aParams[0], aParams[1]);
|
||||
@@ -662,14 +676,14 @@ void OBBTool::ProcessDiTetrahedron()
|
||||
// Use the standard DiTo approach
|
||||
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[2], true);
|
||||
|
||||
if (myTriIdx[3] <= myNbExtremalPoints)
|
||||
if (myTriIdx[3] < myNbExtremalPoints)
|
||||
{
|
||||
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[3], false);
|
||||
ProcessTriangle(myTriIdx[1], myTriIdx[2], myTriIdx[3], false);
|
||||
ProcessTriangle(myTriIdx[0], myTriIdx[2], myTriIdx[3], false);
|
||||
}
|
||||
|
||||
if (myTriIdx[4] <= myNbExtremalPoints)
|
||||
if (myTriIdx[4] < myNbExtremalPoints)
|
||||
{
|
||||
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[4], false);
|
||||
ProcessTriangle(myTriIdx[1], myTriIdx[2], myTriIdx[4], false);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <Standard.hxx>
|
||||
#include <Standard_DefineAlloc.hxx>
|
||||
#include <Standard_Handle.hxx>
|
||||
#include <Standard_Real.hxx>
|
||||
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
@@ -39,6 +38,18 @@ class Bnd_OBB
|
||||
public:
|
||||
DEFINE_STANDARD_ALLOC
|
||||
|
||||
//! Structure containing the OBB half-size dimensions.
|
||||
//! Can be used with C++17 structured bindings:
|
||||
//! @code
|
||||
//! auto [aHX, aHY, aHZ] = anOBB.GetHalfSizes();
|
||||
//! @endcode
|
||||
struct HalfSizes
|
||||
{
|
||||
double X; //!< Half-size along X axis
|
||||
double Y; //!< Half-size along Y axis
|
||||
double Z; //!< Half-size along Z axis
|
||||
};
|
||||
|
||||
//! Empty constructor
|
||||
Bnd_OBB()
|
||||
: myIsAABox(false)
|
||||
@@ -144,31 +155,44 @@ public:
|
||||
//! gp_Trsf aLoc;
|
||||
//! aLoc.SetTransformation (theOBB.Position(), gp::XOY());
|
||||
//! @endcode
|
||||
gp_Ax3 Position() const { return gp_Ax3(myCenter, ZDirection(), XDirection()); }
|
||||
[[nodiscard]] gp_Ax3 Position() const { return gp_Ax3(myCenter, ZDirection(), XDirection()); }
|
||||
|
||||
//! Returns the center of OBB
|
||||
const gp_XYZ& Center() const { return myCenter; }
|
||||
[[nodiscard]] const gp_XYZ& Center() const noexcept { return myCenter; }
|
||||
|
||||
//! Returns the X Direction of OBB
|
||||
const gp_XYZ& XDirection() const { return myAxes[0]; }
|
||||
[[nodiscard]] const gp_XYZ& XDirection() const noexcept { return myAxes[0]; }
|
||||
|
||||
//! Returns the Y Direction of OBB
|
||||
const gp_XYZ& YDirection() const { return myAxes[1]; }
|
||||
[[nodiscard]] const gp_XYZ& YDirection() const noexcept { return myAxes[1]; }
|
||||
|
||||
//! Returns the Z Direction of OBB
|
||||
const gp_XYZ& ZDirection() const { return myAxes[2]; }
|
||||
[[nodiscard]] const gp_XYZ& ZDirection() const noexcept { return myAxes[2]; }
|
||||
|
||||
//! Returns the X Dimension of OBB
|
||||
double XHSize() const { return myHDims[0]; }
|
||||
[[nodiscard]] double XHSize() const noexcept { return myHDims[0]; }
|
||||
|
||||
//! Returns the Y Dimension of OBB
|
||||
double YHSize() const { return myHDims[1]; }
|
||||
[[nodiscard]] double YHSize() const noexcept { return myHDims[1]; }
|
||||
|
||||
//! Returns the Z Dimension of OBB
|
||||
double ZHSize() const { return myHDims[2]; }
|
||||
[[nodiscard]] double ZHSize() const noexcept { return myHDims[2]; }
|
||||
|
||||
//! Returns the half-size dimensions of the OBB as a HalfSizes structure.
|
||||
//! Can be used with C++17 structured bindings:
|
||||
//! @code
|
||||
//! auto [aHX, aHY, aHZ] = anOBB.GetHalfSizes();
|
||||
//! @endcode
|
||||
[[nodiscard]] HalfSizes GetHalfSizes() const noexcept
|
||||
{
|
||||
return {myHDims[0], myHDims[1], myHDims[2]};
|
||||
}
|
||||
|
||||
//! Checks if the box is empty.
|
||||
bool IsVoid() const { return ((myHDims[0] < 0.0) || (myHDims[1] < 0.0) || (myHDims[2] < 0.0)); }
|
||||
[[nodiscard]] bool IsVoid() const noexcept
|
||||
{
|
||||
return ((myHDims[0] < 0.0) || (myHDims[1] < 0.0) || (myHDims[2] < 0.0));
|
||||
}
|
||||
|
||||
//! Clears this box
|
||||
void SetVoid()
|
||||
@@ -182,7 +206,7 @@ public:
|
||||
void SetAABox(const bool& theFlag) { myIsAABox = theFlag; }
|
||||
|
||||
//! Returns TRUE if the box is axes aligned
|
||||
bool IsAABox() const { return myIsAABox; }
|
||||
[[nodiscard]] bool IsAABox() const noexcept { return myIsAABox; }
|
||||
|
||||
//! Enlarges the box with the given value
|
||||
void Enlarge(const double theGapAdd)
|
||||
@@ -230,19 +254,25 @@ public:
|
||||
}
|
||||
|
||||
//! Returns square diagonal of this box
|
||||
double SquareExtent() const
|
||||
[[nodiscard]] double SquareExtent() const noexcept
|
||||
{
|
||||
return 4.0 * (myHDims[0] * myHDims[0] + myHDims[1] * myHDims[1] + myHDims[2] * myHDims[2]);
|
||||
}
|
||||
|
||||
//! Check if the box do not interfere the other box.
|
||||
Standard_EXPORT bool IsOut(const Bnd_OBB& theOther) const;
|
||||
[[nodiscard]] Standard_EXPORT bool IsOut(const Bnd_OBB& theOther) const;
|
||||
|
||||
//! Check if the point is inside of <this>.
|
||||
Standard_EXPORT bool IsOut(const gp_Pnt& theP) const;
|
||||
[[nodiscard]] Standard_EXPORT bool IsOut(const gp_Pnt& theP) const;
|
||||
|
||||
//! Returns True if the point is inside or on the boundary of this OBB.
|
||||
[[nodiscard]] bool Contains(const gp_Pnt& theP) const { return !IsOut(theP); }
|
||||
|
||||
//! Returns True if the other OBB intersects or is inside this OBB.
|
||||
[[nodiscard]] bool Intersects(const Bnd_OBB& theOther) const { return !IsOut(theOther); }
|
||||
|
||||
//! Check if the theOther is completely inside *this.
|
||||
Standard_EXPORT bool IsCompletelyInside(const Bnd_OBB& theOther) const;
|
||||
[[nodiscard]] Standard_EXPORT bool IsCompletelyInside(const Bnd_OBB& theOther) const;
|
||||
|
||||
//! Rebuilds this in order to include all previous objects
|
||||
//! (which it was created from) and theOther.
|
||||
|
||||
@@ -23,6 +23,7 @@ void Bnd_Range::Common(const Bnd_Range& theOther)
|
||||
if (theOther.IsVoid())
|
||||
{
|
||||
SetVoid();
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsVoid())
|
||||
@@ -55,10 +56,11 @@ bool Bnd_Range::Union(const Bnd_Range& theOther)
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
int Bnd_Range::IsIntersected(const double theVal, const double thePeriod) const
|
||||
Bnd_Range::IntersectStatus Bnd_Range::IsIntersected(const double theVal,
|
||||
const double thePeriod) const
|
||||
{
|
||||
if (IsVoid())
|
||||
return false;
|
||||
return IntersectStatus_Out;
|
||||
|
||||
const double aPeriod = std::abs(thePeriod);
|
||||
const double aDF = myFirst - theVal, aDL = myLast - theVal;
|
||||
@@ -67,12 +69,12 @@ int Bnd_Range::IsIntersected(const double theVal, const double thePeriod) const
|
||||
{
|
||||
const double aDelta = aDF * aDL;
|
||||
if (IsEqual(aDelta, 0.0))
|
||||
return 2;
|
||||
return IntersectStatus_Boundary;
|
||||
|
||||
if (aDelta > 0.0)
|
||||
return 0;
|
||||
return IntersectStatus_Out;
|
||||
|
||||
return 1;
|
||||
return IntersectStatus_In;
|
||||
}
|
||||
|
||||
// If <this> intersects theVal then there exists an integer
|
||||
@@ -97,20 +99,20 @@ int Bnd_Range::IsIntersected(const double theVal, const double thePeriod) const
|
||||
{ // Interval (myFirst, myLast] intersects seam-edge
|
||||
if (IsEqual(aVal2, static_cast<double>(aPar2)))
|
||||
{ // aVal2 is an integer number => myLast lies ON the "seam-edge"
|
||||
return 2;
|
||||
return IntersectStatus_Boundary;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return IntersectStatus_In;
|
||||
}
|
||||
|
||||
// Here, aPar1 == aPar2.
|
||||
|
||||
if (IsEqual(aVal1, static_cast<double>(aPar1)))
|
||||
{ // aVal1 is an integer number => myFirst lies ON the "seam-edge"
|
||||
return 2;
|
||||
return IntersectStatus_Boundary;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return IntersectStatus_Out;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
@@ -120,7 +122,7 @@ void Bnd_Range::Split(const double theVal,
|
||||
const double thePeriod) const
|
||||
{
|
||||
const double aPeriod = std::abs(thePeriod);
|
||||
if (IsIntersected(theVal, aPeriod) != 1)
|
||||
if (IsIntersected(theVal, aPeriod) != IntersectStatus_In)
|
||||
{
|
||||
theList.Append(*this);
|
||||
return;
|
||||
|
||||
@@ -20,12 +20,25 @@
|
||||
|
||||
#include <NCollection_List.hxx>
|
||||
|
||||
#include <optional>
|
||||
|
||||
//! This class describes a range in 1D space restricted
|
||||
//! by two real values.
|
||||
//! A range can be void indicating there is no point included in the range.
|
||||
class Bnd_Range
|
||||
{
|
||||
public:
|
||||
//! Structure containing the range bounds (Min, Max).
|
||||
//! Can be used with C++17 structured bindings:
|
||||
//! @code
|
||||
//! auto [aMin, aMax] = aRange.Get();
|
||||
//! @endcode
|
||||
struct Bounds
|
||||
{
|
||||
double Min; //!< Minimum value of the range
|
||||
double Max; //!< Maximum value of the range
|
||||
};
|
||||
|
||||
//! Default constructor. Creates VOID range.
|
||||
Bnd_Range()
|
||||
: myFirst(0.0),
|
||||
@@ -50,7 +63,7 @@ public:
|
||||
//! Returns false if the operation cannot be done (e.g.
|
||||
//! input arguments are empty or separated).
|
||||
//! @sa use method ::Add() to merge two ranges unconditionally
|
||||
Standard_EXPORT bool Union(const Bnd_Range& theOther);
|
||||
[[nodiscard]] Standard_EXPORT bool Union(const Bnd_Range& theOther);
|
||||
|
||||
//! Splits <this> to several sub-ranges by theVal value
|
||||
//! (e.g. range [3, 15] will be split by theVal==5 to the two
|
||||
@@ -66,16 +79,22 @@ public:
|
||||
NCollection_List<Bnd_Range>& theList,
|
||||
const double thePeriod = 0.0) const;
|
||||
|
||||
//! Status of intersection check with a periodic value.
|
||||
//! @sa IsIntersected()
|
||||
enum IntersectStatus
|
||||
{
|
||||
IntersectStatus_Out = 0, //!< No intersection with theVal+k*thePeriod
|
||||
IntersectStatus_In = 1, //!< Range strictly contains theVal+k*thePeriod
|
||||
IntersectStatus_Boundary = 2 //!< Range boundary coincides with theVal+k*thePeriod
|
||||
};
|
||||
|
||||
//! Checks if <this> intersects values like
|
||||
//! theVal+k*thePeriod, where k is an integer number (k = 0, +/-1, +/-2, ...).
|
||||
//! Returns:
|
||||
//! 0 - if <this> does not intersect the theVal+k*thePeriod.
|
||||
//! 1 - if <this> intersects theVal+k*thePeriod.
|
||||
//! 2 - if myFirst or/and myLast are equal to theVal+k*thePeriod.
|
||||
//!
|
||||
//! ATTENTION!!!
|
||||
//! If (myFirst == myLast) then this function will return only either 0 or 2.
|
||||
Standard_EXPORT int IsIntersected(const double theVal, const double thePeriod = 0.0) const;
|
||||
//! If (myFirst == myLast) then this function will return only either Out or Boundary.
|
||||
Standard_EXPORT IntersectStatus IsIntersected(const double theVal,
|
||||
const double thePeriod = 0.0) const;
|
||||
|
||||
//! Extends <this> to include theParameter
|
||||
void Add(const double theParameter)
|
||||
@@ -101,6 +120,7 @@ public:
|
||||
else if (IsVoid())
|
||||
{
|
||||
*this = theRange;
|
||||
return;
|
||||
}
|
||||
myFirst = (std::min)(myFirst, theRange.myFirst);
|
||||
myLast = (std::max)(myLast, theRange.myLast);
|
||||
@@ -146,6 +166,22 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Returns the bounds of this range as a Bounds structure.
|
||||
//! Returns std::nullopt if IsVoid().
|
||||
//! Can be used with C++17 structured bindings:
|
||||
//! @code
|
||||
//! if (auto aBounds = aRange.Get())
|
||||
//! {
|
||||
//! auto [aMin, aMax] = *aBounds;
|
||||
//! }
|
||||
//! @endcode
|
||||
[[nodiscard]] std::optional<Bounds> Get() const noexcept
|
||||
{
|
||||
if (IsVoid())
|
||||
return std::nullopt;
|
||||
return Bounds{myFirst, myLast};
|
||||
}
|
||||
|
||||
//! Obtain theParameter satisfied to the equation
|
||||
//! (theParameter-MIN)/(MAX-MIN) == theLambda.
|
||||
//! * theLambda == 0 --> MIN boundary will be returned;
|
||||
@@ -165,21 +201,30 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Returns the center of this range ((Min + Max) / 2).
|
||||
//! Returns std::nullopt if IsVoid().
|
||||
[[nodiscard]] std::optional<double> Center() const noexcept
|
||||
{
|
||||
if (IsVoid())
|
||||
return std::nullopt;
|
||||
return 0.5 * (myFirst + myLast);
|
||||
}
|
||||
|
||||
//! Returns range value (MAX-MIN). Returns negative value for VOID range.
|
||||
double Delta() const { return (myLast - myFirst); }
|
||||
[[nodiscard]] double Delta() const noexcept { return (myLast - myFirst); }
|
||||
|
||||
//! Is <this> initialized.
|
||||
bool IsVoid() const { return (myLast < myFirst); }
|
||||
[[nodiscard]] bool IsVoid() const noexcept { return (myLast < myFirst); }
|
||||
|
||||
//! Initializes <this> by default parameters. Makes <this> VOID.
|
||||
void SetVoid()
|
||||
void SetVoid() noexcept
|
||||
{
|
||||
myLast = -1.0;
|
||||
myFirst = 0.0;
|
||||
}
|
||||
|
||||
//! Extends this to the given value (in both side)
|
||||
void Enlarge(const double theDelta)
|
||||
void Enlarge(const double theDelta) noexcept
|
||||
{
|
||||
if (IsVoid())
|
||||
{
|
||||
@@ -191,13 +236,13 @@ public:
|
||||
}
|
||||
|
||||
//! Returns the copy of <*this> shifted by theVal
|
||||
Bnd_Range Shifted(const double theVal) const
|
||||
[[nodiscard]] Bnd_Range Shifted(const double theVal) const
|
||||
{
|
||||
return !IsVoid() ? Bnd_Range(myFirst + theVal, myLast + theVal) : Bnd_Range();
|
||||
}
|
||||
|
||||
//! Shifts <*this> by theVal
|
||||
void Shift(const double theVal)
|
||||
void Shift(const double theVal) noexcept
|
||||
{
|
||||
if (!IsVoid())
|
||||
{
|
||||
@@ -208,7 +253,7 @@ public:
|
||||
|
||||
//! Trims the First value in range by the given lower limit.
|
||||
//! Marks range as Void if the given Lower value is greater than range Max.
|
||||
void TrimFrom(const double theValLower)
|
||||
void TrimFrom(const double theValLower) noexcept
|
||||
{
|
||||
if (!IsVoid())
|
||||
{
|
||||
@@ -218,7 +263,7 @@ public:
|
||||
|
||||
//! Trim the Last value in range by the given Upper limit.
|
||||
//! Marks range as Void if the given Upper value is smaller than range Max.
|
||||
void TrimTo(const double theValUpper)
|
||||
void TrimTo(const double theValUpper) noexcept
|
||||
{
|
||||
if (!IsVoid())
|
||||
{
|
||||
@@ -227,16 +272,46 @@ public:
|
||||
}
|
||||
|
||||
//! Returns True if the value is out of this range.
|
||||
bool IsOut(double theValue) const { return IsVoid() || theValue < myFirst || theValue > myLast; }
|
||||
[[nodiscard]] bool IsOut(double theValue) const noexcept
|
||||
{
|
||||
return IsVoid() || theValue < myFirst || theValue > myLast;
|
||||
}
|
||||
|
||||
//! Returns True if the given range is out of this range.
|
||||
bool IsOut(const Bnd_Range& theRange) const
|
||||
[[nodiscard]] bool IsOut(const Bnd_Range& theRange) const noexcept
|
||||
{
|
||||
return IsVoid() || theRange.IsVoid() || theRange.myLast < myFirst || theRange.myFirst > myLast;
|
||||
}
|
||||
|
||||
//! Returns True if the value is within this range.
|
||||
[[nodiscard]] bool Contains(double theValue) const noexcept { return !IsOut(theValue); }
|
||||
|
||||
//! Returns True if the given range intersects (overlaps with) this range.
|
||||
[[nodiscard]] bool Intersects(const Bnd_Range& theRange) const noexcept
|
||||
{
|
||||
return !IsOut(theRange);
|
||||
}
|
||||
|
||||
//! Returns the MIN boundary of <this>.
|
||||
//! Returns std::nullopt if IsVoid().
|
||||
[[nodiscard]] std::optional<double> Min() const noexcept
|
||||
{
|
||||
if (IsVoid())
|
||||
return std::nullopt;
|
||||
return myFirst;
|
||||
}
|
||||
|
||||
//! Returns the MAX boundary of <this>.
|
||||
//! Returns std::nullopt if IsVoid().
|
||||
[[nodiscard]] std::optional<double> Max() const noexcept
|
||||
{
|
||||
if (IsVoid())
|
||||
return std::nullopt;
|
||||
return myLast;
|
||||
}
|
||||
|
||||
//! Returns TRUE if theOther is equal to <*this>
|
||||
bool operator==(const Bnd_Range& theOther) const
|
||||
[[nodiscard]] bool operator==(const Bnd_Range& theOther) const noexcept
|
||||
{
|
||||
return ((myFirst == theOther.myFirst) && (myLast == theOther.myLast));
|
||||
}
|
||||
|
||||
@@ -36,9 +36,10 @@ Bnd_Sphere::Bnd_Sphere(const gp_XYZ& theCenter,
|
||||
|
||||
void Bnd_Sphere::SquareDistances(const gp_XYZ& theXYZ, double& theMin, double& theMax) const
|
||||
{
|
||||
theMax = (theXYZ - myCenter).SquareModulus();
|
||||
theMin = (theMax - myRadius < 0 ? 0.0 : theMax - myRadius * myRadius);
|
||||
theMax += myRadius * myRadius;
|
||||
theMax = (theXYZ - myCenter).SquareModulus();
|
||||
const double aRadSq = myRadius * myRadius;
|
||||
theMin = (theMax < aRadSq ? 0.0 : theMax - aRadSq);
|
||||
theMax += aRadSq;
|
||||
}
|
||||
|
||||
void Bnd_Sphere::Distances(const gp_XYZ& theXYZ, double& theMin, double& theMax) const
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <Standard_Handle.hxx>
|
||||
|
||||
#include <gp_XYZ.hxx>
|
||||
#include <Standard_Real.hxx>
|
||||
#include <Standard_Boolean.hxx>
|
||||
|
||||
//! This class represents a bounding sphere of a geometric entity
|
||||
//! (triangle, segment of line or whatever else).
|
||||
@@ -41,22 +39,22 @@ public:
|
||||
const int theV);
|
||||
|
||||
//! Returns the U parameter on shape
|
||||
int U() const;
|
||||
int U() const noexcept { return myU; }
|
||||
|
||||
//! Returns the V parameter on shape
|
||||
int V() const;
|
||||
int V() const noexcept { return myV; }
|
||||
|
||||
//! Returns validity status, indicating that this
|
||||
//! sphere corresponds to a real entity
|
||||
bool IsValid() const;
|
||||
bool IsValid() const noexcept { return myIsValid; }
|
||||
|
||||
void SetValid(const bool isValid);
|
||||
void SetValid(const bool isValid) noexcept { myIsValid = isValid; }
|
||||
|
||||
//! Returns center of sphere object
|
||||
const gp_XYZ& Center() const;
|
||||
const gp_XYZ& Center() const noexcept { return myCenter; }
|
||||
|
||||
//! Returns the radius value
|
||||
double Radius() const;
|
||||
double Radius() const noexcept { return myRadius; }
|
||||
|
||||
//! Calculate and return minimal and maximal distance to sphere.
|
||||
//! NOTE: This function is tightly optimized; any modifications
|
||||
@@ -95,6 +93,4 @@ private:
|
||||
int myV;
|
||||
};
|
||||
|
||||
#include <Bnd_Sphere.lxx>
|
||||
|
||||
#endif // _Bnd_Sphere_HeaderFile
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) 1999-2014 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
inline int Bnd_Sphere::U() const
|
||||
{
|
||||
return myU;
|
||||
}
|
||||
|
||||
inline int Bnd_Sphere::V() const
|
||||
{
|
||||
return myV;
|
||||
}
|
||||
|
||||
inline bool Bnd_Sphere::IsValid() const
|
||||
{
|
||||
return myIsValid;
|
||||
}
|
||||
|
||||
inline void Bnd_Sphere::SetValid(const bool isValid)
|
||||
{
|
||||
myIsValid = isValid;
|
||||
}
|
||||
|
||||
inline const gp_XYZ& Bnd_Sphere::Center() const
|
||||
{
|
||||
return myCenter;
|
||||
}
|
||||
|
||||
inline double Bnd_Sphere::Radius() const
|
||||
{
|
||||
return myRadius;
|
||||
}
|
||||
@@ -18,6 +18,5 @@ set(OCCT_Bnd_FILES
|
||||
Bnd_Range.hxx
|
||||
Bnd_Sphere.cxx
|
||||
Bnd_Sphere.hxx
|
||||
Bnd_Sphere.lxx
|
||||
Bnd_Tools.hxx
|
||||
)
|
||||
|
||||
443
src/FoundationClasses/TKMath/GTests/Bnd_Box2d_Test.cxx
Normal file
443
src/FoundationClasses/TKMath/GTests/Bnd_Box2d_Test.cxx
Normal file
@@ -0,0 +1,443 @@
|
||||
// Copyright (c) 2025 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <Bnd_Box2d.hxx>
|
||||
#include <gp_Dir2d.hxx>
|
||||
#include <gp_Lin2d.hxx>
|
||||
#include <gp_Pnt2d.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Bnd_Box2dTest, DefaultConstructor)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
EXPECT_TRUE(aBox.IsVoid());
|
||||
EXPECT_FALSE(aBox.IsWhole());
|
||||
EXPECT_DOUBLE_EQ(aBox.GetGap(), 0.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, SetVoid)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
EXPECT_FALSE(aBox.IsVoid());
|
||||
aBox.SetVoid();
|
||||
EXPECT_TRUE(aBox.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, SetWhole)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.SetWhole();
|
||||
EXPECT_TRUE(aBox.IsWhole());
|
||||
EXPECT_FALSE(aBox.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Update_Bounds)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(1.0, 2.0, 10.0, 20.0);
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aBox.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 2.0);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 10.0);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 20.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Update_SinglePoint)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(5.0, 7.0);
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aBox.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 7.0);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 7.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Update_Expansion)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(1.0, 2.0, 10.0, 20.0);
|
||||
aBox.Update(0.0, 0.0, 15.0, 25.0);
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aBox.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 0.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 0.0);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 15.0);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 25.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, GapOperations)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
EXPECT_DOUBLE_EQ(aBox.GetGap(), 0.0);
|
||||
aBox.SetGap(2.0);
|
||||
EXPECT_DOUBLE_EQ(aBox.GetGap(), 2.0);
|
||||
aBox.SetGap(-3.0);
|
||||
EXPECT_DOUBLE_EQ(aBox.GetGap(), 3.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Enlarge)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
aBox.Enlarge(5.0);
|
||||
EXPECT_DOUBLE_EQ(aBox.GetGap(), 5.0);
|
||||
aBox.Enlarge(3.0);
|
||||
EXPECT_DOUBLE_EQ(aBox.GetGap(), 5.0); // max(5, 3) = 5
|
||||
aBox.Enlarge(7.0);
|
||||
EXPECT_DOUBLE_EQ(aBox.GetGap(), 7.0); // max(5, 7) = 7
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Get_WithGap)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(1.0, 2.0, 10.0, 20.0);
|
||||
aBox.SetGap(0.5);
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aBox.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 0.5);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 1.5);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 10.5);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 20.5);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Get_StructuredBindings)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(1.0, 2.0, 10.0, 20.0);
|
||||
const auto [aXmin, aXmax, aYmin, aYmax] = aBox.Get();
|
||||
EXPECT_DOUBLE_EQ(aXmin, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 10.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 2.0);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 20.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Set_Point)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Set(gp_Pnt2d(5.0, 7.0));
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aBox.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 7.0);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 7.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Add_Point)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Add(gp_Pnt2d(1.0, 2.0));
|
||||
aBox.Add(gp_Pnt2d(10.0, 20.0));
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aBox.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 2.0);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 10.0);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 20.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Add_Box)
|
||||
{
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 5.0, 5.0);
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(3.0, 3.0, 10.0, 10.0);
|
||||
aBox1.Add(aBox2);
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aBox1.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 0.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 0.0);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 10.0);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Add_VoidBox)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(1.0, 2.0, 5.0, 6.0);
|
||||
Bnd_Box2d aVoidBox;
|
||||
aBox.Add(aVoidBox);
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aBox.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 2.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Add_ToVoidBox)
|
||||
{
|
||||
Bnd_Box2d aVoidBox;
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(1.0, 2.0, 5.0, 6.0);
|
||||
aVoidBox.Add(aBox);
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aVoidBox.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 2.0);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 6.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, OpenDirections)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
EXPECT_FALSE(aBox.IsOpenXmin());
|
||||
EXPECT_FALSE(aBox.IsOpenXmax());
|
||||
EXPECT_FALSE(aBox.IsOpenYmin());
|
||||
EXPECT_FALSE(aBox.IsOpenYmax());
|
||||
|
||||
aBox.OpenXmin();
|
||||
EXPECT_TRUE(aBox.IsOpenXmin());
|
||||
aBox.OpenYmax();
|
||||
EXPECT_TRUE(aBox.IsOpenYmax());
|
||||
EXPECT_FALSE(aBox.IsWhole());
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_Point)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
EXPECT_FALSE(aBox.IsOut(gp_Pnt2d(5.0, 5.0)));
|
||||
EXPECT_TRUE(aBox.IsOut(gp_Pnt2d(15.0, 5.0)));
|
||||
EXPECT_TRUE(aBox.IsOut(gp_Pnt2d(-1.0, 5.0)));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_Box_Overlapping)
|
||||
{
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 10.0, 10.0);
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(5.0, 5.0, 15.0, 15.0);
|
||||
EXPECT_FALSE(aBox1.IsOut(aBox2));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_Box_Separated)
|
||||
{
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 5.0, 5.0);
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(10.0, 10.0, 15.0, 15.0);
|
||||
EXPECT_TRUE(aBox1.IsOut(aBox2));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_Box_FastPath)
|
||||
{
|
||||
// Both non-void, non-whole, non-open -> fast path
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 10.0, 10.0);
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(5.0, 5.0, 15.0, 15.0);
|
||||
EXPECT_FALSE(aBox1.IsOut(aBox2));
|
||||
|
||||
Bnd_Box2d aBox3;
|
||||
aBox3.Update(20.0, 20.0, 30.0, 30.0);
|
||||
EXPECT_TRUE(aBox1.IsOut(aBox3));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_Box_FastPath_WithGap)
|
||||
{
|
||||
// Boxes separated by 1.0, but gap bridges it
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 5.0, 5.0);
|
||||
aBox1.SetGap(1.0);
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(6.0, 0.0, 10.0, 5.0);
|
||||
// Gap from box1 = 1.0, gap from box2 = 0.0, total = 1.0
|
||||
// Xmin1 - Xmax2 = 0 - 10 = -10 (not > 1.0) -> not out in X
|
||||
// Xmin2 - Xmax1 = 6 - 5 = 1 (not > 1.0, equal) -> not out
|
||||
EXPECT_FALSE(aBox1.IsOut(aBox2));
|
||||
|
||||
// Now increase separation
|
||||
Bnd_Box2d aBox3;
|
||||
aBox3.Update(7.0, 0.0, 10.0, 5.0);
|
||||
// Xmin3 - Xmax1 = 7 - 5 = 2 > 1.0 -> out
|
||||
EXPECT_TRUE(aBox1.IsOut(aBox3));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_VoidBox)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
Bnd_Box2d aVoid;
|
||||
EXPECT_TRUE(aBox.IsOut(aVoid));
|
||||
EXPECT_TRUE(aVoid.IsOut(aBox));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_WholeBox)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
Bnd_Box2d aWhole;
|
||||
aWhole.SetWhole();
|
||||
EXPECT_FALSE(aBox.IsOut(aWhole));
|
||||
EXPECT_FALSE(aWhole.IsOut(aBox));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_OpenBox)
|
||||
{
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 10.0, 10.0);
|
||||
aBox1.OpenXmin(); // extends to -infinity in X
|
||||
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(-100.0, 0.0, -50.0, 10.0);
|
||||
|
||||
// aBox1 is open in Xmin, so extends to -infinity: should overlap
|
||||
EXPECT_FALSE(aBox1.IsOut(aBox2));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_Line)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
|
||||
// Line that intersects
|
||||
gp_Lin2d aLinInside(gp_Pnt2d(5.0, -5.0), gp_Dir2d(0.0, 1.0));
|
||||
EXPECT_FALSE(aBox.IsOut(aLinInside));
|
||||
|
||||
// Line that doesn't intersect
|
||||
gp_Lin2d aLinOutside(gp_Pnt2d(20.0, -5.0), gp_Dir2d(0.0, 1.0));
|
||||
EXPECT_TRUE(aBox.IsOut(aLinOutside));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, IsOut_Segment)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
|
||||
// Segment that crosses
|
||||
EXPECT_FALSE(aBox.IsOut(gp_Pnt2d(5.0, -5.0), gp_Pnt2d(5.0, 15.0)));
|
||||
|
||||
// Segment fully outside
|
||||
EXPECT_TRUE(aBox.IsOut(gp_Pnt2d(20.0, 0.0), gp_Pnt2d(20.0, 10.0)));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Transformed)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
|
||||
gp_Trsf2d aTrsf;
|
||||
aTrsf.SetTranslation(gp_Pnt2d(0.0, 0.0), gp_Pnt2d(5.0, 5.0));
|
||||
Bnd_Box2d aTransformed = aBox.Transformed(aTrsf);
|
||||
|
||||
double aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
|
||||
aTransformed.Get(aXmin, aYmin, aXmax, aYmax);
|
||||
EXPECT_DOUBLE_EQ(aXmin, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aYmin, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aXmax, 15.0);
|
||||
EXPECT_DOUBLE_EQ(aYmax, 15.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, SquareExtent)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 3.0, 4.0);
|
||||
// Diagonal^2 = 3^2 + 4^2 = 25
|
||||
EXPECT_DOUBLE_EQ(aBox.SquareExtent(), 25.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, SquareExtent_Void)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
EXPECT_DOUBLE_EQ(aBox.SquareExtent(), 0.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Add_Direction)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Set(gp_Pnt2d(5.0, 5.0));
|
||||
aBox.Add(gp_Dir2d(1.0, 0.0));
|
||||
EXPECT_TRUE(aBox.IsOpenXmax());
|
||||
EXPECT_FALSE(aBox.IsOpenXmin());
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Contains_Point)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 10.0);
|
||||
EXPECT_TRUE(aBox.Contains(gp_Pnt2d(5.0, 5.0)));
|
||||
EXPECT_TRUE(aBox.Contains(gp_Pnt2d(0.0, 0.0)));
|
||||
EXPECT_FALSE(aBox.Contains(gp_Pnt2d(-1.0, 5.0)));
|
||||
EXPECT_FALSE(aBox.Contains(gp_Pnt2d(5.0, 11.0)));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Intersects_Box)
|
||||
{
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 10.0, 10.0);
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(5.0, 5.0, 15.0, 15.0);
|
||||
Bnd_Box2d aBox3;
|
||||
aBox3.Update(20.0, 20.0, 30.0, 30.0);
|
||||
EXPECT_TRUE(aBox1.Intersects(aBox2));
|
||||
EXPECT_FALSE(aBox1.Intersects(aBox3));
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Distance_Separated)
|
||||
{
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 1.0, 1.0);
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(4.0, 0.0, 5.0, 1.0);
|
||||
EXPECT_NEAR(aBox1.Distance(aBox2), 3.0, 1e-10);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Distance_Overlapping)
|
||||
{
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 10.0, 10.0);
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(5.0, 5.0, 15.0, 15.0);
|
||||
EXPECT_DOUBLE_EQ(aBox1.Distance(aBox2), 0.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Distance_Diagonal)
|
||||
{
|
||||
Bnd_Box2d aBox1;
|
||||
aBox1.Update(0.0, 0.0, 1.0, 1.0);
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(4.0, 4.0, 5.0, 5.0);
|
||||
EXPECT_NEAR(aBox1.Distance(aBox2), std::sqrt(18.0), 1e-10);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Distance_Void)
|
||||
{
|
||||
Bnd_Box2d aBox1;
|
||||
Bnd_Box2d aBox2;
|
||||
aBox2.Update(0.0, 0.0, 1.0, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aBox1.Distance(aBox2), 0.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Center)
|
||||
{
|
||||
Bnd_Box2d aBox;
|
||||
aBox.Update(0.0, 0.0, 10.0, 20.0);
|
||||
auto aCenter = aBox.Center();
|
||||
ASSERT_TRUE(aCenter.has_value());
|
||||
EXPECT_DOUBLE_EQ(aCenter->X(), 5.0);
|
||||
EXPECT_DOUBLE_EQ(aCenter->Y(), 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_Box2dTest, Center_VoidNullopt)
|
||||
{
|
||||
Bnd_Box2d aVoid;
|
||||
EXPECT_FALSE(aVoid.Center().has_value());
|
||||
}
|
||||
@@ -845,4 +845,38 @@ TEST(Bnd_BoxTest, OCC16485_CumulativeEnlargeTolerance)
|
||||
// Verify that Xmin is approximately -tolerance (not growing with iterations)
|
||||
EXPECT_NEAR(-aTol, aXmin, 1e-10) << "Xmin should be equal to -tolerance";
|
||||
EXPECT_NEAR(aNbStep + aTol, aXmax, 1e-10) << "Xmax should be equal to nbstep + tolerance";
|
||||
}
|
||||
|
||||
TEST(Bnd_BoxTest, Contains_Point)
|
||||
{
|
||||
Bnd_Box aBox(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 10));
|
||||
EXPECT_TRUE(aBox.Contains(gp_Pnt(5, 5, 5)));
|
||||
EXPECT_TRUE(aBox.Contains(gp_Pnt(0, 0, 0)));
|
||||
EXPECT_FALSE(aBox.Contains(gp_Pnt(-1, 5, 5)));
|
||||
EXPECT_FALSE(aBox.Contains(gp_Pnt(5, 5, 11)));
|
||||
}
|
||||
|
||||
TEST(Bnd_BoxTest, Intersects_Box)
|
||||
{
|
||||
Bnd_Box aBox1(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 10));
|
||||
Bnd_Box aBox2(gp_Pnt(5, 5, 5), gp_Pnt(15, 15, 15));
|
||||
Bnd_Box aBox3(gp_Pnt(20, 20, 20), gp_Pnt(30, 30, 30));
|
||||
EXPECT_TRUE(aBox1.Intersects(aBox2));
|
||||
EXPECT_FALSE(aBox1.Intersects(aBox3));
|
||||
}
|
||||
|
||||
TEST(Bnd_BoxTest, Center)
|
||||
{
|
||||
Bnd_Box aBox(gp_Pnt(0, 0, 0), gp_Pnt(10, 20, 30));
|
||||
auto aCenter = aBox.Center();
|
||||
ASSERT_TRUE(aCenter.has_value());
|
||||
EXPECT_DOUBLE_EQ(aCenter->X(), 5.0);
|
||||
EXPECT_DOUBLE_EQ(aCenter->Y(), 10.0);
|
||||
EXPECT_DOUBLE_EQ(aCenter->Z(), 15.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_BoxTest, Center_VoidNullopt)
|
||||
{
|
||||
Bnd_Box aVoid;
|
||||
EXPECT_FALSE(aVoid.Center().has_value());
|
||||
}
|
||||
@@ -77,3 +77,30 @@ TEST(Bnd_OBB_Test, OCC30704_AddPointToVoidBox)
|
||||
EXPECT_DOUBLE_EQ(aCenter.Y(), 200.0);
|
||||
EXPECT_DOUBLE_EQ(aCenter.Z(), 300.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_OBB_Test, Contains_Point)
|
||||
{
|
||||
Bnd_OBB anOBB(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0), gp_Dir(0, 1, 0), gp_Dir(0, 0, 1), 5.0, 5.0, 5.0);
|
||||
EXPECT_TRUE(anOBB.Contains(gp_Pnt(0, 0, 0)));
|
||||
EXPECT_TRUE(anOBB.Contains(gp_Pnt(4, 4, 4)));
|
||||
EXPECT_FALSE(anOBB.Contains(gp_Pnt(10, 0, 0)));
|
||||
}
|
||||
|
||||
TEST(Bnd_OBB_Test, Intersects_OBB)
|
||||
{
|
||||
Bnd_OBB anOBB1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0), gp_Dir(0, 1, 0), gp_Dir(0, 0, 1), 5.0, 5.0, 5.0);
|
||||
Bnd_OBB anOBB2(gp_Pnt(8, 0, 0), gp_Dir(1, 0, 0), gp_Dir(0, 1, 0), gp_Dir(0, 0, 1), 5.0, 5.0, 5.0);
|
||||
Bnd_OBB
|
||||
anOBB3(gp_Pnt(20, 0, 0), gp_Dir(1, 0, 0), gp_Dir(0, 1, 0), gp_Dir(0, 0, 1), 5.0, 5.0, 5.0);
|
||||
EXPECT_TRUE(anOBB1.Intersects(anOBB2));
|
||||
EXPECT_FALSE(anOBB1.Intersects(anOBB3));
|
||||
}
|
||||
|
||||
TEST(Bnd_OBB_Test, GetHalfSizes_StructuredBindings)
|
||||
{
|
||||
Bnd_OBB anOBB(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0), gp_Dir(0, 1, 0), gp_Dir(0, 0, 1), 3.0, 5.0, 7.0);
|
||||
const auto [aHX, aHY, aHZ] = anOBB.GetHalfSizes();
|
||||
EXPECT_DOUBLE_EQ(aHX, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aHY, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aHZ, 7.0);
|
||||
}
|
||||
|
||||
511
src/FoundationClasses/TKMath/GTests/Bnd_Range_Test.cxx
Normal file
511
src/FoundationClasses/TKMath/GTests/Bnd_Range_Test.cxx
Normal file
@@ -0,0 +1,511 @@
|
||||
// Copyright (c) 2025 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <Bnd_Range.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
#include <Standard_ConstructionError.hxx>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Bnd_RangeTest, DefaultConstructor_IsVoid)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
EXPECT_TRUE(aRange.IsVoid());
|
||||
EXPECT_LT(aRange.Delta(), 0.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, ParameterizedConstructor)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 15.0);
|
||||
EXPECT_FALSE(aRange.IsVoid());
|
||||
EXPECT_DOUBLE_EQ(aRange.Delta(), 12.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, ParameterizedConstructor_InvalidRange)
|
||||
{
|
||||
EXPECT_THROW(Bnd_Range(10.0, 5.0), Standard_ConstructionError);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, ParameterizedConstructor_PointRange)
|
||||
{
|
||||
Bnd_Range aRange(5.0, 5.0);
|
||||
EXPECT_FALSE(aRange.IsVoid());
|
||||
EXPECT_DOUBLE_EQ(aRange.Delta(), 0.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, GetMin_GetMax_GetBounds)
|
||||
{
|
||||
Bnd_Range aRange(2.0, 8.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetMin(aMin));
|
||||
EXPECT_DOUBLE_EQ(aMin, 2.0);
|
||||
EXPECT_TRUE(aRange.GetMax(aMax));
|
||||
EXPECT_DOUBLE_EQ(aMax, 8.0);
|
||||
|
||||
double aFirst = 0.0, aLast = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aFirst, aLast));
|
||||
EXPECT_DOUBLE_EQ(aFirst, 2.0);
|
||||
EXPECT_DOUBLE_EQ(aLast, 8.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, GetMin_GetMax_Void)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
double aVal = 0.0;
|
||||
EXPECT_FALSE(aRange.GetMin(aVal));
|
||||
EXPECT_FALSE(aRange.GetMax(aVal));
|
||||
|
||||
double aFirst = 0.0, aLast = 0.0;
|
||||
EXPECT_FALSE(aRange.GetBounds(aFirst, aLast));
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, GetIntermediatePoint)
|
||||
{
|
||||
Bnd_Range aRange(10.0, 20.0);
|
||||
double aPar = 0.0;
|
||||
EXPECT_TRUE(aRange.GetIntermediatePoint(0.0, aPar));
|
||||
EXPECT_DOUBLE_EQ(aPar, 10.0);
|
||||
EXPECT_TRUE(aRange.GetIntermediatePoint(0.5, aPar));
|
||||
EXPECT_DOUBLE_EQ(aPar, 15.0);
|
||||
EXPECT_TRUE(aRange.GetIntermediatePoint(1.0, aPar));
|
||||
EXPECT_DOUBLE_EQ(aPar, 20.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, GetIntermediatePoint_Void)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
double aPar = 0.0;
|
||||
EXPECT_FALSE(aRange.GetIntermediatePoint(0.5, aPar));
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, SetVoid)
|
||||
{
|
||||
Bnd_Range aRange(1.0, 5.0);
|
||||
EXPECT_FALSE(aRange.IsVoid());
|
||||
aRange.SetVoid();
|
||||
EXPECT_TRUE(aRange.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Add_Double_ToVoid)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
aRange.Add(5.0);
|
||||
EXPECT_FALSE(aRange.IsVoid());
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 5.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Add_Double_Extends)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 7.0);
|
||||
aRange.Add(1.0);
|
||||
aRange.Add(10.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Add_Range_ToVoid)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
Bnd_Range anOther(3.0, 7.0);
|
||||
aRange.Add(anOther);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 7.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Add_VoidRange)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 7.0);
|
||||
Bnd_Range aVoid;
|
||||
aRange.Add(aVoid);
|
||||
// Should remain unchanged
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 7.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Add_Range_VoidToVoid)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
Bnd_Range aVoid;
|
||||
aRange.Add(aVoid);
|
||||
EXPECT_TRUE(aRange.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Add_Range_Extends)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 7.0);
|
||||
Bnd_Range anOther(1.0, 10.0);
|
||||
aRange.Add(anOther);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Common_Overlapping)
|
||||
{
|
||||
Bnd_Range aRange(1.0, 10.0);
|
||||
Bnd_Range anOther(5.0, 15.0);
|
||||
aRange.Common(anOther);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Common_NoOverlap)
|
||||
{
|
||||
Bnd_Range aRange(1.0, 5.0);
|
||||
Bnd_Range anOther(7.0, 10.0);
|
||||
aRange.Common(anOther);
|
||||
EXPECT_TRUE(aRange.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Common_WithVoid)
|
||||
{
|
||||
Bnd_Range aRange(1.0, 5.0);
|
||||
Bnd_Range aVoid;
|
||||
aRange.Common(aVoid);
|
||||
EXPECT_TRUE(aRange.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Union_Overlapping)
|
||||
{
|
||||
Bnd_Range aRange(1.0, 7.0);
|
||||
Bnd_Range anOther(5.0, 15.0);
|
||||
EXPECT_TRUE(aRange.Union(anOther));
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 15.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Union_Separated)
|
||||
{
|
||||
Bnd_Range aRange(1.0, 5.0);
|
||||
Bnd_Range anOther(7.0, 10.0);
|
||||
EXPECT_FALSE(aRange.Union(anOther));
|
||||
// aRange should remain unchanged
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 1.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 5.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Union_WithVoid)
|
||||
{
|
||||
Bnd_Range aRange(1.0, 5.0);
|
||||
Bnd_Range aVoid;
|
||||
EXPECT_FALSE(aRange.Union(aVoid));
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsIntersected_Void)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
EXPECT_EQ(aRange.IsIntersected(5.0), Bnd_Range::IntersectStatus_Out);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsIntersected_Contains)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 15.0);
|
||||
EXPECT_EQ(aRange.IsIntersected(5.0), Bnd_Range::IntersectStatus_In);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsIntersected_Outside)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 15.0);
|
||||
EXPECT_EQ(aRange.IsIntersected(20.0), Bnd_Range::IntersectStatus_Out);
|
||||
EXPECT_EQ(aRange.IsIntersected(1.0), Bnd_Range::IntersectStatus_Out);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsIntersected_OnBoundary)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 15.0);
|
||||
EXPECT_EQ(aRange.IsIntersected(3.0), Bnd_Range::IntersectStatus_Boundary);
|
||||
EXPECT_EQ(aRange.IsIntersected(15.0), Bnd_Range::IntersectStatus_Boundary);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsIntersected_PointRange)
|
||||
{
|
||||
// When myFirst == myLast, only Out or Boundary possible
|
||||
Bnd_Range aRange(5.0, 5.0);
|
||||
EXPECT_EQ(aRange.IsIntersected(5.0), Bnd_Range::IntersectStatus_Boundary);
|
||||
EXPECT_EQ(aRange.IsIntersected(3.0), Bnd_Range::IntersectStatus_Out);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsIntersected_Periodic_Contains)
|
||||
{
|
||||
// Range [3, 15], period 4, val 1
|
||||
// Check: val + k*period in [3, 15]
|
||||
// k=1: 1+4=5, inside [3,15] -> In
|
||||
Bnd_Range aRange(3.0, 15.0);
|
||||
EXPECT_EQ(aRange.IsIntersected(1.0, 4.0), Bnd_Range::IntersectStatus_In);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsIntersected_Periodic_OnBoundary)
|
||||
{
|
||||
// Range [3, 15], period 4, val 3 -> val + 0*4 = 3 exactly
|
||||
Bnd_Range aRange(3.0, 15.0);
|
||||
EXPECT_EQ(aRange.IsIntersected(3.0, 4.0), Bnd_Range::IntersectStatus_Boundary);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsIntersected_Periodic_Outside)
|
||||
{
|
||||
// Range [3.5, 3.9], period 4, val 0
|
||||
// Check: 0 + k*4 in [3.5, 3.9] -> k=1 gives 4.0, not in range
|
||||
Bnd_Range aRange(3.5, 3.9);
|
||||
EXPECT_EQ(aRange.IsIntersected(0.0, 4.0), Bnd_Range::IntersectStatus_Out);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Split_NoIntersection)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 15.0);
|
||||
NCollection_List<Bnd_Range> aList;
|
||||
aRange.Split(20.0, aList);
|
||||
EXPECT_EQ(aList.Size(), 1);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aList.First().GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 15.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Split_AtInteriorPoint)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 15.0);
|
||||
NCollection_List<Bnd_Range> aList;
|
||||
aRange.Split(5.0, aList);
|
||||
EXPECT_EQ(aList.Size(), 2);
|
||||
double aMin1 = 0.0, aMax1 = 0.0;
|
||||
EXPECT_TRUE(aList.First().GetBounds(aMin1, aMax1));
|
||||
EXPECT_DOUBLE_EQ(aMin1, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aMax1, 5.0);
|
||||
double aMin2 = 0.0, aMax2 = 0.0;
|
||||
EXPECT_TRUE(aList.Last().GetBounds(aMin2, aMax2));
|
||||
EXPECT_DOUBLE_EQ(aMin2, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aMax2, 15.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Split_Periodic)
|
||||
{
|
||||
// Range [3, 15], split at val=5, period=4
|
||||
// Split points: 5, 9, 13 -> sub-ranges: [3,5], [5,9], [9,13], [13,15]
|
||||
Bnd_Range aRange(3.0, 15.0);
|
||||
NCollection_List<Bnd_Range> aList;
|
||||
aRange.Split(5.0, aList, 4.0);
|
||||
EXPECT_EQ(aList.Size(), 4);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Enlarge)
|
||||
{
|
||||
Bnd_Range aRange(5.0, 10.0);
|
||||
aRange.Enlarge(2.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 12.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Enlarge_Void)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
aRange.Enlarge(2.0);
|
||||
EXPECT_TRUE(aRange.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Shifted)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 7.0);
|
||||
Bnd_Range aShifted = aRange.Shifted(10.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aShifted.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 13.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 17.0);
|
||||
// Original unchanged
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 7.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Shifted_Void)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
Bnd_Range aShifted = aRange.Shifted(10.0);
|
||||
EXPECT_TRUE(aShifted.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Shift)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 7.0);
|
||||
aRange.Shift(10.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 13.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 17.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, TrimFrom)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
aRange.TrimFrom(5.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 5.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, TrimFrom_MakesVoid)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
aRange.TrimFrom(15.0);
|
||||
EXPECT_TRUE(aRange.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, TrimTo)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
aRange.TrimTo(7.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
EXPECT_TRUE(aRange.GetBounds(aMin, aMax));
|
||||
EXPECT_DOUBLE_EQ(aMin, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 7.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, TrimTo_MakesVoid)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
aRange.TrimTo(1.0);
|
||||
EXPECT_TRUE(aRange.IsVoid());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsOut_Value)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
EXPECT_FALSE(aRange.IsOut(5.0));
|
||||
EXPECT_FALSE(aRange.IsOut(3.0));
|
||||
EXPECT_FALSE(aRange.IsOut(10.0));
|
||||
EXPECT_TRUE(aRange.IsOut(1.0));
|
||||
EXPECT_TRUE(aRange.IsOut(15.0));
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsOut_Void)
|
||||
{
|
||||
Bnd_Range aRange;
|
||||
EXPECT_TRUE(aRange.IsOut(5.0));
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsOut_Range)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
EXPECT_FALSE(aRange.IsOut(Bnd_Range(5.0, 8.0)));
|
||||
EXPECT_FALSE(aRange.IsOut(Bnd_Range(1.0, 5.0)));
|
||||
EXPECT_TRUE(aRange.IsOut(Bnd_Range(11.0, 15.0)));
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, IsOut_Range_Void)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
Bnd_Range aVoid;
|
||||
EXPECT_TRUE(aRange.IsOut(aVoid));
|
||||
EXPECT_TRUE(aVoid.IsOut(aRange));
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Equality)
|
||||
{
|
||||
Bnd_Range aRange1(3.0, 10.0);
|
||||
Bnd_Range aRange2(3.0, 10.0);
|
||||
Bnd_Range aRange3(3.0, 11.0);
|
||||
EXPECT_TRUE(aRange1 == aRange2);
|
||||
EXPECT_FALSE(aRange1 == aRange3);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Contains_Value)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
EXPECT_TRUE(aRange.Contains(5.0));
|
||||
EXPECT_TRUE(aRange.Contains(3.0));
|
||||
EXPECT_TRUE(aRange.Contains(10.0));
|
||||
EXPECT_FALSE(aRange.Contains(2.0));
|
||||
EXPECT_FALSE(aRange.Contains(11.0));
|
||||
|
||||
Bnd_Range aVoid;
|
||||
EXPECT_FALSE(aVoid.Contains(5.0));
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Intersects_Range)
|
||||
{
|
||||
Bnd_Range aRange1(3.0, 10.0);
|
||||
Bnd_Range aRange2(5.0, 15.0);
|
||||
Bnd_Range aRange3(11.0, 20.0);
|
||||
EXPECT_TRUE(aRange1.Intersects(aRange2));
|
||||
EXPECT_FALSE(aRange1.Intersects(aRange3));
|
||||
|
||||
Bnd_Range aVoid;
|
||||
EXPECT_FALSE(aRange1.Intersects(aVoid));
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Min_Max_DirectAccess)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
ASSERT_TRUE(aRange.Min().has_value());
|
||||
ASSERT_TRUE(aRange.Max().has_value());
|
||||
EXPECT_DOUBLE_EQ(*aRange.Min(), 3.0);
|
||||
EXPECT_DOUBLE_EQ(*aRange.Max(), 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Min_Max_NulloptOnVoid)
|
||||
{
|
||||
Bnd_Range aVoid;
|
||||
EXPECT_FALSE(aVoid.Min().has_value());
|
||||
EXPECT_FALSE(aVoid.Max().has_value());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Get_StructuredBindings)
|
||||
{
|
||||
Bnd_Range aRange(3.0, 10.0);
|
||||
auto aBounds = aRange.Get();
|
||||
ASSERT_TRUE(aBounds.has_value());
|
||||
const auto [aMin, aMax] = *aBounds;
|
||||
EXPECT_DOUBLE_EQ(aMin, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Get_NulloptOnVoid)
|
||||
{
|
||||
Bnd_Range aVoid;
|
||||
EXPECT_FALSE(aVoid.Get().has_value());
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Center)
|
||||
{
|
||||
Bnd_Range aRange(2.0, 8.0);
|
||||
ASSERT_TRUE(aRange.Center().has_value());
|
||||
EXPECT_DOUBLE_EQ(*aRange.Center(), 5.0);
|
||||
|
||||
Bnd_Range aPoint(3.0, 3.0);
|
||||
ASSERT_TRUE(aPoint.Center().has_value());
|
||||
EXPECT_DOUBLE_EQ(*aPoint.Center(), 3.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_RangeTest, Center_NulloptOnVoid)
|
||||
{
|
||||
Bnd_Range aVoid;
|
||||
EXPECT_FALSE(aVoid.Center().has_value());
|
||||
}
|
||||
224
src/FoundationClasses/TKMath/GTests/Bnd_Sphere_Test.cxx
Normal file
224
src/FoundationClasses/TKMath/GTests/Bnd_Sphere_Test.cxx
Normal file
@@ -0,0 +1,224 @@
|
||||
// Copyright (c) 2025 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <Bnd_Sphere.hxx>
|
||||
#include <gp_XYZ.hxx>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Bnd_SphereTest, DefaultConstructor)
|
||||
{
|
||||
Bnd_Sphere aSphere;
|
||||
EXPECT_DOUBLE_EQ(aSphere.Center().X(), 0.0);
|
||||
EXPECT_DOUBLE_EQ(aSphere.Center().Y(), 0.0);
|
||||
EXPECT_DOUBLE_EQ(aSphere.Center().Z(), 0.0);
|
||||
EXPECT_DOUBLE_EQ(aSphere.Radius(), 0.0);
|
||||
EXPECT_FALSE(aSphere.IsValid());
|
||||
EXPECT_EQ(aSphere.U(), 0);
|
||||
EXPECT_EQ(aSphere.V(), 0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, ParameterizedConstructor)
|
||||
{
|
||||
const gp_XYZ aCenter(1.0, 2.0, 3.0);
|
||||
Bnd_Sphere aSphere(aCenter, 5.0, 10, 20);
|
||||
EXPECT_DOUBLE_EQ(aSphere.Center().X(), 1.0);
|
||||
EXPECT_DOUBLE_EQ(aSphere.Center().Y(), 2.0);
|
||||
EXPECT_DOUBLE_EQ(aSphere.Center().Z(), 3.0);
|
||||
EXPECT_DOUBLE_EQ(aSphere.Radius(), 5.0);
|
||||
EXPECT_EQ(aSphere.U(), 10);
|
||||
EXPECT_EQ(aSphere.V(), 20);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, Validity)
|
||||
{
|
||||
Bnd_Sphere aSphere;
|
||||
EXPECT_FALSE(aSphere.IsValid());
|
||||
aSphere.SetValid(true);
|
||||
EXPECT_TRUE(aSphere.IsValid());
|
||||
aSphere.SetValid(false);
|
||||
EXPECT_FALSE(aSphere.IsValid());
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, Distance)
|
||||
{
|
||||
const gp_XYZ aCenter(0.0, 0.0, 0.0);
|
||||
Bnd_Sphere aSphere(aCenter, 1.0, 0, 0);
|
||||
const gp_XYZ aPoint(3.0, 4.0, 0.0);
|
||||
const double aDist = aSphere.Distance(aPoint);
|
||||
EXPECT_DOUBLE_EQ(aDist, 5.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, SquareDistance)
|
||||
{
|
||||
const gp_XYZ aCenter(0.0, 0.0, 0.0);
|
||||
Bnd_Sphere aSphere(aCenter, 1.0, 0, 0);
|
||||
const gp_XYZ aPoint(3.0, 4.0, 0.0);
|
||||
EXPECT_DOUBLE_EQ(aSphere.SquareDistance(aPoint), 25.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, Distances_PointOutside)
|
||||
{
|
||||
const gp_XYZ aCenter(0.0, 0.0, 0.0);
|
||||
Bnd_Sphere aSphere(aCenter, 2.0, 0, 0);
|
||||
const gp_XYZ aPoint(5.0, 0.0, 0.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
aSphere.Distances(aPoint, aMin, aMax);
|
||||
EXPECT_DOUBLE_EQ(aMin, 3.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 7.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, Distances_PointInside)
|
||||
{
|
||||
const gp_XYZ aCenter(0.0, 0.0, 0.0);
|
||||
Bnd_Sphere aSphere(aCenter, 5.0, 0, 0);
|
||||
const gp_XYZ aPoint(1.0, 0.0, 0.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
aSphere.Distances(aPoint, aMin, aMax);
|
||||
EXPECT_DOUBLE_EQ(aMin, 0.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 6.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, SquareDistances_PointOutside)
|
||||
{
|
||||
const gp_XYZ aCenter(0.0, 0.0, 0.0);
|
||||
Bnd_Sphere aSphere(aCenter, 2.0, 0, 0);
|
||||
const gp_XYZ aPoint(5.0, 0.0, 0.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
aSphere.SquareDistances(aPoint, aMin, aMax);
|
||||
// d^2 = 25, r^2 = 4
|
||||
// min = d^2 - r^2 = 21, max = d^2 + r^2 = 29
|
||||
EXPECT_DOUBLE_EQ(aMin, 21.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 29.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, SquareDistances_PointInside)
|
||||
{
|
||||
const gp_XYZ aCenter(0.0, 0.0, 0.0);
|
||||
Bnd_Sphere aSphere(aCenter, 5.0, 0, 0);
|
||||
const gp_XYZ aPoint(1.0, 0.0, 0.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
aSphere.SquareDistances(aPoint, aMin, aMax);
|
||||
// d^2 = 1, r^2 = 25
|
||||
// d^2 < r^2 -> min = 0, max = d^2 + r^2 = 26
|
||||
EXPECT_DOUBLE_EQ(aMin, 0.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 26.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, SquareDistances_PointAtCenter)
|
||||
{
|
||||
const gp_XYZ aCenter(0.0, 0.0, 0.0);
|
||||
Bnd_Sphere aSphere(aCenter, 3.0, 0, 0);
|
||||
const gp_XYZ aPoint(0.0, 0.0, 0.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
aSphere.SquareDistances(aPoint, aMin, aMax);
|
||||
// d^2 = 0, r^2 = 9
|
||||
// d^2 < r^2 -> min = 0, max = 0 + 9 = 9
|
||||
EXPECT_DOUBLE_EQ(aMin, 0.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 9.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, SquareDistances_PointOnSurface)
|
||||
{
|
||||
const gp_XYZ aCenter(0.0, 0.0, 0.0);
|
||||
Bnd_Sphere aSphere(aCenter, 3.0, 0, 0);
|
||||
const gp_XYZ aPoint(3.0, 0.0, 0.0);
|
||||
double aMin = 0.0, aMax = 0.0;
|
||||
aSphere.SquareDistances(aPoint, aMin, aMax);
|
||||
// d^2 = 9, r^2 = 9
|
||||
// d^2 < r^2 is false (equal), so min = d^2 - r^2 = 0, max = d^2 + r^2 = 18
|
||||
EXPECT_DOUBLE_EQ(aMin, 0.0);
|
||||
EXPECT_DOUBLE_EQ(aMax, 18.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, Project)
|
||||
{
|
||||
const gp_XYZ aCenter(1.0, 2.0, 3.0);
|
||||
Bnd_Sphere aSphere(aCenter, 5.0, 0, 0);
|
||||
const gp_XYZ aNode(10.0, 20.0, 30.0);
|
||||
gp_XYZ aProjNode;
|
||||
double aDist = 0.0;
|
||||
bool anInside = false;
|
||||
const bool isOk = aSphere.Project(aNode, aProjNode, aDist, anInside);
|
||||
EXPECT_TRUE(isOk);
|
||||
EXPECT_TRUE(anInside);
|
||||
EXPECT_DOUBLE_EQ(aProjNode.X(), aCenter.X());
|
||||
EXPECT_DOUBLE_EQ(aProjNode.Y(), aCenter.Y());
|
||||
EXPECT_DOUBLE_EQ(aProjNode.Z(), aCenter.Z());
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, Add_EnclosingSphere)
|
||||
{
|
||||
Bnd_Sphere aSphere1(gp_XYZ(0.0, 0.0, 0.0), 10.0, 0, 0);
|
||||
Bnd_Sphere aSphere2(gp_XYZ(1.0, 0.0, 0.0), 2.0, 0, 0);
|
||||
aSphere1.Add(aSphere2);
|
||||
// aSphere1 already encloses aSphere2, should remain unchanged
|
||||
EXPECT_DOUBLE_EQ(aSphere1.Radius(), 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, Add_EnclosedBySphere)
|
||||
{
|
||||
Bnd_Sphere aSphere1(gp_XYZ(0.0, 0.0, 0.0), 2.0, 0, 0);
|
||||
Bnd_Sphere aSphere2(gp_XYZ(0.0, 0.0, 0.0), 10.0, 0, 0);
|
||||
aSphere1.Add(aSphere2);
|
||||
// aSphere2 encloses aSphere1, should take aSphere2
|
||||
EXPECT_DOUBLE_EQ(aSphere1.Radius(), 10.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, Add_PartialOverlap)
|
||||
{
|
||||
Bnd_Sphere aSphere1(gp_XYZ(0.0, 0.0, 0.0), 3.0, 0, 0);
|
||||
Bnd_Sphere aSphere2(gp_XYZ(5.0, 0.0, 0.0), 3.0, 0, 0);
|
||||
aSphere1.Add(aSphere2);
|
||||
// Combined radius should be (5 + 3 + 3) / 2 = 5.5
|
||||
EXPECT_DOUBLE_EQ(aSphere1.Radius(), 5.5);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, IsOut_Separated)
|
||||
{
|
||||
Bnd_Sphere aSphere1(gp_XYZ(0.0, 0.0, 0.0), 1.0, 0, 0);
|
||||
Bnd_Sphere aSphere2(gp_XYZ(10.0, 0.0, 0.0), 1.0, 0, 0);
|
||||
EXPECT_TRUE(aSphere1.IsOut(aSphere2));
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, IsOut_Overlapping)
|
||||
{
|
||||
Bnd_Sphere aSphere1(gp_XYZ(0.0, 0.0, 0.0), 3.0, 0, 0);
|
||||
Bnd_Sphere aSphere2(gp_XYZ(4.0, 0.0, 0.0), 3.0, 0, 0);
|
||||
EXPECT_FALSE(aSphere1.IsOut(aSphere2));
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, IsOut_PointWithMaxDist)
|
||||
{
|
||||
Bnd_Sphere aSphere(gp_XYZ(0.0, 0.0, 0.0), 5.0, 0, 0);
|
||||
const gp_XYZ aPoint(20.0, 0.0, 0.0);
|
||||
double aMaxDist = 100.0;
|
||||
aSphere.SetValid(true);
|
||||
EXPECT_FALSE(aSphere.IsOut(aPoint, aMaxDist));
|
||||
// aMaxDist should be updated to aCurMaxDist = 20 + 5 = 25
|
||||
EXPECT_DOUBLE_EQ(aMaxDist, 25.0);
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, IsOut_PointTooFar)
|
||||
{
|
||||
Bnd_Sphere aSphere(gp_XYZ(0.0, 0.0, 0.0), 1.0, 0, 0);
|
||||
const gp_XYZ aPoint(20.0, 0.0, 0.0);
|
||||
double aMaxDist = 10.0;
|
||||
EXPECT_TRUE(aSphere.IsOut(aPoint, aMaxDist));
|
||||
}
|
||||
|
||||
TEST(Bnd_SphereTest, SquareExtent)
|
||||
{
|
||||
Bnd_Sphere aSphere(gp_XYZ(0.0, 0.0, 0.0), 3.0, 0, 0);
|
||||
EXPECT_DOUBLE_EQ(aSphere.SquareExtent(), 36.0);
|
||||
}
|
||||
@@ -6,7 +6,10 @@ set(OCCT_TKMath_GTests_FILES
|
||||
Bnd_B3_Test.cxx
|
||||
Bnd_BoundSortBox_Test.cxx
|
||||
Bnd_Box_Test.cxx
|
||||
Bnd_Box2d_Test.cxx
|
||||
Bnd_OBB_Test.cxx
|
||||
Bnd_Range_Test.cxx
|
||||
Bnd_Sphere_Test.cxx
|
||||
BSplCLib_Cache_Test.cxx
|
||||
BSplCLib_Test.cxx
|
||||
BSplSLib_Cache_Test.cxx
|
||||
|
||||
@@ -613,10 +613,10 @@ static bool IsSeamOrBound(const IntSurf_PntOn2S& thePtf,
|
||||
aBndR[i].Add(aParF[i]);
|
||||
aBndR[i].Add(aParL[i]);
|
||||
|
||||
if (aBndR[i].IsIntersected(theFBound[i], theArrPeriods[i]) == 1)
|
||||
if (aBndR[i].IsIntersected(theFBound[i], theArrPeriods[i]) == Bnd_Range::IntersectStatus_In)
|
||||
return true;
|
||||
|
||||
if (aBndR[i].IsIntersected(theLBound[i], theArrPeriods[i]) == 1)
|
||||
if (aBndR[i].IsIntersected(theLBound[i], theArrPeriods[i]) == Bnd_Range::IntersectStatus_In)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -635,7 +635,7 @@ static bool IsSeamOrBound(const IntSurf_PntOn2S& thePtf,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aBndR[i].IsIntersected(0.0, theArrPeriods[i]) == 1)
|
||||
if (aBndR[i].IsIntersected(0.0, theArrPeriods[i]) == Bnd_Range::IntersectStatus_In)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user