segment_segment_squared_distance.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #include "segment_segment_squared_distance.h"
  2. // http://geomalgorithms.com/a07-_distance.html
  3. template < typename Kernel>
  4. IGL_INLINE bool igl::copyleft::cgal::segment_segment_squared_distance(
  5. const CGAL::Segment_3<Kernel> & S1,
  6. const CGAL::Segment_3<Kernel> & S2,
  7. CGAL::Point_3<Kernel> & P1,
  8. CGAL::Point_3<Kernel> & P2,
  9. typename Kernel::FT & d)
  10. {
  11. typedef CGAL::Point_3<Kernel> Point_3;
  12. typedef CGAL::Vector_3<Kernel> Vector_3;
  13. typedef Kernel::FT EScalar;
  14. if(S1.is_degenerate())
  15. {
  16. // All points on S1 are the same
  17. P1 = S1.source();
  18. point_segment_squared_distance(P1,S2,P2,d);
  19. return true;
  20. }else if(S2.is_degenerate())
  21. {
  22. assert(!S1.is_degenerate());
  23. // All points on S2 are the same
  24. P2 = S2.source();
  25. point_segment_squared_distance(P2,S1,P1,d);
  26. return true;
  27. }
  28. assert(!S1.is_degenerate());
  29. assert(!S2.is_degenerate());
  30. Vector_3 u = S1.target() - S1.source();
  31. Vector_3 v = S2.target() - S2.source();
  32. Vector_3 w = S1.source() - S2.source();
  33. const auto a = u.dot(u); // always >= 0
  34. const auto b = u.dot(v);
  35. const auto c = v.dot(v); // always >= 0
  36. const auto d = u.dot(w);
  37. const auto e = v.dot(w);
  38. const auto D = a*c - b*b; // always >= 0
  39. assert(D>=0);
  40. const auto sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0
  41. const auto tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
  42. bool parallel = false;
  43. // compute the line parameters of the two closest points
  44. if (D==0)
  45. {
  46. // the lines are almost parallel
  47. parallel = true;
  48. sN = 0.0; // force using source point on segment S1
  49. sD = 1.0; // to prevent possible division by 0.0 later
  50. tN = e;
  51. tD = c;
  52. } else
  53. {
  54. // get the closest points on the infinite lines
  55. sN = (b*e - c*d);
  56. tN = (a*e - b*d);
  57. if (sN < 0.0)
  58. {
  59. // sc < 0 => the s=0 edge is visible
  60. sN = 0.0;
  61. tN = e;
  62. tD = c;
  63. } else if (sN > sD)
  64. { // sc > 1 => the s=1 edge is visible
  65. sN = sD;
  66. tN = e + b;
  67. tD = c;
  68. }
  69. }
  70. if (tN < 0.0)
  71. {
  72. // tc < 0 => the t=0 edge is visible
  73. tN = 0.0;
  74. // recompute sc for this edge
  75. if (-d < 0.0)
  76. {
  77. sN = 0.0;
  78. }else if (-d > a)
  79. {
  80. sN = sD;
  81. }else
  82. {
  83. sN = -d;
  84. sD = a;
  85. }
  86. }else if (tN > tD)
  87. {
  88. // tc > 1 => the t=1 edge is visible
  89. tN = tD;
  90. // recompute sc for this edge
  91. if ((-d + b) < 0.0)
  92. {
  93. sN = 0;
  94. }else if ((-d + b) > a)
  95. {
  96. sN = sD;
  97. }else
  98. {
  99. sN = (-d + b);
  100. sD = a;
  101. }
  102. }
  103. // finally do the division to get sc and tc
  104. sc = (abs(sN) == 0 ? 0.0 : sN / sD);
  105. tc = (abs(tN) == 0 ? 0.0 : tN / tD);
  106. // get the difference of the two closest points
  107. P1 = S1.source() + sc*(S1.target()-S1.source());
  108. P2 = S2.source() + sc*(S2.target()-S2.source());
  109. Vector_3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
  110. assert(dP == (P1-P2));
  111. d = dP.squared_length(); // return the closest distance
  112. return parallel;
  113. }