Skip to content

Commit

Permalink
include index of MultiLineString geometries in nearest-point-on-line (#…
Browse files Browse the repository at this point in the history
…2574)

* include index of multilinestring geometries in nearest-point-on-line

* readme updated

* prefix unused variable with _
  • Loading branch information
andrewharvey authored Aug 6, 2024
1 parent 15e1449 commit 1ccf197
Show file tree
Hide file tree
Showing 15 changed files with 34,924 additions and 9,039 deletions.
2 changes: 1 addition & 1 deletion packages/turf-nearest-point-on-line/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var addToMap = [line, pt, snapped];
snapped.properties['marker-color'] = '#00f';
```

Returns **[Feature][4]<[Point][1]>** closest point on the `line` to `point`. The properties object will contain three values: `index`: closest point was found on nth line part, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.
Returns **[Feature][4]<[Point][1]>** 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.

[1]: https://tools.ietf.org/html/rfc7946#section-3.1.2

Expand Down
170 changes: 93 additions & 77 deletions packages/turf-nearest-point-on-line/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { getCoords } from "@turf/invariant";
* @param {Geometry|Feature<Point>|number[]} pt point to snap from
* @param {Object} [options={}] Optional parameters
* @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
* @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain three values: `index`: closest point was found on nth line part, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.
* @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.
* @example
* var line = turf.lineString([
* [-77.031669, 38.878605],
Expand All @@ -42,6 +42,7 @@ function nearestPointOnLine<G extends LineString | MultiLineString>(
{
dist: number;
index: number;
multiFeatureIndex: number;
location: number;
[key: string]: any;
}
Expand All @@ -52,96 +53,111 @@ function nearestPointOnLine<G extends LineString | MultiLineString>(

let closestPt: Feature<
Point,
{ dist: number; index: number; location: number }
{ dist: number; index: number; multiFeatureIndex: number; location: number }
> = point([Infinity, Infinity], {
dist: Infinity,
index: -1,
multiFeatureIndex: -1,
location: -1,
});

let length = 0.0;
flattenEach(lines, function (line: any) {
const coords: any = getCoords(line);
flattenEach(
lines,
function (line: any, _featureIndex: number, multiFeatureIndex: number) {
const coords: any = getCoords(line);

for (let i = 0; i < coords.length - 1; i++) {
//start
const start: Feature<Point, { dist: number }> = point(coords[i]);
start.properties.dist = distance(pt, start, options);
//stop
const stop: Feature<Point, { dist: number }> = point(coords[i + 1]);
stop.properties.dist = distance(pt, stop, options);
// sectionLength
const sectionLength = distance(start, stop, options);
//perpendicular
const heightDistance = Math.max(
start.properties.dist,
stop.properties.dist
);
const direction = bearing(start, stop);
const perpendicularPt1 = destination(
pt,
heightDistance,
direction + 90,
options
);
const perpendicularPt2 = destination(
pt,
heightDistance,
direction - 90,
options
);
const intersect = lineIntersects(
lineString([
perpendicularPt1.geometry.coordinates,
perpendicularPt2.geometry.coordinates,
]),
lineString([start.geometry.coordinates, stop.geometry.coordinates])
);
let intersectPt:
| Feature<Point, { dist: number; location: number }>
| undefined;
for (let i = 0; i < coords.length - 1; i++) {
//start
const start: Feature<Point, { dist: number }> = point(coords[i]);
start.properties.dist = distance(pt, start, options);
//stop
const stop: Feature<Point, { dist: number }> = point(coords[i + 1]);
stop.properties.dist = distance(pt, stop, options);
// sectionLength
const sectionLength = distance(start, stop, options);
//perpendicular
const heightDistance = Math.max(
start.properties.dist,
stop.properties.dist
);
const direction = bearing(start, stop);
const perpendicularPt1 = destination(
pt,
heightDistance,
direction + 90,
options
);
const perpendicularPt2 = destination(
pt,
heightDistance,
direction - 90,
options
);
const intersect = lineIntersects(
lineString([
perpendicularPt1.geometry.coordinates,
perpendicularPt2.geometry.coordinates,
]),
lineString([start.geometry.coordinates, stop.geometry.coordinates])
);
let intersectPt:
| Feature<
Point,
{ dist: number; multiFeatureIndex: number; location: number }
>
| undefined;

if (intersect.features.length > 0 && intersect.features[0]) {
intersectPt = {
...intersect.features[0],
properties: {
dist: distance(pt, intersect.features[0], options),
location: length + distance(start, intersect.features[0], options),
},
};
}
if (intersect.features.length > 0 && intersect.features[0]) {
intersectPt = {
...intersect.features[0],
properties: {
dist: distance(pt, intersect.features[0], options),
multiFeatureIndex: multiFeatureIndex,
location:
length + distance(start, intersect.features[0], options),
},
};
}

if (start.properties.dist < closestPt.properties.dist) {
closestPt = {
...start,
properties: { ...start.properties, index: i, location: length },
};
}
if (start.properties.dist < closestPt.properties.dist) {
closestPt = {
...start,
properties: {
...start.properties,
index: i,
multiFeatureIndex: multiFeatureIndex,
location: length,
},
};
}

if (stop.properties.dist < closestPt.properties.dist) {
closestPt = {
...stop,
properties: {
...stop.properties,
index: i + 1,
location: length + sectionLength,
},
};
}
if (stop.properties.dist < closestPt.properties.dist) {
closestPt = {
...stop,
properties: {
...stop.properties,
index: i + 1,
multiFeatureIndex: multiFeatureIndex,
location: length + sectionLength,
},
};
}

if (
intersectPt &&
intersectPt.properties.dist < closestPt.properties.dist
) {
closestPt = {
...intersectPt,
properties: { ...intersectPt.properties, index: i },
};
if (
intersectPt &&
intersectPt.properties.dist < closestPt.properties.dist
) {
closestPt = {
...intersectPt,
properties: { ...intersectPt.properties, index: i },
};
}
// update length
length += sectionLength;
}
// update length
length += sectionLength;
}
});
);

return closestPt;
}
Expand Down
22 changes: 22 additions & 0 deletions packages/turf-nearest-point-on-line/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,25 @@ test("turf-point-on-line -- Geometry Support", (t) => {
);
t.end();
});

test("turf-point-on-line -- multifeature index", (t) => {
const pt = point([4, 30]);
const multiLine = multiLineString([
[
[7, 50],
[8, 50],
[9, 50],
],
[
[17, 30],
[4, 30],
[2, 30],
],
]);
t.equal(
nearestPointOnLine(multiLine.geometry, pt).properties.multiFeatureIndex,
1,
"multiFeatureIndex"
);
t.end();
});
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
[0, 0, 0, 0, 0, 0, 0, 0]
[
0,
0,
0,
0,
0,
0,
0,
0
]
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
[0.362058, 0.362058, 0.362058, 0.362058]
[
0.362058,
0.362058,
0.362058,
0.362058
]
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
[
[0, 0.162908, 0.362058],
[
0,
435.152731,
848.38422,
1506.62747,
1877.71515,
2362.640364,
2951.524644,
3346.548084,
3711.226929
],
[
0,
0.011338,
0.021306,
0.033964,
0.057049,
0.082838,
0.161154,
0.207251,
0.243733,
0.287901,
0.320556,
0.396017,
0.491916
]
[
0,
0.162908,
0.362058
],
[
0,
435.152731,
848.38422,
1506.62747,
1877.71515,
2362.640364,
2951.524644,
3346.548084,
3711.226929
],
[
0,
0.011338,
0.021306,
0.033964,
0.057049,
0.082838,
0.161154,
0.207251,
0.243733,
0.287901,
0.320556,
0.396017,
0.491916
]
]
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[
0,
0.030566,
0.061133,
0.091699,
0.122265,
0.152831,
0.183398,
0.213964,
0.24453,
0.275097
0,
0.030566,
0.061133,
0.091699,
0.122265,
0.152831,
0.183398,
0.213964,
0.24453,
0.275097
]
Loading

0 comments on commit 1ccf197

Please sign in to comment.