mvc.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. //
  2. // mvc.h
  3. //
  4. // Created by Olga Diamanti on 9/11/11.
  5. // Copyright (c) 2011 ETH Zurich. All rights reserved.
  6. //
  7. #ifndef IGL_MVC_H
  8. #define IGL_MVC_H
  9. #include <Eigen/Core>
  10. namespace igl
  11. {
  12. // MVC - MEAN VALUE COORDINATES
  13. //
  14. // mvc(V,C,W)
  15. //
  16. // Inputs:
  17. // V #V x dim list of vertex positions (dim = 2 or dim = 3)
  18. // C #C x dim list of polygon vertex positions in counter-clockwise order (dim = 2 or dim = 3)
  19. //
  20. // Outputs:
  21. // W weights, #V by #C matrix of weights
  22. //
  23. inline void mvc(const Eigen::MatrixXd &V, const Eigen::MatrixXd &C, Eigen::MatrixXd &W);
  24. }
  25. // Broken Implementation
  26. inline void igl::mvc(const Eigen::MatrixXd &V, const Eigen::MatrixXd &C, Eigen::MatrixXd &W)
  27. {
  28. // at least three control points
  29. assert(C.rows()>2);
  30. // dimension of points
  31. assert(C.cols() == 3 || C.cols() == 2);
  32. assert(V.cols() == 3 || V.cols() == 2);
  33. // number of polygon points
  34. int num = C.rows();
  35. Eigen::MatrixXd V1,C1;
  36. int i_prev, i_next;
  37. // check if either are 3D but really all z's are 0
  38. bool V_flat = (V.cols() == 3) && (std::sqrt( (V.col(3)).dot(V.col(3)) ) < 1e-10);
  39. bool C_flat = (C.cols() == 3) && (std::sqrt( (C.col(3)).dot(C.col(3)) ) < 1e-10);
  40. // if both are essentially 2D then ignore z-coords
  41. if((C.cols() == 2 || C_flat) && (V.cols() == 2 || V_flat))
  42. {
  43. // ignore z coordinate
  44. V1 = V.block(0,0,V.rows(),2);
  45. C1 = C.block(0,0,C.rows(),2);
  46. }
  47. else
  48. {
  49. // give dummy z coordinate to either mesh or poly
  50. if(V.rows() == 2)
  51. {
  52. V1 = Eigen::MatrixXd(V.rows(),3);
  53. V1.block(0,0,V.rows(),2) = V;
  54. }
  55. else
  56. V1 = V;
  57. if(C.rows() == 2)
  58. {
  59. C1 = Eigen::MatrixXd(C.rows(),3);
  60. C1.block(0,0,C.rows(),2) = C;
  61. }
  62. else
  63. C1 = C;
  64. // check that C is planar
  65. // average normal around poly corners
  66. Eigen::Vector3d n = Eigen::Vector3d::Zero();
  67. // take centroid as point on plane
  68. Eigen::Vector3d p = Eigen::Vector3d::Zero();
  69. for (int i = 0; i<num; ++i)
  70. {
  71. i_prev = (i>0)?(i-1):(num-1);
  72. i_next = (i<num-1)?(i+1):0;
  73. Eigen::Vector3d vnext = (C1.row(i_next) - C1.row(i)).transpose();
  74. Eigen::Vector3d vprev = (C1.row(i_prev) - C1.row(i)).transpose();
  75. n += vnext.cross(vprev);
  76. p += C1.row(i);
  77. }
  78. p/=num;
  79. n/=num;
  80. // normalize n
  81. n /= std::sqrt(n.dot(n));
  82. // check that poly is really coplanar
  83. for (int i = 0; i<num; ++i)
  84. {
  85. double dist_to_plane_C = std::abs((C1.row(i)-p.transpose()).dot(n));
  86. assert(dist_to_plane_C<1e-10);
  87. }
  88. // check that poly is really coplanar
  89. for (int i = 0; i<V1.rows(); ++i)
  90. {
  91. double dist_to_plane_V = std::abs((V1.row(i)-p.transpose()).dot(n));
  92. if(dist_to_plane_V>1e-10)
  93. std::cerr<<"Distance from V to plane of C is large..."<<std::endl;
  94. }
  95. // change of basis
  96. Eigen::Vector3d b1 = C1.row(1)-C1.row(0);
  97. Eigen::Vector3d b2 = n.cross(b1);
  98. // normalize basis rows
  99. b1 /= std::sqrt(b1.dot(b1));
  100. b2 /= std::sqrt(b2.dot(b2));
  101. n /= std::sqrt(n.dot(n));
  102. //transpose of the basis matrix in the m-file
  103. Eigen::Matrix3d basis = Eigen::Matrix3d::Zero();
  104. basis.col(0) = b1;
  105. basis.col(1) = b2;
  106. basis.col(2) = n;
  107. // change basis of rows vectors by right multiplying with inverse of matrix
  108. // with basis vectors as rows
  109. Eigen::ColPivHouseholderQR<Eigen::Matrix3d> solver = basis.colPivHouseholderQr();
  110. // Throw away coordinates in normal direction
  111. V1 = solver.solve(V1.transpose()).transpose().block(0,0,V1.rows(),2);
  112. C1 = solver.solve(C1.transpose()).transpose().block(0,0,C1.rows(),2);
  113. }
  114. // vectors from V to every C, where CmV(i,j,:) is the vector from domain
  115. // vertex j to handle i
  116. double EPSILON = 1e-10;
  117. Eigen::MatrixXd WW = Eigen::MatrixXd(C1.rows(), V1.rows());
  118. Eigen::MatrixXd dist_C_V (C1.rows(), V1.rows());
  119. std::vector< std::pair<int,int> > on_corner(0);
  120. std::vector< std::pair<int,int> > on_segment(0);
  121. for (int i = 0; i<C1.rows(); ++i)
  122. {
  123. i_prev = (i>0)?(i-1):(num-1);
  124. i_next = (i<num-1)?(i+1):0;
  125. // distance from each corner in C to the next corner so that edge_length(i)
  126. // is the distance from C(i,:) to C(i+1,:) defined cyclically
  127. double edge_length = std::sqrt((C1.row(i) - C1.row(i_next)).dot(C1.row(i) - C1.row(i_next)));
  128. for (int j = 0; j<V1.rows(); ++j)
  129. {
  130. Eigen::VectorXd v = C1.row(i) - V1.row(j);
  131. Eigen::VectorXd vnext = C1.row(i_next) - V1.row(j);
  132. Eigen::VectorXd vprev = C1.row(i_prev) - V1.row(j);
  133. // distance from V to every C, where dist_C_V(i,j) is the distance from domain
  134. // vertex j to handle i
  135. dist_C_V(i,j) = std::sqrt(v.dot(v));
  136. double dist_C_V_next = std::sqrt(vnext.dot(vnext));
  137. double a_prev = std::atan2(vprev[1],vprev[0]) - std::atan2(v[1],v[0]);
  138. double a_next = std::atan2(v[1],v[0]) - std::atan2(vnext[1],vnext[0]);
  139. // mean value coordinates
  140. WW(i,j) = (std::tan(a_prev/2.0) + std::tan(a_next/2.0)) / dist_C_V(i,j);
  141. if (dist_C_V(i,j) < EPSILON)
  142. on_corner.push_back(std::make_pair(j,i));
  143. else
  144. // only in case of no-corner (no need for checking for multiple segments afterwards --
  145. // should only be on one segment (otherwise must be on a corner and we already
  146. // handled that)
  147. // domain vertex j is on the segment from i to i+1 if the distances from vj to
  148. // pi and pi+1 are about
  149. if(abs((dist_C_V(i,j) + dist_C_V_next) / edge_length - 1) < EPSILON)
  150. on_segment.push_back(std::make_pair(j,i));
  151. }
  152. }
  153. // handle degenerate cases
  154. // snap vertices close to corners
  155. for (unsigned i = 0; i<on_corner.size(); ++i)
  156. {
  157. int vi = on_corner[i].first;
  158. int ci = on_corner[i].second;
  159. for (int ii = 0; ii<C.rows(); ++ii)
  160. WW(ii,vi) = (ii==ci)?1:0;
  161. }
  162. // snap vertices close to segments
  163. for (unsigned i = 0; i<on_segment.size(); ++i)
  164. {
  165. int vi = on_segment[i].first;
  166. int ci = on_segment[i].second;
  167. int ci_next = (ci<num-1)?(ci+1):0;
  168. for (int ii = 0; ii<C.rows(); ++ii)
  169. if (ii == ci)
  170. WW(ii,vi) = dist_C_V(ci_next,vi);
  171. else
  172. {
  173. if ( ii == ci_next)
  174. WW(ii,vi) = dist_C_V(ci,vi);
  175. else
  176. WW(ii,vi) = 0;
  177. }
  178. }
  179. // normalize W
  180. for (int i = 0; i<V.rows(); ++i)
  181. WW.col(i) /= WW.col(i).sum();
  182. // we've made W transpose
  183. W = WW.transpose();
  184. }
  185. #endif