#pragma once #include "SurfaceMeshModel.h" // Special math library #include "OBB_Volume_math.h" // Eigen: for rotations #include #include using namespace Eigen; class OBB_Volume{ private: // computes the OBB for this set of points relative to this transform matrix. void computeOBB(size_t vcount,const REAL *points,size_t pstride,REAL *sides,REAL *matrix) { const char *src = (const char *) points; double max_dbl = DBL_MAX, min_dbl = -DBL_MAX; REAL bmin[3] = { max_dbl, max_dbl, max_dbl }; REAL bmax[3] = { min_dbl, min_dbl, min_dbl }; for (size_t i=0; i bmax[0] ) bmax[0] = t[0]; if ( t[1] > bmax[1] ) bmax[1] = t[1]; if ( t[2] > bmax[2] ) bmax[2] = t[2]; src+=pstride; } REAL center[3]; sides[0] = bmax[0]-bmin[0]; sides[1] = bmax[1]-bmin[1]; sides[2] = bmax[2]-bmin[2]; center[0] = sides[0]*0.5f+bmin[0]; center[1] = sides[1]*0.5f+bmin[1]; center[2] = sides[2]*0.5f+bmin[2]; REAL ocenter[3]; fm_rotate(matrix,center,ocenter); matrix[12]+=ocenter[0]; matrix[13]+=ocenter[1]; matrix[14]+=ocenter[2]; } void fm_computeBestFitOBB(size_t vcount,const REAL *points,size_t pstride,REAL *sides,REAL *matrix,bool bruteForce) { REAL plane[4]; fm_computeBestFitPlane(vcount,points,pstride,0,0,plane); fm_planeToMatrix(plane,matrix); computeOBB( vcount, points, pstride, sides, matrix ); REAL refmatrix[16]; memcpy(refmatrix,matrix,16*sizeof(REAL)); REAL volume = sides[0]*sides[1]*sides[2]; if ( bruteForce ) { for (REAL a=10; a<180; a+=10) { REAL quat[4]; fm_eulerToQuat(0,a*FM_DEG_TO_RAD,0,quat); REAL temp[16]; REAL pmatrix[16]; fm_quatToMatrix(quat,temp); fm_matrixMultiply(temp,refmatrix,pmatrix); REAL psides[3]; computeOBB( vcount, points, pstride, psides, pmatrix ); REAL v = psides[0]*psides[1]*psides[2]; if ( v < volume ) { volume = v; memcpy(matrix,pmatrix,sizeof(REAL)*16); sides[0] = psides[0]; sides[1] = psides[1]; sides[2] = psides[2]; } } } } void fm_computeBestFitOBB(size_t vcount,const REAL *points,size_t pstride,REAL *sides,REAL *pos,REAL *quat,bool bruteForce) { REAL matrix[16]; fm_computeBestFitOBB(vcount,points,pstride,sides,matrix,bruteForce); fm_getTranslation(matrix,pos); fm_matrixToQuat(matrix,quat); } public: Eigen::Matrix sides; Eigen::Matrix translation; Eigen::Matrix rotation; // as quat. bool isReady; OBB_Volume(Surface_mesh * mesh = NULL) { if(mesh == NULL) { isReady = false; return; } // Get points std::vector pnts; Surface_mesh::Vertex_property points = mesh->vertex_property("v:point"); Surface_mesh::Vertex_iterator vit, vend = mesh->vertices_end(); for (vit = mesh->vertices_begin(); vit != vend; ++vit) pnts.push_back(points[vit]); sides = translation = Vector3d(0,0,0); rotation = Vector4d(0,0,0,0); fm_computeBestFitOBB(pnts.size(), &pnts.front()[0], sizeof(Vector3d), &sides[0], &translation[0], &rotation[0], true); isReady = true; } std::vector corners() { Vector3d p(translation.x(), translation.y(), translation.z()); Vector4d r(rotation[0], rotation[1], rotation[2], rotation[3]); Transform t = Translation3d(p) * Quaterniond(r); double width = sides.x()/2; double length = sides.y()/2; double height = sides.z()/2; Vector3d c[8]; c[0] = Vector3d (width, length, height); c[1] = Vector3d (-width, length, height); c[2] = Vector3d (-width, -length, height); c[3] = Vector3d (width, -length, height); c[4] = Vector3d (width, length, -height); c[5] = Vector3d (-width, length, -height); c[6] = Vector3d (-width, -length, -height); c[7] = Vector3d (width, -length, -height); std::vector result; for(int i = 0; i < 8; i++) { Vector3d p(c[i][0], c[i][1], c[i][2]); Vector3d pt = t * p; result.push_back( Vector3d(pt[0], pt[1], pt[2]) ); } return result; } void draw() { if(!isReady) return; std::vector corner = corners(); Vector3d c1, c2, c3, c4; Vector3d bc1, bc2, bc3, bc4; c1 = corner[0]; c2 = corner[1]; c3 = corner[2]; c4 = corner[3]; bc1 = corner[4]; bc2 = corner[5]; bc3 = corner[6]; bc4 = corner[7]; glDisable(GL_LIGHTING); glColor3d(0, 0, 1); glLineWidth(1.0); glBegin(GL_LINES); glVertex3dv(c1.data());glVertex3dv(bc1.data()); glVertex3dv(c2.data());glVertex3dv(bc2.data()); glVertex3dv(c3.data());glVertex3dv(bc3.data()); glVertex3dv(c4.data());glVertex3dv(bc4.data()); glVertex3dv(c1.data());glVertex3dv(c2.data()); glVertex3dv(c3.data());glVertex3dv(c4.data()); glVertex3dv(c1.data());glVertex3dv(c4.data()); glVertex3dv(c2.data());glVertex3dv(c3.data()); glVertex3dv(bc1.data());glVertex3dv(bc2.data()); glVertex3dv(bc3.data());glVertex3dv(bc4.data()); glVertex3dv(bc1.data());glVertex3dv(bc4.data()); glVertex3dv(bc2.data());glVertex3dv(bc3.data()); glEnd(); glEnable(GL_LIGHTING); glPopMatrix(); } std::vector axis() { std::vector result; Vector3f p(0, 0, 0); Vector4f r(rotation[0], rotation[1], rotation[2], rotation[3]); Transform t = Translation3f(p) * Quaternionf(r); Vector3f xAxis(1,0,0); xAxis = t * xAxis; Vector3f yAxis(0,1,0); yAxis = t * yAxis; Vector3f zAxis(0,0,1); zAxis = t * zAxis; result.push_back(Vector3d(xAxis[0], xAxis[1], xAxis[2])); result.push_back(Vector3d(yAxis[0], yAxis[1], yAxis[2])); result.push_back(Vector3d(zAxis[0], zAxis[1], zAxis[2])); return result; } Point center() { return translation; } Vector3d extents() { return sides * 0.5; } };