// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2014 Stefan Brugger // // This Source Code Form is subject to the terms of the Mozilla Public License // v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. #include "procrustes.h" #include "polar_svd.h" #include "polar_dec.h" template < typename DerivedX, typename DerivedY, typename Scalar, typename DerivedR, typename DerivedT> IGL_INLINE void igl::procrustes( const Eigen::PlainObjectBase& X, const Eigen::PlainObjectBase& Y, bool includeScaling, bool includeReflections, Scalar& scale, Eigen::PlainObjectBase& R, Eigen::PlainObjectBase& t) { using namespace Eigen; assert (X.rows() == Y.rows() && "Same number of points"); assert(X.cols() == Y.cols() && "Points have same dimensions"); // Center data const VectorXd Xmean = X.colwise().mean(); const VectorXd Ymean = Y.colwise().mean(); MatrixXd XC = X.rowwise() - Xmean.transpose(); MatrixXd YC = Y.rowwise() - Ymean.transpose(); // Scale scale = 1.; if (includeScaling) { double scaleX = XC.norm() / XC.rows(); double scaleY = YC.norm() / YC.rows(); scale = scaleY/scaleX; XC *= scale; assert (std::abs(XC.norm() / XC.rows() - scaleY) < 1e-8); } // Rotation MatrixXd S = XC.transpose() * YC; MatrixXd T; if (includeReflections) { polar_dec(S,R,T); }else { polar_svd(S,R,T); } // R.transposeInPlace(); // Translation t = Ymean - scale*R.transpose()*Xmean; } template < typename DerivedX, typename DerivedY, typename Scalar, int DIM, int TType> IGL_INLINE void igl::procrustes( const Eigen::PlainObjectBase& X, const Eigen::PlainObjectBase& Y, bool includeScaling, bool includeReflections, Eigen::Transform& T) { using namespace Eigen; double scale; MatrixXd R; VectorXd t; procrustes(X,Y,includeScaling,includeReflections,scale,R,t); // Combine T = Translation(t) * R * Scaling(scale); } template < typename DerivedX, typename DerivedY, typename DerivedR, typename DerivedT> IGL_INLINE void igl::procrustes( const Eigen::PlainObjectBase& X, const Eigen::PlainObjectBase& Y, bool includeScaling, bool includeReflections, Eigen::PlainObjectBase& S, Eigen::PlainObjectBase& t) { double scale; procrustes(X,Y,includeScaling,includeReflections,scale,S,t); S *= scale; } template < typename DerivedX, typename DerivedY, typename DerivedR, typename DerivedT> IGL_INLINE void igl::procrustes( const Eigen::PlainObjectBase& X, const Eigen::PlainObjectBase& Y, Eigen::PlainObjectBase& R, Eigen::PlainObjectBase& t) { procrustes(X,Y,false,false,R,t); } template < typename DerivedX, typename DerivedY, typename Scalar, typename DerivedT> IGL_INLINE void igl::procrustes( const Eigen::PlainObjectBase& X, const Eigen::PlainObjectBase& Y, Eigen::Rotation2D& R, Eigen::PlainObjectBase& t) { using namespace Eigen; assert (X.cols() == 2 && Y.cols() == 2 && "Points must have dimension 2"); Matrix2d Rmat; procrustes(X,Y,false,false,Rmat,t); R.fromRotationMatrix(Rmat); } #ifdef IGL_STATIC_LIBRARY template void igl::procrustes, Eigen::Matrix, double, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, bool, bool, double&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif