outer_hull.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #include "outer_hull.h"
  2. #include "outer_facet.h"
  3. #include "facet_components.h"
  4. #include "winding_number.h"
  5. #include "triangle_triangle_adjacency.h"
  6. #include "unique_edge_map.h"
  7. #include "barycenter.h"
  8. #include "per_face_normals.h"
  9. #include "all_edges.h"
  10. #include "colon.h"
  11. #include "get_seconds.h"
  12. #include <Eigen/Geometry>
  13. #include <vector>
  14. #include <map>
  15. #include <queue>
  16. #include <iostream>
  17. template <
  18. typename DerivedV,
  19. typename DerivedF,
  20. typename DerivedG,
  21. typename DerivedJ,
  22. typename Derivedflip>
  23. IGL_INLINE void igl::outer_hull(
  24. const Eigen::PlainObjectBase<DerivedV> & V,
  25. const Eigen::PlainObjectBase<DerivedF> & F,
  26. Eigen::PlainObjectBase<DerivedG> & G,
  27. Eigen::PlainObjectBase<DerivedJ> & J,
  28. Eigen::PlainObjectBase<Derivedflip> & flip)
  29. {
  30. using namespace Eigen;
  31. using namespace std;
  32. using namespace igl;
  33. typedef typename DerivedF::Index Index;
  34. Matrix<Index,DerivedF::RowsAtCompileTime,1> C;
  35. typedef Matrix<typename DerivedV::Scalar,Dynamic,DerivedV::ColsAtCompileTime> MatrixXV;
  36. typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
  37. typedef Matrix<typename DerivedG::Scalar,Dynamic,DerivedG::ColsAtCompileTime> MatrixXG;
  38. typedef Matrix<typename DerivedJ::Scalar,Dynamic,DerivedJ::ColsAtCompileTime> MatrixXJ;
  39. const Index m = F.rows();
  40. typedef Matrix<typename DerivedF::Scalar,Dynamic,2> MatrixX2I;
  41. typedef Matrix<typename DerivedF::Index,Dynamic,1> VectorXI;
  42. MatrixX2I E,uE;
  43. VectorXI EMAP;
  44. vector<vector<typename DerivedF::Index> > uE2E;
  45. unique_edge_map(F,E,uE,EMAP,uE2E);
  46. vector<vector<vector<Index > > > TT,_1;
  47. triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
  48. VectorXI counts;
  49. facet_components(TT,C,counts);
  50. assert(C.maxCoeff()+1 == counts.rows());
  51. const size_t ncc = counts.rows();
  52. G.resize(0,F.cols());
  53. J.resize(0,1);
  54. flip.setConstant(m,1,false);
  55. // precompute face normals
  56. typename Eigen::Matrix<
  57. typename DerivedV::Scalar,
  58. DerivedF::RowsAtCompileTime,
  59. 3> N;
  60. per_face_normals(V,F,N);
  61. // H contains list of faces on outer hull;
  62. vector<bool> FH(m,false);
  63. vector<bool> EH(3*m,false);
  64. vector<MatrixXG> vG(ncc);
  65. vector<MatrixXJ> vJ(ncc);
  66. vector<MatrixXJ> vIM(ncc);
  67. for(size_t id = 0;id<ncc;id++)
  68. {
  69. vIM[id].resize(counts[id],1);
  70. }
  71. // current index into each IM
  72. vector<size_t> g(ncc,0);
  73. // place order of each face in its respective component
  74. for(Index f = 0;f<m;f++)
  75. {
  76. vIM[C(f)](g[C(f)]++) = f;
  77. }
  78. // assumes that "resolve" has handled any coplanar cases correctly and nearly
  79. // coplanar cases can be sorted based on barycenter.
  80. MatrixXV BC;
  81. barycenter(V,F,BC);
  82. for(Index id = 0;id<(Index)ncc;id++)
  83. {
  84. auto & IM = vIM[id];
  85. // starting face that's guaranteed to be on the outer hull and in this
  86. // component
  87. int f;
  88. bool f_flip;
  89. outer_facet(V,F,N,IM,f,f_flip);
  90. int FHcount = 0;
  91. // Q contains list of face edges to continue traversing upong
  92. queue<int> Q;
  93. Q.push(f+0*m);
  94. Q.push(f+1*m);
  95. Q.push(f+2*m);
  96. flip[f] = f_flip;
  97. while(!Q.empty())
  98. {
  99. // face-edge
  100. const int e = Q.front();
  101. Q.pop();
  102. // face
  103. const int f = e%m;
  104. // corner
  105. const int c = e/m;
  106. // Should never see edge again...
  107. if(EH[e] == true)
  108. {
  109. continue;
  110. }
  111. EH[e] = true;
  112. // first time seeing face
  113. if(!FH[f])
  114. {
  115. FH[f] = true;
  116. FHcount++;
  117. }
  118. // find overlapping face-edges
  119. const auto & neighbors = uE2E[EMAP(e)];
  120. const auto & fN = (flip[f]?-1.:1.)*N.row(f);
  121. // source of edge according to f
  122. const int fs = flip[f]?F(f,(c+2)%3):F(f,(c+1)%3);
  123. // destination of edge according to f
  124. const int fd = flip[f]?F(f,(c+1)%3):F(f,(c+2)%3);
  125. const auto & eV = (V.row(fd)-V.row(fs)).normalized();
  126. // Loop over and find max dihedral angle
  127. typename DerivedV::Scalar max_di = -1;
  128. int max_ne = -1;
  129. typename Eigen::Matrix< typename DerivedV::Scalar, 1, 3> max_nN;
  130. for(const auto & ne : neighbors)
  131. {
  132. const int nf = ne%m;
  133. if(nf == f)
  134. {
  135. continue;
  136. }
  137. const int nc = ne/m;
  138. // are faces consistently oriented
  139. //const int ns = F(nf,(nc+1)%3);
  140. const int nd = F(nf,(nc+2)%3);
  141. const bool cons = (flip[f]?fd:fs) == nd;
  142. const auto & nN = (cons? (flip[f]?-1:1.) : (flip[f]?1.:-1.) )*N.row(nf);
  143. const auto & ndi = M_PI - atan2( fN.cross(nN).dot(eV), fN.dot(nN));
  144. if(ndi>=max_di)
  145. {
  146. max_ne = ne;
  147. max_di = ndi;
  148. max_nN = nN;
  149. }
  150. }
  151. if(max_ne>=0)
  152. {
  153. const int nf = max_ne%m;
  154. const int nc = max_ne/m;
  155. const int nd = F(nf,(nc+2)%3);
  156. const bool cons = (flip[f]?fd:fs) == nd;
  157. flip[nf] = (cons ? flip[f] : !flip[f]);
  158. const int ne1 = nf+((nc+1)%3)*m;
  159. const int ne2 = nf+((nc+2)%3)*m;
  160. if(!EH[ne1])
  161. {
  162. Q.push(ne1);
  163. }
  164. if(!EH[ne2])
  165. {
  166. Q.push(ne2);
  167. }
  168. }
  169. }
  170. {
  171. vG[id].resize(FHcount,3);
  172. vJ[id].resize(FHcount,1);
  173. //nG += FHcount;
  174. size_t h = 0;
  175. assert(counts(id) == IM.rows());
  176. for(int i = 0;i<counts(id);i++)
  177. {
  178. const size_t f = IM(i);
  179. //if(f_flip)
  180. //{
  181. // flip[f] = !flip[f];
  182. //}
  183. if(FH[f])
  184. {
  185. vG[id].row(h) = (flip[f]?F.row(f).reverse().eval():F.row(f));
  186. vJ[id](h,0) = f;
  187. h++;
  188. }
  189. }
  190. assert(h == FHcount);
  191. }
  192. }
  193. // Is A inside B? Assuming A and B are consistently oriented but closed and
  194. // non-intersecting.
  195. const auto & is_component_inside_other = [](
  196. const Eigen::PlainObjectBase<DerivedV> & V,
  197. const MatrixXV & BC,
  198. const MatrixXG & A,
  199. const MatrixXJ & AJ,
  200. const MatrixXG & B)->bool
  201. {
  202. const auto & bounding_box = [](
  203. const Eigen::PlainObjectBase<DerivedV> & V,
  204. const MatrixXG & F)->
  205. MatrixXV
  206. {
  207. MatrixXV BB(2,3);
  208. BB<<
  209. 1e26,1e26,1e26,
  210. -1e26,-1e26,-1e26;
  211. const size_t m = F.rows();
  212. for(size_t f = 0;f<m;f++)
  213. {
  214. for(size_t c = 0;c<3;c++)
  215. {
  216. const auto & vfc = V.row(F(f,c));
  217. BB.row(0) = BB.row(0).array().min(vfc.array()).eval();
  218. BB.row(1) = BB.row(1).array().max(vfc.array()).eval();
  219. }
  220. }
  221. return BB;
  222. };
  223. // A lot of the time we're dealing with unrelated, distant components: cull
  224. // them.
  225. MatrixXV ABB = bounding_box(V,A);
  226. MatrixXV BBB = bounding_box(V,B);
  227. if( (BBB.row(0)-ABB.row(1)).maxCoeff()>0 ||
  228. (ABB.row(0)-BBB.row(1)).maxCoeff()>0 )
  229. {
  230. // bounding boxes do not overlap
  231. return false;
  232. }
  233. ////////////////////////////////////////////////////////////////////////
  234. // POTENTIAL ROBUSTNESS WEAK AREA
  235. ////////////////////////////////////////////////////////////////////////
  236. //
  237. // q could be so close (<~1e-16) to B that the winding number is not a robust way to
  238. // determine inside/outsideness. We could try to find a _better_ q which is
  239. // farther away, but couldn't they all be bad?
  240. MatrixXV q = BC.row(AJ(1));
  241. // In a perfect world, it's enough to test a single point.
  242. double w;
  243. winding_number_3(
  244. V.data(),V.rows(),
  245. B.data(),B.rows(),
  246. q.data(),1,&w);
  247. return fabs(w)>0.5;
  248. };
  249. // Reject components which are completely inside other components
  250. vector<bool> keep(ncc,true);
  251. size_t nG = 0;
  252. // This is O( ncc * ncc * m)
  253. for(size_t id = 0;id<ncc;id++)
  254. {
  255. for(size_t oid = 0;oid<ncc;oid++)
  256. {
  257. if(id == oid)
  258. {
  259. continue;
  260. }
  261. keep[id] = keep[id] &&
  262. !is_component_inside_other(V,BC,vG[id],vJ[id],vG[oid]);
  263. }
  264. if(keep[id])
  265. {
  266. nG += vJ[id].rows();
  267. }
  268. }
  269. // collect G and J across components
  270. G.resize(nG,3);
  271. J.resize(nG,1);
  272. {
  273. size_t off = 0;
  274. for(Index id = 0;id<(Index)ncc;id++)
  275. {
  276. if(keep[id])
  277. {
  278. assert(vG[id].rows() == vJ[id].rows());
  279. G.block(off,0,vG[id].rows(),vG[id].cols()) = vG[id];
  280. J.block(off,0,vJ[id].rows(),vJ[id].cols()) = vJ[id];
  281. off += vG[id].rows();
  282. }
  283. }
  284. }
  285. }
  286. #ifdef IGL_STATIC_LIBRARY
  287. // Explicit template specialization
  288. template void igl::outer_hull<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::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(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> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
  289. #endif