boundary_loop.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2014 Stefan Brugger <stefanbrugger@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 "boundary_loop.h"
  9. #include "triangle_triangle_adjacency.h"
  10. #include "vertex_triangle_adjacency.h"
  11. IGL_INLINE void igl::boundary_loop(
  12. const Eigen::MatrixXd& V,
  13. const Eigen::MatrixXi& F,
  14. Eigen::VectorXi& b)
  15. {
  16. std::vector<int> bnd;
  17. bnd.clear();
  18. std::vector<bool> isVisited(V.rows(),false);
  19. // Actually mesh only needs to be manifold near boundary, so this is
  20. // over zealous (see gptoolbox's outline_loop for a more general
  21. // (and probably faster) implementation)
  22. assert(is_manifold(V,F) && "Mesh must be manifold");
  23. Eigen::MatrixXi TT,TTi;
  24. std::vector<std::vector<int> > VF, VFi;
  25. igl::triangle_triangle_adjacency(V,F,TT,TTi);
  26. igl::vertex_triangle_adjacency(V,F,VF,VFi);
  27. // Extract one boundary edge
  28. bool done = false;
  29. for (int i = 0; i < TT.rows() && !done; i++)
  30. {
  31. for (int j = 0; j < TT.cols(); j++)
  32. {
  33. if (TT(i,j) < 0)
  34. {
  35. int idx1, idx2;
  36. idx1 = F(i,j);
  37. idx2 = F(i,(j+1) % F.cols());
  38. bnd.push_back(idx1);
  39. bnd.push_back(idx2);
  40. isVisited[idx1] = true;
  41. isVisited[idx2] = true;
  42. done = true;
  43. break;
  44. }
  45. }
  46. }
  47. // Traverse boundary
  48. while(1)
  49. {
  50. bool changed = false;
  51. int lastV;
  52. lastV = bnd[bnd.size()-1];
  53. for (int i = 0; i < (int)VF[lastV].size(); i++)
  54. {
  55. int curr_neighbor = VF[lastV][i];
  56. if (TT.row(curr_neighbor).minCoeff() < 0.) // Face contains boundary edge
  57. {
  58. int idx_lastV_in_face;
  59. if (F(curr_neighbor,0) == lastV) idx_lastV_in_face = 0;
  60. if (F(curr_neighbor,1) == lastV) idx_lastV_in_face = 1;
  61. if (F(curr_neighbor,2) == lastV) idx_lastV_in_face = 2;
  62. int idx_prev = (idx_lastV_in_face + F.cols()-1) % F.cols();
  63. int idx_next = (idx_lastV_in_face + 1) % F.cols();
  64. bool isPrevVisited = isVisited[F(curr_neighbor,idx_prev)];
  65. bool isNextVisited = isVisited[F(curr_neighbor,idx_next)];
  66. bool gotBndEdge = false;
  67. int next_bnd_vertex;
  68. if (!isNextVisited && TT(curr_neighbor,idx_lastV_in_face) < 0)
  69. {
  70. next_bnd_vertex = idx_next;
  71. gotBndEdge = true;
  72. }
  73. else if (!isPrevVisited && TT(curr_neighbor,(idx_lastV_in_face+2) % F.cols()) < 0)
  74. {
  75. next_bnd_vertex = idx_prev;
  76. gotBndEdge = true;
  77. }
  78. if (gotBndEdge)
  79. {
  80. changed = true;
  81. bnd.push_back(F(curr_neighbor,next_bnd_vertex));
  82. isVisited[F(curr_neighbor,next_bnd_vertex)] = true;
  83. break;
  84. }
  85. }
  86. }
  87. if (!changed)
  88. break;
  89. }
  90. b.resize(bnd.size());
  91. for(unsigned i=0;i<bnd.size();++i)
  92. b(i) = bnd[i];
  93. }