uniformly_sample_two_manifold.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2013 Alec Jacobson <[email protected]>
  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 "uniformly_sample_two_manifold.h"
  9. #include "verbose.h"
  10. #include "colon.h"
  11. #include "all_pairs_distances.h"
  12. #include "vertex_triangle_adjacency.h"
  13. #include "get_seconds.h"
  14. #include "cat.h"
  15. #include "placeholders.h"
  16. //#include "MT19937.h"
  17. #include "partition.h"
  18. //////////////////////////////////////////////////////////////////////////////
  19. // Helper functions
  20. //////////////////////////////////////////////////////////////////////////////
  21. IGL_INLINE void igl::uniformly_sample_two_manifold(
  22. const Eigen::MatrixXd & W,
  23. const Eigen::MatrixXi & F,
  24. const int k,
  25. const double push,
  26. Eigen::MatrixXd & WS)
  27. {
  28. // Euclidean distance between two points on a mesh given as barycentric
  29. // coordinates
  30. // Inputs:
  31. // W #W by dim positions of mesh in weight space
  32. // F #F by 3 indices of triangles
  33. // face_A face index where 1st point lives
  34. // bary_A barycentric coordinates of 1st point on face_A
  35. // face_B face index where 2nd point lives
  36. // bary_B barycentric coordinates of 2nd point on face_B
  37. // Returns distance in euclidean space
  38. const auto & bary_dist = [] (
  39. const Eigen::MatrixXd & W,
  40. const Eigen::MatrixXi & F,
  41. const int face_A,
  42. const Eigen::Vector3d & bary_A,
  43. const int face_B,
  44. const Eigen::Vector3d & bary_B) -> double
  45. {
  46. return
  47. ((bary_A(0)*W.row(F(face_A,0)) +
  48. bary_A(1)*W.row(F(face_A,1)) +
  49. bary_A(2)*W.row(F(face_A,2)))
  50. -
  51. (bary_B(0)*W.row(F(face_B,0)) +
  52. bary_B(1)*W.row(F(face_B,1)) +
  53. bary_B(2)*W.row(F(face_B,2)))).norm();
  54. };
  55. // Base case if F is a tet list, find all faces and pass as non-manifold
  56. // triangle mesh
  57. if(F.cols() == 4)
  58. {
  59. verbose("uniform_sample.h: sampling tet mesh\n");
  60. Eigen::MatrixXi T0 = F.col(0);
  61. Eigen::MatrixXi T1 = F.col(1);
  62. Eigen::MatrixXi T2 = F.col(2);
  63. Eigen::MatrixXi T3 = F.col(3);
  64. // Faces from tets
  65. Eigen::MatrixXi TF =
  66. cat(1,
  67. cat(1,
  68. cat(2,T0, cat(2,T1,T2)),
  69. cat(2,T0, cat(2,T2,T3))),
  70. cat(1,
  71. cat(2,T0, cat(2,T3,T1)),
  72. cat(2,T1, cat(2,T3,T2)))
  73. );
  74. assert(TF.rows() == 4*F.rows());
  75. assert(TF.cols() == 3);
  76. uniformly_sample_two_manifold(W,TF,k,push,WS);
  77. return;
  78. }
  79. double start = get_seconds();
  80. Eigen::VectorXi S;
  81. // First get sampling as best as possible on mesh
  82. uniformly_sample_two_manifold_at_vertices(W,k,push,S);
  83. verbose("Lap: %g\n",get_seconds()-start);
  84. WS = W(S,igl::placeholders::all);
  85. //cout<<"WSmesh=["<<endl<<WS<<endl<<"];"<<endl;
  86. //#ifdef EXTREME_VERBOSE
  87. //cout<<"S=["<<endl<<S<<endl<<"];"<<endl;
  88. //#endif
  89. // Build map from vertices to list of incident faces
  90. std::vector<std::vector<int> > VF,VFi;
  91. vertex_triangle_adjacency(W,F,VF,VFi);
  92. // List of list of face indices, for each sample gives index to face it is on
  93. std::vector<std::vector<int> > sample_faces; sample_faces.resize(k);
  94. // List of list of barycentric coordinates, for each sample gives b-coords in
  95. // face its on
  96. std::vector<std::vector<Eigen::Vector3d> > sample_barys; sample_barys.resize(k);
  97. // List of current maxmins amongst samples
  98. std::vector<int> cur_maxmin; cur_maxmin.resize(k);
  99. // List of distance matrices, D(i)(s,j) reveals distance from i's sth sample
  100. // to jth seed if j<k or (j-k)th "pushed" corner
  101. std::vector<Eigen::MatrixXd> D; D.resize(k);
  102. // Precompute an W.cols() by W.cols() identity matrix
  103. Eigen::MatrixXd I(Eigen::MatrixXd::Identity(W.cols(),W.cols()));
  104. // Describe each seed as a face index and barycentric coordinates
  105. for(int i = 0;i < k;i++)
  106. {
  107. // Unreferenced vertex?
  108. assert(VF[S(i)].size() > 0);
  109. sample_faces[i].push_back(VF[S(i)][0]);
  110. // We're right on a face vertex so barycentric coordinates are 0, but 1 at
  111. // that vertex
  112. Eigen::Vector3d bary(0,0,0);
  113. bary( VFi[S(i)][0] ) = 1;
  114. sample_barys[i].push_back(bary);
  115. // initialize this to current maxmin
  116. cur_maxmin[i] = 0;
  117. }
  118. // initialize radius
  119. double radius = 1.0;
  120. // minimum radius (bound on precision)
  121. //double min_radius = 1e-5;
  122. double min_radius = 1e-5;
  123. int max_num_rand_samples_per_triangle = 100;
  124. int max_sample_attempts_per_triangle = 1000;
  125. // Max number of outer iterations for a given radius
  126. int max_iters = 1000;
  127. // continue iterating until radius is smaller than some threshold
  128. while(radius > min_radius)
  129. {
  130. // initialize each seed
  131. for(int i = 0;i < k;i++)
  132. {
  133. // Keep track of cur_maxmin data
  134. int face_i = sample_faces[i][cur_maxmin[i]];
  135. Eigen::Vector3d bary(sample_barys[i][cur_maxmin[i]]);
  136. // Find index in face of closest mesh vertex (on this face)
  137. int index_in_face =
  138. (bary(0) > bary(1) ? (bary(0) > bary(2) ? 0 : 2)
  139. : (bary(1) > bary(2) ? 1 : 2));
  140. // find closest mesh vertex
  141. int vertex_i = F(face_i,index_in_face);
  142. // incident triangles
  143. std::vector<int> incident_F = VF[vertex_i];
  144. // We're going to try to place num_rand_samples_per_triangle samples on
  145. // each sample *after* this location
  146. sample_barys[i].clear();
  147. sample_faces[i].clear();
  148. cur_maxmin[i] = 0;
  149. sample_barys[i].push_back(bary);
  150. sample_faces[i].push_back(face_i);
  151. // Current seed location in weight space
  152. Eigen::VectorXd seed =
  153. bary(0)*W.row(F(face_i,0)) +
  154. bary(1)*W.row(F(face_i,1)) +
  155. bary(2)*W.row(F(face_i,2));
  156. #ifdef EXTREME_VERBOSE
  157. verbose("i: %d\n",i);
  158. verbose("face_i: %d\n",face_i);
  159. //cout<<"bary: "<<bary<<endl;
  160. verbose("index_in_face: %d\n",index_in_face);
  161. verbose("vertex_i: %d\n",vertex_i);
  162. verbose("incident_F.size(): %d\n",incident_F.size());
  163. //cout<<"seed: "<<seed<<endl;
  164. #endif
  165. // loop over indcident triangles
  166. for(int f=0;f<(int)incident_F.size();f++)
  167. {
  168. #ifdef EXTREME_VERBOSE
  169. verbose("incident_F[%d]: %d\n",f,incident_F[f]);
  170. #endif
  171. int face_f = incident_F[f];
  172. int num_samples_f = 0;
  173. for(int s=0;s<max_sample_attempts_per_triangle;s++)
  174. {
  175. // Randomly sample unit square
  176. double u,v;
  177. // double ru = fgenrand();
  178. // double rv = fgenrand();
  179. double ru = (double)rand() / RAND_MAX;
  180. double rv = (double)rand() / RAND_MAX;
  181. // Reflect to lower triangle if above
  182. if((ru+rv)>1)
  183. {
  184. u = 1-rv;
  185. v = 1-ru;
  186. }else
  187. {
  188. u = ru;
  189. v = rv;
  190. }
  191. Eigen::Vector3d sample_bary(u,v,1-u-v);
  192. double d = bary_dist(W,F,face_i,bary,face_f,sample_bary);
  193. // check that sample is close enough
  194. if(d<radius)
  195. {
  196. // add sample to list
  197. sample_faces[i].push_back(face_f);
  198. sample_barys[i].push_back(sample_bary);
  199. num_samples_f++;
  200. }
  201. // Keep track of which random samples came from which face
  202. if(num_samples_f >= max_num_rand_samples_per_triangle)
  203. {
  204. #ifdef EXTREME_VERBOSE
  205. verbose("Reached maximum number of samples per face\n");
  206. #endif
  207. break;
  208. }
  209. if(s==(max_sample_attempts_per_triangle-1))
  210. {
  211. #ifdef EXTREME_VERBOSE
  212. verbose("Reached maximum sample attempts per triangle\n");
  213. #endif
  214. }
  215. }
  216. #ifdef EXTREME_VERBOSE
  217. verbose("sample_faces[%d].size(): %d\n",i,sample_faces[i].size());
  218. verbose("sample_barys[%d].size(): %d\n",i,sample_barys[i].size());
  219. #endif
  220. }
  221. }
  222. // Precompute distances from each seed's random samples to each "pushed"
  223. // corner
  224. // Put -1 in entries corresponding distance of a seed's random samples to
  225. // self
  226. // Loop over seeds
  227. for(int i = 0;i < k;i++)
  228. {
  229. // resize distance matrix for new samples
  230. D[i].resize(sample_faces[i].size(),k+W.cols());
  231. // Loop over i's samples
  232. for(int s = 0;s<(int)sample_faces[i].size();s++)
  233. {
  234. int sample_face = sample_faces[i][s];
  235. Eigen::Vector3d sample_bary = sample_barys[i][s];
  236. // Loop over other seeds
  237. for(int j = 0;j < k;j++)
  238. {
  239. // distance from sample(i,s) to seed j
  240. double d;
  241. if(i==j)
  242. {
  243. // phony self distance: Ilya's idea of infinite
  244. d = 10;
  245. }else
  246. {
  247. int seed_j_face = sample_faces[j][cur_maxmin[j]];
  248. Eigen::Vector3d seed_j_bary(sample_barys[j][cur_maxmin[j]]);
  249. d = bary_dist(W,F,sample_face,sample_bary,seed_j_face,seed_j_bary);
  250. }
  251. D[i](s,j) = d;
  252. }
  253. // Loop over corners
  254. for(int j = 0;j < W.cols();j++)
  255. {
  256. // distance from sample(i,s) to corner j
  257. double d =
  258. ((sample_bary(0)*W.row(F(sample_face,0)) +
  259. sample_bary(1)*W.row(F(sample_face,1)) +
  260. sample_bary(2)*W.row(F(sample_face,2)))
  261. - I.row(j)).norm()/push;
  262. // append after distances to seeds
  263. D[i](s,k+j) = d;
  264. }
  265. }
  266. }
  267. int iters = 0;
  268. while(true)
  269. {
  270. bool has_changed = false;
  271. // try to move each seed
  272. for(int i = 0;i < k;i++)
  273. {
  274. // for each sample look at distance to closest seed/corner
  275. Eigen::VectorXd minD = D[i].rowwise().minCoeff();
  276. assert(minD.size() == (int)sample_faces[i].size());
  277. // find random sample with maximum minimum distance to other seeds
  278. int old_cur_maxmin = cur_maxmin[i];
  279. double max_min = -2;
  280. for(int s = 0;s<(int)sample_faces[i].size();s++)
  281. {
  282. if(max_min < minD(s))
  283. {
  284. max_min = minD(s);
  285. // Set this as the new seed location
  286. cur_maxmin[i] = s;
  287. }
  288. }
  289. #ifdef EXTREME_VERBOSE
  290. verbose("max_min: %g\n",max_min);
  291. verbose("cur_maxmin[%d]: %d->%d\n",i,old_cur_maxmin,cur_maxmin[i]);
  292. #endif
  293. // did location change?
  294. has_changed |= (old_cur_maxmin!=cur_maxmin[i]);
  295. // update distances of random samples of other seeds
  296. }
  297. // if no seed moved, exit
  298. if(!has_changed)
  299. {
  300. break;
  301. }
  302. iters++;
  303. if(iters>=max_iters)
  304. {
  305. verbose("Hit max iters (%d) before converging\n",iters);
  306. }
  307. }
  308. // shrink radius
  309. //radius *= 0.9;
  310. //radius *= 0.99;
  311. radius *= 0.9;
  312. }
  313. // Collect weight space locations
  314. WS.resize(k,W.cols());
  315. for(int i = 0;i<k;i++)
  316. {
  317. int face_i = sample_faces[i][cur_maxmin[i]];
  318. Eigen::Vector3d bary(sample_barys[i][cur_maxmin[i]]);
  319. WS.row(i) =
  320. bary(0)*W.row(F(face_i,0)) +
  321. bary(1)*W.row(F(face_i,1)) +
  322. bary(2)*W.row(F(face_i,2));
  323. }
  324. verbose("Lap: %g\n",get_seconds()-start);
  325. //cout<<"WSafter=["<<endl<<WS<<endl<<"];"<<endl;
  326. }
  327. IGL_INLINE void igl::uniformly_sample_two_manifold_at_vertices(
  328. const Eigen::MatrixXd & OW,
  329. const int k,
  330. const double push,
  331. Eigen::VectorXi & S)
  332. {
  333. // Copy weights and faces
  334. const Eigen::MatrixXd & W = OW;
  335. /*const Eigen::MatrixXi & F = OF;*/
  336. // Initialize seeds
  337. Eigen::VectorXi G;
  338. Eigen::Matrix<double ,Eigen::Dynamic,1> ignore;
  339. partition(W,k+W.cols(),G,S,ignore);
  340. // Remove corners, which better be at top
  341. S = S.segment(W.cols(),k).eval();
  342. Eigen::MatrixXd WS = W(S,igl::placeholders::all);
  343. //cout<<"WSpartition=["<<endl<<WS<<endl<<"];"<<endl;
  344. // number of vertices
  345. int n = W.rows();
  346. // number of dimensions in weight space
  347. int m = W.cols();
  348. // Corners of weight space
  349. Eigen::MatrixXd I = Eigen::MatrixXd::Identity(m,m);
  350. // append corners to bottom of weights
  351. Eigen::MatrixXd WI(n+m,m);
  352. WI << W,I;
  353. // Weights at seeds and corners
  354. Eigen::MatrixXd WSC(k+m,m);
  355. for(int i = 0;i<k;i++)
  356. {
  357. WSC.row(i) = W.row(S(i));
  358. }
  359. for(int i = 0;i<m;i++)
  360. {
  361. WSC.row(i+k) = WI.row(n+i);
  362. }
  363. // initialize all pairs sqaured distances
  364. Eigen::MatrixXd sqrD;
  365. all_pairs_distances(WI,WSC,true,sqrD);
  366. // bring in corners by push factor (squared because distances are squared)
  367. sqrD.block(0,k,sqrD.rows(),m) /= push*push;
  368. int max_iters = 30;
  369. int j = 0;
  370. for(;j<max_iters;j++)
  371. {
  372. bool has_changed = false;
  373. // loop over seeds
  374. for(int i =0;i<k;i++)
  375. {
  376. int old_si = S(i);
  377. // set distance to ilya's idea of infinity
  378. sqrD.col(i).setZero();
  379. sqrD.col(i).array() += 10;
  380. // find vertex farthers from all other seeds
  381. Eigen::MatrixXd minsqrD = sqrD.rowwise().minCoeff();
  382. Eigen::MatrixXd::Index si,PHONY;
  383. minsqrD.maxCoeff(&si,&PHONY);
  384. Eigen::MatrixXd Wsi = W.row(si);
  385. Eigen::MatrixXd sqrDi;
  386. all_pairs_distances(WI,Wsi,true,sqrDi);
  387. sqrD.col(i) = sqrDi;
  388. S(i) = si;
  389. has_changed |= si!=old_si;
  390. }
  391. if(j == max_iters)
  392. {
  393. verbose("uniform_sample.h: Warning: hit max iters\n");
  394. }
  395. if(!has_changed)
  396. {
  397. break;
  398. }
  399. }
  400. }