index.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. var __defProp = Object.defineProperty;
  2. var __defProps = Object.defineProperties;
  3. var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
  4. var __getOwnPropSymbols = Object.getOwnPropertySymbols;
  5. var __hasOwnProp = Object.prototype.hasOwnProperty;
  6. var __propIsEnum = Object.prototype.propertyIsEnumerable;
  7. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  8. var __spreadValues = (a, b) => {
  9. for (var prop in b || (b = {}))
  10. if (__hasOwnProp.call(b, prop))
  11. __defNormalProp(a, prop, b[prop]);
  12. if (__getOwnPropSymbols)
  13. for (var prop of __getOwnPropSymbols(b)) {
  14. if (__propIsEnum.call(b, prop))
  15. __defNormalProp(a, prop, b[prop]);
  16. }
  17. return a;
  18. };
  19. var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
  20. // index.ts
  21. import { distance } from "@turf/distance";
  22. import { flattenEach } from "@turf/meta";
  23. import {
  24. point,
  25. degreesToRadians,
  26. radiansToDegrees
  27. } from "@turf/helpers";
  28. import { getCoord, getCoords } from "@turf/invariant";
  29. function nearestPointOnLine(lines, pt, options = {}) {
  30. if (!lines || !pt) {
  31. throw new Error("lines and pt are required arguments");
  32. }
  33. const ptPos = getCoord(pt);
  34. let closestPt = point([Infinity, Infinity], {
  35. dist: Infinity,
  36. index: -1,
  37. multiFeatureIndex: -1,
  38. location: -1
  39. });
  40. let length = 0;
  41. flattenEach(
  42. lines,
  43. function(line, _featureIndex, multiFeatureIndex) {
  44. const coords = getCoords(line);
  45. for (let i = 0; i < coords.length - 1; i++) {
  46. const start = point(coords[i]);
  47. start.properties.dist = distance(pt, start, options);
  48. const startPos = getCoord(start);
  49. const stop = point(coords[i + 1]);
  50. stop.properties.dist = distance(pt, stop, options);
  51. const stopPos = getCoord(stop);
  52. const sectionLength = distance(start, stop, options);
  53. let intersectPos;
  54. let wasEnd;
  55. if (startPos[0] === ptPos[0] && startPos[1] === ptPos[1]) {
  56. [intersectPos, , wasEnd] = [startPos, void 0, false];
  57. } else if (stopPos[0] === ptPos[0] && stopPos[1] === ptPos[1]) {
  58. [intersectPos, , wasEnd] = [stopPos, void 0, true];
  59. } else {
  60. [intersectPos, , wasEnd] = nearestPointOnSegment(
  61. start.geometry.coordinates,
  62. stop.geometry.coordinates,
  63. getCoord(pt)
  64. );
  65. }
  66. let intersectPt;
  67. if (intersectPos) {
  68. intersectPt = point(intersectPos, {
  69. dist: distance(pt, intersectPos, options),
  70. multiFeatureIndex,
  71. location: length + distance(start, intersectPos, options)
  72. });
  73. }
  74. if (intersectPt && intersectPt.properties.dist < closestPt.properties.dist) {
  75. closestPt = __spreadProps(__spreadValues({}, intersectPt), {
  76. properties: __spreadProps(__spreadValues({}, intersectPt.properties), {
  77. // Legacy behaviour where index progresses to next segment # if we
  78. // went with the end point this iteration.
  79. index: wasEnd ? i + 1 : i
  80. })
  81. });
  82. }
  83. length += sectionLength;
  84. }
  85. }
  86. );
  87. return closestPt;
  88. }
  89. function dot(v1, v2) {
  90. const [v1x, v1y, v1z] = v1;
  91. const [v2x, v2y, v2z] = v2;
  92. return v1x * v2x + v1y * v2y + v1z * v2z;
  93. }
  94. function cross(v1, v2) {
  95. const [v1x, v1y, v1z] = v1;
  96. const [v2x, v2y, v2z] = v2;
  97. return [v1y * v2z - v1z * v2y, v1z * v2x - v1x * v2z, v1x * v2y - v1y * v2x];
  98. }
  99. function magnitude(v) {
  100. return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));
  101. }
  102. function angle(v1, v2) {
  103. const theta = dot(v1, v2) / (magnitude(v1) * magnitude(v2));
  104. return Math.acos(Math.min(Math.max(theta, -1), 1));
  105. }
  106. function lngLatToVector(a) {
  107. const lat = degreesToRadians(a[1]);
  108. const lng = degreesToRadians(a[0]);
  109. return [
  110. Math.cos(lat) * Math.cos(lng),
  111. Math.cos(lat) * Math.sin(lng),
  112. Math.sin(lat)
  113. ];
  114. }
  115. function vectorToLngLat(v) {
  116. const [x, y, z] = v;
  117. const lat = radiansToDegrees(Math.asin(z));
  118. const lng = radiansToDegrees(Math.atan2(y, x));
  119. return [lng, lat];
  120. }
  121. function nearestPointOnSegment(posA, posB, posC) {
  122. const A = lngLatToVector(posA);
  123. const B = lngLatToVector(posB);
  124. const C = lngLatToVector(posC);
  125. const [Cx, Cy, Cz] = C;
  126. const [D, E, F] = cross(A, B);
  127. const a = E * Cz - F * Cy;
  128. const b = F * Cx - D * Cz;
  129. const c = D * Cy - E * Cx;
  130. const f = c * E - b * F;
  131. const g = a * F - c * D;
  132. const h = b * D - a * E;
  133. const t = 1 / Math.sqrt(Math.pow(f, 2) + Math.pow(g, 2) + Math.pow(h, 2));
  134. const I1 = [f * t, g * t, h * t];
  135. const I2 = [-1 * f * t, -1 * g * t, -1 * h * t];
  136. const angleAB = angle(A, B);
  137. const angleAI1 = angle(A, I1);
  138. const angleBI1 = angle(B, I1);
  139. const angleAI2 = angle(A, I2);
  140. const angleBI2 = angle(B, I2);
  141. let I;
  142. if (angleAI1 < angleAI2 && angleAI1 < angleBI2 || angleBI1 < angleAI2 && angleBI1 < angleBI2) {
  143. I = I1;
  144. } else {
  145. I = I2;
  146. }
  147. if (angle(A, I) > angleAB || angle(B, I) > angleAB) {
  148. if (distance(vectorToLngLat(I), vectorToLngLat(A)) <= distance(vectorToLngLat(I), vectorToLngLat(B))) {
  149. return [vectorToLngLat(A), true, false];
  150. } else {
  151. return [vectorToLngLat(B), false, true];
  152. }
  153. }
  154. return [vectorToLngLat(I), false, false];
  155. }
  156. var turf_nearest_point_on_line_default = nearestPointOnLine;
  157. export {
  158. turf_nearest_point_on_line_default as default,
  159. nearestPointOnLine
  160. };
  161. //# sourceMappingURL=index.js.map