BsLineSegment3.cpp 2.1 KB

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