loop.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2016 Oded Stein <oded.stein@columbia.edu>
  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 "loop.h"
  9. #include <igl/adjacency_list.h>
  10. #include <igl/triangle_triangle_adjacency.h>
  11. #include <igl/unique.h>
  12. #include <vector>
  13. template <
  14. typename DerivedF,
  15. typename SType,
  16. typename DerivedNF>
  17. IGL_INLINE void igl::loop(
  18. const int n_verts,
  19. const Eigen::PlainObjectBase<DerivedF> & F,
  20. Eigen::SparseMatrix<SType>& S,
  21. Eigen::PlainObjectBase<DerivedNF> & NF)
  22. {
  23. typedef Eigen::SparseMatrix<SType> SparseMat;
  24. typedef Eigen::Triplet<SType> Triplet_t;
  25. //Ref. https://graphics.stanford.edu/~mdfisher/subdivision.html
  26. //Heavily borrowing from igl::upsample
  27. DerivedF FF, FFi;
  28. triangle_triangle_adjacency(F, FF, FFi);
  29. std::vector<std::vector<typename DerivedF::Scalar>> adjacencyList;
  30. adjacency_list(F, adjacencyList, true);
  31. //Compute the number and positions of the vertices to insert (on edges)
  32. Eigen::MatrixXi NI = Eigen::MatrixXi::Constant(FF.rows(), FF.cols(), -1);
  33. Eigen::MatrixXi NIdoubles = Eigen::MatrixXi::Zero(FF.rows(), FF.cols());
  34. Eigen::VectorXi vertIsOnBdry = Eigen::VectorXi::Zero(n_verts);
  35. int counter = 0;
  36. for(int i=0; i<FF.rows(); ++i)
  37. {
  38. for(int j=0; j<3; ++j)
  39. {
  40. if(NI(i,j) == -1)
  41. {
  42. NI(i,j) = counter;
  43. NIdoubles(i,j) = 0;
  44. if (FF(i,j) != -1)
  45. {
  46. //If it is not a boundary
  47. NI(FF(i,j), FFi(i,j)) = counter;
  48. NIdoubles(i,j) = 1;
  49. } else
  50. {
  51. //Mark boundary vertices for later
  52. vertIsOnBdry(F(i,j)) = 1;
  53. vertIsOnBdry(F(i,(j+1)%3)) = 1;
  54. }
  55. ++counter;
  56. }
  57. }
  58. }
  59. const int& n_odd = n_verts;
  60. const int& n_even = counter;
  61. const int n_newverts = n_odd + n_even;
  62. //Construct vertex positions
  63. std::vector<Triplet_t> tripletList;
  64. for(int i=0; i<n_odd; ++i)
  65. {
  66. //Old vertices
  67. const std::vector<int>& localAdjList = adjacencyList[i];
  68. if(vertIsOnBdry(i)==1)
  69. {
  70. //Boundary vertex
  71. tripletList.emplace_back(i, localAdjList.front(), 1./8.);
  72. tripletList.emplace_back(i, localAdjList.back(), 1./8.);
  73. tripletList.emplace_back(i, i, 3./4.);
  74. } else
  75. {
  76. const int n = localAdjList.size();
  77. const SType dn = n;
  78. SType beta;
  79. if(n==3)
  80. {
  81. beta = 3./16.;
  82. } else
  83. {
  84. beta = 3./8./dn;
  85. }
  86. for(int j=0; j<n; ++j)
  87. {
  88. tripletList.emplace_back(i, localAdjList[j], beta);
  89. }
  90. tripletList.emplace_back(i, i, 1.-dn*beta);
  91. }
  92. }
  93. for(int i=0; i<FF.rows(); ++i)
  94. {
  95. //New vertices
  96. for(int j=0; j<3; ++j)
  97. {
  98. if(NIdoubles(i,j)==0)
  99. {
  100. if(FF(i,j)==-1)
  101. {
  102. //Boundary vertex
  103. tripletList.emplace_back(NI(i,j) + n_odd, F(i,j), 1./2.);
  104. tripletList.emplace_back(NI(i,j) + n_odd, F(i, (j+1)%3), 1./2.);
  105. } else
  106. {
  107. tripletList.emplace_back(NI(i,j) + n_odd, F(i,j), 3./8.);
  108. tripletList.emplace_back(NI(i,j) + n_odd, F(i, (j+1)%3), 3./8.);
  109. tripletList.emplace_back(NI(i,j) + n_odd, F(i, (j+2)%3), 1./8.);
  110. tripletList.emplace_back(NI(i,j) + n_odd, F(FF(i,j), (FFi(i,j)+2)%3), 1./8.);
  111. }
  112. }
  113. }
  114. }
  115. S.resize(n_newverts, n_verts);
  116. S.setFromTriplets(tripletList.begin(), tripletList.end());
  117. // Build the new topology (Every face is replaced by four)
  118. NF.resize(F.rows()*4, 3);
  119. for(int i=0; i<F.rows();++i)
  120. {
  121. Eigen::VectorXi VI(6);
  122. VI << F(i,0), F(i,1), F(i,2), NI(i,0) + n_odd, NI(i,1) + n_odd, NI(i,2) + n_odd;
  123. Eigen::VectorXi f0(3), f1(3), f2(3), f3(3);
  124. f0 << VI(0), VI(3), VI(5);
  125. f1 << VI(1), VI(4), VI(3);
  126. f2 << VI(3), VI(4), VI(5);
  127. f3 << VI(4), VI(2), VI(5);
  128. NF.row((i*4)+0) = f0;
  129. NF.row((i*4)+1) = f1;
  130. NF.row((i*4)+2) = f2;
  131. NF.row((i*4)+3) = f3;
  132. }
  133. }
  134. template <
  135. typename DerivedV,
  136. typename DerivedF,
  137. typename DerivedNV,
  138. typename DerivedNF>
  139. IGL_INLINE void igl::loop(
  140. const Eigen::PlainObjectBase<DerivedV>& V,
  141. const Eigen::PlainObjectBase<DerivedF>& F,
  142. Eigen::PlainObjectBase<DerivedNV>& NV,
  143. Eigen::PlainObjectBase<DerivedNF>& NF,
  144. const int number_of_subdivs)
  145. {
  146. NV = V;
  147. NF = F;
  148. for(int i=0; i<number_of_subdivs; ++i)
  149. {
  150. DerivedNF tempF = NF;
  151. Eigen::SparseMatrix<typename DerivedV::Scalar> S;
  152. loop(NV.rows(), tempF, S, NF);
  153. // This .eval is super important
  154. NV = (S*NV).eval();
  155. }
  156. }
  157. #ifdef IGL_STATIC_LIBRARY
  158. template void igl::loop<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<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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, int);
  159. #endif