uniformly_sample_two_manifold.cpp 13 KB

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