@turf/nearest-point-on-line 7.2.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,13 +6,17 @@
6
6
 
7
7
  Returns the nearest point on a line to a given point.
8
8
 
9
+ If any of the segments in the input line string are antipodal and therefore
10
+ have an undefined arc, this function will instead return that the point lies
11
+ on the line.
12
+
9
13
  ### Parameters
10
14
 
11
15
  * `lines` **([Geometry][1] | [Feature][2]<([LineString][3] | [MultiLineString][4])>)** lines to snap to
12
16
  * `pt` **([Geometry][1] | [Feature][2]<[Point][5]> | [Array][6]<[number][7]>)** point to snap from
13
17
  * `options` **[Object][8]** Optional parameters (optional, default `{}`)
14
18
 
15
- * `options.units` **[string][9]** can be degrees, radians, miles, or kilometers (optional, default `'kilometers'`)
19
+ * `options.units` **Units** Supports all valid Turf [Units][9] (optional, default `'kilometers'`)
16
20
 
17
21
  ### Examples
18
22
 
@@ -52,7 +56,7 @@ Returns **[Feature][2]<[Point][5]>** closest point on the `line` to `point`. The
52
56
 
53
57
  [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
54
58
 
55
- [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
59
+ [9]: https://turfjs.org/docs/api/types/Units
56
60
 
57
61
  <!-- This file is automatically generated. Please don't edit it directly. If you find an error, edit the source file of the module in question (likely index.js or index.ts), and re-run "yarn docs" from the root of the turf project. -->
58
62
 
@@ -45,34 +45,29 @@ function nearestPointOnLine(lines, pt, options = {}) {
45
45
  const coords = _invariant.getCoords.call(void 0, line);
46
46
  for (let i = 0; i < coords.length - 1; i++) {
47
47
  const start = _helpers.point.call(void 0, coords[i]);
48
- start.properties.dist = _distance.distance.call(void 0, pt, start, options);
49
48
  const startPos = _invariant.getCoord.call(void 0, start);
50
49
  const stop = _helpers.point.call(void 0, coords[i + 1]);
51
- stop.properties.dist = _distance.distance.call(void 0, pt, stop, options);
52
50
  const stopPos = _invariant.getCoord.call(void 0, stop);
53
51
  const sectionLength = _distance.distance.call(void 0, start, stop, options);
54
52
  let intersectPos;
55
53
  let wasEnd;
56
- if (startPos[0] === ptPos[0] && startPos[1] === ptPos[1]) {
57
- [intersectPos, , wasEnd] = [startPos, void 0, false];
58
- } else if (stopPos[0] === ptPos[0] && stopPos[1] === ptPos[1]) {
59
- [intersectPos, , wasEnd] = [stopPos, void 0, true];
54
+ if (stopPos[0] === ptPos[0] && stopPos[1] === ptPos[1]) {
55
+ [intersectPos, wasEnd] = [stopPos, true];
56
+ } else if (startPos[0] === ptPos[0] && startPos[1] === ptPos[1]) {
57
+ [intersectPos, wasEnd] = [startPos, false];
60
58
  } else {
61
- [intersectPos, , wasEnd] = nearestPointOnSegment(
62
- start.geometry.coordinates,
63
- stop.geometry.coordinates,
64
- _invariant.getCoord.call(void 0, pt)
59
+ [intersectPos, wasEnd] = nearestPointOnSegment(
60
+ startPos,
61
+ stopPos,
62
+ ptPos
65
63
  );
66
64
  }
67
- let intersectPt;
68
- if (intersectPos) {
69
- intersectPt = _helpers.point.call(void 0, intersectPos, {
70
- dist: _distance.distance.call(void 0, pt, intersectPos, options),
71
- multiFeatureIndex,
72
- location: length + _distance.distance.call(void 0, start, intersectPos, options)
73
- });
74
- }
75
- if (intersectPt && intersectPt.properties.dist < closestPt.properties.dist) {
65
+ const intersectPt = _helpers.point.call(void 0, intersectPos, {
66
+ dist: _distance.distance.call(void 0, pt, intersectPos, options),
67
+ multiFeatureIndex,
68
+ location: length + _distance.distance.call(void 0, start, intersectPos, options)
69
+ });
70
+ if (intersectPt.properties.dist < closestPt.properties.dist) {
76
71
  closestPt = __spreadProps(__spreadValues({}, intersectPt), {
77
72
  properties: __spreadProps(__spreadValues({}, intersectPt.properties), {
78
73
  // Legacy behaviour where index progresses to next segment # if we
@@ -100,9 +95,9 @@ function cross(v1, v2) {
100
95
  function magnitude(v) {
101
96
  return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));
102
97
  }
103
- function angle(v1, v2) {
104
- const theta = dot(v1, v2) / (magnitude(v1) * magnitude(v2));
105
- return Math.acos(Math.min(Math.max(theta, -1), 1));
98
+ function normalize(v) {
99
+ const mag = magnitude(v);
100
+ return [v[0] / mag, v[1] / mag, v[2] / mag];
106
101
  }
107
102
  function lngLatToVector(a) {
108
103
  const lat = _helpers.degreesToRadians.call(void 0, a[1]);
@@ -115,7 +110,8 @@ function lngLatToVector(a) {
115
110
  }
116
111
  function vectorToLngLat(v) {
117
112
  const [x, y, z] = v;
118
- const lat = _helpers.radiansToDegrees.call(void 0, Math.asin(z));
113
+ const zClamp = Math.min(Math.max(z, -1), 1);
114
+ const lat = _helpers.radiansToDegrees.call(void 0, Math.asin(zClamp));
119
115
  const lng = _helpers.radiansToDegrees.call(void 0, Math.atan2(y, x));
120
116
  return [lng, lat];
121
117
  }
@@ -123,40 +119,37 @@ function nearestPointOnSegment(posA, posB, posC) {
123
119
  const A = lngLatToVector(posA);
124
120
  const B = lngLatToVector(posB);
125
121
  const C = lngLatToVector(posC);
126
- const [Cx, Cy, Cz] = C;
127
- const [D, E, F] = cross(A, B);
128
- const a = E * Cz - F * Cy;
129
- const b = F * Cx - D * Cz;
130
- const c = D * Cy - E * Cx;
131
- const f = c * E - b * F;
132
- const g = a * F - c * D;
133
- const h = b * D - a * E;
134
- const t = 1 / Math.sqrt(Math.pow(f, 2) + Math.pow(g, 2) + Math.pow(h, 2));
135
- const I1 = [f * t, g * t, h * t];
136
- const I2 = [-1 * f * t, -1 * g * t, -1 * h * t];
137
- const angleAB = angle(A, B);
138
- const angleAI1 = angle(A, I1);
139
- const angleBI1 = angle(B, I1);
140
- const angleAI2 = angle(A, I2);
141
- const angleBI2 = angle(B, I2);
142
- let I;
143
- if (angleAI1 < angleAI2 && angleAI1 < angleBI2 || angleBI1 < angleAI2 && angleBI1 < angleBI2) {
144
- I = I1;
145
- } else {
146
- I = I2;
147
- }
148
- if (angle(A, I) > angleAB || angle(B, I) > angleAB) {
149
- if (_distance.distance.call(void 0, vectorToLngLat(I), vectorToLngLat(A)) <= _distance.distance.call(void 0, vectorToLngLat(I), vectorToLngLat(B))) {
150
- return [vectorToLngLat(A), true, false];
122
+ const segmentAxis = cross(A, B);
123
+ if (segmentAxis[0] === 0 && segmentAxis[1] === 0 && segmentAxis[2] === 0) {
124
+ if (dot(A, B) > 0) {
125
+ return [[...posB], true];
151
126
  } else {
152
- return [vectorToLngLat(B), false, true];
127
+ return [[...posC], false];
153
128
  }
154
129
  }
155
- return [vectorToLngLat(I), false, false];
130
+ const targetAxis = cross(segmentAxis, C);
131
+ if (targetAxis[0] === 0 && targetAxis[1] === 0 && targetAxis[2] === 0) {
132
+ return [[...posB], true];
133
+ }
134
+ const intersectionAxis = cross(targetAxis, segmentAxis);
135
+ const I1 = normalize(intersectionAxis);
136
+ const I2 = [-I1[0], -I1[1], -I1[2]];
137
+ const I = dot(C, I1) > dot(C, I2) ? I1 : I2;
138
+ const segmentAxisNorm = normalize(segmentAxis);
139
+ const cmpAI = dot(cross(A, I), segmentAxisNorm);
140
+ const cmpIB = dot(cross(I, B), segmentAxisNorm);
141
+ if (cmpAI >= 0 && cmpIB >= 0) {
142
+ return [vectorToLngLat(I), false];
143
+ }
144
+ if (dot(A, C) > dot(B, C)) {
145
+ return [[...posA], false];
146
+ } else {
147
+ return [[...posB], true];
148
+ }
156
149
  }
157
- var turf_nearest_point_on_line_default = nearestPointOnLine;
150
+ var index_default = nearestPointOnLine;
158
151
 
159
152
 
160
153
 
161
- exports.default = turf_nearest_point_on_line_default; exports.nearestPointOnLine = nearestPointOnLine;
154
+ exports.default = index_default; exports.nearestPointOnLine = nearestPointOnLine;
162
155
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/turf/turf/packages/turf-nearest-point-on-line/dist/cjs/index.cjs","../../index.ts"],"names":[],"mappings":"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","file":"/home/runner/work/turf/turf/packages/turf-nearest-point-on-line/dist/cjs/index.cjs","sourcesContent":[null,"import { Feature, Point, Position, LineString, MultiLineString } from \"geojson\";\nimport { distance } from \"@turf/distance\";\nimport { flattenEach } from \"@turf/meta\";\nimport {\n point,\n degreesToRadians,\n radiansToDegrees,\n Coord,\n Units,\n} from \"@turf/helpers\";\nimport { getCoord, getCoords } from \"@turf/invariant\";\n\n/**\n * Returns the nearest point on a line to a given point.\n *\n * @function\n * @param {Geometry|Feature<LineString|MultiLineString>} lines lines to snap to\n * @param {Geometry|Feature<Point>|number[]} pt point to snap from\n * @param {Object} [options={}] Optional parameters\n * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers\n * @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain four values: `index`: closest point was found on nth line part, `multiFeatureIndex`: closest point was found on the nth line of the `MultiLineString`, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.\n * @example\n * var line = turf.lineString([\n * [-77.031669, 38.878605],\n * [-77.029609, 38.881946],\n * [-77.020339, 38.884084],\n * [-77.025661, 38.885821],\n * [-77.021884, 38.889563],\n * [-77.019824, 38.892368]\n * ]);\n * var pt = turf.point([-77.037076, 38.884017]);\n *\n * var snapped = turf.nearestPointOnLine(line, pt, {units: 'miles'});\n *\n * //addToMap\n * var addToMap = [line, pt, snapped];\n * snapped.properties['marker-color'] = '#00f';\n */\nfunction nearestPointOnLine<G extends LineString | MultiLineString>(\n lines: Feature<G> | G,\n pt: Coord,\n options: { units?: Units } = {}\n): Feature<\n Point,\n {\n dist: number;\n index: number;\n multiFeatureIndex: number;\n location: number;\n [key: string]: any;\n }\n> {\n if (!lines || !pt) {\n throw new Error(\"lines and pt are required arguments\");\n }\n\n const ptPos = getCoord(pt);\n\n let closestPt: Feature<\n Point,\n { dist: number; index: number; multiFeatureIndex: number; location: number }\n > = point([Infinity, Infinity], {\n dist: Infinity,\n index: -1,\n multiFeatureIndex: -1,\n location: -1,\n });\n\n let length = 0.0;\n flattenEach(\n lines,\n function (line: any, _featureIndex: number, multiFeatureIndex: number) {\n const coords: any = getCoords(line);\n\n for (let i = 0; i < coords.length - 1; i++) {\n //start - start of current line section\n const start: Feature<Point, { dist: number }> = point(coords[i]);\n start.properties.dist = distance(pt, start, options);\n const startPos = getCoord(start);\n\n //stop - end of current line section\n const stop: Feature<Point, { dist: number }> = point(coords[i + 1]);\n stop.properties.dist = distance(pt, stop, options);\n const stopPos = getCoord(stop);\n\n // sectionLength\n const sectionLength = distance(start, stop, options);\n let intersectPos: Position;\n let wasEnd: boolean;\n\n // Short circuit if snap point is start or end position of the line\n // segment.\n if (startPos[0] === ptPos[0] && startPos[1] === ptPos[1]) {\n [intersectPos, , wasEnd] = [startPos, undefined, false];\n } else if (stopPos[0] === ptPos[0] && stopPos[1] === ptPos[1]) {\n [intersectPos, , wasEnd] = [stopPos, undefined, true];\n } else {\n // Otherwise, find the nearest point the hard way.\n [intersectPos, , wasEnd] = nearestPointOnSegment(\n start.geometry.coordinates,\n stop.geometry.coordinates,\n getCoord(pt)\n );\n }\n let intersectPt:\n | Feature<\n Point,\n { dist: number; multiFeatureIndex: number; location: number }\n >\n | undefined;\n\n if (intersectPos) {\n intersectPt = point(intersectPos, {\n dist: distance(pt, intersectPos, options),\n multiFeatureIndex: multiFeatureIndex,\n location: length + distance(start, intersectPos, options),\n });\n }\n\n if (\n intersectPt &&\n intersectPt.properties.dist < closestPt.properties.dist\n ) {\n closestPt = {\n ...intersectPt,\n properties: {\n ...intersectPt.properties,\n // Legacy behaviour where index progresses to next segment # if we\n // went with the end point this iteration.\n index: wasEnd ? i + 1 : i,\n },\n };\n }\n\n // update length\n length += sectionLength;\n }\n }\n );\n\n return closestPt;\n}\n\n/*\n * Plan is to externalise these vector functions to a simple third party\n * library.\n * Possible candidate is @amandaghassaei/vector-math though having some import\n * issues.\n */\ntype Vector = [number, number, number];\n\nfunction dot(v1: Vector, v2: Vector): number {\n const [v1x, v1y, v1z] = v1;\n const [v2x, v2y, v2z] = v2;\n return v1x * v2x + v1y * v2y + v1z * v2z;\n}\n\n// https://en.wikipedia.org/wiki/Cross_product\nfunction cross(v1: Vector, v2: Vector): Vector {\n const [v1x, v1y, v1z] = v1;\n const [v2x, v2y, v2z] = v2;\n return [v1y * v2z - v1z * v2y, v1z * v2x - v1x * v2z, v1x * v2y - v1y * v2x];\n}\n\nfunction magnitude(v: Vector) {\n return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));\n}\n\nfunction angle(v1: Vector, v2: Vector): number {\n const theta = dot(v1, v2) / (magnitude(v1) * magnitude(v2));\n return Math.acos(Math.min(Math.max(theta, -1), 1));\n}\n\nfunction lngLatToVector(a: Position): Vector {\n const lat = degreesToRadians(a[1]);\n const lng = degreesToRadians(a[0]);\n return [\n Math.cos(lat) * Math.cos(lng),\n Math.cos(lat) * Math.sin(lng),\n Math.sin(lat),\n ];\n}\n\nfunction vectorToLngLat(v: Vector): Position {\n const [x, y, z] = v;\n const lat = radiansToDegrees(Math.asin(z));\n const lng = radiansToDegrees(Math.atan2(y, x));\n\n return [lng, lat];\n}\n\nfunction nearestPointOnSegment(\n posA: Position, // start point of segment to measure to\n posB: Position, // end point of segment to measure to\n posC: Position // point to measure from\n): [Position, boolean, boolean] {\n // Based heavily on this article on finding cross track distance to an arc:\n // https://gis.stackexchange.com/questions/209540/projecting-cross-track-distance-on-great-circle\n\n // Convert spherical (lng, lat) to cartesian vector coords (x, y, z)\n // In the below https://tikz.net/spherical_1/ we convert lng (𝜙) and lat (𝜃)\n // into vectors with x, y, and z components with a length (r) of 1.\n const A = lngLatToVector(posA); // the vector from 0,0,0 to posA\n const B = lngLatToVector(posB); // ... to posB\n const C = lngLatToVector(posC); // ... to posC\n\n // Components of target point.\n const [Cx, Cy, Cz] = C;\n\n // Calculate coefficients.\n const [D, E, F] = cross(A, B);\n const a = E * Cz - F * Cy;\n const b = F * Cx - D * Cz;\n const c = D * Cy - E * Cx;\n\n const f = c * E - b * F;\n const g = a * F - c * D;\n const h = b * D - a * E;\n\n const t = 1 / Math.sqrt(Math.pow(f, 2) + Math.pow(g, 2) + Math.pow(h, 2));\n\n // Vectors to the two points these great circles intersect.\n const I1: Vector = [f * t, g * t, h * t];\n const I2: Vector = [-1 * f * t, -1 * g * t, -1 * h * t];\n\n // Figure out which is the closest intersection to this segment of the great\n // circle.\n const angleAB = angle(A, B);\n const angleAI1 = angle(A, I1);\n const angleBI1 = angle(B, I1);\n const angleAI2 = angle(A, I2);\n const angleBI2 = angle(B, I2);\n\n let I: Vector;\n\n if (\n (angleAI1 < angleAI2 && angleAI1 < angleBI2) ||\n (angleBI1 < angleAI2 && angleBI1 < angleBI2)\n ) {\n I = I1;\n } else {\n I = I2;\n }\n\n // I is the closest intersection to the segment, though might not actually be\n // ON the segment.\n\n // If angle AI or BI is greater than angleAB, I lies on the circle *beyond* A\n // and B so use the closest of A or B as the intersection\n if (angle(A, I) > angleAB || angle(B, I) > angleAB) {\n if (\n distance(vectorToLngLat(I), vectorToLngLat(A)) <=\n distance(vectorToLngLat(I), vectorToLngLat(B))\n ) {\n return [vectorToLngLat(A), true, false];\n } else {\n return [vectorToLngLat(B), false, true];\n }\n }\n\n // As angleAI nor angleBI don't exceed angleAB, I is on the segment\n return [vectorToLngLat(I), false, false];\n}\n\nexport { nearestPointOnLine };\nexport default nearestPointOnLine;\n"]}
1
+ {"version":3,"sources":["/home/runner/work/turf/turf/packages/turf-nearest-point-on-line/dist/cjs/index.cjs","../../index.ts"],"names":[],"mappings":"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","file":"/home/runner/work/turf/turf/packages/turf-nearest-point-on-line/dist/cjs/index.cjs","sourcesContent":[null,"import { Feature, Point, Position, LineString, MultiLineString } from \"geojson\";\nimport { distance } from \"@turf/distance\";\nimport { flattenEach } from \"@turf/meta\";\nimport {\n point,\n degreesToRadians,\n radiansToDegrees,\n Coord,\n Units,\n} from \"@turf/helpers\";\nimport { getCoord, getCoords } from \"@turf/invariant\";\n\n/**\n * Returns the nearest point on a line to a given point.\n *\n * If any of the segments in the input line string are antipodal and therefore\n * have an undefined arc, this function will instead return that the point lies\n * on the line.\n *\n * @function\n * @param {Geometry|Feature<LineString|MultiLineString>} lines lines to snap to\n * @param {Geometry|Feature<Point>|number[]} pt point to snap from\n * @param {Object} [options={}] Optional parameters\n * @param {Units} [options.units='kilometers'] Supports all valid Turf {@link https://turfjs.org/docs/api/types/Units Units}\n * @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain four values: `index`: closest point was found on nth line part, `multiFeatureIndex`: closest point was found on the nth line of the `MultiLineString`, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.\n * @example\n * var line = turf.lineString([\n * [-77.031669, 38.878605],\n * [-77.029609, 38.881946],\n * [-77.020339, 38.884084],\n * [-77.025661, 38.885821],\n * [-77.021884, 38.889563],\n * [-77.019824, 38.892368]\n * ]);\n * var pt = turf.point([-77.037076, 38.884017]);\n *\n * var snapped = turf.nearestPointOnLine(line, pt, {units: 'miles'});\n *\n * //addToMap\n * var addToMap = [line, pt, snapped];\n * snapped.properties['marker-color'] = '#00f';\n */\nfunction nearestPointOnLine<G extends LineString | MultiLineString>(\n lines: Feature<G> | G,\n pt: Coord,\n options: { units?: Units } = {}\n): Feature<\n Point,\n {\n dist: number;\n index: number;\n multiFeatureIndex: number;\n location: number;\n [key: string]: any;\n }\n> {\n if (!lines || !pt) {\n throw new Error(\"lines and pt are required arguments\");\n }\n\n const ptPos = getCoord(pt);\n\n let closestPt: Feature<\n Point,\n { dist: number; index: number; multiFeatureIndex: number; location: number }\n > = point([Infinity, Infinity], {\n dist: Infinity,\n index: -1,\n multiFeatureIndex: -1,\n location: -1,\n });\n\n let length = 0.0;\n flattenEach(\n lines,\n function (line: any, _featureIndex: number, multiFeatureIndex: number) {\n const coords: any = getCoords(line);\n\n for (let i = 0; i < coords.length - 1; i++) {\n //start - start of current line section\n const start: Feature<Point, { dist: number }> = point(coords[i]);\n const startPos = getCoord(start);\n\n //stop - end of current line section\n const stop: Feature<Point, { dist: number }> = point(coords[i + 1]);\n const stopPos = getCoord(stop);\n\n // sectionLength\n const sectionLength = distance(start, stop, options);\n let intersectPos: Position;\n let wasEnd: boolean;\n\n // Short circuit if snap point is start or end position of the line\n // Test the end position first for consistency in case they are\n // coincident\n if (stopPos[0] === ptPos[0] && stopPos[1] === ptPos[1]) {\n [intersectPos, wasEnd] = [stopPos, true];\n } else if (startPos[0] === ptPos[0] && startPos[1] === ptPos[1]) {\n [intersectPos, wasEnd] = [startPos, false];\n } else {\n // Otherwise, find the nearest point the hard way.\n [intersectPos, wasEnd] = nearestPointOnSegment(\n startPos,\n stopPos,\n ptPos\n );\n }\n\n const intersectPt = point(intersectPos, {\n dist: distance(pt, intersectPos, options),\n multiFeatureIndex: multiFeatureIndex,\n location: length + distance(start, intersectPos, options),\n });\n\n if (intersectPt.properties.dist < closestPt.properties.dist) {\n closestPt = {\n ...intersectPt,\n properties: {\n ...intersectPt.properties,\n // Legacy behaviour where index progresses to next segment # if we\n // went with the end point this iteration.\n index: wasEnd ? i + 1 : i,\n },\n };\n }\n\n // update length\n length += sectionLength;\n }\n }\n );\n\n return closestPt;\n}\n\n// A simple Vector3 type for cartesian operations.\ntype Vector = [number, number, number];\n\nfunction dot(v1: Vector, v2: Vector): number {\n const [v1x, v1y, v1z] = v1;\n const [v2x, v2y, v2z] = v2;\n return v1x * v2x + v1y * v2y + v1z * v2z;\n}\n\n// https://en.wikipedia.org/wiki/Cross_product\nfunction cross(v1: Vector, v2: Vector): Vector {\n const [v1x, v1y, v1z] = v1;\n const [v2x, v2y, v2z] = v2;\n return [v1y * v2z - v1z * v2y, v1z * v2x - v1x * v2z, v1x * v2y - v1y * v2x];\n}\n\nfunction magnitude(v: Vector): number {\n return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));\n}\n\nfunction normalize(v: Vector): Vector {\n const mag = magnitude(v);\n return [v[0] / mag, v[1] / mag, v[2] / mag];\n}\n\nfunction lngLatToVector(a: Position): Vector {\n const lat = degreesToRadians(a[1]);\n const lng = degreesToRadians(a[0]);\n return [\n Math.cos(lat) * Math.cos(lng),\n Math.cos(lat) * Math.sin(lng),\n Math.sin(lat),\n ];\n}\n\nfunction vectorToLngLat(v: Vector): Position {\n const [x, y, z] = v;\n // Clamp the z-value to ensure that is inside the [-1, 1] domain as required\n // by asin. Note therefore that this function should only be applied to unit\n // vectors so z > 1 should not exist\n const zClamp = Math.min(Math.max(z, -1), 1);\n const lat = radiansToDegrees(Math.asin(zClamp));\n const lng = radiansToDegrees(Math.atan2(y, x));\n\n return [lng, lat];\n}\n\nfunction nearestPointOnSegment(\n posA: Position, // start point of segment to measure to\n posB: Position, // end point of segment to measure to\n posC: Position // point to measure from\n): [Position, boolean] {\n // Based heavily on this article on finding cross track distance to an arc:\n // https://gis.stackexchange.com/questions/209540/projecting-cross-track-distance-on-great-circle\n\n // Convert spherical (lng, lat) to cartesian vector coords (x, y, z)\n // In the below https://tikz.net/spherical_1/ we convert lng (𝜙) and lat (𝜃)\n // into vectors with x, y, and z components with a length (r) of 1.\n const A = lngLatToVector(posA); // the vector from 0,0,0 to posA\n const B = lngLatToVector(posB); // ... to posB\n const C = lngLatToVector(posC); // ... to posC\n\n // The axis (normal vector) of the great circle plane containing the line segment\n const segmentAxis = cross(A, B);\n\n // Two degenerate cases exist for the segment axis cross product. The first is\n // when vectors are aligned (within the bounds of floating point tolerance).\n // The second is where vectors are antipodal (again within the bounds of\n // tolerance. Both cases produce a [0, 0, 0] cross product which invalidates\n // the rest of the algorithm, but each case must be handled separately:\n // - The aligned case indicates coincidence of A and B. therefore this can be\n // an early return assuming the closest point is the end (for consistency).\n // - The antipodal case is truly degenerate - an infinte number of great\n // circles are possible and one will always pass through C. However, given\n // that this case is both highly unlikely to occur in practice and that is\n // will usually be logically sound to return that the point is on the\n // segment, we choose to return the provided point.\n if (segmentAxis[0] === 0 && segmentAxis[1] === 0 && segmentAxis[2] === 0) {\n if (dot(A, B) > 0) {\n return [[...posB], true];\n } else {\n return [[...posC], false];\n }\n }\n\n // The axis of the great circle passing through the segment's axis and the\n // target point\n const targetAxis = cross(segmentAxis, C);\n\n // This cross product also has a degenerate case where the segment axis is\n // coincident with or antipodal to the target point. In this case the point\n // is equidistant to the entire segment. For consistency, we early return the\n // endpoint as the matching point.\n if (targetAxis[0] === 0 && targetAxis[1] === 0 && targetAxis[2] === 0) {\n return [[...posB], true];\n }\n\n // The line of intersection between the two great circle planes\n const intersectionAxis = cross(targetAxis, segmentAxis);\n\n // Vectors to the two points these great circles intersect are the normalized\n // intersection and its antipodes\n const I1 = normalize(intersectionAxis);\n const I2: Vector = [-I1[0], -I1[1], -I1[2]];\n\n // Figure out which is the closest intersection to this segment of the great circle\n // Note that for points on a unit sphere, the dot product represents the\n // cosine of the angle between the two vectors which monotonically increases\n // the closer the two points are together and therefore determines proximity\n const I = dot(C, I1) > dot(C, I2) ? I1 : I2;\n\n // I is the closest intersection to the segment, though might not actually be\n // ON the segment. To test whether the closest intersection lies on the arc or\n // not, we do a cross product comparison to check rotation around the unit\n // circle defined by the great circle plane.\n const segmentAxisNorm = normalize(segmentAxis);\n const cmpAI = dot(cross(A, I), segmentAxisNorm);\n const cmpIB = dot(cross(I, B), segmentAxisNorm);\n\n // When both comparisons are positive, the rotation from A to I to B is in the\n // same direction, implying that I lies between A and B\n if (cmpAI >= 0 && cmpIB >= 0) {\n return [vectorToLngLat(I), false];\n }\n\n // Finally process the case where the intersection is not on the segment,\n // using the dot product with the original point to find the closest endpoint\n if (dot(A, C) > dot(B, C)) {\n // Clone position when returning as it is reasonable to not expect structural\n // sharing on the returned Position in all return cases\n return [[...posA], false];\n } else {\n return [[...posB], true];\n }\n}\n\nexport { nearestPointOnLine };\nexport default nearestPointOnLine;\n"]}
@@ -4,11 +4,15 @@ import { Coord, Units } from '@turf/helpers';
4
4
  /**
5
5
  * Returns the nearest point on a line to a given point.
6
6
  *
7
+ * If any of the segments in the input line string are antipodal and therefore
8
+ * have an undefined arc, this function will instead return that the point lies
9
+ * on the line.
10
+ *
7
11
  * @function
8
12
  * @param {Geometry|Feature<LineString|MultiLineString>} lines lines to snap to
9
13
  * @param {Geometry|Feature<Point>|number[]} pt point to snap from
10
14
  * @param {Object} [options={}] Optional parameters
11
- * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
15
+ * @param {Units} [options.units='kilometers'] Supports all valid Turf {@link https://turfjs.org/docs/api/types/Units Units}
12
16
  * @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain four values: `index`: closest point was found on nth line part, `multiFeatureIndex`: closest point was found on the nth line of the `MultiLineString`, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.
13
17
  * @example
14
18
  * var line = turf.lineString([
@@ -4,11 +4,15 @@ import { Coord, Units } from '@turf/helpers';
4
4
  /**
5
5
  * Returns the nearest point on a line to a given point.
6
6
  *
7
+ * If any of the segments in the input line string are antipodal and therefore
8
+ * have an undefined arc, this function will instead return that the point lies
9
+ * on the line.
10
+ *
7
11
  * @function
8
12
  * @param {Geometry|Feature<LineString|MultiLineString>} lines lines to snap to
9
13
  * @param {Geometry|Feature<Point>|number[]} pt point to snap from
10
14
  * @param {Object} [options={}] Optional parameters
11
- * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
15
+ * @param {Units} [options.units='kilometers'] Supports all valid Turf {@link https://turfjs.org/docs/api/types/Units Units}
12
16
  * @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain four values: `index`: closest point was found on nth line part, `multiFeatureIndex`: closest point was found on the nth line of the `MultiLineString`, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.
13
17
  * @example
14
18
  * var line = turf.lineString([
package/dist/esm/index.js CHANGED
@@ -45,34 +45,29 @@ function nearestPointOnLine(lines, pt, options = {}) {
45
45
  const coords = getCoords(line);
46
46
  for (let i = 0; i < coords.length - 1; i++) {
47
47
  const start = point(coords[i]);
48
- start.properties.dist = distance(pt, start, options);
49
48
  const startPos = getCoord(start);
50
49
  const stop = point(coords[i + 1]);
51
- stop.properties.dist = distance(pt, stop, options);
52
50
  const stopPos = getCoord(stop);
53
51
  const sectionLength = distance(start, stop, options);
54
52
  let intersectPos;
55
53
  let wasEnd;
56
- if (startPos[0] === ptPos[0] && startPos[1] === ptPos[1]) {
57
- [intersectPos, , wasEnd] = [startPos, void 0, false];
58
- } else if (stopPos[0] === ptPos[0] && stopPos[1] === ptPos[1]) {
59
- [intersectPos, , wasEnd] = [stopPos, void 0, true];
54
+ if (stopPos[0] === ptPos[0] && stopPos[1] === ptPos[1]) {
55
+ [intersectPos, wasEnd] = [stopPos, true];
56
+ } else if (startPos[0] === ptPos[0] && startPos[1] === ptPos[1]) {
57
+ [intersectPos, wasEnd] = [startPos, false];
60
58
  } else {
61
- [intersectPos, , wasEnd] = nearestPointOnSegment(
62
- start.geometry.coordinates,
63
- stop.geometry.coordinates,
64
- getCoord(pt)
59
+ [intersectPos, wasEnd] = nearestPointOnSegment(
60
+ startPos,
61
+ stopPos,
62
+ ptPos
65
63
  );
66
64
  }
67
- let intersectPt;
68
- if (intersectPos) {
69
- intersectPt = point(intersectPos, {
70
- dist: distance(pt, intersectPos, options),
71
- multiFeatureIndex,
72
- location: length + distance(start, intersectPos, options)
73
- });
74
- }
75
- if (intersectPt && intersectPt.properties.dist < closestPt.properties.dist) {
65
+ const intersectPt = point(intersectPos, {
66
+ dist: distance(pt, intersectPos, options),
67
+ multiFeatureIndex,
68
+ location: length + distance(start, intersectPos, options)
69
+ });
70
+ if (intersectPt.properties.dist < closestPt.properties.dist) {
76
71
  closestPt = __spreadProps(__spreadValues({}, intersectPt), {
77
72
  properties: __spreadProps(__spreadValues({}, intersectPt.properties), {
78
73
  // Legacy behaviour where index progresses to next segment # if we
@@ -100,9 +95,9 @@ function cross(v1, v2) {
100
95
  function magnitude(v) {
101
96
  return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));
102
97
  }
103
- function angle(v1, v2) {
104
- const theta = dot(v1, v2) / (magnitude(v1) * magnitude(v2));
105
- return Math.acos(Math.min(Math.max(theta, -1), 1));
98
+ function normalize(v) {
99
+ const mag = magnitude(v);
100
+ return [v[0] / mag, v[1] / mag, v[2] / mag];
106
101
  }
107
102
  function lngLatToVector(a) {
108
103
  const lat = degreesToRadians(a[1]);
@@ -115,7 +110,8 @@ function lngLatToVector(a) {
115
110
  }
116
111
  function vectorToLngLat(v) {
117
112
  const [x, y, z] = v;
118
- const lat = radiansToDegrees(Math.asin(z));
113
+ const zClamp = Math.min(Math.max(z, -1), 1);
114
+ const lat = radiansToDegrees(Math.asin(zClamp));
119
115
  const lng = radiansToDegrees(Math.atan2(y, x));
120
116
  return [lng, lat];
121
117
  }
@@ -123,40 +119,37 @@ function nearestPointOnSegment(posA, posB, posC) {
123
119
  const A = lngLatToVector(posA);
124
120
  const B = lngLatToVector(posB);
125
121
  const C = lngLatToVector(posC);
126
- const [Cx, Cy, Cz] = C;
127
- const [D, E, F] = cross(A, B);
128
- const a = E * Cz - F * Cy;
129
- const b = F * Cx - D * Cz;
130
- const c = D * Cy - E * Cx;
131
- const f = c * E - b * F;
132
- const g = a * F - c * D;
133
- const h = b * D - a * E;
134
- const t = 1 / Math.sqrt(Math.pow(f, 2) + Math.pow(g, 2) + Math.pow(h, 2));
135
- const I1 = [f * t, g * t, h * t];
136
- const I2 = [-1 * f * t, -1 * g * t, -1 * h * t];
137
- const angleAB = angle(A, B);
138
- const angleAI1 = angle(A, I1);
139
- const angleBI1 = angle(B, I1);
140
- const angleAI2 = angle(A, I2);
141
- const angleBI2 = angle(B, I2);
142
- let I;
143
- if (angleAI1 < angleAI2 && angleAI1 < angleBI2 || angleBI1 < angleAI2 && angleBI1 < angleBI2) {
144
- I = I1;
145
- } else {
146
- I = I2;
147
- }
148
- if (angle(A, I) > angleAB || angle(B, I) > angleAB) {
149
- if (distance(vectorToLngLat(I), vectorToLngLat(A)) <= distance(vectorToLngLat(I), vectorToLngLat(B))) {
150
- return [vectorToLngLat(A), true, false];
122
+ const segmentAxis = cross(A, B);
123
+ if (segmentAxis[0] === 0 && segmentAxis[1] === 0 && segmentAxis[2] === 0) {
124
+ if (dot(A, B) > 0) {
125
+ return [[...posB], true];
151
126
  } else {
152
- return [vectorToLngLat(B), false, true];
127
+ return [[...posC], false];
153
128
  }
154
129
  }
155
- return [vectorToLngLat(I), false, false];
130
+ const targetAxis = cross(segmentAxis, C);
131
+ if (targetAxis[0] === 0 && targetAxis[1] === 0 && targetAxis[2] === 0) {
132
+ return [[...posB], true];
133
+ }
134
+ const intersectionAxis = cross(targetAxis, segmentAxis);
135
+ const I1 = normalize(intersectionAxis);
136
+ const I2 = [-I1[0], -I1[1], -I1[2]];
137
+ const I = dot(C, I1) > dot(C, I2) ? I1 : I2;
138
+ const segmentAxisNorm = normalize(segmentAxis);
139
+ const cmpAI = dot(cross(A, I), segmentAxisNorm);
140
+ const cmpIB = dot(cross(I, B), segmentAxisNorm);
141
+ if (cmpAI >= 0 && cmpIB >= 0) {
142
+ return [vectorToLngLat(I), false];
143
+ }
144
+ if (dot(A, C) > dot(B, C)) {
145
+ return [[...posA], false];
146
+ } else {
147
+ return [[...posB], true];
148
+ }
156
149
  }
157
- var turf_nearest_point_on_line_default = nearestPointOnLine;
150
+ var index_default = nearestPointOnLine;
158
151
  export {
159
- turf_nearest_point_on_line_default as default,
152
+ index_default as default,
160
153
  nearestPointOnLine
161
154
  };
162
155
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../index.ts"],"sourcesContent":["import { Feature, Point, Position, LineString, MultiLineString } from \"geojson\";\nimport { distance } from \"@turf/distance\";\nimport { flattenEach } from \"@turf/meta\";\nimport {\n point,\n degreesToRadians,\n radiansToDegrees,\n Coord,\n Units,\n} from \"@turf/helpers\";\nimport { getCoord, getCoords } from \"@turf/invariant\";\n\n/**\n * Returns the nearest point on a line to a given point.\n *\n * @function\n * @param {Geometry|Feature<LineString|MultiLineString>} lines lines to snap to\n * @param {Geometry|Feature<Point>|number[]} pt point to snap from\n * @param {Object} [options={}] Optional parameters\n * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers\n * @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain four values: `index`: closest point was found on nth line part, `multiFeatureIndex`: closest point was found on the nth line of the `MultiLineString`, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.\n * @example\n * var line = turf.lineString([\n * [-77.031669, 38.878605],\n * [-77.029609, 38.881946],\n * [-77.020339, 38.884084],\n * [-77.025661, 38.885821],\n * [-77.021884, 38.889563],\n * [-77.019824, 38.892368]\n * ]);\n * var pt = turf.point([-77.037076, 38.884017]);\n *\n * var snapped = turf.nearestPointOnLine(line, pt, {units: 'miles'});\n *\n * //addToMap\n * var addToMap = [line, pt, snapped];\n * snapped.properties['marker-color'] = '#00f';\n */\nfunction nearestPointOnLine<G extends LineString | MultiLineString>(\n lines: Feature<G> | G,\n pt: Coord,\n options: { units?: Units } = {}\n): Feature<\n Point,\n {\n dist: number;\n index: number;\n multiFeatureIndex: number;\n location: number;\n [key: string]: any;\n }\n> {\n if (!lines || !pt) {\n throw new Error(\"lines and pt are required arguments\");\n }\n\n const ptPos = getCoord(pt);\n\n let closestPt: Feature<\n Point,\n { dist: number; index: number; multiFeatureIndex: number; location: number }\n > = point([Infinity, Infinity], {\n dist: Infinity,\n index: -1,\n multiFeatureIndex: -1,\n location: -1,\n });\n\n let length = 0.0;\n flattenEach(\n lines,\n function (line: any, _featureIndex: number, multiFeatureIndex: number) {\n const coords: any = getCoords(line);\n\n for (let i = 0; i < coords.length - 1; i++) {\n //start - start of current line section\n const start: Feature<Point, { dist: number }> = point(coords[i]);\n start.properties.dist = distance(pt, start, options);\n const startPos = getCoord(start);\n\n //stop - end of current line section\n const stop: Feature<Point, { dist: number }> = point(coords[i + 1]);\n stop.properties.dist = distance(pt, stop, options);\n const stopPos = getCoord(stop);\n\n // sectionLength\n const sectionLength = distance(start, stop, options);\n let intersectPos: Position;\n let wasEnd: boolean;\n\n // Short circuit if snap point is start or end position of the line\n // segment.\n if (startPos[0] === ptPos[0] && startPos[1] === ptPos[1]) {\n [intersectPos, , wasEnd] = [startPos, undefined, false];\n } else if (stopPos[0] === ptPos[0] && stopPos[1] === ptPos[1]) {\n [intersectPos, , wasEnd] = [stopPos, undefined, true];\n } else {\n // Otherwise, find the nearest point the hard way.\n [intersectPos, , wasEnd] = nearestPointOnSegment(\n start.geometry.coordinates,\n stop.geometry.coordinates,\n getCoord(pt)\n );\n }\n let intersectPt:\n | Feature<\n Point,\n { dist: number; multiFeatureIndex: number; location: number }\n >\n | undefined;\n\n if (intersectPos) {\n intersectPt = point(intersectPos, {\n dist: distance(pt, intersectPos, options),\n multiFeatureIndex: multiFeatureIndex,\n location: length + distance(start, intersectPos, options),\n });\n }\n\n if (\n intersectPt &&\n intersectPt.properties.dist < closestPt.properties.dist\n ) {\n closestPt = {\n ...intersectPt,\n properties: {\n ...intersectPt.properties,\n // Legacy behaviour where index progresses to next segment # if we\n // went with the end point this iteration.\n index: wasEnd ? i + 1 : i,\n },\n };\n }\n\n // update length\n length += sectionLength;\n }\n }\n );\n\n return closestPt;\n}\n\n/*\n * Plan is to externalise these vector functions to a simple third party\n * library.\n * Possible candidate is @amandaghassaei/vector-math though having some import\n * issues.\n */\ntype Vector = [number, number, number];\n\nfunction dot(v1: Vector, v2: Vector): number {\n const [v1x, v1y, v1z] = v1;\n const [v2x, v2y, v2z] = v2;\n return v1x * v2x + v1y * v2y + v1z * v2z;\n}\n\n// https://en.wikipedia.org/wiki/Cross_product\nfunction cross(v1: Vector, v2: Vector): Vector {\n const [v1x, v1y, v1z] = v1;\n const [v2x, v2y, v2z] = v2;\n return [v1y * v2z - v1z * v2y, v1z * v2x - v1x * v2z, v1x * v2y - v1y * v2x];\n}\n\nfunction magnitude(v: Vector) {\n return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));\n}\n\nfunction angle(v1: Vector, v2: Vector): number {\n const theta = dot(v1, v2) / (magnitude(v1) * magnitude(v2));\n return Math.acos(Math.min(Math.max(theta, -1), 1));\n}\n\nfunction lngLatToVector(a: Position): Vector {\n const lat = degreesToRadians(a[1]);\n const lng = degreesToRadians(a[0]);\n return [\n Math.cos(lat) * Math.cos(lng),\n Math.cos(lat) * Math.sin(lng),\n Math.sin(lat),\n ];\n}\n\nfunction vectorToLngLat(v: Vector): Position {\n const [x, y, z] = v;\n const lat = radiansToDegrees(Math.asin(z));\n const lng = radiansToDegrees(Math.atan2(y, x));\n\n return [lng, lat];\n}\n\nfunction nearestPointOnSegment(\n posA: Position, // start point of segment to measure to\n posB: Position, // end point of segment to measure to\n posC: Position // point to measure from\n): [Position, boolean, boolean] {\n // Based heavily on this article on finding cross track distance to an arc:\n // https://gis.stackexchange.com/questions/209540/projecting-cross-track-distance-on-great-circle\n\n // Convert spherical (lng, lat) to cartesian vector coords (x, y, z)\n // In the below https://tikz.net/spherical_1/ we convert lng (𝜙) and lat (𝜃)\n // into vectors with x, y, and z components with a length (r) of 1.\n const A = lngLatToVector(posA); // the vector from 0,0,0 to posA\n const B = lngLatToVector(posB); // ... to posB\n const C = lngLatToVector(posC); // ... to posC\n\n // Components of target point.\n const [Cx, Cy, Cz] = C;\n\n // Calculate coefficients.\n const [D, E, F] = cross(A, B);\n const a = E * Cz - F * Cy;\n const b = F * Cx - D * Cz;\n const c = D * Cy - E * Cx;\n\n const f = c * E - b * F;\n const g = a * F - c * D;\n const h = b * D - a * E;\n\n const t = 1 / Math.sqrt(Math.pow(f, 2) + Math.pow(g, 2) + Math.pow(h, 2));\n\n // Vectors to the two points these great circles intersect.\n const I1: Vector = [f * t, g * t, h * t];\n const I2: Vector = [-1 * f * t, -1 * g * t, -1 * h * t];\n\n // Figure out which is the closest intersection to this segment of the great\n // circle.\n const angleAB = angle(A, B);\n const angleAI1 = angle(A, I1);\n const angleBI1 = angle(B, I1);\n const angleAI2 = angle(A, I2);\n const angleBI2 = angle(B, I2);\n\n let I: Vector;\n\n if (\n (angleAI1 < angleAI2 && angleAI1 < angleBI2) ||\n (angleBI1 < angleAI2 && angleBI1 < angleBI2)\n ) {\n I = I1;\n } else {\n I = I2;\n }\n\n // I is the closest intersection to the segment, though might not actually be\n // ON the segment.\n\n // If angle AI or BI is greater than angleAB, I lies on the circle *beyond* A\n // and B so use the closest of A or B as the intersection\n if (angle(A, I) > angleAB || angle(B, I) > angleAB) {\n if (\n distance(vectorToLngLat(I), vectorToLngLat(A)) <=\n distance(vectorToLngLat(I), vectorToLngLat(B))\n ) {\n return [vectorToLngLat(A), true, false];\n } else {\n return [vectorToLngLat(B), false, true];\n }\n }\n\n // As angleAI nor angleBI don't exceed angleAB, I is on the segment\n return [vectorToLngLat(I), false, false];\n}\n\nexport { nearestPointOnLine };\nexport default nearestPointOnLine;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../index.ts"],"sourcesContent":["import { Feature, Point, Position, LineString, MultiLineString } from \"geojson\";\nimport { distance } from \"@turf/distance\";\nimport { flattenEach } from \"@turf/meta\";\nimport {\n point,\n degreesToRadians,\n radiansToDegrees,\n Coord,\n Units,\n} from \"@turf/helpers\";\nimport { getCoord, getCoords } from \"@turf/invariant\";\n\n/**\n * Returns the nearest point on a line to a given point.\n *\n * If any of the segments in the input line string are antipodal and therefore\n * have an undefined arc, this function will instead return that the point lies\n * on the line.\n *\n * @function\n * @param {Geometry|Feature<LineString|MultiLineString>} lines lines to snap to\n * @param {Geometry|Feature<Point>|number[]} pt point to snap from\n * @param {Object} [options={}] Optional parameters\n * @param {Units} [options.units='kilometers'] Supports all valid Turf {@link https://turfjs.org/docs/api/types/Units Units}\n * @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain four values: `index`: closest point was found on nth line part, `multiFeatureIndex`: closest point was found on the nth line of the `MultiLineString`, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.\n * @example\n * var line = turf.lineString([\n * [-77.031669, 38.878605],\n * [-77.029609, 38.881946],\n * [-77.020339, 38.884084],\n * [-77.025661, 38.885821],\n * [-77.021884, 38.889563],\n * [-77.019824, 38.892368]\n * ]);\n * var pt = turf.point([-77.037076, 38.884017]);\n *\n * var snapped = turf.nearestPointOnLine(line, pt, {units: 'miles'});\n *\n * //addToMap\n * var addToMap = [line, pt, snapped];\n * snapped.properties['marker-color'] = '#00f';\n */\nfunction nearestPointOnLine<G extends LineString | MultiLineString>(\n lines: Feature<G> | G,\n pt: Coord,\n options: { units?: Units } = {}\n): Feature<\n Point,\n {\n dist: number;\n index: number;\n multiFeatureIndex: number;\n location: number;\n [key: string]: any;\n }\n> {\n if (!lines || !pt) {\n throw new Error(\"lines and pt are required arguments\");\n }\n\n const ptPos = getCoord(pt);\n\n let closestPt: Feature<\n Point,\n { dist: number; index: number; multiFeatureIndex: number; location: number }\n > = point([Infinity, Infinity], {\n dist: Infinity,\n index: -1,\n multiFeatureIndex: -1,\n location: -1,\n });\n\n let length = 0.0;\n flattenEach(\n lines,\n function (line: any, _featureIndex: number, multiFeatureIndex: number) {\n const coords: any = getCoords(line);\n\n for (let i = 0; i < coords.length - 1; i++) {\n //start - start of current line section\n const start: Feature<Point, { dist: number }> = point(coords[i]);\n const startPos = getCoord(start);\n\n //stop - end of current line section\n const stop: Feature<Point, { dist: number }> = point(coords[i + 1]);\n const stopPos = getCoord(stop);\n\n // sectionLength\n const sectionLength = distance(start, stop, options);\n let intersectPos: Position;\n let wasEnd: boolean;\n\n // Short circuit if snap point is start or end position of the line\n // Test the end position first for consistency in case they are\n // coincident\n if (stopPos[0] === ptPos[0] && stopPos[1] === ptPos[1]) {\n [intersectPos, wasEnd] = [stopPos, true];\n } else if (startPos[0] === ptPos[0] && startPos[1] === ptPos[1]) {\n [intersectPos, wasEnd] = [startPos, false];\n } else {\n // Otherwise, find the nearest point the hard way.\n [intersectPos, wasEnd] = nearestPointOnSegment(\n startPos,\n stopPos,\n ptPos\n );\n }\n\n const intersectPt = point(intersectPos, {\n dist: distance(pt, intersectPos, options),\n multiFeatureIndex: multiFeatureIndex,\n location: length + distance(start, intersectPos, options),\n });\n\n if (intersectPt.properties.dist < closestPt.properties.dist) {\n closestPt = {\n ...intersectPt,\n properties: {\n ...intersectPt.properties,\n // Legacy behaviour where index progresses to next segment # if we\n // went with the end point this iteration.\n index: wasEnd ? i + 1 : i,\n },\n };\n }\n\n // update length\n length += sectionLength;\n }\n }\n );\n\n return closestPt;\n}\n\n// A simple Vector3 type for cartesian operations.\ntype Vector = [number, number, number];\n\nfunction dot(v1: Vector, v2: Vector): number {\n const [v1x, v1y, v1z] = v1;\n const [v2x, v2y, v2z] = v2;\n return v1x * v2x + v1y * v2y + v1z * v2z;\n}\n\n// https://en.wikipedia.org/wiki/Cross_product\nfunction cross(v1: Vector, v2: Vector): Vector {\n const [v1x, v1y, v1z] = v1;\n const [v2x, v2y, v2z] = v2;\n return [v1y * v2z - v1z * v2y, v1z * v2x - v1x * v2z, v1x * v2y - v1y * v2x];\n}\n\nfunction magnitude(v: Vector): number {\n return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));\n}\n\nfunction normalize(v: Vector): Vector {\n const mag = magnitude(v);\n return [v[0] / mag, v[1] / mag, v[2] / mag];\n}\n\nfunction lngLatToVector(a: Position): Vector {\n const lat = degreesToRadians(a[1]);\n const lng = degreesToRadians(a[0]);\n return [\n Math.cos(lat) * Math.cos(lng),\n Math.cos(lat) * Math.sin(lng),\n Math.sin(lat),\n ];\n}\n\nfunction vectorToLngLat(v: Vector): Position {\n const [x, y, z] = v;\n // Clamp the z-value to ensure that is inside the [-1, 1] domain as required\n // by asin. Note therefore that this function should only be applied to unit\n // vectors so z > 1 should not exist\n const zClamp = Math.min(Math.max(z, -1), 1);\n const lat = radiansToDegrees(Math.asin(zClamp));\n const lng = radiansToDegrees(Math.atan2(y, x));\n\n return [lng, lat];\n}\n\nfunction nearestPointOnSegment(\n posA: Position, // start point of segment to measure to\n posB: Position, // end point of segment to measure to\n posC: Position // point to measure from\n): [Position, boolean] {\n // Based heavily on this article on finding cross track distance to an arc:\n // https://gis.stackexchange.com/questions/209540/projecting-cross-track-distance-on-great-circle\n\n // Convert spherical (lng, lat) to cartesian vector coords (x, y, z)\n // In the below https://tikz.net/spherical_1/ we convert lng (𝜙) and lat (𝜃)\n // into vectors with x, y, and z components with a length (r) of 1.\n const A = lngLatToVector(posA); // the vector from 0,0,0 to posA\n const B = lngLatToVector(posB); // ... to posB\n const C = lngLatToVector(posC); // ... to posC\n\n // The axis (normal vector) of the great circle plane containing the line segment\n const segmentAxis = cross(A, B);\n\n // Two degenerate cases exist for the segment axis cross product. The first is\n // when vectors are aligned (within the bounds of floating point tolerance).\n // The second is where vectors are antipodal (again within the bounds of\n // tolerance. Both cases produce a [0, 0, 0] cross product which invalidates\n // the rest of the algorithm, but each case must be handled separately:\n // - The aligned case indicates coincidence of A and B. therefore this can be\n // an early return assuming the closest point is the end (for consistency).\n // - The antipodal case is truly degenerate - an infinte number of great\n // circles are possible and one will always pass through C. However, given\n // that this case is both highly unlikely to occur in practice and that is\n // will usually be logically sound to return that the point is on the\n // segment, we choose to return the provided point.\n if (segmentAxis[0] === 0 && segmentAxis[1] === 0 && segmentAxis[2] === 0) {\n if (dot(A, B) > 0) {\n return [[...posB], true];\n } else {\n return [[...posC], false];\n }\n }\n\n // The axis of the great circle passing through the segment's axis and the\n // target point\n const targetAxis = cross(segmentAxis, C);\n\n // This cross product also has a degenerate case where the segment axis is\n // coincident with or antipodal to the target point. In this case the point\n // is equidistant to the entire segment. For consistency, we early return the\n // endpoint as the matching point.\n if (targetAxis[0] === 0 && targetAxis[1] === 0 && targetAxis[2] === 0) {\n return [[...posB], true];\n }\n\n // The line of intersection between the two great circle planes\n const intersectionAxis = cross(targetAxis, segmentAxis);\n\n // Vectors to the two points these great circles intersect are the normalized\n // intersection and its antipodes\n const I1 = normalize(intersectionAxis);\n const I2: Vector = [-I1[0], -I1[1], -I1[2]];\n\n // Figure out which is the closest intersection to this segment of the great circle\n // Note that for points on a unit sphere, the dot product represents the\n // cosine of the angle between the two vectors which monotonically increases\n // the closer the two points are together and therefore determines proximity\n const I = dot(C, I1) > dot(C, I2) ? I1 : I2;\n\n // I is the closest intersection to the segment, though might not actually be\n // ON the segment. To test whether the closest intersection lies on the arc or\n // not, we do a cross product comparison to check rotation around the unit\n // circle defined by the great circle plane.\n const segmentAxisNorm = normalize(segmentAxis);\n const cmpAI = dot(cross(A, I), segmentAxisNorm);\n const cmpIB = dot(cross(I, B), segmentAxisNorm);\n\n // When both comparisons are positive, the rotation from A to I to B is in the\n // same direction, implying that I lies between A and B\n if (cmpAI >= 0 && cmpIB >= 0) {\n return [vectorToLngLat(I), false];\n }\n\n // Finally process the case where the intersection is not on the segment,\n // using the dot product with the original point to find the closest endpoint\n if (dot(A, C) > dot(B, C)) {\n // Clone position when returning as it is reasonable to not expect structural\n // sharing on the returned Position in all return cases\n return [[...posA], false];\n } else {\n return [[...posB], true];\n }\n}\n\nexport { nearestPointOnLine };\nexport default nearestPointOnLine;\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@turf/nearest-point-on-line",
3
- "version": "7.2.0",
4
- "description": "turf nearest-point-on-line module",
3
+ "version": "7.3.0",
4
+ "description": "Finds the nearest point on a line to a given point",
5
5
  "author": "Turf Authors",
6
+ "contributors": [
7
+ "Angel Lacret <@alacret>",
8
+ "Jon Miles <@jonmiles>",
9
+ "John Ziebro <@Insighttful>"
10
+ ],
6
11
  "license": "MIT",
7
12
  "bugs": {
8
13
  "url": "https://github.com/Turfjs/turf/issues"
@@ -46,27 +51,27 @@
46
51
  "test:types": "tsc --esModuleInterop --module node16 --moduleResolution node16 --noEmit --strict types.ts"
47
52
  },
48
53
  "devDependencies": {
49
- "@turf/along": "^7.2.0",
50
- "@turf/length": "^7.2.0",
51
- "@turf/truncate": "^7.2.0",
54
+ "@turf/along": "7.3.0",
55
+ "@turf/length": "7.3.0",
56
+ "@turf/truncate": "7.3.0",
52
57
  "@types/benchmark": "^2.1.5",
53
- "@types/tape": "^4.13.4",
58
+ "@types/tape": "^5.8.1",
54
59
  "benchmark": "^2.1.4",
55
60
  "load-json-file": "^7.0.1",
56
61
  "npm-run-all": "^4.1.5",
57
62
  "tape": "^5.9.0",
58
- "tsup": "^8.3.5",
59
- "tsx": "^4.19.2",
60
- "typescript": "^5.5.4",
61
- "write-json-file": "^5.0.0"
63
+ "tsup": "^8.4.0",
64
+ "tsx": "^4.19.4",
65
+ "typescript": "^5.8.3",
66
+ "write-json-file": "^6.0.0"
62
67
  },
63
68
  "dependencies": {
64
- "@turf/distance": "^7.2.0",
65
- "@turf/helpers": "^7.2.0",
66
- "@turf/invariant": "^7.2.0",
67
- "@turf/meta": "^7.2.0",
69
+ "@turf/distance": "7.3.0",
70
+ "@turf/helpers": "7.3.0",
71
+ "@turf/invariant": "7.3.0",
72
+ "@turf/meta": "7.3.0",
68
73
  "@types/geojson": "^7946.0.10",
69
74
  "tslib": "^2.8.1"
70
75
  },
71
- "gitHead": "7b0f0374c4668cd569f8904c71e2ae7d941be867"
76
+ "gitHead": "9f58a103e8f9a587ab640307ed03ba5233913ddd"
72
77
  }