segment_segment_squared_distance.cpp 3.3 KB

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