loop.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. namespace igl
  14. {
  15. IGL_INLINE void loop(const int n_verts,
  16. const Eigen::MatrixXi& F,
  17. Eigen::SparseMatrix<double>& S,
  18. Eigen::MatrixXi& newF)
  19. {
  20. typedef Eigen::SparseMatrix<double> SparseMat;
  21. typedef Eigen::Triplet<double> Triplet_t;
  22. //Ref. https://graphics.stanford.edu/~mdfisher/subdivision.html
  23. //Heavily borrowing from igl::upsample
  24. Eigen::MatrixXi FF, FFi;
  25. triangle_triangle_adjacency(F, FF, FFi);
  26. std::vector<std::vector<int>> adjacencyList;
  27. adjacency_list(F, adjacencyList, true);
  28. //Compute the number and positions of the vertices to insert (on edges)
  29. Eigen::MatrixXi NI = Eigen::MatrixXi::Constant(FF.rows(), FF.cols(), -1);
  30. Eigen::MatrixXi NIdoubles = Eigen::MatrixXi::Zero(FF.rows(), FF.cols());
  31. Eigen::VectorXi vertIsOnBdry = Eigen::VectorXi::Zero(n_verts);
  32. int counter = 0;
  33. for(int i=0; i<FF.rows(); ++i)
  34. {
  35. for(int j=0; j<3; ++j)
  36. {
  37. if(NI(i,j) == -1)
  38. {
  39. NI(i,j) = counter;
  40. NIdoubles(i,j) = 0;
  41. if (FF(i,j) != -1) {
  42. //If it is not a boundary
  43. NI(FF(i,j), FFi(i,j)) = counter;
  44. NIdoubles(i,j) = 1;
  45. } else {
  46. //Mark boundary vertices for later
  47. vertIsOnBdry(F(i,j)) = 1;
  48. vertIsOnBdry(F(i,(j+1)%3)) = 1;
  49. }
  50. ++counter;
  51. }
  52. }
  53. }
  54. const int& n_odd = n_verts;
  55. const int& n_even = counter;
  56. const int n_newverts = n_odd + n_even;
  57. //Construct vertex positions
  58. std::vector<Triplet_t> tripletList;
  59. for(int i=0; i<n_odd; ++i) {
  60. //Old vertices
  61. const std::vector<int>& localAdjList = adjacencyList[i];
  62. if(vertIsOnBdry(i)==1) {
  63. //Boundary vertex
  64. tripletList.emplace_back(i, localAdjList.front(), 1./8.);
  65. tripletList.emplace_back(i, localAdjList.back(), 1./8.);
  66. tripletList.emplace_back(i, i, 3./4.);
  67. } else {
  68. const int n = localAdjList.size();
  69. const double dn = n;
  70. double beta;
  71. if(n==3)
  72. beta = 3./16.;
  73. else
  74. beta = 3./8./dn;
  75. for(int j=0; j<n; ++j)
  76. tripletList.emplace_back(i, localAdjList[j], beta);
  77. tripletList.emplace_back(i, i, 1.-dn*beta);
  78. }
  79. }
  80. for(int i=0; i<FF.rows(); ++i) {
  81. //New vertices
  82. for(int j=0; j<3; ++j) {
  83. if(NIdoubles(i,j)==0) {
  84. if(FF(i,j)==-1) {
  85. //Boundary vertex
  86. tripletList.emplace_back(NI(i,j) + n_odd, F(i,j), 1./2.);
  87. tripletList.emplace_back(NI(i,j) + n_odd, F(i, (j+1)%3), 1./2.);
  88. } else {
  89. tripletList.emplace_back(NI(i,j) + n_odd, F(i,j), 3./8.);
  90. tripletList.emplace_back(NI(i,j) + n_odd, F(i, (j+1)%3), 3./8.);
  91. tripletList.emplace_back(NI(i,j) + n_odd, F(i, (j+2)%3), 1./8.);
  92. tripletList.emplace_back(NI(i,j) + n_odd, F(FF(i,j), (FFi(i,j)+2)%3), 1./8.);
  93. }
  94. }
  95. }
  96. }
  97. S.resize(n_newverts, n_verts);
  98. S.setFromTriplets(tripletList.begin(), tripletList.end());
  99. // Build the new topology (Every face is replaced by four)
  100. newF.resize(F.rows()*4, 3);
  101. for(int i=0; i<F.rows();++i)
  102. {
  103. Eigen::VectorXi VI(6);
  104. 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;
  105. Eigen::VectorXi f0(3), f1(3), f2(3), f3(3);
  106. f0 << VI(0), VI(3), VI(5);
  107. f1 << VI(1), VI(4), VI(3);
  108. f2 << VI(3), VI(4), VI(5);
  109. f3 << VI(4), VI(2), VI(5);
  110. newF.row((i*4)+0) = f0;
  111. newF.row((i*4)+1) = f1;
  112. newF.row((i*4)+2) = f2;
  113. newF.row((i*4)+3) = f3;
  114. }
  115. }
  116. IGL_INLINE void loop(const Eigen::MatrixXd& V,
  117. const Eigen::MatrixXi& F,
  118. Eigen::MatrixXd& newV,
  119. Eigen::MatrixXi& newF,
  120. const int number_of_subdivs)
  121. {
  122. typedef Eigen::SparseMatrix<double> SparseMat;
  123. typedef Eigen::Triplet<double> Triplet_t;
  124. newV = V;
  125. newF = F;
  126. for(int i=0; i<number_of_subdivs; ++i) {
  127. Eigen::MatrixXi tempF = newF;
  128. SparseMat S;
  129. loop(newV.rows(), tempF, S, newF);
  130. newV = S*newV;
  131. }
  132. }
  133. }