streamlines.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2016 Francisca Gil Ureta <gilureta@cs.nyu.edu>
  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 "edge_topology.h"
  9. #include "sort_vectors_ccw.h"
  10. #include "streamlines.h"
  11. #include "per_face_normals.h"
  12. #include "polyvector_field_matchings.h"
  13. #include "segment_segment_intersect.h"
  14. #include "triangle_triangle_adjacency.h"
  15. #include "barycenter.h"
  16. #include "slice.h"
  17. #include <Eigen/Geometry>
  18. IGL_INLINE void igl::streamlines_init(
  19. const Eigen::MatrixXd V,
  20. const Eigen::MatrixXi F,
  21. const Eigen::MatrixXd &temp_field,
  22. const bool treat_as_symmetric,
  23. StreamlineData &data,
  24. StreamlineState &state,
  25. double percentage
  26. ){
  27. using namespace Eigen;
  28. using namespace std;
  29. igl::edge_topology(V, F, data.E, data.F2E, data.E2F);
  30. igl::triangle_triangle_adjacency(F, data.TT);
  31. // prepare vector field
  32. // --------------------------
  33. int half_degree = temp_field.cols() / 3;
  34. int degree = treat_as_symmetric ? half_degree * 2 : half_degree;
  35. data.degree = degree;
  36. Eigen::MatrixXd FN;
  37. Eigen::VectorXi order;
  38. Eigen::RowVectorXd sorted;
  39. igl::per_face_normals(V, F, FN);
  40. data.field.setZero(F.rows(), degree * 3);
  41. for (unsigned i = 0; i < F.rows(); ++i){
  42. const Eigen::RowVectorXd &n = FN.row(i);
  43. Eigen::RowVectorXd temp(1, degree * 3);
  44. if (treat_as_symmetric)
  45. temp << temp_field.row(i), -temp_field.row(i);
  46. else
  47. temp = temp_field.row(i);
  48. igl::sort_vectors_ccw(temp, n, order, sorted);
  49. // project vectors to tangent plane
  50. for (int j = 0; j < degree; ++j)
  51. {
  52. Eigen::RowVector3d pd = sorted.segment(j * 3, 3);
  53. pd = (pd - (n.dot(pd)) * n).normalized();
  54. data.field.block(i, j * 3, 1, 3) = pd;
  55. }
  56. }
  57. Eigen::VectorXd curl;
  58. igl::polyvector_field_matchings(data.field, V, F, false, treat_as_symmetric, data.match_ab, data.match_ba, curl);
  59. // create seeds for tracing
  60. // --------------------------
  61. Eigen::VectorXi samples;
  62. int nsamples;
  63. nsamples = percentage * F.rows();
  64. Eigen::VectorXd r;
  65. r.setRandom(nsamples, 1);
  66. r = (1 + r.array()) / 2.;
  67. samples = (r.array() * F.rows()).cast<int>();
  68. data.nsample = nsamples;
  69. Eigen::MatrixXd BC, BC_sample;
  70. igl::barycenter(V, F, BC);
  71. igl::slice(BC, samples, 1, BC_sample);
  72. // initialize state for tracing vector field
  73. state.start_point = BC_sample.replicate(degree,1);
  74. state.end_point = state.start_point;
  75. state.current_face = samples.replicate(1, degree);
  76. state.current_direction.setZero(nsamples, degree);
  77. for (int i = 0; i < nsamples; ++i)
  78. for (int j = 0; j < degree; ++j)
  79. state.current_direction(i, j) = j;
  80. }
  81. IGL_INLINE void igl::streamlines_next(
  82. const Eigen::MatrixXd V,
  83. const Eigen::MatrixXi F,
  84. const StreamlineData & data,
  85. StreamlineState & state
  86. ){
  87. using namespace Eigen;
  88. using namespace std;
  89. int degree = data.degree;
  90. int nsample = data.nsample;
  91. state.start_point = state.end_point;
  92. for (int i = 0; i < degree; ++i)
  93. {
  94. for (int j = 0; j < nsample; ++j)
  95. {
  96. int f0 = state.current_face(j,i);
  97. if (f0 == -1) // reach boundary
  98. continue;
  99. int m0 = state.current_direction(j, i);
  100. // the starting point of the vector
  101. const Eigen::RowVector3d &p = state.start_point.row(j + nsample * i);
  102. // the direction where we are trying to go
  103. const Eigen::RowVector3d &r = data.field.block(f0, 3 * m0, 1, 3);
  104. // new state,
  105. int f1, m1;
  106. for (int k = 0; k < 3; ++k)
  107. {
  108. f1 = data.TT(f0, k);
  109. // edge vertices
  110. const Eigen::RowVector3d &q = V.row(F(f0, k));
  111. const Eigen::RowVector3d &qs = V.row(F(f0, (k + 1) % 3));
  112. // edge direction
  113. Eigen::RowVector3d s = qs - q;
  114. double u;
  115. double t;
  116. if (igl::segments_intersect(p, r, q, s, t, u))
  117. {
  118. // point on next face
  119. state.end_point.row(j + nsample * i) = p + t * r;
  120. state.current_face(j,i) = f1;
  121. // matching direction on next face
  122. int e1 = data.F2E(f0, k);
  123. if (data.E2F(e1, 0) == f0)
  124. m1 = data.match_ab(e1, m0);
  125. else
  126. m1 = data.match_ba(e1, m0);
  127. state.current_direction(j, i) = m1;
  128. break;
  129. }
  130. }
  131. }
  132. }
  133. }