uniformly_sample_two_manifold.cpp 13 KB

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