// Compute the OBB for a set of points relative to a transform matrix and see if it is smaller than the current best value. If // so, return it. static void computeOBB(TheaArray<Vector3> const & points, CoordinateFrame3 const & cframe, OBB & current_best_result, bool overwrite) { if (points.empty()) return; Vector3 lo, hi; lo = hi = cframe.pointToObjectSpace(points[0]); Vector3 p; for (array_size_t i = 1; i < points.size(); ++i) { p = cframe.pointToObjectSpace(points[i]); lo = lo.min(p); hi = hi.max(p); } Vector3 e = hi - lo; double volume = e.x() * e.y() * e.z(); if (overwrite || volume < current_best_result.volume) { Vector3 c = 0.5f * (lo + hi); Vector3 he = 0.5f * e; current_best_result = OBB(c - he, c + he, cframe, volume); } }
// A rather hacky way of forming a joint descriptor, suitable only for exact matches like we want here void accumGroupFeatures(MeshGroup const & mg, TheaArray<double> & features) { for (MeshGroup::MeshConstIterator mi = mg.meshesBegin(); mi != mg.meshesEnd(); ++mi) { TheaArray<double> const & mf = (*mi)->getFeatures(); if (features.empty()) features.resize(mf.size()); alwaysAssertM(mf.size() == features.size(), "Feature vectors have different sizes"); for (array_size_t j = 0; j < features.size(); ++j) features[j] += mf[j]; } for (MeshGroup::GroupConstIterator ci = mg.childrenBegin(); ci != mg.childrenEnd(); ++ci) accumGroupFeatures(**ci, features); }
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); }