outer_hull.cpp 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199
  1. #include "outer_hull.h"
  2. #include "outer_facet.h"
  3. #include "sortrows.h"
  4. #include "facet_components.h"
  5. #include "winding_number.h"
  6. #include "triangle_triangle_adjacency.h"
  7. #include "unique_edge_map.h"
  8. #include "barycenter.h"
  9. #include "per_face_normals.h"
  10. #include "writePLY.h"
  11. #include "sort_angles.h"
  12. #include <Eigen/Geometry>
  13. #include <vector>
  14. #include <map>
  15. #include <queue>
  16. #include <iostream>
  17. #include <CGAL/number_utils.h>
  18. //#define IGL_OUTER_HULL_DEBUG
  19. template <
  20. typename DerivedV,
  21. typename DerivedF,
  22. typename DerivedN,
  23. typename DerivedG,
  24. typename DerivedJ,
  25. typename Derivedflip>
  26. IGL_INLINE void igl::outer_hull(
  27. const Eigen::PlainObjectBase<DerivedV> & V,
  28. const Eigen::PlainObjectBase<DerivedF> & F,
  29. const Eigen::PlainObjectBase<DerivedN> & N,
  30. Eigen::PlainObjectBase<DerivedG> & G,
  31. Eigen::PlainObjectBase<DerivedJ> & J,
  32. Eigen::PlainObjectBase<Derivedflip> & flip)
  33. {
  34. std::cout.precision(20);
  35. //for (size_t i=0; i<V.rows(); i++) {
  36. // std::cout << "v " << V.row(i) << std::endl;
  37. //}
  38. #ifdef IGL_OUTER_HULL_DEBUG
  39. std::cerr << "Extracting outer hull" << std::endl;
  40. writePLY("outer_hull_input.ply", V, F);
  41. #endif
  42. using namespace Eigen;
  43. using namespace std;
  44. typedef typename DerivedF::Index Index;
  45. Matrix<Index,DerivedF::RowsAtCompileTime,1> C;
  46. typedef Matrix<typename DerivedV::Scalar,Dynamic,DerivedV::ColsAtCompileTime> MatrixXV;
  47. typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
  48. typedef Matrix<typename DerivedG::Scalar,Dynamic,DerivedG::ColsAtCompileTime> MatrixXG;
  49. typedef Matrix<typename DerivedJ::Scalar,Dynamic,DerivedJ::ColsAtCompileTime> MatrixXJ;
  50. typedef Matrix<typename DerivedN::Scalar,1,3> RowVector3N;
  51. const Index m = F.rows();
  52. const auto & duplicate_simplex = [&F](const int f, const int g)->bool
  53. {
  54. return
  55. (F(f,0) == F(g,0) && F(f,1) == F(g,1) && F(f,2) == F(g,2)) ||
  56. (F(f,1) == F(g,0) && F(f,2) == F(g,1) && F(f,0) == F(g,2)) ||
  57. (F(f,2) == F(g,0) && F(f,0) == F(g,1) && F(f,1) == F(g,2)) ||
  58. (F(f,0) == F(g,2) && F(f,1) == F(g,1) && F(f,2) == F(g,0)) ||
  59. (F(f,1) == F(g,2) && F(f,2) == F(g,1) && F(f,0) == F(g,0)) ||
  60. (F(f,2) == F(g,2) && F(f,0) == F(g,1) && F(f,1) == F(g,0));
  61. };
  62. #ifdef IGL_OUTER_HULL_DEBUG
  63. cout<<"outer hull..."<<endl;
  64. #endif
  65. #ifdef IGL_OUTER_HULL_DEBUG
  66. cout<<"edge map..."<<endl;
  67. #endif
  68. typedef Matrix<typename DerivedF::Scalar,Dynamic,2> MatrixX2I;
  69. typedef Matrix<typename DerivedF::Index,Dynamic,1> VectorXI;
  70. typedef Matrix<typename DerivedV::Scalar, 3, 1> Vector3F;
  71. MatrixX2I E,uE;
  72. VectorXI EMAP;
  73. vector<vector<typename DerivedF::Index> > uE2E;
  74. unique_edge_map(F,E,uE,EMAP,uE2E);
  75. #ifdef IGL_OUTER_HULL_DEBUG
  76. for (size_t ui=0; ui<uE.rows(); ui++) {
  77. std::cout << ui << ": " << uE2E[ui].size() << " -- (";
  78. for (size_t i=0; i<uE2E[ui].size(); i++) {
  79. std::cout << uE2E[ui][i] << ", ";
  80. }
  81. std::cout << ")" << std::endl;
  82. }
  83. #endif
  84. // TODO:
  85. // uE --> face-edge index, sorted CCW around edge according to normal
  86. // uE --> sorted order index
  87. // uE --> bool, whether needed to flip face to make "consistent" with unique
  88. // edge
  89. // Place order of each half-edge in its corresponding sorted list around edge
  90. VectorXI diIM(3*m);
  91. // Whether face's edge used for sorting is consistent with unique edge
  92. VectorXI dicons(3*m);
  93. // dihedral angles of faces around edge with face of edge in dicons
  94. vector<vector<typename Eigen::Vector2d> > di(uE2E.size());
  95. // For each list of face-edges incide on a unique edge
  96. for(size_t ui = 0;ui<(size_t)uE.rows();ui++)
  97. {
  98. // Base normal vector to orient against
  99. const auto fe0 = uE2E[ui][0];
  100. const RowVector3N & eVp = N.row(fe0%m);
  101. MatrixXd di_I(uE2E[ui].size(),3);
  102. const typename DerivedF::Scalar o = F(fe0%m, fe0/m);
  103. const typename DerivedF::Scalar d = F(fe0%m,((fe0/m)+2)%3);
  104. const typename DerivedF::Scalar s = F(fe0%m,((fe0/m)+1)%3);
  105. // Edge vector
  106. auto eV = (V.row(d)-V.row(s)).normalized();
  107. auto edge_len = (V.row(d) - V.row(s)).norm();
  108. auto edge_valance = uE2E[ui].size();
  109. auto eO = V.row(o) - V.row(s);
  110. assert(edge_valance % 2 == 0);
  111. const typename DerivedV::Scalar EPS = 1e-12;
  112. bool degenerated = !eV.allFinite() || edge_len < EPS;
  113. bool all_faces_are_degenerated_and_coplanar = false;
  114. #ifdef IGL_OUTER_HULL_DEBUG
  115. if (degenerated && edge_valance > 2) {
  116. cerr.precision(30);
  117. std::cerr << ui << ": " << (V.row(d) - V.row(s)).norm() << std::endl;
  118. std::cerr << "Edge valance: " << edge_valance << std::endl;
  119. std::cerr << V.row(d) << std::endl;
  120. std::cerr << V.row(s) << std::endl;
  121. }
  122. #endif
  123. if (degenerated) {
  124. const size_t num_adj_faces = uE2E[ui].size();
  125. Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3>
  126. normals(num_adj_faces, 3);
  127. for (size_t fei=0; fei<num_adj_faces; fei++) {
  128. const auto & fe = uE2E[ui][fei];
  129. const auto f = fe % m;
  130. const RowVector3N & n = N.row(f);
  131. normals.row(fei) = n;
  132. }
  133. for (size_t i=0; i<num_adj_faces; i++) {
  134. size_t j = (i+1) % num_adj_faces;
  135. eV = normals.row(i).cross(normals.row(j));
  136. auto length = eV.norm();
  137. if (length > 0) {
  138. eV /= length;
  139. break;
  140. }
  141. }
  142. }
  143. if (!eV.allFinite() || eV.norm() < EPS) {
  144. //cerr << "This is bad... all adj face normals are colinear" << std::endl;
  145. eV.setZero();
  146. all_faces_are_degenerated_and_coplanar = true;
  147. }
  148. if (degenerated){
  149. // Adjust edge direction.
  150. Vector3F in_face_vec = V.row(o) - V.row(s);
  151. Vector3F edge = eV;
  152. if (edge.cross(in_face_vec).dot(eVp) < 0) {
  153. #ifdef IGL_OUTER_HULL_DEBUG
  154. cerr << "Flipping edge..." << std::endl;
  155. #endif
  156. eV *= -1;
  157. }
  158. //cerr << "Resolved: " << eV << std::endl;
  159. }
  160. #ifdef IGL_OUTER_HULL_DEBUG
  161. if (degenerated) {
  162. cerr << "eV: " << eV << std::endl;
  163. }
  164. #endif
  165. vector<bool> cons(uE2E[ui].size());
  166. // Loop over incident face edges
  167. for(size_t fei = 0;fei<uE2E[ui].size();fei++)
  168. {
  169. const auto & fe = uE2E[ui][fei];
  170. const auto f = fe % m;
  171. const auto c = fe / m;
  172. // source should match destination to be consistent
  173. cons[fei] = (d == F(f,(c+1)%3));
  174. assert( cons[fei] || (d == F(f,(c+2)%3)));
  175. assert(!cons[fei] || (s == F(f,(c+2)%3)));
  176. assert(!cons[fei] || (d == F(f,(c+1)%3)));
  177. // Angle between n and f
  178. const RowVector3N & n = N.row(f);
  179. #ifdef IGL_OUTER_HULL_DEBUG
  180. if (degenerated)
  181. cerr << "n " << fei << ": " << n << std::endl;
  182. #endif
  183. if (!all_faces_are_degenerated_and_coplanar) {
  184. di_I(fei, 0) = eVp.cross(n).dot(eV);
  185. } else {
  186. auto crossed = eVp.cross(n);
  187. di_I(fei, 0) = crossed.norm();
  188. int sign = eVp.cross(crossed).dot(eO);
  189. if (sign < 0) {
  190. di_I(fei, 0) *= -1;
  191. }
  192. }
  193. di_I(fei, 1) = eVp.dot(n);
  194. assert(di_I(fei,0) == di_I(fei,0) && "NaN Alert!");
  195. assert(di_I(fei,1) == di_I(fei,1) && "NaN Alert!");
  196. if (cons[fei]) {
  197. di_I(fei, 0) *= -1;
  198. di_I(fei, 1) *= -1;
  199. }
  200. di_I(fei, 0) *= -1; // Sort clockwise.
  201. // This signing is very important to make sure different edges sort
  202. // duplicate faces the same way, regardless of their orientations
  203. di_I(fei,2) = (cons[fei]?1.:-1.)*(f+1);
  204. }
  205. #if 0
  206. // Despite the effort to get stable normals the atan2 up doesn't
  207. // compute (exactly) -θ for -n if it computes θ for n. So just
  208. // explicitly check if there's a duplicate face
  209. // Shitty O(val^2) implementation
  210. for(size_t fei = 0;fei<uE2E[ui].size();fei++)
  211. {
  212. const auto & fe = uE2E[ui][fei];
  213. const auto f = fe % m;
  214. for(size_t gei = fei+1;gei<uE2E[ui].size();gei++)
  215. {
  216. const auto & ge = uE2E[ui][gei];
  217. const auto g = ge % m;
  218. if(duplicate_simplex(f,g))
  219. {
  220. #ifdef IGL_OUTER_HULL_DEBUG
  221. cout<<"Forcing duplicate: "<<(f+1)<<","<<(g+1)<<endl;
  222. #endif
  223. di_I(gei,0) = di_I(fei,0);
  224. }
  225. }
  226. }
  227. #endif
  228. VectorXi IM;
  229. //igl::sort(di[ui],true,di[ui],IM);
  230. // Sort, but break ties using "signed index" to ensure that duplicates
  231. // always show up in same order.
  232. igl::sort_angles(di_I, IM);
  233. vector<typename DerivedF::Index> temp = uE2E[ui];
  234. #ifdef IGL_OUTER_HULL_DEBUG
  235. std::cout.precision(20);
  236. //std::cout << "sorted" << std::endl;
  237. #endif
  238. for(size_t fei = 0;fei<uE2E[ui].size();fei++)
  239. {
  240. #ifdef IGL_OUTER_HULL_DEBUG
  241. //std::cout << di_I.row(IM(fei)) << std::endl;
  242. #endif
  243. uE2E[ui][fei] = temp[IM(fei)];
  244. const auto & fe = uE2E[ui][fei];
  245. diIM(fe) = fei;
  246. dicons(fe) = cons[IM(fei)];
  247. }
  248. di[ui].resize(uE2E[ui].size());
  249. for (size_t i=0; i<di[ui].size(); i++) {
  250. di[ui][i] = di_I.row(IM(i)).segment<2>(0);
  251. }
  252. //MatrixXd s_di_I;
  253. //igl::sortrows(di_I,true,s_di_I,IM);
  254. //di[ui].resize(uE2E[ui].size());
  255. //for(size_t i = 0;i<di[ui].size();i++)
  256. //{
  257. // di[ui][i] = s_di_I(i,0);
  258. //}
  259. //// copy old list
  260. //vector<typename DerivedF::Index> temp = uE2E[ui];
  261. //for(size_t fei = 0;fei<uE2E[ui].size();fei++)
  262. //{
  263. // uE2E[ui][fei] = temp[IM(fei)];
  264. // const auto & fe = uE2E[ui][fei];
  265. // diIM(fe) = fei;
  266. // dicons(fe) = cons[IM(fei)];
  267. //}
  268. }
  269. vector<vector<vector<Index > > > TT,_1;
  270. triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
  271. VectorXI counts;
  272. #ifdef IGL_OUTER_HULL_DEBUG
  273. cout<<"facet components..."<<endl;
  274. #endif
  275. facet_components(TT,C,counts);
  276. assert(C.maxCoeff()+1 == counts.rows());
  277. const size_t ncc = counts.rows();
  278. G.resize(0,F.cols());
  279. J.resize(0,1);
  280. flip.setConstant(m,1,false);
  281. #ifdef IGL_OUTER_HULL_DEBUG
  282. cout<<"reindex..."<<endl;
  283. #endif
  284. // H contains list of faces on outer hull;
  285. vector<bool> FH(m,false);
  286. vector<bool> EH(3*m,false);
  287. vector<MatrixXG> vG(ncc);
  288. vector<MatrixXJ> vJ(ncc);
  289. vector<MatrixXJ> vIM(ncc);
  290. size_t face_count = 0;
  291. for(size_t id = 0;id<ncc;id++)
  292. {
  293. vIM[id].resize(counts[id],1);
  294. }
  295. // current index into each IM
  296. vector<size_t> g(ncc,0);
  297. // place order of each face in its respective component
  298. for(Index f = 0;f<m;f++)
  299. {
  300. vIM[C(f)](g[C(f)]++) = f;
  301. }
  302. #ifdef IGL_OUTER_HULL_DEBUG
  303. cout<<"barycenters..."<<endl;
  304. #endif
  305. // assumes that "resolve" has handled any coplanar cases correctly and nearly
  306. // coplanar cases can be sorted based on barycenter.
  307. MatrixXV BC;
  308. barycenter(V,F,BC);
  309. #ifdef IGL_OUTER_HULL_DEBUG
  310. cout<<"loop over CCs (="<<ncc<<")..."<<endl;
  311. #endif
  312. for(Index id = 0;id<(Index)ncc;id++)
  313. {
  314. auto & IM = vIM[id];
  315. // starting face that's guaranteed to be on the outer hull and in this
  316. // component
  317. int f;
  318. bool f_flip;
  319. #ifdef IGL_OUTER_HULL_DEBUG
  320. cout<<"outer facet..."<<endl;
  321. #endif
  322. outer_facet(V,F,N,IM,f,f_flip);
  323. #ifdef IGL_OUTER_HULL_DEBUG
  324. cout<<"outer facet: "<<f<<endl;
  325. cout << V.row(F(f, 0)) << std::endl;
  326. cout << V.row(F(f, 1)) << std::endl;
  327. cout << V.row(F(f, 2)) << std::endl;
  328. #endif
  329. int FHcount = 1;
  330. FH[f] = true;
  331. // Q contains list of face edges to continue traversing upong
  332. queue<int> Q;
  333. Q.push(f+0*m);
  334. Q.push(f+1*m);
  335. Q.push(f+2*m);
  336. flip(f) = f_flip;
  337. //std::cout << "face " << face_count++ << ": " << f << std::endl;
  338. //std::cout << "f " << F.row(f).array()+1 << std::endl;
  339. //cout<<"flip("<<f<<") = "<<(flip(f)?"true":"false")<<endl;
  340. #ifdef IGL_OUTER_HULL_DEBUG
  341. cout<<"BFS..."<<endl;
  342. #endif
  343. while(!Q.empty())
  344. {
  345. // face-edge
  346. const int e = Q.front();
  347. Q.pop();
  348. // face
  349. const int f = e%m;
  350. // corner
  351. const int c = e/m;
  352. #ifdef IGL_OUTER_HULL_DEBUG
  353. std::cout << "edge: " << e << ", ue: " << EMAP(e) << std::endl;
  354. std::cout << "face: " << f << std::endl;
  355. std::cout << "corner: " << c << std::endl;
  356. std::cout << "consistent: " << dicons(e) << std::endl;
  357. #endif
  358. // Should never see edge again...
  359. if(EH[e] == true)
  360. {
  361. continue;
  362. }
  363. EH[e] = true;
  364. // source of edge according to f
  365. const int fs = flip(f)?F(f,(c+2)%3):F(f,(c+1)%3);
  366. // destination of edge according to f
  367. const int fd = flip(f)?F(f,(c+1)%3):F(f,(c+2)%3);
  368. // edge valence
  369. const size_t val = uE2E[EMAP(e)].size();
  370. #ifdef IGL_OUTER_HULL_DEBUG
  371. std::cout << "vd: " << V.row(fd) << std::endl;
  372. std::cout << "vs: " << V.row(fs) << std::endl;
  373. std::cout << "edge: " << V.row(fd) - V.row(fs) << std::endl;
  374. for (size_t i=0; i<val; i++) {
  375. if (i == diIM(e)) {
  376. std::cout << "* ";
  377. } else {
  378. std::cout << " ";
  379. }
  380. std::cout << i << ": " << di[EMAP(e)][i].transpose()
  381. << " (e: " << uE2E[EMAP(e)][i] << ", f: "
  382. << uE2E[EMAP(e)][i] % m * (dicons(uE2E[EMAP(e)][i]) ? 1:-1) << ")" << std::endl;
  383. }
  384. #endif
  385. //// find overlapping face-edges
  386. //const auto & neighbors = uE2E[EMAP(e)];
  387. //// normal after possible flipping
  388. //const auto & fN = (flip(f)?-1.:1.)*N.row(f);
  389. //// Edge vector according to f's (flipped) orientation.
  390. ////const auto & eV = (V.row(fd)-V.row(fs)).normalized();
  391. //#warning "EXPERIMENTAL, DO NOT USE"
  392. //// THIS IS WRONG! The first face is---after sorting---no longer the face
  393. //// used for orienting the sort.
  394. //const auto ui = EMAP(e);
  395. //const auto fe0 = uE2E[ui][0];
  396. //const auto es = F(fe0%m,((fe0/m)+1)%3);
  397. // is edge consistent with edge of face used for sorting
  398. const int e_cons = (dicons(e) ? 1: -1);
  399. int nfei = -1;
  400. // Loop once around trying to find suitable next face
  401. for(size_t step = 1; step<val+2;step++)
  402. {
  403. const int nfei_new = (diIM(e) + 2*val + e_cons*step*(flip(f)?-1:1))%val;
  404. const int nf = uE2E[EMAP(e)][nfei_new] % m;
  405. // Don't consider faces with identical dihedral angles
  406. //if ((di[EMAP(e)][diIM(e)].array() != di[EMAP(e)][nfei_new].array()).any())
  407. //if((di[EMAP(e)][diIM(e)] != di[EMAP(e)][nfei_new]))
  408. //#warning "THIS IS HACK, FIX ME"
  409. // if( abs(di[EMAP(e)][diIM(e)] - di[EMAP(e)][nfei_new]) < 1e-15 )
  410. {
  411. #ifdef IGL_OUTER_HULL_DEBUG
  412. //cout<<"Next facet: "<<(f+1)<<" --> "<<(nf+1)<<", |"<<
  413. // di[EMAP(e)][diIM(e)]<<" - "<<di[EMAP(e)][nfei_new]<<"| = "<<
  414. // abs(di[EMAP(e)][diIM(e)] - di[EMAP(e)][nfei_new])
  415. // <<endl;
  416. #endif
  417. // Only use this face if not already seen
  418. if(!FH[nf])
  419. {
  420. nfei = nfei_new;
  421. //} else {
  422. // std::cout << "skipping face " << nfei_new << " because it is seen before"
  423. // << std::endl;
  424. }
  425. break;
  426. //} else {
  427. // std::cout << di[EMAP(e)][diIM(e)].transpose() << std::endl;
  428. // std::cout << di[EMAP(e)][diIM(nfei_new)].transpose() << std::endl;
  429. // std::cout << "skipping face " << nfei_new << " with identical dihedral angle"
  430. // << std::endl;
  431. }
  432. //#ifdef IGL_OUTER_HULL_DEBUG
  433. // cout<<"Skipping co-planar facet: "<<(f+1)<<" --> "<<(nf+1)<<endl;
  434. //#endif
  435. }
  436. int max_ne = -1;
  437. //// Loop over and find max dihedral angle
  438. //typename DerivedV::Scalar max_di = -1;
  439. //for(const auto & ne : neighbors)
  440. //{
  441. // const int nf = ne%m;
  442. // if(nf == f)
  443. // {
  444. // continue;
  445. // }
  446. // // Corner of neighbor
  447. // const int nc = ne/m;
  448. // // Is neighbor oriented consistently with (flipped) f?
  449. // //const int ns = F(nf,(nc+1)%3);
  450. // const int nd = F(nf,(nc+2)%3);
  451. // const bool cons = (flip(f)?fd:fs) == nd;
  452. // // Normal after possibly flipping to match flip or orientation of f
  453. // const auto & nN = (cons? (flip(f)?-1:1.) : (flip(f)?1.:-1.) )*N.row(nf);
  454. // // Angle between n and f
  455. // const auto & ndi = M_PI - atan2( fN.cross(nN).dot(eV), fN.dot(nN));
  456. // if(ndi>=max_di)
  457. // {
  458. // max_ne = ne;
  459. // max_di = ndi;
  460. // }
  461. //}
  462. ////cout<<(max_ne != max_ne_2)<<" =?= "<<e_cons<<endl;
  463. //if(max_ne != max_ne_2)
  464. //{
  465. // cout<<(f+1)<<" ---> "<<(max_ne%m)+1<<" != "<<(max_ne_2%m)+1<<" ... "<<e_cons<<" "<<flip(f)<<endl;
  466. // typename DerivedV::Scalar max_di = -1;
  467. // for(size_t nei = 0;nei<neighbors.size();nei++)
  468. // {
  469. // const auto & ne = neighbors[nei];
  470. // const int nf = ne%m;
  471. // if(nf == f)
  472. // {
  473. // cout<<" "<<(ne%m)+1<<":\t"<<0<<"\t"<<di[EMAP[e]][nei]<<" "<<diIM(ne)<<endl;
  474. // continue;
  475. // }
  476. // // Corner of neighbor
  477. // const int nc = ne/m;
  478. // // Is neighbor oriented consistently with (flipped) f?
  479. // //const int ns = F(nf,(nc+1)%3);
  480. // const int nd = F(nf,(nc+2)%3);
  481. // const bool cons = (flip(f)?fd:fs) == nd;
  482. // // Normal after possibly flipping to match flip or orientation of f
  483. // const auto & nN = (cons? (flip(f)?-1:1.) : (flip(f)?1.:-1.) )*N.row(nf);
  484. // // Angle between n and f
  485. // const auto & ndi = M_PI - atan2( fN.cross(nN).dot(eV), fN.dot(nN));
  486. // cout<<" "<<(ne%m)+1<<":\t"<<ndi<<"\t"<<di[EMAP[e]][nei]<<" "<<diIM(ne)<<endl;
  487. // if(ndi>=max_di)
  488. // {
  489. // max_ne = ne;
  490. // max_di = ndi;
  491. // }
  492. // }
  493. //}
  494. if(nfei >= 0)
  495. {
  496. max_ne = uE2E[EMAP(e)][nfei];
  497. }
  498. if(max_ne>=0)
  499. {
  500. // face of neighbor
  501. const int nf = max_ne%m;
  502. #ifdef IGL_OUTER_HULL_DEBUG
  503. if(!FH[nf])
  504. {
  505. // first time seeing face
  506. cout<<(f+1)<<" --> "<<(nf+1)<<endl;
  507. }
  508. #endif
  509. FH[nf] = true;
  510. //std::cout << "face " << face_count++ << ": " << nf << std::endl;
  511. //std::cout << "f " << F.row(nf).array()+1 << std::endl;
  512. FHcount++;
  513. // corner of neighbor
  514. const int nc = max_ne/m;
  515. const int nd = F(nf,(nc+2)%3);
  516. const bool cons = (flip(f)?fd:fs) == nd;
  517. flip(nf) = (cons ? flip(f) : !flip(f));
  518. //cout<<"flip("<<nf<<") = "<<(flip(nf)?"true":"false")<<endl;
  519. const int ne1 = nf+((nc+1)%3)*m;
  520. const int ne2 = nf+((nc+2)%3)*m;
  521. if(!EH[ne1])
  522. {
  523. Q.push(ne1);
  524. }
  525. if(!EH[ne2])
  526. {
  527. Q.push(ne2);
  528. }
  529. }
  530. }
  531. {
  532. vG[id].resize(FHcount,3);
  533. vJ[id].resize(FHcount,1);
  534. //nG += FHcount;
  535. size_t h = 0;
  536. assert(counts(id) == IM.rows());
  537. for(int i = 0;i<counts(id);i++)
  538. {
  539. const size_t f = IM(i);
  540. //if(f_flip)
  541. //{
  542. // flip(f) = !flip(f);
  543. //}
  544. if(FH[f])
  545. {
  546. vG[id].row(h) = (flip(f)?F.row(f).reverse().eval():F.row(f));
  547. vJ[id](h,0) = f;
  548. h++;
  549. }
  550. }
  551. assert((int)h == FHcount);
  552. }
  553. }
  554. // Is A inside B? Assuming A and B are consistently oriented but closed and
  555. // non-intersecting.
  556. const auto & is_component_inside_other = [](
  557. const Eigen::PlainObjectBase<DerivedV> & V,
  558. const MatrixXV & BC,
  559. const MatrixXG & A,
  560. const MatrixXJ & AJ,
  561. const MatrixXG & B)->bool
  562. {
  563. const auto & bounding_box = [](
  564. const Eigen::PlainObjectBase<DerivedV> & V,
  565. const MatrixXG & F)->
  566. MatrixXV
  567. {
  568. MatrixXV BB(2,3);
  569. BB<<
  570. 1e26,1e26,1e26,
  571. -1e26,-1e26,-1e26;
  572. const size_t m = F.rows();
  573. for(size_t f = 0;f<m;f++)
  574. {
  575. for(size_t c = 0;c<3;c++)
  576. {
  577. const auto & vfc = V.row(F(f,c));
  578. BB.row(0) = BB.row(0).array().min(vfc.array()).eval();
  579. BB.row(1) = BB.row(1).array().max(vfc.array()).eval();
  580. }
  581. }
  582. return BB;
  583. };
  584. // A lot of the time we're dealing with unrelated, distant components: cull
  585. // them.
  586. MatrixXV ABB = bounding_box(V,A);
  587. MatrixXV BBB = bounding_box(V,B);
  588. if( (BBB.row(0)-ABB.row(1)).maxCoeff()>0 ||
  589. (ABB.row(0)-BBB.row(1)).maxCoeff()>0 )
  590. {
  591. // bounding boxes do not overlap
  592. return false;
  593. }
  594. ////////////////////////////////////////////////////////////////////////
  595. // POTENTIAL ROBUSTNESS WEAK AREA
  596. ////////////////////////////////////////////////////////////////////////
  597. //
  598. // q could be so close (<~1e-15) to B that the winding number is not a robust way to
  599. // determine inside/outsideness. We could try to find a _better_ q which is
  600. // farther away, but couldn't they all be bad?
  601. MatrixXV q = BC.row(AJ(0));
  602. // In a perfect world, it's enough to test a single point.
  603. double w;
  604. // winding_number_3 expects colmajor
  605. const typename DerivedV::Scalar * Vdata;
  606. Vdata = V.data();
  607. Matrix<
  608. typename DerivedV::Scalar,
  609. DerivedV::RowsAtCompileTime,
  610. DerivedV::ColsAtCompileTime,
  611. ColMajor> Vcol;
  612. if(DerivedV::IsRowMajor)
  613. {
  614. // copy to convert to colmajor
  615. Vcol = V;
  616. Vdata = Vcol.data();
  617. }
  618. winding_number_3(
  619. Vdata,V.rows(),
  620. B.data(),B.rows(),
  621. q.data(),1,&w);
  622. return fabs(w)>0.5;
  623. };
  624. // Reject components which are completely inside other components
  625. vector<bool> keep(ncc,true);
  626. size_t nG = 0;
  627. // This is O( ncc * ncc * m)
  628. for(size_t id = 0;id<ncc;id++)
  629. {
  630. for(size_t oid = 0;oid<ncc;oid++)
  631. {
  632. if(id == oid)
  633. {
  634. continue;
  635. }
  636. const bool inside = is_component_inside_other(V,BC,vG[id],vJ[id],vG[oid]);
  637. #ifdef IGL_OUTER_HULL_DEBUG
  638. cout<<id<<" is inside "<<oid<<" ? "<<inside<<endl;
  639. #endif
  640. keep[id] = keep[id] && !inside;
  641. }
  642. if(keep[id])
  643. {
  644. nG += vJ[id].rows();
  645. }
  646. }
  647. // collect G and J across components
  648. G.resize(nG,3);
  649. J.resize(nG,1);
  650. {
  651. size_t off = 0;
  652. for(Index id = 0;id<(Index)ncc;id++)
  653. {
  654. if(keep[id])
  655. {
  656. assert(vG[id].rows() == vJ[id].rows());
  657. G.block(off,0,vG[id].rows(),vG[id].cols()) = vG[id];
  658. J.block(off,0,vJ[id].rows(),vJ[id].cols()) = vJ[id];
  659. off += vG[id].rows();
  660. }
  661. }
  662. }
  663. }
  664. template <
  665. typename DerivedV,
  666. typename DerivedF,
  667. typename DerivedG,
  668. typename DerivedJ,
  669. typename Derivedflip>
  670. IGL_INLINE void igl::outer_hull(
  671. const Eigen::PlainObjectBase<DerivedV> & V,
  672. const Eigen::PlainObjectBase<DerivedF> & F,
  673. Eigen::PlainObjectBase<DerivedG> & G,
  674. Eigen::PlainObjectBase<DerivedJ> & J,
  675. Eigen::PlainObjectBase<Derivedflip> & flip)
  676. {
  677. Eigen::Matrix<typename DerivedV::Scalar,DerivedF::RowsAtCompileTime,3> N;
  678. per_face_normals_stable(V,F,N);
  679. return outer_hull(V,F,N,G,J,flip);
  680. }
  681. template <
  682. typename Kernel,
  683. typename DerivedV,
  684. typename DerivedF,
  685. typename DerivedN,
  686. typename DerivedG,
  687. typename DerivedJ,
  688. typename Derivedflip>
  689. IGL_INLINE void igl::outer_hull_exact(
  690. const Eigen::PlainObjectBase<DerivedV> & V,
  691. const Eigen::PlainObjectBase<DerivedF> & F,
  692. const Eigen::PlainObjectBase<DerivedN> & N,
  693. Eigen::PlainObjectBase<DerivedG> & G,
  694. Eigen::PlainObjectBase<DerivedJ> & J,
  695. Eigen::PlainObjectBase<Derivedflip> & flip)
  696. {
  697. std::cout.precision(20);
  698. //for (size_t i=0; i<V.rows(); i++) {
  699. // std::cout << "v " << V.row(i) << std::endl;
  700. //}
  701. #ifdef IGL_OUTER_HULL_DEBUG
  702. std::cerr << "Extracting outer hull" << std::endl;
  703. writePLY("outer_hull_input.ply", V, F);
  704. #endif
  705. using namespace Eigen;
  706. using namespace std;
  707. typedef typename DerivedF::Index Index;
  708. Matrix<Index,DerivedF::RowsAtCompileTime,1> C;
  709. typedef Matrix<typename DerivedV::Scalar,Dynamic,DerivedV::ColsAtCompileTime> MatrixXV;
  710. typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
  711. typedef Matrix<typename DerivedG::Scalar,Dynamic,DerivedG::ColsAtCompileTime> MatrixXG;
  712. typedef Matrix<typename DerivedJ::Scalar,Dynamic,DerivedJ::ColsAtCompileTime> MatrixXJ;
  713. typedef Matrix<typename DerivedN::Scalar,1,3> RowVector3N;
  714. const Index m = F.rows();
  715. const auto & duplicate_simplex = [&F](const int f, const int g)->bool
  716. {
  717. return
  718. (F(f,0) == F(g,0) && F(f,1) == F(g,1) && F(f,2) == F(g,2)) ||
  719. (F(f,1) == F(g,0) && F(f,2) == F(g,1) && F(f,0) == F(g,2)) ||
  720. (F(f,2) == F(g,0) && F(f,0) == F(g,1) && F(f,1) == F(g,2)) ||
  721. (F(f,0) == F(g,2) && F(f,1) == F(g,1) && F(f,2) == F(g,0)) ||
  722. (F(f,1) == F(g,2) && F(f,2) == F(g,1) && F(f,0) == F(g,0)) ||
  723. (F(f,2) == F(g,2) && F(f,0) == F(g,1) && F(f,1) == F(g,0));
  724. };
  725. #ifdef IGL_OUTER_HULL_DEBUG
  726. cout<<"outer hull..."<<endl;
  727. #endif
  728. #ifdef IGL_OUTER_HULL_DEBUG
  729. cout<<"edge map..."<<endl;
  730. #endif
  731. typedef Matrix<typename DerivedF::Scalar,Dynamic,2> MatrixX2I;
  732. typedef Matrix<typename DerivedF::Index,Dynamic,1> VectorXI;
  733. typedef Matrix<typename DerivedV::Scalar, 3, 1> Vector3F;
  734. MatrixX2I E,uE;
  735. VectorXI EMAP;
  736. vector<vector<typename DerivedF::Index> > uE2E;
  737. unique_edge_map(F,E,uE,EMAP,uE2E);
  738. #ifdef IGL_OUTER_HULL_DEBUG
  739. for (size_t ui=0; ui<uE.rows(); ui++) {
  740. std::cout << ui << ": " << uE2E[ui].size() << " -- (";
  741. for (size_t i=0; i<uE2E[ui].size(); i++) {
  742. std::cout << uE2E[ui][i] << ", ";
  743. }
  744. std::cout << ")" << std::endl;
  745. }
  746. #endif
  747. // TODO:
  748. // uE --> face-edge index, sorted CCW around edge according to normal
  749. // uE --> sorted order index
  750. // uE --> bool, whether needed to flip face to make "consistent" with unique
  751. // edge
  752. // Place order of each half-edge in its corresponding sorted list around edge
  753. VectorXI diIM(3*m);
  754. // Whether face's edge used for sorting is consistent with unique edge
  755. VectorXI dicons(3*m);
  756. // dihedral angles of faces around edge with face of edge in dicons
  757. vector<vector<typename Eigen::Vector2d> > di(uE2E.size());
  758. // For each list of face-edges incide on a unique edge
  759. for(size_t ui = 0;ui<(size_t)uE.rows();ui++)
  760. {
  761. // Base normal vector to orient against
  762. const auto fe0 = uE2E[ui][0];
  763. const RowVector3N & eVp = N.row(fe0%m);
  764. MatrixXd di_I(uE2E[ui].size(),3);
  765. const typename DerivedF::Scalar o = F(fe0%m, fe0/m);
  766. const typename DerivedF::Scalar d = F(fe0%m,((fe0/m)+2)%3);
  767. const typename DerivedF::Scalar s = F(fe0%m,((fe0/m)+1)%3);
  768. // Edge vector
  769. typename Kernel::Vector_3 exact_eV(
  770. V(d, 0) - V(s, 0),
  771. V(d, 1) - V(s, 1),
  772. V(d, 2) - V(s, 2));
  773. auto sq_length = exact_eV.squared_length();
  774. if (sq_length > 0.0) {
  775. exact_eV = exact_eV / sq_length;
  776. }
  777. RowVector3N eV(
  778. CGAL::to_double(exact_eV[0]),
  779. CGAL::to_double(exact_eV[1]),
  780. CGAL::to_double(exact_eV[2]));
  781. if (sq_length > 0.0) {
  782. eV.normalize();
  783. }
  784. vector<bool> cons(uE2E[ui].size());
  785. // Loop over incident face edges
  786. for(size_t fei = 0;fei<uE2E[ui].size();fei++)
  787. {
  788. const auto & fe = uE2E[ui][fei];
  789. const auto f = fe % m;
  790. const auto c = fe / m;
  791. // source should match destination to be consistent
  792. cons[fei] = (d == F(f,(c+1)%3));
  793. assert( cons[fei] || (d == F(f,(c+2)%3)));
  794. assert(!cons[fei] || (s == F(f,(c+2)%3)));
  795. assert(!cons[fei] || (d == F(f,(c+1)%3)));
  796. // Angle between n and f
  797. const RowVector3N & n = N.row(f);
  798. di_I(fei, 0) = eVp.cross(n).dot(eV);
  799. di_I(fei, 1) = eVp.dot(n);
  800. assert(di_I(fei,0) == di_I(fei,0) && "NaN Alert!");
  801. assert(di_I(fei,1) == di_I(fei,1) && "NaN Alert!");
  802. if (cons[fei]) {
  803. di_I(fei, 0) *= -1;
  804. di_I(fei, 1) *= -1;
  805. }
  806. di_I(fei, 0) *= -1; // Sort clockwise.
  807. // This signing is very important to make sure different edges sort
  808. // duplicate faces the same way, regardless of their orientations
  809. di_I(fei,2) = (cons[fei]?1.:-1.)*(f+1);
  810. }
  811. VectorXi IM;
  812. // Sort, but break ties using "signed index" to ensure that duplicates
  813. // always show up in same order.
  814. igl::sort_angles(di_I, IM);
  815. vector<typename DerivedF::Index> temp = uE2E[ui];
  816. #ifdef IGL_OUTER_HULL_DEBUG
  817. std::cout.precision(20);
  818. //std::cout << "sorted" << std::endl;
  819. #endif
  820. for(size_t fei = 0;fei<uE2E[ui].size();fei++)
  821. {
  822. #ifdef IGL_OUTER_HULL_DEBUG
  823. //std::cout << di_I.row(IM(fei)) << std::endl;
  824. #endif
  825. uE2E[ui][fei] = temp[IM(fei)];
  826. const auto & fe = uE2E[ui][fei];
  827. diIM(fe) = fei;
  828. dicons(fe) = cons[IM(fei)];
  829. }
  830. di[ui].resize(uE2E[ui].size());
  831. for (size_t i=0; i<di[ui].size(); i++) {
  832. di[ui][i] = di_I.row(IM(i)).segment<2>(0);
  833. }
  834. }
  835. vector<vector<vector<Index > > > TT,_1;
  836. triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
  837. VectorXI counts;
  838. #ifdef IGL_OUTER_HULL_DEBUG
  839. cout<<"facet components..."<<endl;
  840. #endif
  841. facet_components(TT,C,counts);
  842. assert(C.maxCoeff()+1 == counts.rows());
  843. const size_t ncc = counts.rows();
  844. G.resize(0,F.cols());
  845. J.resize(0,1);
  846. flip.setConstant(m,1,false);
  847. #ifdef IGL_OUTER_HULL_DEBUG
  848. cout<<"reindex..."<<endl;
  849. #endif
  850. // H contains list of faces on outer hull;
  851. vector<bool> FH(m,false);
  852. vector<bool> EH(3*m,false);
  853. vector<MatrixXG> vG(ncc);
  854. vector<MatrixXJ> vJ(ncc);
  855. vector<MatrixXJ> vIM(ncc);
  856. size_t face_count = 0;
  857. for(size_t id = 0;id<ncc;id++)
  858. {
  859. vIM[id].resize(counts[id],1);
  860. }
  861. // current index into each IM
  862. vector<size_t> g(ncc,0);
  863. // place order of each face in its respective component
  864. for(Index f = 0;f<m;f++)
  865. {
  866. vIM[C(f)](g[C(f)]++) = f;
  867. }
  868. #ifdef IGL_OUTER_HULL_DEBUG
  869. cout<<"barycenters..."<<endl;
  870. #endif
  871. // assumes that "resolve" has handled any coplanar cases correctly and nearly
  872. // coplanar cases can be sorted based on barycenter.
  873. MatrixXV BC;
  874. barycenter(V,F,BC);
  875. #ifdef IGL_OUTER_HULL_DEBUG
  876. cout<<"loop over CCs (="<<ncc<<")..."<<endl;
  877. #endif
  878. for(Index id = 0;id<(Index)ncc;id++)
  879. {
  880. auto & IM = vIM[id];
  881. // starting face that's guaranteed to be on the outer hull and in this
  882. // component
  883. int f;
  884. bool f_flip;
  885. #ifdef IGL_OUTER_HULL_DEBUG
  886. cout<<"outer facet..."<<endl;
  887. #endif
  888. outer_facet(V,F,N,IM,f,f_flip);
  889. #ifdef IGL_OUTER_HULL_DEBUG
  890. cout<<"outer facet: "<<f<<endl;
  891. cout << V.row(F(f, 0)) << std::endl;
  892. cout << V.row(F(f, 1)) << std::endl;
  893. cout << V.row(F(f, 2)) << std::endl;
  894. #endif
  895. int FHcount = 1;
  896. FH[f] = true;
  897. // Q contains list of face edges to continue traversing upong
  898. queue<int> Q;
  899. Q.push(f+0*m);
  900. Q.push(f+1*m);
  901. Q.push(f+2*m);
  902. flip(f) = f_flip;
  903. //std::cout << "face " << face_count++ << ": " << f << std::endl;
  904. //std::cout << "f " << F.row(f).array()+1 << std::endl;
  905. //cout<<"flip("<<f<<") = "<<(flip(f)?"true":"false")<<endl;
  906. #ifdef IGL_OUTER_HULL_DEBUG
  907. cout<<"BFS..."<<endl;
  908. #endif
  909. while(!Q.empty())
  910. {
  911. // face-edge
  912. const int e = Q.front();
  913. Q.pop();
  914. // face
  915. const int f = e%m;
  916. // corner
  917. const int c = e/m;
  918. #ifdef IGL_OUTER_HULL_DEBUG
  919. std::cout << "edge: " << e << ", ue: " << EMAP(e) << std::endl;
  920. std::cout << "face: " << f << std::endl;
  921. std::cout << "corner: " << c << std::endl;
  922. std::cout << "consistent: " << dicons(e) << std::endl;
  923. #endif
  924. // Should never see edge again...
  925. if(EH[e] == true)
  926. {
  927. continue;
  928. }
  929. EH[e] = true;
  930. // source of edge according to f
  931. const int fs = flip(f)?F(f,(c+2)%3):F(f,(c+1)%3);
  932. // destination of edge according to f
  933. const int fd = flip(f)?F(f,(c+1)%3):F(f,(c+2)%3);
  934. // edge valence
  935. const size_t val = uE2E[EMAP(e)].size();
  936. #ifdef IGL_OUTER_HULL_DEBUG
  937. std::cout << "vd: " << V.row(fd) << std::endl;
  938. std::cout << "vs: " << V.row(fs) << std::endl;
  939. std::cout << "edge: " << V.row(fd) - V.row(fs) << std::endl;
  940. for (size_t i=0; i<val; i++) {
  941. if (i == diIM(e)) {
  942. std::cout << "* ";
  943. } else {
  944. std::cout << " ";
  945. }
  946. std::cout << i << ": " << di[EMAP(e)][i].transpose()
  947. << " (e: " << uE2E[EMAP(e)][i] << ", f: "
  948. << uE2E[EMAP(e)][i] % m * (dicons(uE2E[EMAP(e)][i]) ? 1:-1) << ")" << std::endl;
  949. }
  950. #endif
  951. // is edge consistent with edge of face used for sorting
  952. const int e_cons = (dicons(e) ? 1: -1);
  953. int nfei = -1;
  954. // Loop once around trying to find suitable next face
  955. for(size_t step = 1; step<val+2;step++)
  956. {
  957. const int nfei_new = (diIM(e) + 2*val + e_cons*step*(flip(f)?-1:1))%val;
  958. const int nf = uE2E[EMAP(e)][nfei_new] % m;
  959. {
  960. // Only use this face if not already seen
  961. if(!FH[nf])
  962. {
  963. nfei = nfei_new;
  964. }
  965. break;
  966. }
  967. }
  968. int max_ne = -1;
  969. if(nfei >= 0)
  970. {
  971. max_ne = uE2E[EMAP(e)][nfei];
  972. }
  973. if(max_ne>=0)
  974. {
  975. // face of neighbor
  976. const int nf = max_ne%m;
  977. #ifdef IGL_OUTER_HULL_DEBUG
  978. if(!FH[nf])
  979. {
  980. // first time seeing face
  981. cout<<(f+1)<<" --> "<<(nf+1)<<endl;
  982. }
  983. #endif
  984. FH[nf] = true;
  985. //std::cout << "face " << face_count++ << ": " << nf << std::endl;
  986. //std::cout << "f " << F.row(nf).array()+1 << std::endl;
  987. FHcount++;
  988. // corner of neighbor
  989. const int nc = max_ne/m;
  990. const int nd = F(nf,(nc+2)%3);
  991. const bool cons = (flip(f)?fd:fs) == nd;
  992. flip(nf) = (cons ? flip(f) : !flip(f));
  993. //cout<<"flip("<<nf<<") = "<<(flip(nf)?"true":"false")<<endl;
  994. const int ne1 = nf+((nc+1)%3)*m;
  995. const int ne2 = nf+((nc+2)%3)*m;
  996. if(!EH[ne1])
  997. {
  998. Q.push(ne1);
  999. }
  1000. if(!EH[ne2])
  1001. {
  1002. Q.push(ne2);
  1003. }
  1004. }
  1005. }
  1006. {
  1007. vG[id].resize(FHcount,3);
  1008. vJ[id].resize(FHcount,1);
  1009. //nG += FHcount;
  1010. size_t h = 0;
  1011. assert(counts(id) == IM.rows());
  1012. for(int i = 0;i<counts(id);i++)
  1013. {
  1014. const size_t f = IM(i);
  1015. //if(f_flip)
  1016. //{
  1017. // flip(f) = !flip(f);
  1018. //}
  1019. if(FH[f])
  1020. {
  1021. vG[id].row(h) = (flip(f)?F.row(f).reverse().eval():F.row(f));
  1022. vJ[id](h,0) = f;
  1023. h++;
  1024. }
  1025. }
  1026. assert((int)h == FHcount);
  1027. }
  1028. }
  1029. // Is A inside B? Assuming A and B are consistently oriented but closed and
  1030. // non-intersecting.
  1031. const auto & is_component_inside_other = [](
  1032. const Eigen::PlainObjectBase<DerivedV> & V,
  1033. const MatrixXV & BC,
  1034. const MatrixXG & A,
  1035. const MatrixXJ & AJ,
  1036. const MatrixXG & B)->bool
  1037. {
  1038. const auto & bounding_box = [](
  1039. const Eigen::PlainObjectBase<DerivedV> & V,
  1040. const MatrixXG & F)->
  1041. MatrixXV
  1042. {
  1043. MatrixXV BB(2,3);
  1044. BB<<
  1045. 1e26,1e26,1e26,
  1046. -1e26,-1e26,-1e26;
  1047. const size_t m = F.rows();
  1048. for(size_t f = 0;f<m;f++)
  1049. {
  1050. for(size_t c = 0;c<3;c++)
  1051. {
  1052. const auto & vfc = V.row(F(f,c));
  1053. BB.row(0) = BB.row(0).array().min(vfc.array()).eval();
  1054. BB.row(1) = BB.row(1).array().max(vfc.array()).eval();
  1055. }
  1056. }
  1057. return BB;
  1058. };
  1059. // A lot of the time we're dealing with unrelated, distant components: cull
  1060. // them.
  1061. MatrixXV ABB = bounding_box(V,A);
  1062. MatrixXV BBB = bounding_box(V,B);
  1063. if( (BBB.row(0)-ABB.row(1)).maxCoeff()>0 ||
  1064. (ABB.row(0)-BBB.row(1)).maxCoeff()>0 )
  1065. {
  1066. // bounding boxes do not overlap
  1067. return false;
  1068. }
  1069. ////////////////////////////////////////////////////////////////////////
  1070. // POTENTIAL ROBUSTNESS WEAK AREA
  1071. ////////////////////////////////////////////////////////////////////////
  1072. //
  1073. // q could be so close (<~1e-15) to B that the winding number is not a robust way to
  1074. // determine inside/outsideness. We could try to find a _better_ q which is
  1075. // farther away, but couldn't they all be bad?
  1076. Matrix<double, 1, 3> q(
  1077. CGAL::to_double(BC(AJ(0), 0)),
  1078. CGAL::to_double(BC(AJ(0), 1)),
  1079. CGAL::to_double(BC(AJ(0), 2)));
  1080. // In a perfect world, it's enough to test a single point.
  1081. double w;
  1082. // winding_number_3 expects colmajor
  1083. double* Vdata;
  1084. Matrix<double,
  1085. DerivedV::RowsAtCompileTime,
  1086. DerivedV::ColsAtCompileTime,
  1087. ColMajor> Vcol(V.rows(), V.cols());
  1088. for (size_t i=0; i<V.rows(); i++) {
  1089. for (size_t j=0; j<V.cols(); j++) {
  1090. Vcol(i,j) = CGAL::to_double(V(i,j));
  1091. }
  1092. }
  1093. Vdata = Vcol.data();
  1094. winding_number_3(
  1095. Vdata,V.rows(),
  1096. B.data(),B.rows(),
  1097. q.data(),1,&w);
  1098. return fabs(w)>0.5;
  1099. };
  1100. // Reject components which are completely inside other components
  1101. vector<bool> keep(ncc,true);
  1102. size_t nG = 0;
  1103. // This is O( ncc * ncc * m)
  1104. for(size_t id = 0;id<ncc;id++)
  1105. {
  1106. for(size_t oid = 0;oid<ncc;oid++)
  1107. {
  1108. if(id == oid)
  1109. {
  1110. continue;
  1111. }
  1112. const bool inside = is_component_inside_other(V,BC,vG[id],vJ[id],vG[oid]);
  1113. #ifdef IGL_OUTER_HULL_DEBUG
  1114. cout<<id<<" is inside "<<oid<<" ? "<<inside<<endl;
  1115. #endif
  1116. keep[id] = keep[id] && !inside;
  1117. }
  1118. if(keep[id])
  1119. {
  1120. nG += vJ[id].rows();
  1121. }
  1122. }
  1123. // collect G and J across components
  1124. G.resize(nG,3);
  1125. J.resize(nG,1);
  1126. {
  1127. size_t off = 0;
  1128. for(Index id = 0;id<(Index)ncc;id++)
  1129. {
  1130. if(keep[id])
  1131. {
  1132. assert(vG[id].rows() == vJ[id].rows());
  1133. G.block(off,0,vG[id].rows(),vG[id].cols()) = vG[id];
  1134. J.block(off,0,vJ[id].rows(),vJ[id].cols()) = vJ[id];
  1135. off += vG[id].rows();
  1136. }
  1137. }
  1138. }
  1139. }
  1140. #ifdef IGL_STATIC_LIBRARY
  1141. // Explicit template specialization
  1142. 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> >&);
  1143. template void igl::outer_hull<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::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> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  1144. template void igl::outer_hull<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::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<bool, -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> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
  1145. #endif