// Created on: 2005-09-08 // Created by: Alexander GRIGORIEV // Copyright (c) 2005-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. #ifndef _Bnd_B2_HeaderFile #define _Bnd_B2_HeaderFile #include "Standard.hxx" #include "Standard_DefineAlloc.hxx" #include "Standard_Real.hxx" #include "Standard_ShortReal.hxx" #include "gp_XY.hxx" #include "gp_Pnt2d.hxx" #include "gp_Trsf2d.hxx" #include "gp_Ax2d.hxx" #include //! Template class for 2D bounding box. //! This is a base template that is instantiated for double and float. template class Bnd_B2 { public: DEFINE_STANDARD_ALLOC //! Empty constructor. constexpr Bnd_B2() noexcept; //! Constructor. constexpr Bnd_B2(const gp_XY& theCenter, const gp_XY& theHSize) noexcept; //! Constructor. constexpr Bnd_B2(const std::array& theCenter, const std::array& theHSize) noexcept; //! Returns True if the box is void (non-initialized). constexpr bool IsVoid() const noexcept; //! Reset the box data. void Clear() noexcept; //! Update the box by a point. void Add(const gp_XY& thePnt); //! Update the box by a point. void Add(const gp_Pnt2d& thePnt); //! Update the box by another box. void Add(const Bnd_B2& theBox); //! Query a box corner: (Center - HSize). You must make sure that //! the box is NOT VOID (see IsVoid()), otherwise the method returns //! irrelevant result. gp_XY CornerMin() const noexcept; //! Query a box corner: (Center + HSize). You must make sure that //! the box is NOT VOID (see IsVoid()), otherwise the method returns //! irrelevant result. gp_XY CornerMax() const noexcept; //! Query the square diagonal. If the box is VOID (see method IsVoid()) //! then a very big real value is returned. constexpr double SquareExtent() const noexcept; //! Extend the Box by the absolute value of theDiff. void Enlarge(const double theDiff) noexcept; //! Limit the Box by the internals of theOtherBox. //! Returns True if the limitation takes place, otherwise False //! indicating that the boxes do not intersect. bool Limit(const Bnd_B2& theOtherBox); //! Transform the bounding box with the given transformation. //! The resulting box will be larger if theTrsf contains rotation. [[nodiscard]] Bnd_B2 Transformed(const gp_Trsf2d& theTrsf) const; //! Check the given point for the inclusion in the Box. //! Returns True if the point is outside. constexpr bool IsOut(const gp_XY& thePnt) const noexcept; //! Check a circle for the intersection with the current box. //! Returns True if there is no intersection between boxes. bool IsOut(const gp_XY& theCenter, const double theRadius, const bool isCircleHollow = false) const; //! Check the given box for the intersection with the current box. //! Returns True if there is no intersection between boxes. constexpr bool IsOut(const Bnd_B2& theOtherBox) const noexcept; //! Check the given box oriented by the given transformation //! for the intersection with the current box. //! Returns True if there is no intersection between boxes. bool IsOut(const Bnd_B2& theOtherBox, const gp_Trsf2d& theTrsf) const; //! Check the given Line for the intersection with the current box. //! Returns True if there is no intersection. bool IsOut(const gp_Ax2d& theLine) const; //! Check the Segment defined by the couple of input points //! for the intersection with the current box. //! Returns True if there is no intersection. bool IsOut(const gp_XY& theP0, const gp_XY& theP1) const; //! Check that the box 'this' is inside the given box 'theBox'. Returns //! True if 'this' box is fully inside 'theBox'. constexpr bool IsIn(const Bnd_B2& theBox) const noexcept; //! Check that the box 'this' is inside the given box 'theBox' //! transformed by 'theTrsf'. Returns True if 'this' box is fully //! inside the transformed 'theBox'. bool IsIn(const Bnd_B2& theBox, const gp_Trsf2d& theTrsf) const; //! Set the Center coordinates void SetCenter(const gp_XY& theCenter) noexcept; //! Set the Center coordinates void SetCenter(const std::array& theCenter) noexcept; //! Set the HSize (half-diagonal) coordinates. //! All components of theHSize must be non-negative. void SetHSize(const gp_XY& theHSize) noexcept; //! Set the HSize (half-diagonal) coordinates. //! All components of theHSize must be non-negative. void SetHSize(const std::array& theHSize) noexcept; //! Get the Center coordinates constexpr const std::array& Center() const noexcept; //! Get the HSize (half-diagonal) coordinates constexpr const std::array& HSize() const noexcept; protected: static constexpr bool compareDist(const RealType aHSize[2], const RealType aDist[2]) noexcept { return (std::abs(aDist[0]) > aHSize[0] || std::abs(aDist[1]) > aHSize[1]); } static bool compareDistD(const gp_XY& aHSize, const gp_XY& aDist) noexcept { return (std::abs(aDist.X()) > aHSize.X() || std::abs(aDist.Y()) > aHSize.Y()); } //! Constant representing a very large value for void box initialization static constexpr RealType THE_RealLast = RealType(1e30); private: std::array myCenter; std::array myHSize; }; //================================================================================================= template constexpr inline Bnd_B2::Bnd_B2() noexcept : myCenter{THE_RealLast, THE_RealLast}, myHSize{-THE_RealLast, -THE_RealLast} { } //================================================================================================= template constexpr inline Bnd_B2::Bnd_B2(const gp_XY& theCenter, const gp_XY& theHSize) noexcept : myCenter{RealType(theCenter.X()), RealType(theCenter.Y())}, myHSize{RealType(theHSize.X()), RealType(theHSize.Y())} { } //================================================================================================= template constexpr inline Bnd_B2::Bnd_B2(const std::array& theCenter, const std::array& theHSize) noexcept : myCenter(theCenter), myHSize(theHSize) { } //================================================================================================= template inline void Bnd_B2::Clear() noexcept { myCenter[0] = THE_RealLast; myCenter[1] = THE_RealLast; myHSize[0] = -THE_RealLast; myHSize[1] = -THE_RealLast; } //================================================================================================= template constexpr inline bool Bnd_B2::IsVoid() const noexcept { return (myHSize[0] < -1e-5); } //================================================================================================= template inline void Bnd_B2::Add(const gp_Pnt2d& thePnt) { Add(thePnt.XY()); } //================================================================================================= template inline void Bnd_B2::Add(const Bnd_B2& theBox) { if (!theBox.IsVoid()) { Add(theBox.CornerMin()); Add(theBox.CornerMax()); } } //================================================================================================= template inline gp_XY Bnd_B2::CornerMin() const noexcept { return gp_XY(myCenter[0] - myHSize[0], myCenter[1] - myHSize[1]); } //================================================================================================= template inline gp_XY Bnd_B2::CornerMax() const noexcept { return gp_XY(myCenter[0] + myHSize[0], myCenter[1] + myHSize[1]); } //================================================================================================= template constexpr inline double Bnd_B2::SquareExtent() const noexcept { return 4 * (myHSize[0] * myHSize[0] + myHSize[1] * myHSize[1]); } //================================================================================================= template inline void Bnd_B2::SetCenter(const gp_XY& theCenter) noexcept { myCenter[0] = RealType(theCenter.X()); myCenter[1] = RealType(theCenter.Y()); } //================================================================================================= template inline void Bnd_B2::SetHSize(const gp_XY& theHSize) noexcept { myHSize[0] = RealType(theHSize.X()); myHSize[1] = RealType(theHSize.Y()); } //================================================================================================= template inline void Bnd_B2::SetCenter(const std::array& theCenter) noexcept { myCenter = theCenter; } //================================================================================================= template inline void Bnd_B2::SetHSize(const std::array& theHSize) noexcept { myHSize = theHSize; } //================================================================================================= template constexpr inline const std::array& Bnd_B2::Center() const noexcept { return myCenter; } //================================================================================================= template constexpr inline const std::array& Bnd_B2::HSize() const noexcept { return myHSize; } //================================================================================================= template inline void Bnd_B2::Enlarge(const double aDiff) noexcept { const RealType aD = RealType(std::abs(aDiff)); myHSize[0] += aD; myHSize[1] += aD; } //================================================================================================= template constexpr inline bool Bnd_B2::IsOut(const gp_XY& thePnt) const noexcept { return (std::abs(RealType(thePnt.X()) - myCenter[0]) > myHSize[0] || std::abs(RealType(thePnt.Y()) - myCenter[1]) > myHSize[1]); } //================================================================================================= template constexpr inline bool Bnd_B2::IsOut(const Bnd_B2& theBox) const noexcept { return (std::abs(theBox.myCenter[0] - myCenter[0]) > theBox.myHSize[0] + myHSize[0] || std::abs(theBox.myCenter[1] - myCenter[1]) > theBox.myHSize[1] + myHSize[1]); } //================================================================================================= template constexpr inline bool Bnd_B2::IsIn(const Bnd_B2& theBox) const noexcept { return (std::abs(theBox.myCenter[0] - myCenter[0]) < theBox.myHSize[0] - myHSize[0] && std::abs(theBox.myCenter[1] - myCenter[1]) < theBox.myHSize[1] - myHSize[1]); } //================================================================================================= template void Bnd_B2::Add(const gp_XY& thePnt) { if (IsVoid()) { myCenter[0] = RealType(thePnt.X()); myCenter[1] = RealType(thePnt.Y()); myHSize[0] = 0.; myHSize[1] = 0.; } else { const RealType aDiff[2] = {RealType(thePnt.X()) - myCenter[0], RealType(thePnt.Y()) - myCenter[1]}; if (aDiff[0] > myHSize[0]) { const RealType aShift = (aDiff[0] - myHSize[0]) / 2; myCenter[0] += aShift; myHSize[0] += aShift; } else if (aDiff[0] < -myHSize[0]) { const RealType aShift = (aDiff[0] + myHSize[0]) / 2; myCenter[0] += aShift; myHSize[0] -= aShift; } if (aDiff[1] > myHSize[1]) { const RealType aShift = (aDiff[1] - myHSize[1]) / 2; myCenter[1] += aShift; myHSize[1] += aShift; } else if (aDiff[1] < -myHSize[1]) { const RealType aShift = (aDiff[1] + myHSize[1]) / 2; myCenter[1] += aShift; myHSize[1] -= aShift; } } } //================================================================================================= template bool Bnd_B2::Limit(const Bnd_B2& theBox) { bool aResult(false); const RealType diffC[2] = {theBox.myCenter[0] - myCenter[0], theBox.myCenter[1] - myCenter[1]}; const RealType sumH[2] = {theBox.myHSize[0] + myHSize[0], theBox.myHSize[1] + myHSize[1]}; // check the condition IsOut if (!compareDist(sumH, diffC)) { const RealType diffH[2] = {theBox.myHSize[0] - myHSize[0], theBox.myHSize[1] - myHSize[1]}; if (diffC[0] - diffH[0] > 0.) { const RealType aShift = (diffC[0] - diffH[0]) / 2; // positive myCenter[0] += aShift; myHSize[0] -= aShift; } else if (diffC[0] + diffH[0] < 0.) { const RealType aShift = (diffC[0] + diffH[0]) / 2; // negative myCenter[0] += aShift; myHSize[0] += aShift; } if (diffC[1] - diffH[1] > 0.) { const RealType aShift = (diffC[1] - diffH[1]) / 2; // positive myCenter[1] += aShift; myHSize[1] -= aShift; } else if (diffC[1] + diffH[1] < 0.) { const RealType aShift = (diffC[1] + diffH[1]) / 2; // negative myCenter[1] += aShift; myHSize[1] += aShift; } aResult = true; } return aResult; } //================================================================================================= template Bnd_B2 Bnd_B2::Transformed(const gp_Trsf2d& theTrsf) const { Bnd_B2 aResult; const gp_TrsfForm aForm = theTrsf.Form(); const double aScale = theTrsf.ScaleFactor(); const double aScaleAbs = std::abs(aScale); if (aForm == gp_Identity) aResult = *this; else if (aForm == gp_Translation || aForm == gp_PntMirror || aForm == gp_Scale) { aResult.myCenter[0] = (RealType)(myCenter[0] * aScale + theTrsf.TranslationPart().X()); aResult.myCenter[1] = (RealType)(myCenter[1] * aScale + theTrsf.TranslationPart().Y()); aResult.myHSize[0] = (RealType)(myHSize[0] * aScaleAbs); aResult.myHSize[1] = (RealType)(myHSize[1] * aScaleAbs); } else { gp_XY aCenter((double)myCenter[0], (double)myCenter[1]); theTrsf.Transforms(aCenter); aResult.myCenter[0] = (RealType)aCenter.X(); aResult.myCenter[1] = (RealType)aCenter.Y(); const double* aMat = &theTrsf.HVectorialPart().Value(1, 1); aResult.myHSize[0] = (RealType)(aScaleAbs * (std::abs(aMat[0]) * myHSize[0] + std::abs(aMat[1]) * myHSize[1])); aResult.myHSize[1] = (RealType)(aScaleAbs * (std::abs(aMat[2]) * myHSize[0] + std::abs(aMat[3]) * myHSize[1])); } return aResult; } //================================================================================================= template bool Bnd_B2::IsOut(const gp_XY& theCenter, const double theRadius, const bool isCircleHollow) const { bool aResult(true); if (!isCircleHollow) { // vector from the center of the circle to the nearest box face const double aDist[2] = {std::abs(theCenter.X() - double(myCenter[0])) - double(myHSize[0]), std::abs(theCenter.Y() - double(myCenter[1])) - double(myHSize[1])}; double aD(0.); if (aDist[0] > 0.) aD = aDist[0] * aDist[0]; if (aDist[1] > 0.) aD += aDist[1] * aDist[1]; aResult = (aD > theRadius * theRadius); } else { const double aDistC[2] = {std::abs(theCenter.X() - double(myCenter[0])), std::abs(theCenter.Y() - double(myCenter[1]))}; // vector from the center of the circle to the nearest box face double aDist[2] = {aDistC[0] - double(myHSize[0]), aDistC[1] - double(myHSize[1])}; double aD(0.); if (aDist[0] > 0.) aD = aDist[0] * aDist[0]; if (aDist[1] > 0.) aD += aDist[1] * aDist[1]; if (aD < theRadius * theRadius) { // the box intersects the solid circle; check if it is completely // inside the circle (in such case return isOut==True) aDist[0] = aDistC[0] + double(myHSize[0]); aDist[1] = aDistC[1] + double(myHSize[1]); if (aDist[0] * aDist[0] + aDist[1] * aDist[1] > theRadius * theRadius) aResult = false; } } return aResult; } //================================================================================================= template bool Bnd_B2::IsOut(const Bnd_B2& theBox, const gp_Trsf2d& theTrsf) const { bool aResult(false); const gp_TrsfForm aForm = theTrsf.Form(); const double aScale = theTrsf.ScaleFactor(); const double aScaleAbs = std::abs(aScale); if (aForm == gp_Translation || aForm == gp_Identity || aForm == gp_PntMirror || aForm == gp_Scale) { aResult = (std::abs(RealType(theBox.myCenter[0] * aScale + theTrsf.TranslationPart().X()) - myCenter[0]) > RealType(theBox.myHSize[0] * aScaleAbs) + myHSize[0] || std::abs(RealType(theBox.myCenter[1] * aScale + theTrsf.TranslationPart().Y()) - myCenter[1]) > RealType(theBox.myHSize[1] * aScaleAbs) + myHSize[1]); } else { // theBox is transformed and we check the resulting (enlarged) box against // 'this' box. const double* aMat = &theTrsf.HVectorialPart().Value(1, 1); gp_XY aCenter((double)theBox.myCenter[0], (double)theBox.myCenter[1]); theTrsf.Transforms(aCenter); const double aDist[2] = {aCenter.X() - (double)myCenter[0], aCenter.Y() - (double)myCenter[1]}; const double aMatAbs[4] = {std::abs(aMat[0]), std::abs(aMat[1]), std::abs(aMat[2]), std::abs(aMat[3])}; if (std::abs(aDist[0]) > (aScaleAbs * (aMatAbs[0] * theBox.myHSize[0] + aMatAbs[1] * theBox.myHSize[1]) + (double)myHSize[0]) || std::abs(aDist[1]) > (aScaleAbs * (aMatAbs[2] * theBox.myHSize[0] + aMatAbs[3] * theBox.myHSize[1]) + (double)myHSize[1])) aResult = true; else { // theBox is rotated, scaled and translated. We apply the reverse // translation and scaling then check against the rotated box 'this' if ((std::abs(aMat[0] * aDist[0] + aMat[2] * aDist[1]) > theBox.myHSize[0] * aScaleAbs + (aMatAbs[0] * myHSize[0] + aMatAbs[2] * myHSize[1])) || (std::abs(aMat[1] * aDist[0] + aMat[3] * aDist[1]) > theBox.myHSize[1] * aScaleAbs + (aMatAbs[1] * myHSize[0] + aMatAbs[3] * myHSize[1]))) aResult = true; } } return aResult; } //================================================================================================= template bool Bnd_B2::IsOut(const gp_Ax2d& theLine) const { if (IsVoid()) return true; // Intersect the line containing the segment. const double aProd[3] = { theLine.Direction().XY() ^ (gp_XY(myCenter[0] - theLine.Location().X(), myCenter[1] - theLine.Location().Y())), theLine.Direction().X() * double(myHSize[1]), theLine.Direction().Y() * double(myHSize[0])}; return (std::abs(aProd[0]) > (std::abs(aProd[1]) + std::abs(aProd[2]))); } //================================================================================================= template bool Bnd_B2::IsOut(const gp_XY& theP0, const gp_XY& theP1) const { bool aResult(true); if (!IsVoid()) { // Intersect the line containing the segment. const gp_XY aSegDelta(theP1 - theP0); const double aProd[3] = {aSegDelta ^ (gp_XY(myCenter[0], myCenter[1]) - theP0), aSegDelta.X() * double(myHSize[1]), aSegDelta.Y() * double(myHSize[0])}; if (std::abs(aProd[0]) < (std::abs(aProd[1]) + std::abs(aProd[2]))) { // Intersection with line detected; check the segment as bounding box const gp_XY aHSeg(0.5 * aSegDelta.X(), 0.5 * aSegDelta.Y()); const gp_XY aHSegAbs(std::abs(aHSeg.X()), std::abs(aHSeg.Y())); aResult = compareDistD(gp_XY((double)myHSize[0], (double)myHSize[1]) + aHSegAbs, theP0 + aHSeg - gp_XY((double)myCenter[0], (double)myCenter[1])); } } return aResult; } //================================================================================================= template bool Bnd_B2::IsIn(const Bnd_B2& theBox, const gp_Trsf2d& theTrsf) const { bool aResult(false); const gp_TrsfForm aForm = theTrsf.Form(); const double aScale = theTrsf.ScaleFactor(); const double aScaleAbs = std::abs(aScale); if (aForm == gp_Translation || aForm == gp_Identity || aForm == gp_PntMirror || aForm == gp_Scale) { aResult = (std::abs(RealType(theBox.myCenter[0] * aScale + theTrsf.TranslationPart().X()) - myCenter[0]) < RealType(theBox.myHSize[0] * aScaleAbs) - myHSize[0] && std::abs(RealType(theBox.myCenter[1] * aScale + theTrsf.TranslationPart().Y()) - myCenter[1]) < RealType(theBox.myHSize[1] * aScaleAbs) - myHSize[1]); } else { // theBox is rotated, scaled and translated. We apply the reverse // translation and scaling then check against the rotated box 'this' const double* aMat = &theTrsf.HVectorialPart().Value(1, 1); gp_XY aCenter((double)theBox.myCenter[0], (double)theBox.myCenter[1]); theTrsf.Transforms(aCenter); const double aDist[2] = {aCenter.X() - (double)myCenter[0], aCenter.Y() - (double)myCenter[1]}; if ((std::abs(aMat[0] * aDist[0] + aMat[2] * aDist[1]) < theBox.myHSize[0] * aScaleAbs - (std::abs(aMat[0]) * myHSize[0] + std::abs(aMat[2]) * myHSize[1])) && (std::abs(aMat[1] * aDist[0] + aMat[3] * aDist[1]) < theBox.myHSize[1] * aScaleAbs - (std::abs(aMat[1]) * myHSize[0] + std::abs(aMat[3]) * myHSize[1]))) aResult = true; } return aResult; } //================================================================================================= //! 2D bounding box with double precision using Bnd_B2d = Bnd_B2; //! 2D bounding box with single precision using Bnd_B2f = Bnd_B2; #endif // _Bnd_B2_HeaderFile