/*************************************************************************** * 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 #include namespace Base { class ViewProjMethod; /** The 3D bounding box class. */ template class BoundBox3 { // helper function static bool isOnRayW(_Precision, _Precision, _Precision); static bool isOnRayS(_Precision, _Precision, _Precision); public: typedef _Precision num_type; typedef float_traits 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 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 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 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 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 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 inline BoundBox3<_Precision>::~BoundBox3 () { } template 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 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 bool BoundBox3<_Precision>::operator && (const BoundBox3<_Precision> &rcBB) const { return Intersect(rcBB); } template 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 inline bool BoundBox3<_Precision>::operator && (const BoundBox2d &rcBB) const { return Intersect(rcBB); } template 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 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 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 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 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 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 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 inline bool BoundBox3<_Precision>::IsValid (void) const { return ((MinX <= MaxX) && (MinY <= MaxY) && (MinZ <= MaxZ)); } template 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(usNdx); return true; } template 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 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 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 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 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 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 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 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 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 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 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 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 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 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 inline Vector3<_Precision> BoundBox3<_Precision>::GetCenter (void) const { return Vector3<_Precision>((MaxX + MinX) / 2, (MaxY + MinY) / 2, (MaxZ + MinZ) / 2); } template 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 inline void BoundBox3<_Precision>::SetVoid (void) { MinX = MinY = MinZ = std::numeric_limits<_Precision>::max(); MaxX = MaxY = MaxZ = -std::numeric_limits<_Precision>::max(); } template inline void BoundBox3<_Precision>::Enlarge (_Precision fLen) { MinX -= fLen; MinY -= fLen; MinZ -= fLen; MaxX += fLen; MaxY += fLen; MaxZ += fLen; } template inline void BoundBox3<_Precision>::Shrink (_Precision fLen) { MinX += fLen; MinY += fLen; MinZ += fLen; MaxX -= fLen; MaxY -= fLen; MaxZ -= fLen; } template inline _Precision BoundBox3<_Precision>::LengthX (void) const { return MaxX - MinX; } template inline _Precision BoundBox3<_Precision>::LengthY (void) const { return MaxY - MinY; } template inline _Precision BoundBox3<_Precision>::LengthZ (void) const { return MaxZ - MinZ; } template inline void BoundBox3<_Precision>::MoveX (_Precision f) { MinX += f; MaxX += f; } template inline void BoundBox3<_Precision>::MoveY (_Precision f) { MinY += f; MaxY += f; } template inline void BoundBox3<_Precision>::MoveZ (_Precision f) { MinZ += f; MaxZ += f; } template inline void BoundBox3<_Precision>::ScaleX (_Precision f) { MinX *= f; MaxX *= f; } template inline void BoundBox3<_Precision>::ScaleY (_Precision f) { MinY *= f; MaxY *= f; } template inline void BoundBox3<_Precision>::ScaleZ (_Precision f) { MinZ *= f; MaxZ *= f; } template 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 BoundBox3f; typedef BoundBox3 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