uniformly_sample_two_manifold.cpp 13 KB

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