cotangent.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 "cotangent.h"
  9. #include "edge_lengths.h"
  10. #include "verbose.h"
  11. template <class MatV, class MatF, class MatC>
  12. IGL_INLINE void igl::cotangent(const MatV & V, const MatF & F, MatC & C)
  13. {
  14. using namespace igl;
  15. using namespace std;
  16. using namespace Eigen;
  17. // simplex size (3: triangles, 4: tetrahedra)
  18. int simplex_size = F.cols();
  19. // Number of elements
  20. int m = F.rows();
  21. // Law of cosines + law of sines
  22. if(simplex_size == 3)
  23. {
  24. // Triangles
  25. //Matrix<typename MatC::Scalar,Dynamic,3> l;
  26. //edge_lengths(V,F,l);
  27. // edge lengths numbered same as opposite vertices
  28. Matrix<typename MatC::Scalar,Dynamic,3> l(m,3);
  29. // loop over faces
  30. for(int i = 0;i<m;i++)
  31. {
  32. l(i,0) = sqrt((V.row(F(i,1))-V.row(F(i,2))).array().pow(2).sum());
  33. l(i,1) = sqrt((V.row(F(i,2))-V.row(F(i,0))).array().pow(2).sum());
  34. l(i,2) = sqrt((V.row(F(i,0))-V.row(F(i,1))).array().pow(2).sum());
  35. }
  36. // semiperimeters
  37. Matrix<typename MatC::Scalar,Dynamic,1> s = l.rowwise().sum()*0.5;
  38. assert(s.rows() == m);
  39. // Heron's formula for area
  40. Matrix<typename MatC::Scalar,Dynamic,1> dblA(m);
  41. for(int i = 0;i<m;i++)
  42. {
  43. dblA(i) = 2.0*sqrt(s(i)*(s(i)-l(i,0))*(s(i)-l(i,1))*(s(i)-l(i,2)));
  44. }
  45. // cotangents and diagonal entries for element matrices
  46. // correctly divided by 4 (alec 2010)
  47. C.resize(m,3);
  48. for(int i = 0;i<m;i++)
  49. {
  50. C(i,0) = (l(i,1)*l(i,1) + l(i,2)*l(i,2) - l(i,0)*l(i,0))/dblA(i)/4.0;
  51. C(i,1) = (l(i,2)*l(i,2) + l(i,0)*l(i,0) - l(i,1)*l(i,1))/dblA(i)/4.0;
  52. C(i,2) = (l(i,0)*l(i,0) + l(i,1)*l(i,1) - l(i,2)*l(i,2))/dblA(i)/4.0;
  53. }
  54. }else if(simplex_size == 4)
  55. {
  56. // Tetrahedra
  57. typedef Matrix<typename MatV::Scalar,3,1> Vec3;
  58. typedef Matrix<typename MatV::Scalar,3,3> Mat3;
  59. typedef Matrix<typename MatV::Scalar,3,4> Mat3x4;
  60. typedef Matrix<typename MatV::Scalar,4,4> Mat4x4;
  61. // preassemble right hand side
  62. // COLUMN-MAJOR ORDER FOR LAPACK
  63. Mat3x4 rhs;
  64. rhs <<
  65. 1,0,0,-1,
  66. 0,1,0,-1,
  67. 0,0,1,-1;
  68. bool diag_all_pos = true;
  69. C.resize(m,6);
  70. // loop over tetrahedra
  71. for(int j = 0;j<F.rows();j++)
  72. {
  73. // points a,b,c,d make up the tetrahedra
  74. size_t a = F(j,0);
  75. size_t b = F(j,1);
  76. size_t c = F(j,2);
  77. size_t d = F(j,3);
  78. //const std::vector<double> & pa = vertices[a];
  79. //const std::vector<double> & pb = vertices[b];
  80. //const std::vector<double> & pc = vertices[c];
  81. //const std::vector<double> & pd = vertices[d];
  82. Vec3 pa = V.row(a);
  83. Vec3 pb = V.row(b);
  84. Vec3 pc = V.row(c);
  85. Vec3 pd = V.row(d);
  86. // Following definition that appears in the appendix of: ``Interactive
  87. // Topology-aware Surface Reconstruction,'' by Sharf, A. et al
  88. // http://www.cs.bgu.ac.il/~asharf/Projects/InSuRe/Insure_siggraph_final.pdf
  89. // compute transpose of jacobian Jj
  90. Mat3 JTj;
  91. JTj.row(0) = pa-pd;
  92. JTj.row(1) = pb-pd;
  93. JTj.row(2) = pc-pd;
  94. // compute abs(determinant of JTj)/6 (volume of tet)
  95. // determinant of transpose of A equals determinant of A
  96. double volume = fabs(JTj.determinant())/6.0;
  97. //printf("volume[%d] = %g\n",j+1,volume);
  98. // solve Jj' * Ej = [-I -1], for Ej
  99. // in other words solve JTj * Ej = [-I -1], for Ej
  100. Mat3x4 Ej = JTj.inverse() * rhs;
  101. // compute Ej'*Ej
  102. Mat4x4 EjTEj = Ej.transpose() * Ej;
  103. // Kj = det(JTj)/6 * Ej'Ej
  104. Mat4x4 Kj = EjTEj*volume;
  105. diag_all_pos &= ((Kj(0,0)>0) & (Kj(1,1)>0)) & ((Kj(2,2)>0) & (Kj(3,3)>0));
  106. C(j,0) = Kj(1,2);
  107. C(j,1) = Kj(2,0);
  108. C(j,2) = Kj(0,1);
  109. C(j,3) = Kj(3,0);
  110. C(j,4) = Kj(3,1);
  111. C(j,5) = Kj(3,2);
  112. }
  113. if(diag_all_pos)
  114. {
  115. #ifdef VERBOSE
  116. verbose("cotangent.h: Flipping sign of cotangent, so that cots are positive\n");
  117. #endif
  118. C *= -1.0;
  119. }
  120. }else
  121. {
  122. fprintf(stderr,
  123. "cotangent.h: Error: Simplex size (%d) not supported\n", simplex_size);
  124. assert(false);
  125. }
  126. }
  127. #ifndef IGL_HEADER_ONLY
  128. // Explicit template specialization
  129. // generated by autoexplicit.sh
  130. template void igl::cotangent<Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
  131. // generated by autoexplicit.sh
  132. template void igl::cotangent<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
  133. // generated by autoexplicit.sh
  134. template void igl::cotangent<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
  135. template void igl::cotangent<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<double, -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::Matrix<double, -1, -1, 0, -1, -1>&);
  136. #endif