BsLineSegment3.cpp 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #include "BsLineSegment3.h"
  2. #include "BsRay.h"
  3. namespace BansheeEngine
  4. {
  5. LineSegment3::LineSegment3()
  6. { }
  7. LineSegment3::LineSegment3(const Vector3& start, const Vector3& end)
  8. :mStart(start), mEnd(end)
  9. {
  10. }
  11. std::pair<std::array<Vector3, 2>, float> LineSegment3::getNearestPoint(const Ray& ray) const
  12. {
  13. const Vector3& org = ray.getOrigin();
  14. const Vector3& dir = ray.getDirection();
  15. Vector3 segDir = mEnd - mStart;
  16. float segExtent = segDir.normalize() * 0.5f;
  17. Vector3 segCenter = mStart + segDir * segExtent;
  18. Vector3 diff = org - segCenter;
  19. float a01 = -dir.dot(segDir);
  20. float b0 = diff.dot(dir);
  21. float c = diff.dot(diff);
  22. float det = fabs(1.0f - a01*a01);
  23. float s0, s1;
  24. float sqrDistance;
  25. if (det > 0.0f) // Not parallel
  26. {
  27. float b1 = -diff.dot(segDir);
  28. s1 = a01 * b0 - b1;
  29. float extDet = segExtent * det;
  30. if (s1 >= -extDet)
  31. {
  32. if (s1 <= extDet) // Interior of the segment and interior of the ray are closest
  33. {
  34. float invDet = 1.0f / det;
  35. s0 = (a01*b1 - b0)*invDet;
  36. s1 *= invDet;
  37. sqrDistance = s0*(s0 + a01*s1 + 2.0f*b0) +
  38. s1*(a01*s0 + s1 + 2.0f*b1) + c;
  39. }
  40. else // Segment end and interior of the ray are closest
  41. {
  42. s1 = segExtent;
  43. s0 = -(a01*s1 + b0);
  44. sqrDistance = -s0*s0 + s1*(s1 + (2.0f)*b1) + c;
  45. }
  46. }
  47. else // Segment start and interior of the ray are closest
  48. {
  49. s1 = -segExtent;
  50. s0 = -(a01*s1 + b0);
  51. sqrDistance = -s0*s0 + s1*(s1 + (2.0f)*b1) + c;
  52. }
  53. }
  54. else // Parallel
  55. {
  56. s1 = 0;
  57. s0 = -b0;
  58. sqrDistance = b0*s0 + c;
  59. }
  60. if (sqrDistance < 0.0f)
  61. sqrDistance = 0.0f;
  62. float distance = std::sqrt(sqrDistance);
  63. std::array<Vector3, 2> nearestPoints;
  64. nearestPoints[0] = org + s0 * dir;
  65. nearestPoints[1] = segCenter + s1 * segDir;
  66. return std::make_pair(nearestPoints, distance);
  67. }
  68. }