cut_mesh.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2016 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 <igl/cut_mesh.h>
  9. #include <igl/vertex_triangle_adjacency.h>
  10. #include <igl/triangle_triangle_adjacency.h>
  11. #include <igl/is_border_vertex.h>
  12. #include <igl/HalfEdgeIterator.h>
  13. #include <set>
  14. // This file violates many of the libigl style guidelines.
  15. namespace igl {
  16. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  17. class MeshCutterMini
  18. {
  19. public:
  20. // Input
  21. //mesh
  22. const Eigen::PlainObjectBase<DerivedV> &V;
  23. const Eigen::PlainObjectBase<DerivedF> &F;
  24. // TT is the same type as TTi? This is likely to break at some point
  25. const Eigen::PlainObjectBase<DerivedTT> &TT;
  26. const Eigen::PlainObjectBase<DerivedTT> &TTi;
  27. const std::vector<std::vector<VFType> >& VF;
  28. const std::vector<std::vector<VFType> >& VFi;
  29. const std::vector<bool> &V_border; // bool
  30. //edges to cut
  31. const Eigen::PlainObjectBase<DerivedC> &Handle_Seams; // 3 bool
  32. // total number of scalar variables
  33. int num_scalar_variables;
  34. // per face indexes of vertex in the solver
  35. DerivedF HandleS_Index;
  36. // per vertex variable indexes
  37. std::vector<std::vector<int> > HandleV_Integer;
  38. IGL_INLINE MeshCutterMini(
  39. const Eigen::PlainObjectBase<DerivedV> &_V,
  40. const Eigen::PlainObjectBase<DerivedF> &_F,
  41. const Eigen::PlainObjectBase<DerivedTT> &_TT,
  42. const Eigen::PlainObjectBase<DerivedTT> &_TTi,
  43. const std::vector<std::vector<VFType> > &_VF,
  44. const std::vector<std::vector<VFType> > &_VFi,
  45. const std::vector<bool> &_V_border,
  46. const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams);
  47. // vertex to variable mapping
  48. // initialize the mapping for a given sampled mesh
  49. IGL_INLINE void InitMappingSeam();
  50. private:
  51. IGL_INLINE void FirstPos(const int v, int &f, int &edge);
  52. IGL_INLINE int AddNewIndex(const int v0);
  53. IGL_INLINE bool IsSeam(const int f0, const int f1);
  54. // find initial position of the pos to
  55. // assing face to vert inxex correctly
  56. IGL_INLINE void FindInitialPos(const int vert, int &edge, int &face);
  57. // initialize the mapping given an initial pos
  58. // whih must be initialized with FindInitialPos
  59. IGL_INLINE void MapIndexes(const int vert, const int edge_init, const int f_init);
  60. // initialize the mapping for a given vertex
  61. IGL_INLINE void InitMappingSeam(const int vert);
  62. };
  63. }
  64. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  65. IGL_INLINE igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
  66. MeshCutterMini(
  67. const Eigen::PlainObjectBase<DerivedV> &_V,
  68. const Eigen::PlainObjectBase<DerivedF> &_F,
  69. const Eigen::PlainObjectBase<DerivedTT> &_TT,
  70. const Eigen::PlainObjectBase<DerivedTT> &_TTi,
  71. const std::vector<std::vector<VFType> > &_VF,
  72. const std::vector<std::vector<VFType> > &_VFi,
  73. const std::vector<bool> &_V_border,
  74. const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams):
  75. V(_V),
  76. F(_F),
  77. TT(_TT),
  78. TTi(_TTi),
  79. VF(_VF),
  80. VFi(_VFi),
  81. V_border(_V_border),
  82. Handle_Seams(_Handle_Seams)
  83. {
  84. num_scalar_variables=0;
  85. HandleS_Index.setConstant(F.rows(),3,-1);
  86. HandleV_Integer.resize(V.rows());
  87. }
  88. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  89. IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
  90. FirstPos(const int v, int &f, int &edge)
  91. {
  92. f = VF[v][0]; // f=v->cVFp();
  93. edge = VFi[v][0]; // edge=v->cVFi();
  94. }
  95. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  96. IGL_INLINE int igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
  97. AddNewIndex(const int v0)
  98. {
  99. num_scalar_variables++;
  100. HandleV_Integer[v0].push_back(num_scalar_variables);
  101. return num_scalar_variables;
  102. }
  103. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  104. IGL_INLINE bool igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
  105. IsSeam(const int f0, const int f1)
  106. {
  107. for (int i=0;i<3;i++)
  108. {
  109. int f_clos = TT(f0,i);
  110. if (f_clos == -1)
  111. continue; ///border
  112. if (f_clos == f1)
  113. return(Handle_Seams(f0,i));
  114. }
  115. assert(0);
  116. return false;
  117. }
  118. ///find initial position of the pos to
  119. // assing face to vert inxex correctly
  120. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  121. IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
  122. FindInitialPos(const int vert,
  123. int &edge,
  124. int &face)
  125. {
  126. int f_init;
  127. int edge_init;
  128. FirstPos(vert,f_init,edge_init); // todo manually the function
  129. igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,edge_init);
  130. bool vertexB = V_border[vert];
  131. bool possible_split=false;
  132. bool complete_turn=false;
  133. do
  134. {
  135. int curr_f = VFI.Fi();
  136. int curr_edge=VFI.Ei();
  137. VFI.NextFE();
  138. int next_f=VFI.Fi();
  139. ///test if I've just crossed a border
  140. bool on_border=(TT(curr_f,curr_edge)==-1);
  141. //bool mismatch=false;
  142. bool seam=false;
  143. ///or if I've just crossed a seam
  144. ///if I'm on a border I MUST start from the one next t othe border
  145. if (!vertexB)
  146. //seam=curr_f->IsSeam(next_f);
  147. seam=IsSeam(curr_f,next_f);
  148. // if (vertexB)
  149. // assert(!Handle_Singular(vert));
  150. // ;
  151. //assert(!vert->IsSingular());
  152. possible_split=((on_border)||(seam));
  153. complete_turn = next_f == f_init;
  154. } while ((!possible_split)&&(!complete_turn));
  155. face=VFI.Fi();
  156. edge=VFI.Ei();
  157. }
  158. ///initialize the mapping given an initial pos
  159. ///whih must be initialized with FindInitialPos
  160. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  161. IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
  162. MapIndexes(const int vert,
  163. const int edge_init,
  164. const int f_init)
  165. {
  166. ///check that is not on border..
  167. ///in such case maybe it's non manyfold
  168. ///insert an initial index
  169. int curr_index=AddNewIndex(vert);
  170. ///and initialize the jumping pos
  171. igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,edge_init);
  172. bool complete_turn=false;
  173. do
  174. {
  175. int curr_f = VFI.Fi();
  176. int curr_edge = VFI.Ei();
  177. ///assing the current index
  178. HandleS_Index(curr_f,curr_edge) = curr_index;
  179. VFI.NextFE();
  180. int next_f = VFI.Fi();
  181. ///test if I've finiseh with the face exploration
  182. complete_turn = (next_f==f_init);
  183. ///or if I've just crossed a mismatch
  184. if (!complete_turn)
  185. {
  186. bool seam=false;
  187. //seam=curr_f->IsSeam(next_f);
  188. seam=IsSeam(curr_f,next_f);
  189. if (seam)
  190. {
  191. ///then add a new index
  192. curr_index=AddNewIndex(vert);
  193. }
  194. }
  195. } while (!complete_turn);
  196. }
  197. ///initialize the mapping for a given vertex
  198. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  199. IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
  200. InitMappingSeam(const int vert)
  201. {
  202. ///first rotate until find the first pos after a mismatch
  203. ///or a border or return to the first position...
  204. int f_init = VF[vert][0];
  205. int indexE = VFi[vert][0];
  206. igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,indexE);
  207. int edge_init;
  208. int face_init;
  209. FindInitialPos(vert,edge_init,face_init);
  210. MapIndexes(vert,edge_init,face_init);
  211. }
  212. ///vertex to variable mapping
  213. ///initialize the mapping for a given sampled mesh
  214. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  215. IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
  216. InitMappingSeam()
  217. {
  218. num_scalar_variables=-1;
  219. for (unsigned int i=0;i<V.rows();i++)
  220. InitMappingSeam(i);
  221. for (unsigned int j=0;j<V.rows();j++)
  222. assert(HandleV_Integer[j].size()>0);
  223. }
  224. template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
  225. IGL_INLINE void igl::cut_mesh(
  226. const Eigen::PlainObjectBase<DerivedV> &V,
  227. const Eigen::PlainObjectBase<DerivedF> &F,
  228. const std::vector<std::vector<VFType> >& VF,
  229. const std::vector<std::vector<VFType> >& VFi,
  230. const Eigen::PlainObjectBase<DerivedTT>& TT,
  231. const Eigen::PlainObjectBase<DerivedTT>& TTi,
  232. const std::vector<bool> &V_border,
  233. const Eigen::PlainObjectBase<DerivedC> &cuts,
  234. Eigen::PlainObjectBase<DerivedV> &Vcut,
  235. Eigen::PlainObjectBase<DerivedF> &Fcut)
  236. {
  237. //finding the cuts is done, now we need to actually generate a cut mesh
  238. igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC> mc(V, F, TT, TTi, VF, VFi, V_border, cuts);
  239. mc.InitMappingSeam();
  240. Fcut = mc.HandleS_Index;
  241. //we have the faces, we need the vertices;
  242. int newNumV = Fcut.maxCoeff()+1;
  243. Vcut.setZero(newNumV,3);
  244. for (int vi=0; vi<V.rows(); ++vi)
  245. for (int i=0; i<mc.HandleV_Integer[vi].size();++i)
  246. Vcut.row(mc.HandleV_Integer[vi][i]) = V.row(vi);
  247. //ugly hack to fix some problematic cases (border vertex that is also on the boundary of the hole
  248. for (int fi =0; fi<Fcut.rows(); ++fi)
  249. for (int k=0; k<3; ++k)
  250. if (Fcut(fi,k)==-1)
  251. {
  252. //we need to add a vertex
  253. Fcut(fi,k) = newNumV;
  254. newNumV ++;
  255. Vcut.conservativeResize(newNumV, Eigen::NoChange);
  256. Vcut.row(newNumV-1) = V.row(F(fi,k));
  257. }
  258. }
  259. //Wrapper of the above with only vertices and faces as mesh input
  260. template <typename DerivedV, typename DerivedF, typename DerivedC>
  261. IGL_INLINE void igl::cut_mesh(
  262. const Eigen::PlainObjectBase<DerivedV> &V,
  263. const Eigen::PlainObjectBase<DerivedF> &F,
  264. const Eigen::PlainObjectBase<DerivedC> &cuts,
  265. Eigen::PlainObjectBase<DerivedV> &Vcut,
  266. Eigen::PlainObjectBase<DerivedF> &Fcut)
  267. {
  268. std::vector<std::vector<int> > VF, VFi;
  269. igl::vertex_triangle_adjacency(V,F,VF,VFi);
  270. // Alec: Cast? Why? This is likely to break.
  271. Eigen::MatrixXd Vt = V;
  272. Eigen::MatrixXi Ft = F;
  273. Eigen::MatrixXi TT, TTi;
  274. igl::triangle_triangle_adjacency(Ft,TT,TTi);
  275. std::vector<bool> V_border = igl::is_border_vertex(V,F);
  276. igl::cut_mesh(V, F, VF, VFi, TT, TTi, V_border, cuts, Vcut, Fcut);
  277. }
  278. #ifdef IGL_STATIC_LIBRARY
  279. // Explicit template instantiation
  280. template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -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&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<bool, std::allocator<bool> > 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> >&);
  281. template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -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<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> >&);
  282. template void igl::cut_mesh<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -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::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
  283. template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(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<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
  284. #endif