LineIntersection.js 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import {
  2. pointDistance
  3. } from './Geometry';
  4. import intersectPaths from 'path-intersection';
  5. var round = Math.round,
  6. max = Math.max;
  7. function circlePath(center, r) {
  8. var x = center.x,
  9. y = center.y;
  10. return [
  11. ['M', x, y],
  12. ['m', 0, -r],
  13. ['a', r, r, 0, 1, 1, 0, 2 * r],
  14. ['a', r, r, 0, 1, 1, 0, -2 * r],
  15. ['z']
  16. ];
  17. }
  18. function linePath(points) {
  19. var segments = [];
  20. points.forEach(function(p, idx) {
  21. segments.push([ idx === 0 ? 'M' : 'L', p.x, p.y ]);
  22. });
  23. return segments;
  24. }
  25. var INTERSECTION_THRESHOLD = 10;
  26. function getBendpointIntersection(waypoints, reference) {
  27. var i, w;
  28. for (i = 0; (w = waypoints[i]); i++) {
  29. if (pointDistance(w, reference) <= INTERSECTION_THRESHOLD) {
  30. return {
  31. point: waypoints[i],
  32. bendpoint: true,
  33. index: i
  34. };
  35. }
  36. }
  37. return null;
  38. }
  39. function getPathIntersection(waypoints, reference) {
  40. var intersections = intersectPaths(circlePath(reference, INTERSECTION_THRESHOLD), linePath(waypoints));
  41. var a = intersections[0],
  42. b = intersections[intersections.length - 1],
  43. idx;
  44. if (!a) {
  45. // no intersection
  46. return null;
  47. }
  48. if (a !== b) {
  49. if (a.segment2 !== b.segment2) {
  50. // we use the bendpoint in between both segments
  51. // as the intersection point
  52. idx = max(a.segment2, b.segment2) - 1;
  53. return {
  54. point: waypoints[idx],
  55. bendpoint: true,
  56. index: idx
  57. };
  58. }
  59. return {
  60. point: {
  61. x: (round(a.x + b.x) / 2),
  62. y: (round(a.y + b.y) / 2)
  63. },
  64. index: a.segment2
  65. };
  66. }
  67. return {
  68. point: {
  69. x: round(a.x),
  70. y: round(a.y)
  71. },
  72. index: a.segment2
  73. };
  74. }
  75. /**
  76. * Returns the closest point on the connection towards a given reference point.
  77. *
  78. * @param {Array<Point>} waypoints
  79. * @param {Point} reference
  80. *
  81. * @return {Object} intersection data (segment, point)
  82. */
  83. export function getApproxIntersection(waypoints, reference) {
  84. return getBendpointIntersection(waypoints, reference) || getPathIntersection(waypoints, reference);
  85. }