@turf/nearest-point-on-line 7.3.0 → 7.3.2
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 +19 -6
- package/dist/cjs/index.cjs +57 -26
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +27 -9
- package/dist/esm/index.d.ts +27 -9
- package/dist/esm/index.js +57 -26
- package/dist/esm/index.js.map +1 -1
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -10,10 +10,23 @@ If any of the segments in the input line string are antipodal and therefore
|
|
|
10
10
|
have an undefined arc, this function will instead return that the point lies
|
|
11
11
|
on the line.
|
|
12
12
|
|
|
13
|
+
⚠️ We have begun the process of migrating to different return properties for
|
|
14
|
+
this function. The new properties we recommend using as of v7.4 are:
|
|
15
|
+
|
|
16
|
+
* lineStringIndex - point was found on the nth LineString of an input MultiLineString. Previously `multiFeatureIndex`
|
|
17
|
+
* segmentIndex - point was found on the nth segment of the above LineString. Previously `index`
|
|
18
|
+
* totalDistance - distance from the start of the overall MultiLineString. Previously `location`
|
|
19
|
+
* lineDistance - distance from the start of the relevant LineString
|
|
20
|
+
* segmentDistance - distance from the start of the relevant segment
|
|
21
|
+
* pointDistance - distance between found point is from input reference point. Previously `dist`
|
|
22
|
+
|
|
23
|
+
multiFeatureIndex, index, location, and dist continue to work as previously
|
|
24
|
+
until at least the next major release.
|
|
25
|
+
|
|
13
26
|
### Parameters
|
|
14
27
|
|
|
15
|
-
* `lines` **([Geometry][1] | [Feature][2]<([LineString][3] | [MultiLineString][4])>)**
|
|
16
|
-
* `
|
|
28
|
+
* `lines` **([Geometry][1] | [Feature][2]<([LineString][3] | [MultiLineString][4])>)** Lines to snap to
|
|
29
|
+
* `inputPoint` **([Geometry][1] | [Feature][2]<[Point][5]> | [Array][6]<[number][7]>)** Point to snap from
|
|
17
30
|
* `options` **[Object][8]** Optional parameters (optional, default `{}`)
|
|
18
31
|
|
|
19
32
|
* `options.units` **Units** Supports all valid Turf [Units][9] (optional, default `'kilometers'`)
|
|
@@ -29,16 +42,16 @@ var line = turf.lineString([
|
|
|
29
42
|
[-77.021884, 38.889563],
|
|
30
43
|
[-77.019824, 38.892368]
|
|
31
44
|
]);
|
|
32
|
-
var
|
|
45
|
+
var inputPoint = turf.point([-77.037076, 38.884017]);
|
|
33
46
|
|
|
34
|
-
var snapped = turf.nearestPointOnLine(line,
|
|
47
|
+
var snapped = turf.nearestPointOnLine(line, inputPoint, {units: 'miles'});
|
|
35
48
|
|
|
36
49
|
//addToMap
|
|
37
|
-
var addToMap = [line,
|
|
50
|
+
var addToMap = [line, inputPoint, snapped];
|
|
38
51
|
snapped.properties['marker-color'] = '#00f';
|
|
39
52
|
```
|
|
40
53
|
|
|
41
|
-
Returns **[Feature][2]<[Point][5]>** closest point on the `
|
|
54
|
+
Returns **[Feature][2]<[Point][5]>** closest point on the `lines` to the `inputPoint`. The point will have the following properties: `lineStringIndex`: closest point was found on the nth LineString (only relevant if input is MultiLineString), `segmentIndex`: closest point was found on nth line segment of the LineString, `totalDistance`: distance along the line from the absolute start of the MultiLineString, `lineDistance`: distance along the line from the start of the LineString where the closest point was found, `segmentDistance`: distance along the line from the start of the line segment where the closest point was found, `pointDistance`: distance to the input point.
|
|
42
55
|
|
|
43
56
|
[1]: https://tools.ietf.org/html/rfc7946#section-3.1
|
|
44
57
|
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -27,56 +27,87 @@ var _meta = require('@turf/meta');
|
|
|
27
27
|
|
|
28
28
|
var _helpers = require('@turf/helpers');
|
|
29
29
|
var _invariant = require('@turf/invariant');
|
|
30
|
-
function nearestPointOnLine(lines,
|
|
31
|
-
if (!lines || !
|
|
32
|
-
throw new Error("lines and
|
|
30
|
+
function nearestPointOnLine(lines, inputPoint, options = {}) {
|
|
31
|
+
if (!lines || !inputPoint) {
|
|
32
|
+
throw new Error("lines and inputPoint are required arguments");
|
|
33
33
|
}
|
|
34
|
-
const
|
|
34
|
+
const inputPos = _invariant.getCoord.call(void 0, inputPoint);
|
|
35
35
|
let closestPt = _helpers.point.call(void 0, [Infinity, Infinity], {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
lineStringIndex: -1,
|
|
37
|
+
segmentIndex: -1,
|
|
38
|
+
totalDistance: -1,
|
|
39
|
+
lineDistance: -1,
|
|
40
|
+
segmentDistance: -1,
|
|
41
|
+
pointDistance: Infinity,
|
|
42
|
+
// deprecated properties START
|
|
38
43
|
multiFeatureIndex: -1,
|
|
39
|
-
|
|
44
|
+
index: -1,
|
|
45
|
+
location: -1,
|
|
46
|
+
dist: Infinity
|
|
47
|
+
// deprecated properties END
|
|
40
48
|
});
|
|
41
|
-
let
|
|
49
|
+
let totalDistance = 0;
|
|
50
|
+
let lineDistance = 0;
|
|
51
|
+
let currentLineStringIndex = -1;
|
|
42
52
|
_meta.flattenEach.call(void 0,
|
|
43
53
|
lines,
|
|
44
|
-
function(line, _featureIndex,
|
|
54
|
+
function(line, _featureIndex, lineStringIndex) {
|
|
55
|
+
if (currentLineStringIndex !== lineStringIndex) {
|
|
56
|
+
currentLineStringIndex = lineStringIndex;
|
|
57
|
+
lineDistance = 0;
|
|
58
|
+
}
|
|
45
59
|
const coords = _invariant.getCoords.call(void 0, line);
|
|
60
|
+
const maxSegmentIndex = coords.length - 2;
|
|
46
61
|
for (let i = 0; i < coords.length - 1; i++) {
|
|
47
62
|
const start = _helpers.point.call(void 0, coords[i]);
|
|
48
63
|
const startPos = _invariant.getCoord.call(void 0, start);
|
|
49
64
|
const stop = _helpers.point.call(void 0, coords[i + 1]);
|
|
50
65
|
const stopPos = _invariant.getCoord.call(void 0, stop);
|
|
51
|
-
const
|
|
66
|
+
const segmentLength = _distance.distance.call(void 0, start, stop, options);
|
|
52
67
|
let intersectPos;
|
|
53
68
|
let wasEnd;
|
|
54
|
-
if (stopPos[0] ===
|
|
69
|
+
if (stopPos[0] === inputPos[0] && stopPos[1] === inputPos[1]) {
|
|
55
70
|
[intersectPos, wasEnd] = [stopPos, true];
|
|
56
|
-
} else if (startPos[0] ===
|
|
71
|
+
} else if (startPos[0] === inputPos[0] && startPos[1] === inputPos[1]) {
|
|
57
72
|
[intersectPos, wasEnd] = [startPos, false];
|
|
58
73
|
} else {
|
|
59
74
|
[intersectPos, wasEnd] = nearestPointOnSegment(
|
|
60
75
|
startPos,
|
|
61
76
|
stopPos,
|
|
62
|
-
|
|
77
|
+
inputPos
|
|
63
78
|
);
|
|
64
79
|
}
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
const pointDistance = _distance.distance.call(void 0, inputPoint, intersectPos, options);
|
|
81
|
+
if (pointDistance < closestPt.properties.pointDistance) {
|
|
82
|
+
const segmentDistance = _distance.distance.call(void 0, start, intersectPos, options);
|
|
83
|
+
closestPt = _helpers.point.call(void 0, intersectPos, {
|
|
84
|
+
lineStringIndex,
|
|
85
|
+
// Legacy behaviour where index progresses to next segment if we
|
|
86
|
+
// went with the end point this iteration. Though make sure we
|
|
87
|
+
// only progress to the beginning of the next segment if one
|
|
88
|
+
// actually exists.
|
|
89
|
+
segmentIndex: wasEnd && i + 1 <= maxSegmentIndex ? i + 1 : i,
|
|
90
|
+
totalDistance: totalDistance + segmentDistance,
|
|
91
|
+
lineDistance: lineDistance + segmentDistance,
|
|
92
|
+
segmentDistance,
|
|
93
|
+
pointDistance,
|
|
94
|
+
// deprecated properties START
|
|
95
|
+
multiFeatureIndex: -1,
|
|
96
|
+
index: -1,
|
|
97
|
+
location: -1,
|
|
98
|
+
dist: Infinity
|
|
99
|
+
// deprecated properties END
|
|
100
|
+
});
|
|
101
|
+
closestPt.properties = __spreadProps(__spreadValues({}, closestPt.properties), {
|
|
102
|
+
multiFeatureIndex: closestPt.properties.lineStringIndex,
|
|
103
|
+
index: closestPt.properties.segmentIndex,
|
|
104
|
+
location: closestPt.properties.totalDistance,
|
|
105
|
+
dist: closestPt.properties.pointDistance
|
|
106
|
+
// deprecated properties END
|
|
77
107
|
});
|
|
78
108
|
}
|
|
79
|
-
|
|
109
|
+
totalDistance += segmentLength;
|
|
110
|
+
lineDistance += segmentLength;
|
|
80
111
|
}
|
|
81
112
|
}
|
|
82
113
|
);
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -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 * 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"]}
|
|
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 * ⚠️ We have begun the process of migrating to different return properties for\n * this function. The new properties we recommend using as of v7.4 are:\n * - lineStringIndex - point was found on the nth LineString of an input MultiLineString. Previously `multiFeatureIndex`\n * - segmentIndex - point was found on the nth segment of the above LineString. Previously `index`\n * - totalDistance - distance from the start of the overall MultiLineString. Previously `location`\n * - lineDistance - distance from the start of the relevant LineString\n * - segmentDistance - distance from the start of the relevant segment\n * - pointDistance - distance between found point is from input reference point. Previously `dist`\n *\n * multiFeatureIndex, index, location, and dist continue to work as previously\n * until at least the next major release.\n *\n * @function\n * @param {Geometry|Feature<LineString|MultiLineString>} lines Lines to snap to\n * @param {Geometry|Feature<Point>|number[]} inputPoint 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 `lines` to the `inputPoint`. The point will have the following properties: `lineStringIndex`: closest point was found on the nth LineString (only relevant if input is MultiLineString), `segmentIndex`: closest point was found on nth line segment of the LineString, `totalDistance`: distance along the line from the absolute start of the MultiLineString, `lineDistance`: distance along the line from the start of the LineString where the closest point was found, `segmentDistance`: distance along the line from the start of the line segment where the closest point was found, `pointDistance`: distance to the input 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 inputPoint = turf.point([-77.037076, 38.884017]);\n *\n * var snapped = turf.nearestPointOnLine(line, inputPoint, {units: 'miles'});\n *\n * //addToMap\n * var addToMap = [line, inputPoint, snapped];\n * snapped.properties['marker-color'] = '#00f';\n */\nfunction nearestPointOnLine<G extends LineString | MultiLineString>(\n lines: Feature<G> | G,\n inputPoint: Coord,\n options: { units?: Units } = {}\n): Feature<\n Point,\n {\n lineStringIndex: number;\n segmentIndex: number;\n totalDistance: number;\n lineDistance: number;\n segmentDistance: number;\n pointDistance: number;\n multiFeatureIndex: number;\n index: number;\n location: number;\n dist: number;\n [key: string]: any;\n }\n> {\n if (!lines || !inputPoint) {\n throw new Error(\"lines and inputPoint are required arguments\");\n }\n\n const inputPos = getCoord(inputPoint);\n\n let closestPt = point([Infinity, Infinity], {\n lineStringIndex: -1,\n segmentIndex: -1,\n totalDistance: -1,\n lineDistance: -1,\n segmentDistance: -1,\n pointDistance: Infinity,\n // deprecated properties START\n multiFeatureIndex: -1,\n index: -1,\n location: -1,\n dist: Infinity,\n // deprecated properties END\n });\n\n let totalDistance = 0.0;\n let lineDistance = 0.0;\n let currentLineStringIndex = -1;\n flattenEach(\n lines,\n function (line: any, _featureIndex: number, lineStringIndex: number) {\n //reset lineDistance at each changed lineStringIndex\n if (currentLineStringIndex !== lineStringIndex) {\n currentLineStringIndex = lineStringIndex;\n lineDistance = 0.0;\n }\n\n const coords: any = getCoords(line);\n const maxSegmentIndex = coords.length - 2;\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 // segmentLength\n const segmentLength = 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] === inputPos[0] && stopPos[1] === inputPos[1]) {\n [intersectPos, wasEnd] = [stopPos, true];\n } else if (startPos[0] === inputPos[0] && startPos[1] === inputPos[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 inputPos\n );\n }\n\n const pointDistance = distance(inputPoint, intersectPos, options);\n\n if (pointDistance < closestPt.properties.pointDistance) {\n const segmentDistance = distance(start, intersectPos, options);\n closestPt = point(intersectPos, {\n lineStringIndex: lineStringIndex,\n // Legacy behaviour where index progresses to next segment if we\n // went with the end point this iteration. Though make sure we\n // only progress to the beginning of the next segment if one\n // actually exists.\n segmentIndex: wasEnd && i + 1 <= maxSegmentIndex ? i + 1 : i,\n totalDistance: totalDistance + segmentDistance,\n lineDistance: lineDistance + segmentDistance,\n segmentDistance: segmentDistance,\n pointDistance: pointDistance,\n // deprecated properties START\n multiFeatureIndex: -1,\n index: -1,\n location: -1,\n dist: Infinity,\n // deprecated properties END\n });\n closestPt.properties = {\n ...closestPt.properties,\n multiFeatureIndex: closestPt.properties.lineStringIndex,\n index: closestPt.properties.segmentIndex,\n location: closestPt.properties.totalDistance,\n dist: closestPt.properties.pointDistance,\n // deprecated properties END\n };\n }\n\n // update totalDistance and lineDistance\n totalDistance += segmentLength;\n lineDistance += segmentLength;\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"]}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -8,12 +8,24 @@ import { Coord, Units } from '@turf/helpers';
|
|
|
8
8
|
* have an undefined arc, this function will instead return that the point lies
|
|
9
9
|
* on the line.
|
|
10
10
|
*
|
|
11
|
+
* ⚠️ We have begun the process of migrating to different return properties for
|
|
12
|
+
* this function. The new properties we recommend using as of v7.4 are:
|
|
13
|
+
* - lineStringIndex - point was found on the nth LineString of an input MultiLineString. Previously `multiFeatureIndex`
|
|
14
|
+
* - segmentIndex - point was found on the nth segment of the above LineString. Previously `index`
|
|
15
|
+
* - totalDistance - distance from the start of the overall MultiLineString. Previously `location`
|
|
16
|
+
* - lineDistance - distance from the start of the relevant LineString
|
|
17
|
+
* - segmentDistance - distance from the start of the relevant segment
|
|
18
|
+
* - pointDistance - distance between found point is from input reference point. Previously `dist`
|
|
19
|
+
*
|
|
20
|
+
* multiFeatureIndex, index, location, and dist continue to work as previously
|
|
21
|
+
* until at least the next major release.
|
|
22
|
+
*
|
|
11
23
|
* @function
|
|
12
|
-
* @param {Geometry|Feature<LineString|MultiLineString>} lines
|
|
13
|
-
* @param {Geometry|Feature<Point>|number[]}
|
|
24
|
+
* @param {Geometry|Feature<LineString|MultiLineString>} lines Lines to snap to
|
|
25
|
+
* @param {Geometry|Feature<Point>|number[]} inputPoint Point to snap from
|
|
14
26
|
* @param {Object} [options={}] Optional parameters
|
|
15
27
|
* @param {Units} [options.units='kilometers'] Supports all valid Turf {@link https://turfjs.org/docs/api/types/Units Units}
|
|
16
|
-
* @returns {Feature<Point>} closest point on the `
|
|
28
|
+
* @returns {Feature<Point>} closest point on the `lines` to the `inputPoint`. The point will have the following properties: `lineStringIndex`: closest point was found on the nth LineString (only relevant if input is MultiLineString), `segmentIndex`: closest point was found on nth line segment of the LineString, `totalDistance`: distance along the line from the absolute start of the MultiLineString, `lineDistance`: distance along the line from the start of the LineString where the closest point was found, `segmentDistance`: distance along the line from the start of the line segment where the closest point was found, `pointDistance`: distance to the input point.
|
|
17
29
|
* @example
|
|
18
30
|
* var line = turf.lineString([
|
|
19
31
|
* [-77.031669, 38.878605],
|
|
@@ -23,21 +35,27 @@ import { Coord, Units } from '@turf/helpers';
|
|
|
23
35
|
* [-77.021884, 38.889563],
|
|
24
36
|
* [-77.019824, 38.892368]
|
|
25
37
|
* ]);
|
|
26
|
-
* var
|
|
38
|
+
* var inputPoint = turf.point([-77.037076, 38.884017]);
|
|
27
39
|
*
|
|
28
|
-
* var snapped = turf.nearestPointOnLine(line,
|
|
40
|
+
* var snapped = turf.nearestPointOnLine(line, inputPoint, {units: 'miles'});
|
|
29
41
|
*
|
|
30
42
|
* //addToMap
|
|
31
|
-
* var addToMap = [line,
|
|
43
|
+
* var addToMap = [line, inputPoint, snapped];
|
|
32
44
|
* snapped.properties['marker-color'] = '#00f';
|
|
33
45
|
*/
|
|
34
|
-
declare function nearestPointOnLine<G extends LineString | MultiLineString>(lines: Feature<G> | G,
|
|
46
|
+
declare function nearestPointOnLine<G extends LineString | MultiLineString>(lines: Feature<G> | G, inputPoint: Coord, options?: {
|
|
35
47
|
units?: Units;
|
|
36
48
|
}): Feature<Point, {
|
|
37
|
-
|
|
38
|
-
|
|
49
|
+
lineStringIndex: number;
|
|
50
|
+
segmentIndex: number;
|
|
51
|
+
totalDistance: number;
|
|
52
|
+
lineDistance: number;
|
|
53
|
+
segmentDistance: number;
|
|
54
|
+
pointDistance: number;
|
|
39
55
|
multiFeatureIndex: number;
|
|
56
|
+
index: number;
|
|
40
57
|
location: number;
|
|
58
|
+
dist: number;
|
|
41
59
|
[key: string]: any;
|
|
42
60
|
}>;
|
|
43
61
|
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -8,12 +8,24 @@ import { Coord, Units } from '@turf/helpers';
|
|
|
8
8
|
* have an undefined arc, this function will instead return that the point lies
|
|
9
9
|
* on the line.
|
|
10
10
|
*
|
|
11
|
+
* ⚠️ We have begun the process of migrating to different return properties for
|
|
12
|
+
* this function. The new properties we recommend using as of v7.4 are:
|
|
13
|
+
* - lineStringIndex - point was found on the nth LineString of an input MultiLineString. Previously `multiFeatureIndex`
|
|
14
|
+
* - segmentIndex - point was found on the nth segment of the above LineString. Previously `index`
|
|
15
|
+
* - totalDistance - distance from the start of the overall MultiLineString. Previously `location`
|
|
16
|
+
* - lineDistance - distance from the start of the relevant LineString
|
|
17
|
+
* - segmentDistance - distance from the start of the relevant segment
|
|
18
|
+
* - pointDistance - distance between found point is from input reference point. Previously `dist`
|
|
19
|
+
*
|
|
20
|
+
* multiFeatureIndex, index, location, and dist continue to work as previously
|
|
21
|
+
* until at least the next major release.
|
|
22
|
+
*
|
|
11
23
|
* @function
|
|
12
|
-
* @param {Geometry|Feature<LineString|MultiLineString>} lines
|
|
13
|
-
* @param {Geometry|Feature<Point>|number[]}
|
|
24
|
+
* @param {Geometry|Feature<LineString|MultiLineString>} lines Lines to snap to
|
|
25
|
+
* @param {Geometry|Feature<Point>|number[]} inputPoint Point to snap from
|
|
14
26
|
* @param {Object} [options={}] Optional parameters
|
|
15
27
|
* @param {Units} [options.units='kilometers'] Supports all valid Turf {@link https://turfjs.org/docs/api/types/Units Units}
|
|
16
|
-
* @returns {Feature<Point>} closest point on the `
|
|
28
|
+
* @returns {Feature<Point>} closest point on the `lines` to the `inputPoint`. The point will have the following properties: `lineStringIndex`: closest point was found on the nth LineString (only relevant if input is MultiLineString), `segmentIndex`: closest point was found on nth line segment of the LineString, `totalDistance`: distance along the line from the absolute start of the MultiLineString, `lineDistance`: distance along the line from the start of the LineString where the closest point was found, `segmentDistance`: distance along the line from the start of the line segment where the closest point was found, `pointDistance`: distance to the input point.
|
|
17
29
|
* @example
|
|
18
30
|
* var line = turf.lineString([
|
|
19
31
|
* [-77.031669, 38.878605],
|
|
@@ -23,21 +35,27 @@ import { Coord, Units } from '@turf/helpers';
|
|
|
23
35
|
* [-77.021884, 38.889563],
|
|
24
36
|
* [-77.019824, 38.892368]
|
|
25
37
|
* ]);
|
|
26
|
-
* var
|
|
38
|
+
* var inputPoint = turf.point([-77.037076, 38.884017]);
|
|
27
39
|
*
|
|
28
|
-
* var snapped = turf.nearestPointOnLine(line,
|
|
40
|
+
* var snapped = turf.nearestPointOnLine(line, inputPoint, {units: 'miles'});
|
|
29
41
|
*
|
|
30
42
|
* //addToMap
|
|
31
|
-
* var addToMap = [line,
|
|
43
|
+
* var addToMap = [line, inputPoint, snapped];
|
|
32
44
|
* snapped.properties['marker-color'] = '#00f';
|
|
33
45
|
*/
|
|
34
|
-
declare function nearestPointOnLine<G extends LineString | MultiLineString>(lines: Feature<G> | G,
|
|
46
|
+
declare function nearestPointOnLine<G extends LineString | MultiLineString>(lines: Feature<G> | G, inputPoint: Coord, options?: {
|
|
35
47
|
units?: Units;
|
|
36
48
|
}): Feature<Point, {
|
|
37
|
-
|
|
38
|
-
|
|
49
|
+
lineStringIndex: number;
|
|
50
|
+
segmentIndex: number;
|
|
51
|
+
totalDistance: number;
|
|
52
|
+
lineDistance: number;
|
|
53
|
+
segmentDistance: number;
|
|
54
|
+
pointDistance: number;
|
|
39
55
|
multiFeatureIndex: number;
|
|
56
|
+
index: number;
|
|
40
57
|
location: number;
|
|
58
|
+
dist: number;
|
|
41
59
|
[key: string]: any;
|
|
42
60
|
}>;
|
|
43
61
|
|
package/dist/esm/index.js
CHANGED
|
@@ -27,56 +27,87 @@ import {
|
|
|
27
27
|
radiansToDegrees
|
|
28
28
|
} from "@turf/helpers";
|
|
29
29
|
import { getCoord, getCoords } from "@turf/invariant";
|
|
30
|
-
function nearestPointOnLine(lines,
|
|
31
|
-
if (!lines || !
|
|
32
|
-
throw new Error("lines and
|
|
30
|
+
function nearestPointOnLine(lines, inputPoint, options = {}) {
|
|
31
|
+
if (!lines || !inputPoint) {
|
|
32
|
+
throw new Error("lines and inputPoint are required arguments");
|
|
33
33
|
}
|
|
34
|
-
const
|
|
34
|
+
const inputPos = getCoord(inputPoint);
|
|
35
35
|
let closestPt = point([Infinity, Infinity], {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
lineStringIndex: -1,
|
|
37
|
+
segmentIndex: -1,
|
|
38
|
+
totalDistance: -1,
|
|
39
|
+
lineDistance: -1,
|
|
40
|
+
segmentDistance: -1,
|
|
41
|
+
pointDistance: Infinity,
|
|
42
|
+
// deprecated properties START
|
|
38
43
|
multiFeatureIndex: -1,
|
|
39
|
-
|
|
44
|
+
index: -1,
|
|
45
|
+
location: -1,
|
|
46
|
+
dist: Infinity
|
|
47
|
+
// deprecated properties END
|
|
40
48
|
});
|
|
41
|
-
let
|
|
49
|
+
let totalDistance = 0;
|
|
50
|
+
let lineDistance = 0;
|
|
51
|
+
let currentLineStringIndex = -1;
|
|
42
52
|
flattenEach(
|
|
43
53
|
lines,
|
|
44
|
-
function(line, _featureIndex,
|
|
54
|
+
function(line, _featureIndex, lineStringIndex) {
|
|
55
|
+
if (currentLineStringIndex !== lineStringIndex) {
|
|
56
|
+
currentLineStringIndex = lineStringIndex;
|
|
57
|
+
lineDistance = 0;
|
|
58
|
+
}
|
|
45
59
|
const coords = getCoords(line);
|
|
60
|
+
const maxSegmentIndex = coords.length - 2;
|
|
46
61
|
for (let i = 0; i < coords.length - 1; i++) {
|
|
47
62
|
const start = point(coords[i]);
|
|
48
63
|
const startPos = getCoord(start);
|
|
49
64
|
const stop = point(coords[i + 1]);
|
|
50
65
|
const stopPos = getCoord(stop);
|
|
51
|
-
const
|
|
66
|
+
const segmentLength = distance(start, stop, options);
|
|
52
67
|
let intersectPos;
|
|
53
68
|
let wasEnd;
|
|
54
|
-
if (stopPos[0] ===
|
|
69
|
+
if (stopPos[0] === inputPos[0] && stopPos[1] === inputPos[1]) {
|
|
55
70
|
[intersectPos, wasEnd] = [stopPos, true];
|
|
56
|
-
} else if (startPos[0] ===
|
|
71
|
+
} else if (startPos[0] === inputPos[0] && startPos[1] === inputPos[1]) {
|
|
57
72
|
[intersectPos, wasEnd] = [startPos, false];
|
|
58
73
|
} else {
|
|
59
74
|
[intersectPos, wasEnd] = nearestPointOnSegment(
|
|
60
75
|
startPos,
|
|
61
76
|
stopPos,
|
|
62
|
-
|
|
77
|
+
inputPos
|
|
63
78
|
);
|
|
64
79
|
}
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
const pointDistance = distance(inputPoint, intersectPos, options);
|
|
81
|
+
if (pointDistance < closestPt.properties.pointDistance) {
|
|
82
|
+
const segmentDistance = distance(start, intersectPos, options);
|
|
83
|
+
closestPt = point(intersectPos, {
|
|
84
|
+
lineStringIndex,
|
|
85
|
+
// Legacy behaviour where index progresses to next segment if we
|
|
86
|
+
// went with the end point this iteration. Though make sure we
|
|
87
|
+
// only progress to the beginning of the next segment if one
|
|
88
|
+
// actually exists.
|
|
89
|
+
segmentIndex: wasEnd && i + 1 <= maxSegmentIndex ? i + 1 : i,
|
|
90
|
+
totalDistance: totalDistance + segmentDistance,
|
|
91
|
+
lineDistance: lineDistance + segmentDistance,
|
|
92
|
+
segmentDistance,
|
|
93
|
+
pointDistance,
|
|
94
|
+
// deprecated properties START
|
|
95
|
+
multiFeatureIndex: -1,
|
|
96
|
+
index: -1,
|
|
97
|
+
location: -1,
|
|
98
|
+
dist: Infinity
|
|
99
|
+
// deprecated properties END
|
|
100
|
+
});
|
|
101
|
+
closestPt.properties = __spreadProps(__spreadValues({}, closestPt.properties), {
|
|
102
|
+
multiFeatureIndex: closestPt.properties.lineStringIndex,
|
|
103
|
+
index: closestPt.properties.segmentIndex,
|
|
104
|
+
location: closestPt.properties.totalDistance,
|
|
105
|
+
dist: closestPt.properties.pointDistance
|
|
106
|
+
// deprecated properties END
|
|
77
107
|
});
|
|
78
108
|
}
|
|
79
|
-
|
|
109
|
+
totalDistance += segmentLength;
|
|
110
|
+
lineDistance += segmentLength;
|
|
80
111
|
}
|
|
81
112
|
}
|
|
82
113
|
);
|
package/dist/esm/index.js.map
CHANGED
|
@@ -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 * 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":[]}
|
|
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 * ⚠️ We have begun the process of migrating to different return properties for\n * this function. The new properties we recommend using as of v7.4 are:\n * - lineStringIndex - point was found on the nth LineString of an input MultiLineString. Previously `multiFeatureIndex`\n * - segmentIndex - point was found on the nth segment of the above LineString. Previously `index`\n * - totalDistance - distance from the start of the overall MultiLineString. Previously `location`\n * - lineDistance - distance from the start of the relevant LineString\n * - segmentDistance - distance from the start of the relevant segment\n * - pointDistance - distance between found point is from input reference point. Previously `dist`\n *\n * multiFeatureIndex, index, location, and dist continue to work as previously\n * until at least the next major release.\n *\n * @function\n * @param {Geometry|Feature<LineString|MultiLineString>} lines Lines to snap to\n * @param {Geometry|Feature<Point>|number[]} inputPoint 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 `lines` to the `inputPoint`. The point will have the following properties: `lineStringIndex`: closest point was found on the nth LineString (only relevant if input is MultiLineString), `segmentIndex`: closest point was found on nth line segment of the LineString, `totalDistance`: distance along the line from the absolute start of the MultiLineString, `lineDistance`: distance along the line from the start of the LineString where the closest point was found, `segmentDistance`: distance along the line from the start of the line segment where the closest point was found, `pointDistance`: distance to the input 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 inputPoint = turf.point([-77.037076, 38.884017]);\n *\n * var snapped = turf.nearestPointOnLine(line, inputPoint, {units: 'miles'});\n *\n * //addToMap\n * var addToMap = [line, inputPoint, snapped];\n * snapped.properties['marker-color'] = '#00f';\n */\nfunction nearestPointOnLine<G extends LineString | MultiLineString>(\n lines: Feature<G> | G,\n inputPoint: Coord,\n options: { units?: Units } = {}\n): Feature<\n Point,\n {\n lineStringIndex: number;\n segmentIndex: number;\n totalDistance: number;\n lineDistance: number;\n segmentDistance: number;\n pointDistance: number;\n multiFeatureIndex: number;\n index: number;\n location: number;\n dist: number;\n [key: string]: any;\n }\n> {\n if (!lines || !inputPoint) {\n throw new Error(\"lines and inputPoint are required arguments\");\n }\n\n const inputPos = getCoord(inputPoint);\n\n let closestPt = point([Infinity, Infinity], {\n lineStringIndex: -1,\n segmentIndex: -1,\n totalDistance: -1,\n lineDistance: -1,\n segmentDistance: -1,\n pointDistance: Infinity,\n // deprecated properties START\n multiFeatureIndex: -1,\n index: -1,\n location: -1,\n dist: Infinity,\n // deprecated properties END\n });\n\n let totalDistance = 0.0;\n let lineDistance = 0.0;\n let currentLineStringIndex = -1;\n flattenEach(\n lines,\n function (line: any, _featureIndex: number, lineStringIndex: number) {\n //reset lineDistance at each changed lineStringIndex\n if (currentLineStringIndex !== lineStringIndex) {\n currentLineStringIndex = lineStringIndex;\n lineDistance = 0.0;\n }\n\n const coords: any = getCoords(line);\n const maxSegmentIndex = coords.length - 2;\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 // segmentLength\n const segmentLength = 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] === inputPos[0] && stopPos[1] === inputPos[1]) {\n [intersectPos, wasEnd] = [stopPos, true];\n } else if (startPos[0] === inputPos[0] && startPos[1] === inputPos[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 inputPos\n );\n }\n\n const pointDistance = distance(inputPoint, intersectPos, options);\n\n if (pointDistance < closestPt.properties.pointDistance) {\n const segmentDistance = distance(start, intersectPos, options);\n closestPt = point(intersectPos, {\n lineStringIndex: lineStringIndex,\n // Legacy behaviour where index progresses to next segment if we\n // went with the end point this iteration. Though make sure we\n // only progress to the beginning of the next segment if one\n // actually exists.\n segmentIndex: wasEnd && i + 1 <= maxSegmentIndex ? i + 1 : i,\n totalDistance: totalDistance + segmentDistance,\n lineDistance: lineDistance + segmentDistance,\n segmentDistance: segmentDistance,\n pointDistance: pointDistance,\n // deprecated properties START\n multiFeatureIndex: -1,\n index: -1,\n location: -1,\n dist: Infinity,\n // deprecated properties END\n });\n closestPt.properties = {\n ...closestPt.properties,\n multiFeatureIndex: closestPt.properties.lineStringIndex,\n index: closestPt.properties.segmentIndex,\n location: closestPt.properties.totalDistance,\n dist: closestPt.properties.pointDistance,\n // deprecated properties END\n };\n }\n\n // update totalDistance and lineDistance\n totalDistance += segmentLength;\n lineDistance += segmentLength;\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,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@turf/nearest-point-on-line",
|
|
3
|
-
"version": "7.3.
|
|
3
|
+
"version": "7.3.2",
|
|
4
4
|
"description": "Finds the nearest point on a line to a given point",
|
|
5
5
|
"author": "Turf Authors",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Angel Lacret <@alacret>",
|
|
8
|
+
"Emil Junker <@EmilJunker>",
|
|
8
9
|
"Jon Miles <@jonmiles>",
|
|
9
10
|
"John Ziebro <@Insighttful>"
|
|
10
11
|
],
|
|
@@ -46,19 +47,18 @@
|
|
|
46
47
|
"bench": "tsx bench.ts",
|
|
47
48
|
"build": "tsup --config ../../tsup.config.ts",
|
|
48
49
|
"docs": "tsx ../../scripts/generate-readmes.ts",
|
|
49
|
-
"test": "
|
|
50
|
+
"test": "pnpm run /test:.*/",
|
|
50
51
|
"test:tape": "tsx test.ts",
|
|
51
52
|
"test:types": "tsc --esModuleInterop --module node16 --moduleResolution node16 --noEmit --strict types.ts"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
|
-
"@turf/along": "7.3.
|
|
55
|
-
"@turf/length": "7.3.
|
|
56
|
-
"@turf/truncate": "7.3.
|
|
55
|
+
"@turf/along": "7.3.2",
|
|
56
|
+
"@turf/length": "7.3.2",
|
|
57
|
+
"@turf/truncate": "7.3.2",
|
|
57
58
|
"@types/benchmark": "^2.1.5",
|
|
58
59
|
"@types/tape": "^5.8.1",
|
|
59
60
|
"benchmark": "^2.1.4",
|
|
60
61
|
"load-json-file": "^7.0.1",
|
|
61
|
-
"npm-run-all": "^4.1.5",
|
|
62
62
|
"tape": "^5.9.0",
|
|
63
63
|
"tsup": "^8.4.0",
|
|
64
64
|
"tsx": "^4.19.4",
|
|
@@ -66,12 +66,12 @@
|
|
|
66
66
|
"write-json-file": "^6.0.0"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@turf/distance": "7.3.
|
|
70
|
-
"@turf/helpers": "7.3.
|
|
71
|
-
"@turf/invariant": "7.3.
|
|
72
|
-
"@turf/meta": "7.3.
|
|
69
|
+
"@turf/distance": "7.3.2",
|
|
70
|
+
"@turf/helpers": "7.3.2",
|
|
71
|
+
"@turf/invariant": "7.3.2",
|
|
72
|
+
"@turf/meta": "7.3.2",
|
|
73
73
|
"@types/geojson": "^7946.0.10",
|
|
74
74
|
"tslib": "^2.8.1"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "099d9915467bacf45d554be4533fa9998c4efc88"
|
|
77
77
|
}
|