point_simplex_squared_distance.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2016 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 "point_simplex_squared_distance.h"
  9. #include "project_to_line_segment.h"
  10. #include "barycentric_coordinates.h"
  11. #include <Eigen/Geometry>
  12. #include <limits>
  13. #include <cassert>
  14. template <
  15. int DIM,
  16. typename Derivedp,
  17. typename DerivedV,
  18. typename DerivedEle,
  19. typename Derivedsqr_d,
  20. typename Derivedc>
  21. IGL_INLINE void igl::point_simplex_squared_distance(
  22. const Eigen::PlainObjectBase<Derivedp> & p,
  23. const Eigen::PlainObjectBase<DerivedV> & V,
  24. const Eigen::PlainObjectBase<DerivedEle> & Ele,
  25. const typename DerivedEle::Index primitive,
  26. Derivedsqr_d & sqr_d,
  27. Eigen::PlainObjectBase<Derivedc> & c)
  28. {
  29. assert(p.size() == DIM);
  30. assert(V.cols() == DIM);
  31. assert(Ele.cols() <= DIM+1);
  32. assert(Ele.cols() <= 3 && "Only simplices up to triangles are considered");
  33. typedef Derivedsqr_d Scalar;
  34. typedef typename Eigen::Matrix<Scalar,1,DIM> RowVectorDIMS;
  35. sqr_d = std::numeric_limits<Scalar>::infinity();
  36. const auto & set_min =
  37. [&sqr_d,&c](const Scalar & sqr_d_candidate, const RowVectorDIMS & c_candidate)
  38. {
  39. if(sqr_d_candidate < sqr_d)
  40. {
  41. sqr_d = sqr_d_candidate;
  42. c = c_candidate;
  43. }
  44. };
  45. // Simplex size
  46. const size_t ss = Ele.cols();
  47. // Only one element per node
  48. // plane unit normal
  49. bool inside_triangle = false;
  50. Scalar d_j = std::numeric_limits<Scalar>::infinity();
  51. RowVectorDIMS pp;
  52. // Only consider triangles, and non-degenerate triangles at that
  53. if(ss == 3 &&
  54. Ele(primitive,0) != Ele(primitive,1) &&
  55. Ele(primitive,1) != Ele(primitive,2) &&
  56. Ele(primitive,2) != Ele(primitive,0))
  57. {
  58. assert(DIM == 3 && "Only implemented for 3D triangles");
  59. typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
  60. // can't be const because of annoying DIM template
  61. RowVector3S v10(0,0,0);
  62. v10.head(DIM) = (V.row(Ele(primitive,1))- V.row(Ele(primitive,0)));
  63. RowVector3S v20(0,0,0);
  64. v20.head(DIM) = (V.row(Ele(primitive,2))- V.row(Ele(primitive,0)));
  65. const RowVectorDIMS n = (v10.cross(v20)).head(DIM);
  66. Scalar n_norm = n.norm();
  67. if(n_norm > 0)
  68. {
  69. const RowVectorDIMS un = n/n.norm();
  70. // vector to plane
  71. const RowVectorDIMS bc =
  72. 1./3.*
  73. ( V.row(Ele(primitive,0))+
  74. V.row(Ele(primitive,1))+
  75. V.row(Ele(primitive,2)));
  76. const auto & v = p-bc;
  77. // projected point on plane
  78. d_j = v.dot(un);
  79. pp = p - d_j*un;
  80. // determine if pp is inside triangle
  81. Eigen::Matrix<Scalar,1,3> b;
  82. barycentric_coordinates(
  83. pp,
  84. V.row(Ele(primitive,0)),
  85. V.row(Ele(primitive,1)),
  86. V.row(Ele(primitive,2)),
  87. b);
  88. inside_triangle = fabs(fabs(b(0)) + fabs(b(1)) + fabs(b(2)) - 1.) <= 1e-10;
  89. }
  90. }
  91. const auto & point_point_squared_distance = [&](const RowVectorDIMS & s)
  92. {
  93. const Scalar sqr_d_s = (p-s).squaredNorm();
  94. set_min(sqr_d_s,s);
  95. };
  96. if(inside_triangle)
  97. {
  98. // point-triangle squared distance
  99. const Scalar sqr_d_j = d_j*d_j;
  100. //cout<<"point-triangle..."<<endl;
  101. set_min(sqr_d_j,pp);
  102. }else
  103. {
  104. if(ss >= 2)
  105. {
  106. // point-segment distance
  107. // number of edges
  108. size_t ne = ss==3?3:1;
  109. for(size_t x = 0;x<ne;x++)
  110. {
  111. const size_t e1 = Ele(primitive,(x+1)%ss);
  112. const size_t e2 = Ele(primitive,(x+2)%ss);
  113. const RowVectorDIMS & s = V.row(e1);
  114. const RowVectorDIMS & d = V.row(e2);
  115. // Degenerate edge
  116. if(e1 == e2 || (s-d).squaredNorm()==0)
  117. {
  118. // only consider once
  119. if(e1 < e2)
  120. {
  121. point_point_squared_distance(s);
  122. }
  123. continue;
  124. }
  125. Eigen::Matrix<Scalar,1,1> sqr_d_j_x(1,1);
  126. Eigen::Matrix<Scalar,1,1> t(1,1);
  127. project_to_line_segment(p,s,d,t,sqr_d_j_x);
  128. const RowVectorDIMS q = s+t(0)*(d-s);
  129. set_min(sqr_d_j_x(0),q);
  130. }
  131. }else
  132. {
  133. // So then Ele is just a list of points...
  134. assert(ss == 1);
  135. const RowVectorDIMS & s = V.row(Ele(primitive,0));
  136. point_point_squared_distance(s);
  137. }
  138. }
  139. }
  140. #ifdef IGL_STATIC_LIBRARY
  141. // Explicit template instanciation
  142. template void igl::point_simplex_squared_distance<2, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&);
  143. template void igl::point_simplex_squared_distance<3, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
  144. #endif