segment_segment_squared_distance.cpp 3.4 KB

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