grad.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "grad.h"
  9. #include <Eigen/Geometry>
  10. #include <vector>
  11. #include "per_face_normals.h"
  12. #include "volume.h"
  13. #include "doublearea.h"
  14. template <typename DerivedV, typename DerivedF>
  15. IGL_INLINE void grad_tet(const Eigen::PlainObjectBase<DerivedV>&V,
  16. const Eigen::PlainObjectBase<DerivedF>&T,
  17. Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
  18. bool uniform) {
  19. using namespace Eigen;
  20. assert(T.cols() == 4);
  21. const int n = V.rows(); int m = T.rows();
  22. /*
  23. F = [ ...
  24. T(:,1) T(:,2) T(:,3); ...
  25. T(:,1) T(:,3) T(:,4); ...
  26. T(:,1) T(:,4) T(:,2); ...
  27. T(:,2) T(:,4) T(:,3)]; */
  28. MatrixXi F(4*m,3);
  29. for (int i = 0; i < m; i++) {
  30. F.row(0*m + i) << T(i,0), T(i,1), T(i,2);
  31. F.row(1*m + i) << T(i,0), T(i,2), T(i,3);
  32. F.row(2*m + i) << T(i,0), T(i,3), T(i,1);
  33. F.row(3*m + i) << T(i,1), T(i,3), T(i,2);
  34. }
  35. // compute volume of each tet
  36. VectorXd vol; igl::volume(V,T,vol);
  37. VectorXd A(F.rows());
  38. MatrixXd N(F.rows(),3);
  39. if (!uniform) {
  40. // compute tetrahedron face normals
  41. igl::per_face_normals(V,F,N); int norm_rows = N.rows();
  42. for (int i = 0; i < norm_rows; i++)
  43. N.row(i) /= N.row(i).norm();
  44. igl::doublearea(V,F,A); A/=2.;
  45. } else {
  46. // Use a uniform tetrahedra as a reference, with the same volume as the original one:
  47. //
  48. // Use normals of the uniform tet (V = h*[0,0,0;1,0,0;0.5,sqrt(3)/2.,0;0.5,sqrt(3)/6.,sqrt(2)/sqrt(3)])
  49. // 0 0 1.0000
  50. // 0.8165 -0.4714 -0.3333
  51. // 0 0.9428 -0.3333
  52. // -0.8165 -0.4714 -0.3333
  53. for (int i = 0; i < m; i++) {
  54. N.row(0*m+i) << 0,0,1;
  55. double a = sqrt(2)*std::cbrt(3*vol(i)); // area of a face in a uniform tet with volume = vol(i)
  56. A(0*m+i) = (pow(a,2)*sqrt(3))/4.;
  57. }
  58. for (int i = 0; i < m; i++) {
  59. N.row(1*m+i) << 0.8165,-0.4714,-0.3333;
  60. double a = sqrt(2)*std::cbrt(3*vol(i));
  61. A(1*m+i) = (pow(a,2)*sqrt(3))/4.;
  62. }
  63. for (int i = 0; i < m; i++) {
  64. N.row(2*m+i) << 0,0.9428,-0.3333;
  65. double a = sqrt(2)*std::cbrt(3*vol(i));
  66. A(2*m+i) = (pow(a,2)*sqrt(3))/4.;
  67. }
  68. for (int i = 0; i < m; i++) {
  69. N.row(3*m+i) << -0.8165,-0.4714,-0.3333;
  70. double a = sqrt(2)*std::cbrt(3*vol(i));
  71. A(3*m+i) = (pow(a,2)*sqrt(3))/4.;
  72. }
  73. }
  74. /* G = sparse( ...
  75. [0*m + repmat(1:m,1,4) ...
  76. 1*m + repmat(1:m,1,4) ...
  77. 2*m + repmat(1:m,1,4)], ...
  78. repmat([T(:,4);T(:,2);T(:,3);T(:,1)],3,1), ...
  79. repmat(A./(3*repmat(vol,4,1)),3,1).*N(:), ...
  80. 3*m,n);*/
  81. std::vector<Triplet<double> > G_t;
  82. for (int i = 0; i < 4*m; i++) {
  83. int T_j; // j indexes : repmat([T(:,4);T(:,2);T(:,3);T(:,1)],3,1)
  84. switch (i/m) {
  85. case 0:
  86. T_j = 3;
  87. break;
  88. case 1:
  89. T_j = 1;
  90. break;
  91. case 2:
  92. T_j = 2;
  93. break;
  94. case 3:
  95. T_j = 0;
  96. break;
  97. }
  98. int i_idx = i%m;
  99. int j_idx = T(i_idx,T_j);
  100. double val_before_n = A(i)/(3*vol(i_idx));
  101. G_t.push_back(Triplet<double>(0*m+i_idx, j_idx, val_before_n * N(i,0)));
  102. G_t.push_back(Triplet<double>(1*m+i_idx, j_idx, val_before_n * N(i,1)));
  103. G_t.push_back(Triplet<double>(2*m+i_idx, j_idx, val_before_n * N(i,2)));
  104. }
  105. G.resize(3*m,n);
  106. G.setFromTriplets(G_t.begin(), G_t.end());
  107. }
  108. template <typename DerivedV, typename DerivedF>
  109. IGL_INLINE void grad_tri(const Eigen::PlainObjectBase<DerivedV>&V,
  110. const Eigen::PlainObjectBase<DerivedF>&F,
  111. Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
  112. bool uniform)
  113. {
  114. Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3>
  115. eperp21(F.rows(),3), eperp13(F.rows(),3);
  116. for (int i=0;i<F.rows();++i)
  117. {
  118. // renaming indices of vertices of triangles for convenience
  119. int i1 = F(i,0);
  120. int i2 = F(i,1);
  121. int i3 = F(i,2);
  122. // #F x 3 matrices of triangle edge vectors, named after opposite vertices
  123. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v32 = V.row(i3) - V.row(i2);
  124. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v13 = V.row(i1) - V.row(i3);
  125. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v21 = V.row(i2) - V.row(i1);
  126. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> n = v32.cross(v13);
  127. // area of parallelogram is twice area of triangle
  128. // area of parallelogram is || v1 x v2 ||
  129. // This does correct l2 norm of rows, so that it contains #F list of twice
  130. // triangle areas
  131. double dblA = std::sqrt(n.dot(n));
  132. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> u;
  133. if (!uniform) {
  134. // now normalize normals to get unit normals
  135. u = n / dblA;
  136. } else {
  137. // Abstract equilateral triangle v1=(0,0), v2=(h,0), v3=(h/2, (sqrt(3)/2)*h)
  138. // get h (by the area of the triangle)
  139. double h = sqrt( (dblA)/sin(M_PI / 3.0)); // (h^2*sin(60))/2. = Area => h = sqrt(2*Area/sin_60)
  140. Eigen::VectorXd v1,v2,v3;
  141. v1 << 0,0,0;
  142. v2 << h,0,0;
  143. v3 << h/2.,(sqrt(3)/2.)*h,0;
  144. // now fix v32,v13,v21 and the normal
  145. v32 = v3-v2;
  146. v13 = v1-v3;
  147. v21 = v2-v1;
  148. n = v32.cross(v13);
  149. }
  150. // rotate each vector 90 degrees around normal
  151. double norm21 = std::sqrt(v21.dot(v21));
  152. double norm13 = std::sqrt(v13.dot(v13));
  153. eperp21.row(i) = u.cross(v21);
  154. eperp21.row(i) = eperp21.row(i) / std::sqrt(eperp21.row(i).dot(eperp21.row(i)));
  155. eperp21.row(i) *= norm21 / dblA;
  156. eperp13.row(i) = u.cross(v13);
  157. eperp13.row(i) = eperp13.row(i) / std::sqrt(eperp13.row(i).dot(eperp13.row(i)));
  158. eperp13.row(i) *= norm13 / dblA;
  159. }
  160. std::vector<int> rs;
  161. rs.reserve(F.rows()*4*3);
  162. std::vector<int> cs;
  163. cs.reserve(F.rows()*4*3);
  164. std::vector<double> vs;
  165. vs.reserve(F.rows()*4*3);
  166. // row indices
  167. for(int r=0;r<3;r++)
  168. {
  169. for(int j=0;j<4;j++)
  170. {
  171. for(int i=r*F.rows();i<(r+1)*F.rows();i++) rs.push_back(i);
  172. }
  173. }
  174. // column indices
  175. for(int r=0;r<3;r++)
  176. {
  177. for(int i=0;i<F.rows();i++) cs.push_back(F(i,1));
  178. for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
  179. for(int i=0;i<F.rows();i++) cs.push_back(F(i,2));
  180. for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
  181. }
  182. // values
  183. for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,0));
  184. for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,0));
  185. for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,0));
  186. for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,0));
  187. for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,1));
  188. for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,1));
  189. for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,1));
  190. for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,1));
  191. for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,2));
  192. for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,2));
  193. for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,2));
  194. for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,2));
  195. // create sparse gradient operator matrix
  196. G.resize(3*F.rows(),V.rows());
  197. std::vector<Eigen::Triplet<typename DerivedV::Scalar> > triplets;
  198. for (int i=0;i<(int)vs.size();++i)
  199. {
  200. triplets.push_back(Eigen::Triplet<typename DerivedV::Scalar>(rs[i],cs[i],vs[i]));
  201. }
  202. G.setFromTriplets(triplets.begin(), triplets.end());
  203. }
  204. template <typename DerivedV, typename DerivedF>
  205. IGL_INLINE void igl::grad(const Eigen::PlainObjectBase<DerivedV>&V,
  206. const Eigen::PlainObjectBase<DerivedF>&F,
  207. Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
  208. bool uniform)
  209. {
  210. assert(F.cols() == 3 || F.cols() == 4);
  211. if (F.cols() == 3)
  212. return grad_tri(V,F,G,uniform);
  213. if (F.cols() == 4)
  214. return grad_tet(V,F,G,uniform);
  215. }
  216. #ifdef IGL_STATIC_LIBRARY
  217. // Explicit template specialization
  218. template void igl::grad<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, 0, int>&, bool);
  219. template void igl::grad<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, 0, int>&, bool);
  220. #endif