//////////////////////////////////////////////////////////////////// // OBB.inl // // Copyright 2007 cDc@seacave // Distributed under the Boost Software License, Version 1.0 // (See http://www.boost.org/LICENSE_1_0.txt) // D E F I N E S /////////////////////////////////////////////////// // S T R U C T S /////////////////////////////////////////////////// template inline TOBB::TOBB(bool) : m_rot(MATRIX::Identity()), m_pos(POINT::Zero()), m_ext(POINT::Zero()) { } template inline TOBB::TOBB(const AABB& aabb) { Set(aabb); } template inline TOBB::TOBB(const MATRIX& rot, const POINT& ptMin, const POINT& ptMax) { Set(rot, ptMin, ptMax); } template inline TOBB::TOBB(const POINT* pts, size_t n) { Set(pts, n); } template inline TOBB::TOBB(const POINT* pts, size_t n, const TRIANGLE* tris, size_t s) { Set(pts, n, tris, s); } // constructor template template inline TOBB::TOBB(const TOBB& rhs) : m_rot(rhs.m_rot.template cast()), m_pos(rhs.m_pos.template cast()), m_ext(rhs.m_ext.template cast()) { } // copy constructor /*----------------------------------------------------------------*/ template inline void TOBB::Set(const AABB& aabb) { m_rot.setIdentity(); m_pos = aabb.GetCenter(); m_ext = aabb.GetSize()/TYPE(2); } // build from rotation matrix from world to local, and local min/max corners template inline void TOBB::Set(const MATRIX& rot, const POINT& ptMin, const POINT& ptMax) { m_rot = rot; m_pos = (ptMax + ptMin) * TYPE(0.5); m_ext = (ptMax - ptMin) * TYPE(0.5); } // Inspired from "Fitting Oriented Bounding Boxes" by James Gregson // http://jamesgregson.blogspot.ro/2011/03/latex-test.html // build an OBB from a vector of input points. This // method just forms the covariance matrix and hands // it to the build_from_covariance_matrix method // which handles fitting the box to the points template inline void TOBB::Set(const POINT* pts, size_t n) { ASSERT(n >= DIMS); // loop over the points to find the mean point // location and to build the covariance matrix; // note that we only have // to build terms for the upper triangular // portion since the matrix is symmetric POINT mu(POINT::Zero()); TYPE cxx=0, cxy=0, cxz=0, cyy=0, cyz=0, czz=0; for (size_t i=0; i inline void TOBB::Set(const POINT* pts, size_t n, const TRIANGLE* tris, size_t s) { ASSERT(n >= DIMS); // loop over the triangles this time to find the // mean location POINT mu(POINT::Zero()); TYPE Am=0; TYPE cxx=0, cxy=0, cxz=0, cyy=0, cyz=0, czz=0; for (size_t i=0; i inline void TOBB::Set(const MATRIX& C, const POINT* pts, size_t n) { // extract rotation from the covariance matrix SetRotation(C); // extract size and center from the given points SetBounds(pts, n); } // method to set the OBB rotation which produce a box oriented according to // the covariance matrix C (only the rotations is set) template inline void TOBB::SetRotation(const MATRIX& C) { // extract the eigenvalues and eigenvectors from C const Eigen::SelfAdjointEigenSolver es(C); ASSERT(es.info() == Eigen::Success); // find the right, up and forward vectors from the eigenvectors // and set the rotation matrix using the eigenvectors ASSERT(es.eigenvalues()(0) < es.eigenvalues()(1) && es.eigenvalues()(1) < es.eigenvalues()(2)); m_rot = es.eigenvectors().transpose(); if (m_rot.determinant() < 0) m_rot = -m_rot; } // method to set the OBB center and size that contains the given points // the rotations should be already set template inline void TOBB::SetBounds(const POINT* pts, size_t n) { ASSERT(n >= DIMS); ASSERT(ISEQUAL((m_rot*m_rot.transpose()).trace(), TYPE(3)) && ISEQUAL(m_rot.determinant(), TYPE(1))); // build the bounding box extents in the rotated frame const TYPE tmax = std::numeric_limits::max(); POINT minim(tmax, tmax, tmax), maxim(-tmax, -tmax, -tmax); for (size_t i=0; i p_prime(0)) minim(0) = p_prime(0); if (minim(1) > p_prime(1)) minim(1) = p_prime(1); if (minim(2) > p_prime(2)) minim(2) = p_prime(2); if (maxim(0) < p_prime(0)) maxim(0) = p_prime(0); if (maxim(1) < p_prime(1)) maxim(1) = p_prime(1); if (maxim(2) < p_prime(2)) maxim(2) = p_prime(2); } // set the center of the OBB to be the average of the // minimum and maximum, and the extents be half of the // difference between the minimum and maximum const POINT center((maxim+minim)*TYPE(0.5)); m_pos = m_rot.transpose() * center; m_ext = (maxim-minim)*TYPE(0.5); } // Set /*----------------------------------------------------------------*/ template inline void TOBB::BuildBegin() { m_rot = MATRIX::Zero(); m_pos = POINT::Zero(); m_ext = POINT::Zero(); } template inline void TOBB::BuildAdd(const POINT& p) { // store mean in m_pos m_pos += p; // store covariance params in m_rot m_rot(0,0) += p(0)*p(0); m_rot(0,1) += p(0)*p(1); m_rot(0,2) += p(0)*p(2); m_rot(1,0) += p(1)*p(1); m_rot(1,1) += p(1)*p(2); m_rot(1,2) += p(2)*p(2); // store count in m_ext ++(*((size_t*)m_ext.data())); } template inline void TOBB::BuildEnd() { const TYPE invN(TYPE(1)/TYPE(*((size_t*)m_ext.data()))); const TYPE cxx = (m_rot(0,0) - m_pos(0)*m_pos(0)*invN)*invN; const TYPE cxy = (m_rot(0,1) - m_pos(0)*m_pos(1)*invN)*invN; const TYPE cxz = (m_rot(0,2) - m_pos(0)*m_pos(2)*invN)*invN; const TYPE cyy = (m_rot(1,0) - m_pos(1)*m_pos(1)*invN)*invN; const TYPE cyz = (m_rot(1,1) - m_pos(1)*m_pos(2)*invN)*invN; const TYPE czz = (m_rot(1,2) - m_pos(2)*m_pos(2)*invN)*invN; // now build the covariance matrix MATRIX C; C(0,0) = cxx; C(0,1) = cxy; C(0,2) = cxz; C(1,0) = cxy; C(1,1) = cyy; C(1,2) = cyz; C(2,0) = cxz; C(2,1) = cyz; C(2,2) = czz; SetRotation(C); } // Build /*----------------------------------------------------------------*/ // check if the oriented bounding box has positive size template inline bool TOBB::IsValid() const { return m_ext.minCoeff() > TYPE(0); } // IsValid /*----------------------------------------------------------------*/ template inline TOBB& TOBB::Enlarge(TYPE x) { m_ext.array() += x; return *this; } template inline TOBB& TOBB::EnlargePercent(TYPE x) { m_ext *= x; return *this; } // Enlarge /*----------------------------------------------------------------*/ // Update the box by the given pos delta. template inline void TOBB::Translate(const POINT& d) { m_pos += d; } // Update the box by the given transform. template inline void TOBB::Transform(const MATRIX& m) { m_rot = m * m_rot; m_pos = m * m_pos; } /*----------------------------------------------------------------*/ template inline typename TOBB::POINT TOBB::GetCenter() const { return m_pos; } template inline void TOBB::GetCenter(POINT& ptCenter) const { ptCenter = m_pos; } // GetCenter /*----------------------------------------------------------------*/ template inline typename TOBB::POINT TOBB::GetSize() const { return m_ext*2; } template inline void TOBB::GetSize(POINT& ptSize) const { ptSize = m_ext*2; } // GetSize /*----------------------------------------------------------------*/ template inline void TOBB::GetCorners(POINT pts[numCorners]) const { if (DIMS == 2) { const POINT pEAxis[2] = { m_rot.row(0)*m_ext[0], m_rot.row(1)*m_ext[1] }; const POINT pos(m_rot.transpose()*m_pos); pts[0] = pos - pEAxis[0] - pEAxis[1]; pts[1] = pos + pEAxis[0] - pEAxis[1]; pts[2] = pos + pEAxis[0] + pEAxis[1]; pts[3] = pos - pEAxis[0] + pEAxis[1]; } if (DIMS == 3) { const POINT pEAxis[3] = { m_rot.row(0)*m_ext[0], m_rot.row(1)*m_ext[1], m_rot.row(2)*m_ext[2] }; const POINT pos(m_rot.transpose()*m_pos); pts[0] = pos - pEAxis[0] - pEAxis[1] - pEAxis[2]; pts[1] = pos - pEAxis[0] - pEAxis[1] + pEAxis[2]; pts[2] = pos + pEAxis[0] - pEAxis[1] - pEAxis[2]; pts[3] = pos + pEAxis[0] - pEAxis[1] + pEAxis[2]; pts[4] = pos + pEAxis[0] + pEAxis[1] - pEAxis[2]; pts[5] = pos + pEAxis[0] + pEAxis[1] + pEAxis[2]; pts[6] = pos - pEAxis[0] + pEAxis[1] - pEAxis[2]; pts[7] = pos - pEAxis[0] + pEAxis[1] + pEAxis[2]; } } // GetCorners // constructs the corner of the aligned bounding box in world space template inline typename TOBB::AABB TOBB::GetAABB() const { POINT pts[numCorners]; GetCorners(pts); return AABB(pts, numCorners); } // GetAABB /*----------------------------------------------------------------*/ // computes the volume of the OBB, which is a measure of // how tight the fit is (better OBBs will have smaller volumes) template inline TYPE TOBB::GetVolume() const { return m_ext.prod()*numCorners; } /*----------------------------------------------------------------*/ template bool TOBB::Intersects(const POINT& pt) const { const POINT dist(m_rot * (pt - m_pos)); if (DIMS == 2) { return ABS(dist[0]) <= m_ext[0] && ABS(dist[1]) <= m_ext[1]; } if (DIMS == 3) { return ABS(dist[0]) <= m_ext[0] && ABS(dist[1]) <= m_ext[1] && ABS(dist[2]) <= m_ext[2]; } } // Intersects(POINT) /*----------------------------------------------------------------*/