#include #include #include #include #include template IGL_INLINE void igl::polyvector_field_matching( const Eigen::PlainObjectBase& _ua, const Eigen::PlainObjectBase& _ub, const Eigen::PlainObjectBase& na, const Eigen::PlainObjectBase& nb, const Eigen::PlainObjectBase& e, bool match_with_curl, Eigen::PlainObjectBase& mab, Eigen::PlainObjectBase& mba) { // make sure the matching preserve ccw order of the vectors across the edge // 1) order vectors in a, ccw e.g. (0,1,2,3)_a not ccw --> (0,3,2,1)_a ccw // 2) order vectors in b, ccw e.g. (0,1,2,3)_b not ccw --> (0,2,1,3)_b ccw // 3) the vectors in b that match the ordered vectors in a (in this case (0,3,2,1)_a ) must be a circular shift of the ccw ordered vectors in b - so we need to explicitely check only these matchings to find the best ccw one, there are N of them int hN = _ua.cols()/3; int N = 2*hN; Eigen::Matrix ua (1,N*3); ua <<_ua, -_ua; Eigen::Matrix ub (1,N*3); ub <<_ub, -_ub; Eigen::Matrix order_a, order_b; Eigen::Matrix sorted_unused; Eigen::VectorXi inv_order_unused; igl::sort_vectors_ccw(ua, na, order_a,false,sorted_unused,false,inv_order_unused); igl::sort_vectors_ccw(ub, nb, order_b,false,sorted_unused,false,inv_order_unused); //checking all possible circshifts of order_b as matches for order_a Eigen::Matrix all_matches(N,N); Eigen::Matrix all_scores(1,N); for (int s =0; s< N; ++s) { all_matches.row(s) = order_b; typename DerivedS::Scalar current_score=0; for (int i=0; i< N; ++i) { if (match_with_curl) current_score += fabs(ua.segment(order_a[i]*3, 3).dot(e) - ub.segment(order_b[i]*3, 3).dot(e)); else { Eigen::Matrix na_ = na.transpose(); Eigen::Matrix nb_ = nb.transpose(); Eigen::Matrix uaRot = igl::rotation_matrix_from_directions(na_, nb_)*ua.segment(order_a[i]*3, 3).transpose(); current_score += (uaRot-ub.segment(order_b[i]*3, 3)).norm(); } } all_scores[s] = current_score; // do a circshift on order_b to check the next preserving matching int temp = order_b[0]; for (int i =0; i< N-1; ++i) order_b[i] = order_b[i+1]; order_b(N-1) = temp; } Eigen::Matrix best_matching_for_sorted_a; int best_i; all_scores.minCoeff(&best_i); best_matching_for_sorted_a = all_matches.row(best_i); // best_matching_for_sorted_a is the matching for the sorted vectors in a // get the matching for the initial (unsorted) vectors mab.resize(1,N); for (int i=0; i< N; ++i) mab[order_a[i]] = best_matching_for_sorted_a[i]; //mab contains the best matching a->b, get the opposite too mba.resize(1, N); for (int i=0; i< N; ++i) mba[mab[i]] = i; mab = mab.head(hN); mba = mba.head(hN); } template IGL_INLINE typename DerivedC::Scalar igl::polyvector_field_matchings( const Eigen::PlainObjectBase& sol3D, const Eigen::PlainObjectBase&V, const Eigen::PlainObjectBase&F, const Eigen::PlainObjectBase&E, const Eigen::PlainObjectBase& FN, const Eigen::MatrixXi &E2F, bool match_with_curl, Eigen::PlainObjectBase& match_ab, Eigen::PlainObjectBase& match_ba, Eigen::PlainObjectBase& curl) { int numEdges = E.rows(); int half_degree = sol3D.cols()/3; Eigen::VectorXi isBorderEdge; isBorderEdge.setZero(numEdges,1); for(unsigned i=0; i ce = (V.row(E(ei,1))-V.row(E(ei,0))).normalized().template cast(); Eigen::Matrix mab, mba; igl::polyvector_field_matching(sol3D.row(a).eval(), sol3D.row(b).eval(), FN.row(a).eval(), FN.row(b).eval(), ce, match_with_curl, mab, mba); match_ab.row(ei) = mab; match_ba.row(ei) = mba; Eigen::Matrix matched; matched.resize(1, 3*half_degree); for (int i = 0; i IGL_INLINE typename DerivedC::Scalar igl::polyvector_field_matchings( const Eigen::PlainObjectBase& sol3D, const Eigen::PlainObjectBase&V, const Eigen::PlainObjectBase&F, bool match_with_curl, Eigen::PlainObjectBase& match_ab, Eigen::PlainObjectBase& match_ba, Eigen::PlainObjectBase& curl) { Eigen::MatrixXi E, E2F, F2E; igl::edge_topology(V,F,E,F2E,E2F); #warning "Poor templating of igl::polyvector_field_matchings forces FN to be DerivedV (this could cause issues if DerivedV has fixed number of rows)" DerivedV FN; igl::per_face_normals(V,F,FN); return igl::polyvector_field_matchings(sol3D, V, F, E, FN, E2F, match_with_curl, match_ab, match_ba, curl); } #ifdef IGL_STATIC_LIBRARY // Explicit template specialization template Eigen::Matrix::Scalar igl::polyvector_field_matchings, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); template Eigen::Matrix::Scalar igl::polyvector_field_matchings, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, bool, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif