static void computeBestFitOBB(TheaArray<Vector3> const & points, Box3 & result, bool has_up, Vector3 const & up) { if (points.empty()) { result = Box3(); return; } else if (points.size() == 1) { result = Box3(AxisAlignedBox3(points[0])); return; } Vector3 centroid; CoordinateFrame3 cframe; if (has_up) { centroid = CentroidN<Vector3, 3>::compute(points.begin(), points.end()); Vector3 u, v; up.createOrthonormalBasis(u, v); cframe = CoordinateFrame3::_fromAffine(AffineTransform3(basisMatrix(u, v, up), centroid)); } else { Plane3 plane; LinearLeastSquares3<Vector3>::fitPlane(points.begin(), points.end(), plane, ¢roid); planeToCFrame(plane, centroid, cframe); } OBB best_obb; computeOBB(points, cframe, best_obb, true); Matrix3 rot = Matrix3::rotationAxisAngle((has_up ? up : Vector3::unitY()), Math::degreesToRadians(10)); for (int a = 10; a < 180; a += 10) { cframe._setRotation(cframe.getRotation() * rot); computeOBB(points, cframe, best_obb, false); } result = Box3(AxisAlignedBox3(best_obb.lo, best_obb.hi), best_obb.cframe); }
void computeBestFitOBB(unsigned int vcount,const float *points,unsigned int pstride,float *sides,float *matrix) { float bmin[3]; float bmax[3]; fm_getAABB(vcount,points,pstride,bmin,bmax); float center[3]; center[0] = (bmax[0]-bmin[0])*0.5f + bmin[0]; center[1] = (bmax[1]-bmin[1])*0.5f + bmin[1]; center[2] = (bmax[2]-bmin[2])*0.5f + bmin[2]; float ax = 0; float ay = 0; float az = 0; float sweep = 45.0f; // 180 degree sweep on all three axes. float steps = 8.0f; // 16 steps on each axis. float bestVolume = 1e9; float angle[3]; while ( sweep >= 1 ) { bool found = false; float stepsize = sweep / steps; for (float x=ax-sweep; x<=ax+sweep; x+=stepsize) { for (float y=ay-sweep; y<=ay+sweep; y+=stepsize) { for (float z=az-sweep; z<=az+sweep; z+=stepsize) { float pmatrix[16]; fm_eulerMatrix( x*FM_DEG_TO_RAD, y*FM_DEG_TO_RAD, z*FM_DEG_TO_RAD, pmatrix ); pmatrix[3*4+0] = center[0]; pmatrix[3*4+1] = center[1]; pmatrix[3*4+2] = center[2]; float psides[3]; computeOBB( vcount, points, pstride, psides, pmatrix ); float volume = psides[0]*psides[1]*psides[2]; // the volume of the cube if ( volume <= bestVolume ) { bestVolume = volume; sides[0] = psides[0]; sides[1] = psides[1]; sides[2] = psides[2]; angle[0] = ax; angle[1] = ay; angle[2] = az; memcpy(matrix,pmatrix,sizeof(float)*16); found = true; // yes, we found an improvement. } } } } if ( found ) { ax = angle[0]; ay = angle[1]; az = angle[2]; sweep*=0.5f; // sweep 1/2 the distance as the last time. } else { break; // no improvement, so just } } }