std::vector<double> repo::core::RepoBoundingBox::getTransformationMatrix() const { std::vector<double> transformation(16); RepoVertex centroid = RepoVertex(max+min); transformation[0] = 1; transformation[1] = 0; transformation[2] = 0; transformation[3] = 0; transformation[4] = 0; transformation[5] = 1; transformation[6] = 0; transformation[7] = 0; transformation[8] = 0; transformation[9] = 0; transformation[10] = 1; transformation[11] = 0; transformation[12] = centroid.x/2; transformation[13] = centroid.y/2; transformation[14] = centroid.z/2; transformation[15] = 1; return transformation; }
//------------------------------------------------------------------------------ double repo::core::RepoNodeMesh::getFacesBoundaryLength( const unsigned int & faceIndexA, const unsigned int & faceIndexB) const { double boundaryLength = 0; const aiFace & faceA = faces->at(faceIndexA); const aiFace & faceB = faces->at(faceIndexB); std::vector<repo::core::RepoVertex> commonVertices; for (unsigned int i = 0; i < faceA.mNumIndices; ++i) { RepoVertex a(vertices->at(faceA.mIndices[i])); for (unsigned int j = 0; j < faceB.mNumIndices; ++j) { if (a == RepoVertex(vertices->at(faceB.mIndices[j]))) commonVertices.push_back(a); } } if (commonVertices.size() > 1) { for (unsigned int i = 0; i < commonVertices.size() - 1; ++i) { boundaryLength += RepoVertex::distancePointToPoint<double>( commonVertices[i], commonVertices[i+1]); } } return boundaryLength; }
repo::core::RepoBoundingBox::RepoBoundingBox(const aiMesh * mesh) { if (mesh->mNumVertices) { min = RepoVertex(mesh->mVertices[0]); max = RepoVertex(mesh->mVertices[0]); } for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { RepoVertex tmp = RepoVertex(mesh->mVertices[i]); min.x = std::min(min.x,tmp.x); min.y = std::min(min.y,tmp.y); min.z = std::min(min.z,tmp.z); max.x = std::max(max.x,tmp.x); max.y = std::max(max.y,tmp.y); max.z = std::max(max.z,tmp.z); } }
* License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "repo_vertex.h" #include "../conversion/repo_transcoder_string.h" //------------------------------------------------------------------------------ const repo::core::RepoVertex repo::core::RepoVertex::X_AXIS = RepoVertex(1,0,0); const repo::core::RepoVertex repo::core::RepoVertex::Y_AXIS = RepoVertex(0,1,0); const repo::core::RepoVertex repo::core::RepoVertex::Z_AXIS = RepoVertex(0,0,1); const unsigned int repo::core::RepoVertex::DIMENSIONALITY = 3; //------------------------------------------------------------------------------ std::string repo::core::RepoVertex::toString() const { return "[" + repo::core::RepoTranscoderString::toString(x) + ", " + repo::core::RepoTranscoderString::toString(y) + ", " + repo::core::RepoTranscoderString::toString(z) + "]"; } //------------------------------------------------------------------------------ void repo::core::RepoVertex::updateMinMax(RepoVertex& min, RepoVertex& max) const { for (unsigned int i = 0; i < DIMENSIONALITY; ++i)
void repo::core::RepoPCA::initialize( const std::vector<RepoVertex>& xyzVertices) { //std::set<RepoVertex> vertices; //for each (const RepoVertex& v in vert) // vertices.insert(v); //-------------------------------------------------------------------------- // Calculate the xyzMean vertex and the midpoint of the dataset // See http://en.wikipedia.org/wiki/Sample_mean_and_sample_covariance#Weighted_samples // Weighted mean = (sum w_i x_i) / sum w_i double sumOfWeights = 0; for (unsigned int i = 0; i < xyzVertices.size(); ++i) { RepoVertex v = xyzVertices[i]; xyzMean += RepoVertex(v * (float) v.weight); sumOfWeights += v.weight; } xyzMean /= (float) sumOfWeights; //(float) vertices.size(); //-------------------------------------------------------------------------- // Eigenvalue decomposition of the covariance matrix double eigenVectors[3][3]; double eigenValues[3]; // Calculated eigenValues (and vectors) are in ascending order. // Eigenvectors are in the respective columns. aiMatrix3x3 covarianceMatrix = RepoEigen::covarianceMatrix(xyzVertices, xyzMean); RepoEigen::eigenvalueDecomposition(covarianceMatrix, eigenVectors, eigenValues); //-------------------------------------------------------------------------- // Store eigenVectors and eigenValues. principalComponents.resize(RepoVertex::DIMENSIONALITY); for (unsigned int i = 0; i < principalComponents.size(); ++i) { unsigned int index = RepoVertex::DIMENSIONALITY - i - 1; for (unsigned int xyz = 0; xyz < RepoVertex::DIMENSIONALITY; ++ xyz) principalComponents[i].vector[xyz] = (float) eigenVectors[xyz][index]; principalComponents[i].vector.Normalize(); principalComponents[i].value = eigenValues[index]; } //-------------------------------------------------------------------------- // Get the rotation matrix to transform from XYZ to eigenVectors UVW space. // See http://ocw.mit.edu/courses/aeronautics-and-astronautics/16-07-dynamics-fall-2009/lecture-notes/MIT16_07F09_Lec03.pdf // page 10. uvwRotationMatrix.a1 = principalComponents[U].vector.x;// * RepoVertex::X_AXIS; uvwRotationMatrix.a2 = principalComponents[U].vector.y;// * RepoVertex::Y_AXIS; uvwRotationMatrix.a3 = principalComponents[U].vector.z;// * RepoVertex::Z_AXIS; uvwRotationMatrix.b1 = principalComponents[V].vector.x;// * RepoVertex::X_AXIS; uvwRotationMatrix.b2 = principalComponents[V].vector.y;// * RepoVertex::Y_AXIS; uvwRotationMatrix.b3 = principalComponents[V].vector.z;// * RepoVertex::Z_AXIS; uvwRotationMatrix.c1 = principalComponents[W].vector.x;// * RepoVertex::X_AXIS; uvwRotationMatrix.c2 = principalComponents[W].vector.y;// * RepoVertex::Y_AXIS; uvwRotationMatrix.c3 = principalComponents[W].vector.z;// * RepoVertex::Z_AXIS; //-------------------------------------------------------------------------- // The inverse rotation, in this particular case T^-1 == T' xyzRotationMatrix = aiMatrix3x3t<float>(uvwRotationMatrix).Transpose(); //-------------------------------------------------------------------------- // Rotate the vertices around the xyzMean to the UVW space to get the bbox. uvwMin = RepoVertex(RepoVertex::getMaxVertex<float>()); uvwMax = RepoVertex(RepoVertex::getMinVertex<float>()); //uvwVertices.reserve(vertices.size()); sumOfWeights = 0; for (unsigned int i = 0; i < xyzVertices.size(); ++i) { RepoVertex uvwVertex = transformToUVW(xyzVertices[i]); uvwVertex.updateMinMax(uvwMin, uvwMax); uvwVertices.push_back(uvwVertex); uvwMean += RepoVertex(uvwVertex * (float) uvwVertex.weight); sumOfWeights += uvwVertex.weight; } uvwMean /= (float) sumOfWeights; //(float) vertices.size(); //-------------------------------------------------------------------------- // Store the lengths of the eigenvector oriented bounding box and calculate // the new midpoint in UVW. for (unsigned int i = 0; i < RepoVertex::DIMENSIONALITY; ++i) { // Bbox length along one of the UVW axes. double length = std::abs(uvwMax[i] - uvwMin[i]); principalComponents[i].magnitude = length; uvwCentroid[i] = (float) (uvwMin[i] + length/2.0f); } //-------------------------------------------------------------------------- // Transformed centroid in UVW is the centroid of the PCA bbox in XYZ. xyzCentroid = transformToXYZ(uvwCentroid); xyzMin = transformToXYZ(uvwMin); xyzMax = transformToXYZ(uvwMax); }
repo::core::RepoVertex repo::core::RepoPCA::transformToXYZ(const RepoVertex& v) const { return RepoVertex((xyzRotationMatrix * v) + xyzMean); }
repo::core::RepoVertex repo::core::RepoPCA::transformToUVW(const RepoVertex& v) const { return RepoVertex(uvwRotationMatrix * (v - xyzMean)); }