uniformly_sample_two_manifold.cpp 13 KB

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