1014 lines
35 KiB
C++
1014 lines
35 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2005 Imetric 3D GmbH *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef BASE_BOUNDBOX_H
|
|
#define BASE_BOUNDBOX_H
|
|
|
|
#include "Vector3D.h"
|
|
#include "Matrix.h"
|
|
#include "ViewProj.h"
|
|
#include "Tools2D.h"
|
|
#include <iostream>
|
|
#include <limits>
|
|
|
|
namespace Base {
|
|
|
|
class ViewProjMethod;
|
|
|
|
/** The 3D bounding box class. */
|
|
template <class _Precision>
|
|
class BoundBox3
|
|
{
|
|
// helper function
|
|
static bool isOnRayW(_Precision, _Precision, _Precision);
|
|
static bool isOnRayS(_Precision, _Precision, _Precision);
|
|
|
|
public:
|
|
typedef _Precision num_type;
|
|
typedef float_traits<num_type> traits_type;
|
|
|
|
/** Public attributes */
|
|
//@{
|
|
_Precision MinX;
|
|
_Precision MinY;
|
|
_Precision MinZ;
|
|
_Precision MaxX;
|
|
_Precision MaxY;
|
|
_Precision MaxZ;
|
|
//@}
|
|
|
|
/** Builds box from pairs of x,y,z values. */
|
|
inline explicit BoundBox3 (_Precision fMinX = std::numeric_limits<_Precision>::max(),
|
|
_Precision fMinY = std::numeric_limits<_Precision>::max(),
|
|
_Precision fMinZ = std::numeric_limits<_Precision>::max(),
|
|
_Precision fMaxX = -std::numeric_limits<_Precision>::max(),
|
|
_Precision fMaxY = -std::numeric_limits<_Precision>::max(),
|
|
_Precision fMaxZ = -std::numeric_limits<_Precision>::max());
|
|
BoundBox3 (const BoundBox3<_Precision> &rcBB) { *this = rcBB; }
|
|
/** Builds box from an array of points. */
|
|
inline BoundBox3 (const Vector3<_Precision> *pclVect, unsigned long ulCt);
|
|
|
|
/** Defines a bounding box around the center \a rcCnt with the
|
|
* distances \a fDistance in each coordinate.
|
|
*/
|
|
BoundBox3 (const Vector3<_Precision> &rcCnt, _Precision fDistance);
|
|
~BoundBox3 ();
|
|
|
|
/// Assignment operator
|
|
inline BoundBox3<_Precision>& operator = (const BoundBox3<_Precision> &rcBound);
|
|
|
|
/** Methods for intersection, cuttíng and union of bounding boxes */
|
|
//@{
|
|
/** Checks for intersection. */
|
|
inline bool Intersect (const BoundBox3<_Precision> &rcBB) const;
|
|
/** Checks for intersection. */
|
|
inline bool operator && (const BoundBox3<_Precision> &rcBB) const;
|
|
/** Checks for intersection. */
|
|
inline bool Intersect (const BoundBox2d &rcBB) const;
|
|
/** Checks for intersection. */
|
|
inline bool operator && (const BoundBox2d &rcBB) const;
|
|
/** Computes the intersection between two bounding boxes.
|
|
* The result is also a bounding box.
|
|
*/
|
|
BoundBox3<_Precision> Intersected (const BoundBox3<_Precision> &rcBB) const;
|
|
/** The union of two bounding boxes. */
|
|
BoundBox3<_Precision> United (const BoundBox3<_Precision> &rcBB) const;
|
|
/** Appends the point to the box. The box can grow but not shrink. */
|
|
inline void Add (const Vector3<_Precision> &rclVect);
|
|
/** Appends the bounding box to this box. The box can grow but not shrink. */
|
|
inline void Add (const BoundBox3<_Precision> &rcBB);
|
|
//@}
|
|
|
|
/** Test methods */
|
|
//@{
|
|
/** Checks if this point lies inside the box.
|
|
* @note It's up to the client programmer to make sure that this bounding box is valid.
|
|
*/
|
|
inline bool IsInBox (const Vector3<_Precision> &rcVct) const;
|
|
/** Checks if this 3D box lies inside the box.
|
|
* @note It's up to the client programmer to make sure that both bounding boxes are valid.
|
|
*/
|
|
inline bool IsInBox (const BoundBox3<_Precision> &rcBB) const;
|
|
/** Checks if this 2D box lies inside the box.
|
|
* @note It's up to the client programmer to make sure that both bounding boxes are valid.
|
|
*/
|
|
inline bool IsInBox (const BoundBox2d &rcbb) const;
|
|
/** Checks whether the bounding box is valid. */
|
|
bool IsValid (void) const;
|
|
//@}
|
|
|
|
enum OCTANT {OCT_LDB = 0, OCT_RDB, OCT_LUB, OCT_RUB,
|
|
OCT_LDF, OCT_RDF, OCT_LUF, OCT_RUF};
|
|
bool GetOctantFromVector (const Vector3<_Precision> &rclVct, OCTANT &rclOctant) const;
|
|
BoundBox3<_Precision> CalcOctant (typename BoundBox3<_Precision>::OCTANT Octant) const;
|
|
|
|
enum SIDE { LEFT =0, RIGHT=1, TOP=2, BOTTOM=3, FRONT=4, BACK=5, INVALID=255 };
|
|
|
|
/**
|
|
* Returns the corner point \a usPoint.
|
|
* 0: front,bottom,left 1: front,bottom,right
|
|
* 2: front,top,right 3: front,top,left
|
|
* 4: back,bottom,left 5: back,bottom,right
|
|
* 6: back,top,right 7: back,top,left
|
|
*/
|
|
inline Vector3<_Precision> CalcPoint (unsigned short usPoint) const;
|
|
/** Returns the plane of the given side. */
|
|
void CalcPlane (unsigned short usPlane, Vector3<_Precision>& rBase, Vector3<_Precision>& rNormal ) const;
|
|
/** Calculates the two points of an edge.
|
|
* 0. edge P0-P1 1. edge P1-P2 2. edge P2-P3
|
|
* 3. edge P3-P0 4. edge P4-P5 5. edge P5-P6
|
|
* 6. edge P6-P7 7. edge P7-P4 8. edge P0-P4
|
|
* 9. edge P1-P5 10. edge P2-P6 11. edge P3-P7
|
|
*/
|
|
bool CalcEdge (unsigned short usEdge, Vector3<_Precision>& rcP0, Vector3<_Precision>& rcP1) const;
|
|
/** Intersection point of an inner search ray with the bounding box, built of
|
|
* the base \a rcVct and the direction \a rcVctDir. \a rcVct must lie inside the
|
|
* bounding box.
|
|
*/
|
|
bool IntersectionPoint (const Vector3<_Precision> &rcVct, const Vector3<_Precision> &rcVctDir, Vector3<_Precision>& cVctRes, _Precision epsilon) const;
|
|
/** Checks for intersection with line incl. search tolerance. */
|
|
bool IsCutLine ( const Vector3<_Precision>& rcBase, const Vector3<_Precision>& rcDir, _Precision fTolerance = 0.0f) const;
|
|
/** Checks if this plane specified by (point,normal) cuts this box.
|
|
* @note It's up to the client programmer to make sure that this bounding box is valid.
|
|
*/
|
|
inline bool IsCutPlane (const Vector3<_Precision> &rclBase, const Vector3<_Precision> &rclNormal) const;
|
|
/** Computes the intersection points of line and bounding box. */
|
|
bool IntersectWithLine (const Vector3<_Precision>& rcBase, const Vector3<_Precision>& rcDir, Vector3<_Precision>& rcP0, Vector3<_Precision>& rcP1) const;
|
|
/** Computes the intersection point of line and a plane of the bounding box. */
|
|
bool IntersectPlaneWithLine (unsigned short usSide, const Vector3<_Precision>& rcBase, const Vector3<_Precision>& rcDir,
|
|
Vector3<_Precision>& rcP0) const;
|
|
/** Returns the side of the bounding box the ray exits. */
|
|
typename BoundBox3<_Precision>::SIDE GetSideFromRay (const Vector3<_Precision> &rclPt, const Vector3<_Precision> &rclDir) const;
|
|
/** Returns the side of the bounding box the ray exits. */
|
|
typename BoundBox3<_Precision>::SIDE GetSideFromRay (const Vector3<_Precision> &rclPt, const Vector3<_Precision> &rclDir, Vector3<_Precision>& rcInt) const;
|
|
|
|
/**
|
|
* Searches for the closest point of the bounding box.
|
|
*/
|
|
Vector3<_Precision> ClosestPoint (const Vector3<_Precision> &rclPt) const;
|
|
/** Projects the box onto a plane and returns a 2D box. */
|
|
BoundBox2d ProjectBox(const ViewProjMethod *rclP) const;
|
|
/** Transform the corners of this box with the given matrix and create a new bounding box.
|
|
* @note It's up to the client programmer to make sure that this bounding box is valid.
|
|
*/
|
|
BoundBox3<_Precision> Transformed(const Matrix4D& mat) const;
|
|
|
|
/** Returns the center.of the box. */
|
|
inline Vector3<_Precision> GetCenter (void) const;
|
|
/** Compute the diagonal length of this bounding box.
|
|
* @note It's up to the client programmer to make sure that this bounding box is valid.
|
|
*/
|
|
inline _Precision CalcDiagonalLength (void) const;
|
|
void SetVoid (void);
|
|
|
|
/** Enlarges the box with factor \a fLen. */
|
|
inline void Enlarge (_Precision fLen);
|
|
/** Shrinks the box with factor \a fLen. */
|
|
inline void Shrink (_Precision fLen);
|
|
|
|
/** Calculates expansion in x-direction. */
|
|
inline _Precision LengthX (void) const;
|
|
/** Calculates expansion in y-direction. */
|
|
inline _Precision LengthY (void) const;
|
|
/** Calculates expansion in z-direction. */
|
|
inline _Precision LengthZ (void) const;
|
|
/** Moves in x-direction. */
|
|
inline void MoveX (_Precision f);
|
|
/** Moves in y-direction. */
|
|
inline void MoveY (_Precision f);
|
|
/** Moves in z-direction. */
|
|
inline void MoveZ (_Precision f);
|
|
/** Scales in x-direction. */
|
|
inline void ScaleX (_Precision f);
|
|
/** Scales in y-direction. */
|
|
inline void ScaleY (_Precision f);
|
|
/** Scales in z-direction. */
|
|
inline void ScaleZ (_Precision f);
|
|
|
|
/** Prints the values to stream. */
|
|
void Print (std::ostream&) const;
|
|
};
|
|
|
|
|
|
template <class _Precision>
|
|
bool BoundBox3<_Precision>::isOnRayW(_Precision A, _Precision B, _Precision K)
|
|
{
|
|
// Checks if point K lies on the ray [A,B]
|
|
return ((A <= K) && (K <= B));
|
|
}
|
|
|
|
template <class _Precision>
|
|
bool BoundBox3<_Precision>::isOnRayS(_Precision A, _Precision B, _Precision K)
|
|
{
|
|
// Checks if point K lies on the ray [A,B[
|
|
return ((A <= K) && (K < B));
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox3<_Precision>::BoundBox3 (_Precision fMinX, _Precision fMinY, _Precision fMinZ,
|
|
_Precision fMaxX, _Precision fMaxY, _Precision fMaxZ)
|
|
: MinX(fMinX), MinY(fMinY), MinZ(fMinZ),
|
|
MaxX(fMaxX), MaxY(fMaxY), MaxZ(fMaxZ)
|
|
{
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox3<_Precision>::BoundBox3 (const Vector3<_Precision> *pclVect, unsigned long ulCt)
|
|
: MinX( std::numeric_limits<_Precision>::max())
|
|
, MinY( std::numeric_limits<_Precision>::max())
|
|
, MinZ( std::numeric_limits<_Precision>::max())
|
|
, MaxX(-std::numeric_limits<_Precision>::max())
|
|
, MaxY(-std::numeric_limits<_Precision>::max())
|
|
, MaxZ(-std::numeric_limits<_Precision>::max())
|
|
{
|
|
const Vector3<_Precision> *pI, *pEnd = pclVect + ulCt;
|
|
for (pI = pclVect; pI < pEnd; ++pI) {
|
|
MinX = std::min<_Precision>(MinX, pI->x);
|
|
MinY = std::min<_Precision>(MinY, pI->y);
|
|
MinZ = std::min<_Precision>(MinZ, pI->z);
|
|
MaxX = std::max<_Precision>(MaxX, pI->x);
|
|
MaxY = std::max<_Precision>(MaxY, pI->y);
|
|
MaxZ = std::max<_Precision>(MaxZ, pI->z);
|
|
}
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox3<_Precision>::BoundBox3 (const Vector3<_Precision> &rcVector, _Precision fDistance)
|
|
{
|
|
MinX = rcVector.x - fDistance;
|
|
MaxX = rcVector.x + fDistance;
|
|
MinY = rcVector.y - fDistance;
|
|
MaxY = rcVector.y + fDistance;
|
|
MinZ = rcVector.z - fDistance;
|
|
MaxZ = rcVector.z + fDistance;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox3<_Precision>::~BoundBox3 ()
|
|
{
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox3<_Precision>& BoundBox3<_Precision>::operator = (const BoundBox3<_Precision> &rcBound)
|
|
{
|
|
MinX = rcBound.MinX;
|
|
MinY = rcBound.MinY;
|
|
MinZ = rcBound.MinZ;
|
|
MaxX = rcBound.MaxX;
|
|
MaxY = rcBound.MaxY;
|
|
MaxZ = rcBound.MaxZ;
|
|
return *this;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::Intersect (const BoundBox3<_Precision> &rcBB) const
|
|
{
|
|
if (rcBB.MaxX < this->MinX || rcBB.MinX > this->MaxX)
|
|
return false;
|
|
if (rcBB.MaxY < this->MinY || rcBB.MinY > this->MaxY)
|
|
return false;
|
|
if (rcBB.MaxZ < this->MinZ || rcBB.MinZ > this->MaxZ)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
template <class _Precision>
|
|
bool BoundBox3<_Precision>::operator && (const BoundBox3<_Precision> &rcBB) const
|
|
{
|
|
return Intersect(rcBB);
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::Intersect (const BoundBox2d &rcBB) const
|
|
{
|
|
if (rcBB.MaxX < this->MinX || rcBB.MinX > this->MaxX)
|
|
return false;
|
|
if (rcBB.MaxY < this->MinY || rcBB.MinY > this->MaxY)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::operator && (const BoundBox2d &rcBB) const
|
|
{
|
|
return Intersect(rcBB);
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox3<_Precision> BoundBox3<_Precision>::Intersected(const BoundBox3<_Precision> &rcBB) const
|
|
{
|
|
BoundBox3<_Precision> cBBRes;
|
|
|
|
cBBRes.MinX = std::max<_Precision> (MinX, rcBB.MinX);
|
|
cBBRes.MaxX = std::min<_Precision> (MaxX, rcBB.MaxX);
|
|
cBBRes.MinY = std::max<_Precision> (MinY, rcBB.MinY);
|
|
cBBRes.MaxY = std::min<_Precision> (MaxY, rcBB.MaxY);
|
|
cBBRes.MinZ = std::max<_Precision> (MinZ, rcBB.MinZ);
|
|
cBBRes.MaxZ = std::min<_Precision> (MaxZ, rcBB.MaxZ);
|
|
|
|
return cBBRes;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox3<_Precision> BoundBox3<_Precision>::United(const BoundBox3<_Precision> &rcBB) const
|
|
{
|
|
BoundBox3<_Precision> cBBRes;
|
|
|
|
cBBRes.MinX = std::min<_Precision> (MinX, rcBB.MinX);
|
|
cBBRes.MaxX = std::max<_Precision> (MaxX, rcBB.MaxX);
|
|
cBBRes.MinY = std::min<_Precision> (MinY, rcBB.MinY);
|
|
cBBRes.MaxY = std::max<_Precision> (MaxY, rcBB.MaxY);
|
|
cBBRes.MinZ = std::min<_Precision> (MinZ, rcBB.MinZ);
|
|
cBBRes.MaxZ = std::max<_Precision> (MaxZ, rcBB.MaxZ);
|
|
|
|
return cBBRes;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::Add (const Vector3<_Precision> &rclVect)
|
|
{
|
|
this->MinX = std::min<_Precision>(this->MinX, rclVect.x);
|
|
this->MinY = std::min<_Precision>(this->MinY, rclVect.y);
|
|
this->MinZ = std::min<_Precision>(this->MinZ, rclVect.z);
|
|
this->MaxX = std::max<_Precision>(this->MaxX, rclVect.x);
|
|
this->MaxY = std::max<_Precision>(this->MaxY, rclVect.y);
|
|
this->MaxZ = std::max<_Precision>(this->MaxZ, rclVect.z);
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::Add (const BoundBox3<_Precision> &rcBB)
|
|
{
|
|
this->MinX = std::min<_Precision> (this->MinX, rcBB.MinX);
|
|
this->MaxX = std::max<_Precision> (this->MaxX, rcBB.MaxX);
|
|
this->MinY = std::min<_Precision> (this->MinY, rcBB.MinY);
|
|
this->MaxY = std::max<_Precision> (this->MaxY, rcBB.MaxY);
|
|
this->MinZ = std::min<_Precision> (this->MinZ, rcBB.MinZ);
|
|
this->MaxZ = std::max<_Precision> (this->MaxZ, rcBB.MaxZ);
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::IsInBox (const Vector3<_Precision> &rcVct) const
|
|
{
|
|
if (rcVct.x < this->MinX || rcVct.x > this->MaxX)
|
|
return false;
|
|
if (rcVct.y < this->MinY || rcVct.y > this->MaxY)
|
|
return false;
|
|
if (rcVct.z < this->MinZ || rcVct.z > this->MaxZ)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::IsInBox (const BoundBox3<_Precision> &rcBB) const
|
|
{
|
|
if (rcBB.MinX < this->MinX || rcBB.MaxX > this->MaxX)
|
|
return false;
|
|
if (rcBB.MinY < this->MinY || rcBB.MaxY > this->MaxY)
|
|
return false;
|
|
if (rcBB.MinZ < this->MinZ || rcBB.MaxZ > this->MaxZ)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::IsInBox (const BoundBox2d &rcBB) const
|
|
{
|
|
if (rcBB.MinX < this->MinX || rcBB.MaxX > this->MaxX)
|
|
return false;
|
|
if (rcBB.MinY < this->MinY || rcBB.MaxY > this->MaxY)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::IsValid (void) const
|
|
{
|
|
return ((MinX <= MaxX) && (MinY <= MaxY) && (MinZ <= MaxZ));
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::GetOctantFromVector (const Vector3<_Precision> &rclVct, OCTANT &rclOctant) const
|
|
{
|
|
if (!IsInBox (rclVct))
|
|
return false;
|
|
|
|
unsigned short usNdx = 0;
|
|
if (isOnRayS ((MinX + MaxX)/2, MaxX, rclVct.x)) // left/RIGHT
|
|
usNdx |= 1;
|
|
if (isOnRayS ((MinY + MaxY)/2, MaxY, rclVct.y)) // down/UP
|
|
usNdx |= 2;
|
|
if (isOnRayS ((MinZ + MaxZ)/2, MaxZ, rclVct.z)) // back/FRONT
|
|
usNdx |= 4;
|
|
rclOctant = static_cast<OCTANT>(usNdx);
|
|
return true;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox3<_Precision> BoundBox3<_Precision>::CalcOctant (typename BoundBox3< _Precision >::OCTANT Octant) const
|
|
{
|
|
BoundBox3<_Precision> cOct (*this);
|
|
|
|
switch (Octant) {
|
|
case OCT_LDB:
|
|
cOct.MaxX = (cOct.MinX + cOct.MaxX)/2;
|
|
cOct.MaxY = (cOct.MinY + cOct.MaxY)/2;
|
|
cOct.MaxZ = (cOct.MinZ + cOct.MaxZ)/2;
|
|
break;
|
|
|
|
case OCT_RDB:
|
|
cOct.MinX = (cOct.MinX + cOct.MaxX)/2;
|
|
cOct.MaxY = (cOct.MinY + cOct.MaxY)/2;
|
|
cOct.MaxZ = (cOct.MinZ + cOct.MaxZ)/2;
|
|
break;
|
|
|
|
case OCT_LUB:
|
|
cOct.MaxX = (cOct.MinX + cOct.MaxX)/2;
|
|
cOct.MinY = (cOct.MinY + cOct.MaxY)/2;
|
|
cOct.MaxZ = (cOct.MinZ + cOct.MaxZ)/2;
|
|
break;
|
|
|
|
case OCT_RUB:
|
|
cOct.MinX = (cOct.MinX + cOct.MaxX)/2;
|
|
cOct.MinY = (cOct.MinY + cOct.MaxY)/2;
|
|
cOct.MaxZ = (cOct.MinZ + cOct.MaxZ)/2;
|
|
break;
|
|
|
|
case OCT_LDF:
|
|
cOct.MaxX = (cOct.MinX + cOct.MaxX)/2;
|
|
cOct.MaxY = (cOct.MinY + cOct.MaxY)/2;
|
|
cOct.MinZ = (cOct.MinZ + cOct.MaxZ)/2;
|
|
break;
|
|
|
|
case OCT_RDF:
|
|
cOct.MinX = (cOct.MinX + cOct.MaxX)/2;
|
|
cOct.MaxY = (cOct.MinY + cOct.MaxY)/2;
|
|
cOct.MinZ = (cOct.MinZ + cOct.MaxZ)/2;
|
|
break;
|
|
|
|
case OCT_LUF:
|
|
cOct.MaxX = (cOct.MinX + cOct.MaxX)/2;
|
|
cOct.MinY = (cOct.MinY + cOct.MaxY)/2;
|
|
cOct.MinZ = (cOct.MinZ + cOct.MaxZ)/2;
|
|
break;
|
|
|
|
case OCT_RUF:
|
|
cOct.MinX = (cOct.MinX + cOct.MaxX)/2;
|
|
cOct.MinY = (cOct.MinY + cOct.MaxY)/2;
|
|
cOct.MinZ = (cOct.MinZ + cOct.MaxZ)/2;
|
|
break;
|
|
}
|
|
return cOct;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline Vector3<_Precision> BoundBox3<_Precision>::CalcPoint (unsigned short usPoint) const
|
|
{
|
|
switch (usPoint) {
|
|
case 0: return Vector3<_Precision>(MinX, MinY, MaxZ);
|
|
case 1: return Vector3<_Precision>(MaxX, MinY, MaxZ);
|
|
case 2: return Vector3<_Precision>(MaxX, MaxY, MaxZ);
|
|
case 3: return Vector3<_Precision>(MinX, MaxY, MaxZ);
|
|
case 4: return Vector3<_Precision>(MinX, MinY, MinZ);
|
|
case 5: return Vector3<_Precision>(MaxX, MinY, MinZ);
|
|
case 6: return Vector3<_Precision>(MaxX, MaxY, MinZ);
|
|
case 7: return Vector3<_Precision>(MinX, MaxY, MinZ);
|
|
}
|
|
|
|
return Vector3<_Precision>();
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::CalcPlane (unsigned short usPlane, Vector3<_Precision>& rBase, Vector3<_Precision>& rNormal) const
|
|
{
|
|
switch (usPlane) {
|
|
case LEFT:
|
|
rBase.Set(MinX, MinY, MaxZ);
|
|
rNormal.Set(1.0f, 0.0f, 0.0f);
|
|
break;
|
|
|
|
case RIGHT:
|
|
rBase.Set(MaxX, MinY, MaxZ);
|
|
rNormal.Set(1.0f, 0.0f, 0.0f);
|
|
break;
|
|
|
|
case TOP:
|
|
rBase.Set(MinX, MaxY, MaxZ);
|
|
rNormal.Set(0.0f, 1.0f, 0.0f);
|
|
break;
|
|
|
|
case BOTTOM:
|
|
rBase.Set(MinX, MinY, MaxZ);
|
|
rNormal.Set(0.0f, 1.0f, 0.0f);
|
|
break;
|
|
|
|
case FRONT:
|
|
rBase.Set(MinX, MinY, MaxZ);
|
|
rNormal.Set(0.0f, 0.0f, 1.0f);
|
|
break;
|
|
|
|
case BACK:
|
|
rBase.Set(MinX, MinY, MinZ);
|
|
rNormal.Set(0.0f, 0.0f, 1.0f);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::CalcEdge (unsigned short usEdge, Vector3<_Precision>& rcP0, Vector3<_Precision>& rcP1) const
|
|
{
|
|
switch (usEdge) {
|
|
case 0:
|
|
rcP0 = CalcPoint(0);
|
|
rcP1 = CalcPoint(1);
|
|
break;
|
|
case 1:
|
|
rcP0 = CalcPoint(1);
|
|
rcP1 = CalcPoint(2);
|
|
break;
|
|
case 2:
|
|
rcP0 = CalcPoint(2);
|
|
rcP1 = CalcPoint(3);
|
|
break;
|
|
case 3:
|
|
rcP0 = CalcPoint(3);
|
|
rcP1 = CalcPoint(0);
|
|
break;
|
|
case 4:
|
|
rcP0 = CalcPoint(4);
|
|
rcP1 = CalcPoint(5);
|
|
break;
|
|
case 5:
|
|
rcP0 = CalcPoint(5);
|
|
rcP1 = CalcPoint(6);
|
|
break;
|
|
case 6:
|
|
rcP0 = CalcPoint(6);
|
|
rcP1 = CalcPoint(7);
|
|
break;
|
|
case 7:
|
|
rcP0 = CalcPoint(7);
|
|
rcP1 = CalcPoint(4);
|
|
break;
|
|
case 8:
|
|
rcP0 = CalcPoint(0);
|
|
rcP1 = CalcPoint(4);
|
|
break;
|
|
case 9:
|
|
rcP0 = CalcPoint(1);
|
|
rcP1 = CalcPoint(5);
|
|
break;
|
|
case 10:
|
|
rcP0 = CalcPoint(2);
|
|
rcP1 = CalcPoint(6);
|
|
break;
|
|
case 11:
|
|
rcP0 = CalcPoint(3);
|
|
rcP1 = CalcPoint(7);
|
|
break;
|
|
default:
|
|
return false; // undefined
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::IntersectionPoint (const Vector3<_Precision> &rcVct, const Vector3<_Precision> &rcVctDir, Vector3<_Precision>& cVctRes, _Precision epsilon) const
|
|
{
|
|
bool rc=false;
|
|
BoundBox3<_Precision> cCmpBound(*this);
|
|
unsigned short i;
|
|
|
|
// enlarge bounding box by epsilon
|
|
cCmpBound.Enlarge(epsilon);
|
|
|
|
// Is point inside?
|
|
if (cCmpBound.IsInBox (rcVct)) {
|
|
// test sides
|
|
for (i = 0; (i < 6) && (!rc); i++) {
|
|
rc = IntersectPlaneWithLine(i, rcVct, rcVctDir, cVctRes);
|
|
if (!cCmpBound.IsInBox(cVctRes))
|
|
rc = false;
|
|
if (rc == true) {
|
|
// does intersection point lie in desired direction
|
|
// or was found the opposing side?
|
|
// -> scalar product of both direction vectors > 0 (angle < 90)
|
|
rc = ((cVctRes - rcVct) * rcVctDir) >= 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::IsCutLine (const Vector3<_Precision>& rcBase, const Vector3<_Precision>& rcDir, _Precision fTolerance) const
|
|
{
|
|
_Precision fDist;
|
|
|
|
// zuerst nur grobe und schnelle Pruefung, indem der
|
|
// Abstand der Linie zum Mittelpunkt der BB berechnet wird
|
|
// und mit der maximalen Diagonalenlaenge + fTolerance
|
|
// verglichen wird.
|
|
|
|
// Distanz zwischen Mittelpunkt und Linie
|
|
fDist = (rcDir % (GetCenter() - rcBase)).Length() / rcDir.Length();
|
|
|
|
if (fDist > (CalcDiagonalLength() + fTolerance)) {
|
|
return false;
|
|
}
|
|
else { // hier genauerer Test
|
|
unsigned char i;
|
|
Vector3<_Precision> clVectRes;
|
|
|
|
// schneide jede Seitenflaeche mit der Linie
|
|
for (i = 0; i < 6; i++) {
|
|
if (IntersectPlaneWithLine(i, rcBase, rcDir, clVectRes)) {
|
|
// pruefe, ob Schnittpunkt innerhalb BB-Grenzen + Toleranz
|
|
switch (i) {
|
|
case LEFT : // linke und rechte Ebene
|
|
case RIGHT :
|
|
if ((isOnRayW (MinY - fTolerance, MaxY + fTolerance, clVectRes.y) &&
|
|
isOnRayW (MinZ - fTolerance, MaxZ + fTolerance, clVectRes.z)))
|
|
return true;
|
|
break;
|
|
case TOP : // obere und untere Ebene
|
|
case BOTTOM :
|
|
if ((isOnRayW (MinX - fTolerance, MaxX + fTolerance, clVectRes.x) &&
|
|
isOnRayW (MinZ - fTolerance, MaxZ + fTolerance, clVectRes.z)))
|
|
return true;
|
|
break;
|
|
case FRONT : // vordere und hintere Ebene
|
|
case BACK :
|
|
if ((isOnRayW (MinX - fTolerance, MaxX + fTolerance, clVectRes.x) &&
|
|
isOnRayW (MinY - fTolerance, MaxY + fTolerance, clVectRes.y)))
|
|
return true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::IsCutPlane (const Vector3<_Precision> &rclBase, const Vector3<_Precision> &rclNormal) const
|
|
{
|
|
if (fabs(GetCenter().DistanceToPlane(rclBase, rclNormal)) < CalcDiagonalLength()) {
|
|
_Precision fD = CalcPoint(0).DistanceToPlane(rclBase, rclNormal);
|
|
for (unsigned short i = 1; i < 8; i++) {
|
|
if ((CalcPoint(i).DistanceToPlane(rclBase, rclNormal) * fD) <= 0.0f)
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::IntersectWithLine (const Vector3<_Precision> & rcBase, const Vector3<_Precision>& rcDir,
|
|
Vector3<_Precision>& rcP0, Vector3<_Precision>& rcP1) const
|
|
{
|
|
Vector3<_Precision> clVectRes, clVect[6];
|
|
|
|
unsigned short numIntersect = 0;
|
|
// cut each face with the line
|
|
for (unsigned short i = 0; i < 6; i++) {
|
|
if (IntersectPlaneWithLine(i, rcBase, rcDir, clVectRes)) {
|
|
// check if intersection point is inside
|
|
switch (i) {
|
|
case LEFT : // left and right plane
|
|
case RIGHT :
|
|
if ((isOnRayS(MinY, MaxY, clVectRes.y) &&
|
|
isOnRayS(MinZ, MaxZ, clVectRes.z))) {
|
|
clVect[numIntersect] = clVectRes;
|
|
numIntersect++;
|
|
} break;
|
|
case TOP : // top and bottom plane
|
|
case BOTTOM :
|
|
if ((isOnRayS(MinX, MaxX, clVectRes.x) &&
|
|
isOnRayS(MinZ, MaxZ, clVectRes.z))) {
|
|
clVect[numIntersect] = clVectRes;
|
|
numIntersect++;
|
|
} break;
|
|
case FRONT : // front and back plane
|
|
case BACK :
|
|
if ((isOnRayS(MinX, MaxX, clVectRes.x) &&
|
|
isOnRayS(MinY, MaxY, clVectRes.y))) {
|
|
clVect[numIntersect] = clVectRes;
|
|
numIntersect++;
|
|
} break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (numIntersect == 2) {
|
|
rcP0 = clVect[0];
|
|
rcP1 = clVect[1];
|
|
return true;
|
|
}
|
|
else if (numIntersect > 2) { // search two different intersection points
|
|
for (unsigned short i = 1; i < numIntersect; i++) {
|
|
if (clVect[i] != clVect[0]) {
|
|
rcP0 = clVect[0];
|
|
rcP1 = clVect[i];
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline bool BoundBox3<_Precision>::IntersectPlaneWithLine (unsigned short usSide, const Vector3<_Precision>& rcBase,
|
|
const Vector3<_Precision>& rcDir, Vector3<_Precision>& rcP0) const
|
|
{
|
|
_Precision k;
|
|
Vector3<_Precision> cBase, cNormal;
|
|
Vector3<_Precision> cDir(rcDir);
|
|
CalcPlane(usSide, cBase, cNormal);
|
|
|
|
if ((cNormal * cDir) == 0.0f) {
|
|
return false; // no point of intersection
|
|
}
|
|
else {
|
|
k = (cNormal * (cBase - rcBase)) / (cNormal * cDir);
|
|
cDir.Scale(k, k, k);
|
|
rcP0 = rcBase + cDir;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline typename BoundBox3<_Precision>::SIDE BoundBox3<_Precision>::GetSideFromRay (const Vector3<_Precision> &rclPt, const Vector3<_Precision> &rclDir) const
|
|
{
|
|
Vector3<_Precision> cIntersection;
|
|
return GetSideFromRay( rclPt, rclDir, cIntersection);
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline typename BoundBox3<_Precision>::SIDE BoundBox3<_Precision>::GetSideFromRay (const Vector3<_Precision> &rclPt, const Vector3<_Precision> &rclDir,
|
|
Vector3<_Precision>& rcInt) const
|
|
{
|
|
Vector3<_Precision> cP0, cP1;
|
|
if (IntersectWithLine(rclPt, rclDir, cP0, cP1) == false)
|
|
return INVALID;
|
|
|
|
Vector3<_Precision> cOut;
|
|
// same orientation
|
|
if ((cP1-cP0)*rclDir > 0)
|
|
cOut = cP1;
|
|
else
|
|
cOut = cP0;
|
|
|
|
rcInt = cOut;
|
|
|
|
_Precision fMax = 1.0e-3f;
|
|
SIDE tSide = INVALID;
|
|
|
|
if (fabs(cOut.x - MinX) < fMax) { // left plane
|
|
fMax = _Precision(fabs(cOut.x - MinX));
|
|
tSide = LEFT;
|
|
}
|
|
|
|
if (fabs(cOut.x - MaxX) < fMax) { // right plane
|
|
fMax = _Precision(fabs(cOut.x - MaxX));
|
|
tSide = RIGHT;
|
|
}
|
|
|
|
if (fabs(cOut.y - MinY) < fMax) { // bottom plane
|
|
fMax = _Precision(fabs(cOut.y - MinY));
|
|
tSide = BOTTOM;
|
|
}
|
|
|
|
if (fabs(cOut.y - MaxY) < fMax) { // top plane
|
|
fMax = _Precision(fabs(cOut.y - MaxY));
|
|
tSide = TOP;
|
|
}
|
|
|
|
if (fabs(cOut.z - MinZ) < fMax) { // front plane
|
|
fMax = _Precision(fabs(cOut.z - MinZ));
|
|
tSide = FRONT;
|
|
}
|
|
|
|
if (fabs(cOut.z - MaxZ) < fMax) { // back plane
|
|
fMax = _Precision(fabs(cOut.z - MaxZ));
|
|
tSide = BACK;
|
|
}
|
|
|
|
return tSide;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline Vector3<_Precision> BoundBox3<_Precision>::ClosestPoint (const Vector3<_Precision> &rclPt) const
|
|
{
|
|
#if 0
|
|
// Get the nearest point of the bb, point MUST be inside the bb!
|
|
_Precision fMinDist = std::numeric_limits<_Precision>::max();
|
|
Vector3<_Precision> cBase, cNormal, clRet;
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
Vector3<_Precision> clTemp = rclPt;
|
|
CalcPlane(i, cBase, cNormal);
|
|
clTemp.ProjectToPlane(cBase, cNormal);
|
|
_Precision fDist = (clTemp - rclPt).Length();
|
|
if (fDist < fMinDist) {
|
|
fMinDist = fDist;
|
|
clRet = clTemp;
|
|
}
|
|
}
|
|
|
|
return clRet;
|
|
#else
|
|
Vector3<_Precision> closest = rclPt;
|
|
|
|
Vector3<_Precision> center = GetCenter();
|
|
_Precision devx = closest.x - center.x;
|
|
_Precision devy = closest.y - center.y;
|
|
_Precision devz = closest.z - center.z;
|
|
|
|
_Precision halfwidth = (MaxX - MinX) / 2;
|
|
_Precision halfheight = (MaxY - MinY) / 2;
|
|
_Precision halfdepth = (MaxZ - MinZ) / 2;
|
|
|
|
// Move point to be on the nearest plane of the box.
|
|
if ((fabs(devx) > fabs(devy)) && (fabs(devx) > fabs(devz)))
|
|
closest.x = center.x + halfwidth * ((devx < 0.0) ? -1.0 : 1.0);
|
|
else if (fabs(devy) > fabs(devz))
|
|
closest.y = center.y + halfheight * ((devy < 0.0) ? -1.0 : 1.0);
|
|
else
|
|
closest.z = center.z + halfdepth * ((devz < 0.0) ? -1.0 : 1.0);
|
|
|
|
// Clamp to be inside box.
|
|
closest.x = std::min<_Precision>(std::max<_Precision>(closest.x, MinX), MaxX);
|
|
closest.y = std::min<_Precision>(std::max<_Precision>(closest.y, MinY), MaxY);
|
|
closest.z = std::min<_Precision>(std::max<_Precision>(closest.z, MinZ), MaxZ);
|
|
|
|
return closest;
|
|
#endif
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox2d BoundBox3<_Precision>::ProjectBox(const ViewProjMethod *pclP) const
|
|
{
|
|
BoundBox2d clBB2D;
|
|
clBB2D.SetVoid();
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
Vector3<_Precision> clTrsPt = (*pclP)(CalcPoint(i));
|
|
clBB2D.Add(Vector2d(clTrsPt.x, clTrsPt.y));
|
|
}
|
|
|
|
return clBB2D;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline BoundBox3<_Precision> BoundBox3<_Precision>::Transformed(const Matrix4D& mat) const
|
|
{
|
|
BoundBox3<_Precision> bbox;
|
|
for (int i=0; i<8; i++)
|
|
bbox.Add(mat * CalcPoint(i));
|
|
return bbox;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline Vector3<_Precision> BoundBox3<_Precision>::GetCenter (void) const
|
|
{
|
|
return Vector3<_Precision>((MaxX + MinX) / 2,
|
|
(MaxY + MinY) / 2,
|
|
(MaxZ + MinZ) / 2);
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline _Precision BoundBox3<_Precision>::CalcDiagonalLength (void) const
|
|
{
|
|
return static_cast<_Precision>(sqrt (((MaxX - MinX) * (MaxX - MinX)) +
|
|
((MaxY - MinY) * (MaxY - MinY)) +
|
|
((MaxZ - MinZ) * (MaxZ - MinZ))));
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::SetVoid (void)
|
|
{
|
|
MinX = MinY = MinZ = std::numeric_limits<_Precision>::max();
|
|
MaxX = MaxY = MaxZ = -std::numeric_limits<_Precision>::max();
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::Enlarge (_Precision fLen)
|
|
{
|
|
MinX -= fLen; MinY -= fLen; MinZ -= fLen;
|
|
MaxX += fLen; MaxY += fLen; MaxZ += fLen;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::Shrink (_Precision fLen)
|
|
{
|
|
MinX += fLen; MinY += fLen; MinZ += fLen;
|
|
MaxX -= fLen; MaxY -= fLen; MaxZ -= fLen;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline _Precision BoundBox3<_Precision>::LengthX (void) const
|
|
{
|
|
return MaxX - MinX;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline _Precision BoundBox3<_Precision>::LengthY (void) const
|
|
{
|
|
return MaxY - MinY;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline _Precision BoundBox3<_Precision>::LengthZ (void) const
|
|
{
|
|
return MaxZ - MinZ;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::MoveX (_Precision f)
|
|
{
|
|
MinX += f; MaxX += f;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::MoveY (_Precision f)
|
|
{
|
|
MinY += f; MaxY += f;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::MoveZ (_Precision f)
|
|
{
|
|
MinZ += f; MaxZ += f;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::ScaleX (_Precision f)
|
|
{
|
|
MinX *= f; MaxX *= f;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::ScaleY (_Precision f)
|
|
{
|
|
MinY *= f; MaxY *= f;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::ScaleZ (_Precision f)
|
|
{
|
|
MinZ *= f; MaxZ *= f;
|
|
}
|
|
|
|
template <class _Precision>
|
|
inline void BoundBox3<_Precision>::Print (std::ostream& out) const
|
|
{
|
|
out << "X1 : " << MinX << " Y1 : " << MinY << " Z1 : " << MinZ << std::endl;
|
|
out << "X2 : " << MaxX << " Y2 : " << MaxY << " Z2 : " << MaxZ << std::endl;
|
|
}
|
|
|
|
typedef BoundBox3<float> BoundBox3f;
|
|
typedef BoundBox3<double> BoundBox3d;
|
|
|
|
} // namespace Base
|
|
|
|
inline std::ostream& operator << (std::ostream& out, const Base::BoundBox3f& bb)
|
|
{
|
|
bb.Print(out);
|
|
return out;
|
|
}
|
|
|
|
inline std::ostream& operator << (std::ostream& out, const Base::BoundBox3d& bb)
|
|
{
|
|
bb.Print(out);
|
|
return out;
|
|
}
|
|
|
|
#endif // BASE_BOUNDBOX_H
|
|
|