Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/turf-line-slice-along/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,24 @@ var addToMap = [line, start, stop, sliced]

Returns **[Feature][3]<[LineString][1]>** sliced line

## setInterpolatedAltitude

Assign an interpolated altitude to a coordinate produced by destination().

When both segment endpoints carry an altitude the value is linearly
interpolated at `fraction` (0 = at `from`, 1 = at `to`). If either
endpoint has no altitude, any altitude that destination() may have copied
from its origin is removed so the output remains 2-D.

### Parameters

* `coord` **[Position][7]**&#x20;
* `from` **[Position][7]**&#x20;
* `to` **[Position][7]**&#x20;
* `fraction` **[number][4]**&#x20;

Returns **void**&#x20;

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

[2]: https://tools.ietf.org/html/rfc7946#section-3.1.2
Expand All @@ -45,6 +63,8 @@ Returns **[Feature][3]<[LineString][1]>** sliced line

[6]: https://turfjs.org/docs/api/types/Units

[7]: https://developer.mozilla.org/docs/Web/API/Position

<!-- 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. -->

---
Expand Down
44 changes: 42 additions & 2 deletions packages/turf-line-slice-along/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,17 @@ function lineSliceAlong(
}
direction = bearing(coords[i], coords[i - 1]) - 180;
interpolated = destination(coords[i], overshot, direction, { units });
slice.push(interpolated.geometry.coordinates);
const startIntCoords = interpolated.geometry.coordinates;
const startSegDist = distance(coords[i - 1], coords[i], { units });
const startFrac =
startSegDist > 0 ? 1 - Math.abs(overshot) / startSegDist : 0;
setInterpolatedAltitude(
startIntCoords,
coords[i - 1],
coords[i],
startFrac
);
slice.push(startIntCoords);
}

if (travelled >= stopDist) {
Expand All @@ -68,7 +78,17 @@ function lineSliceAlong(
}
direction = bearing(coords[i], coords[i - 1]) - 180;
interpolated = destination(coords[i], overshot, direction, { units });
slice.push(interpolated.geometry.coordinates);
const stopIntCoords = interpolated.geometry.coordinates;
const stopSegDist = distance(coords[i - 1], coords[i], { units });
const stopFrac =
stopSegDist > 0 ? 1 - Math.abs(overshot) / stopSegDist : 0;
setInterpolatedAltitude(
stopIntCoords,
coords[i - 1],
coords[i],
stopFrac
);
slice.push(stopIntCoords);
return lineString(slice);
}

Expand All @@ -89,6 +109,26 @@ function lineSliceAlong(
var last = coords[coords.length - 1];
return lineString([last, last]);
}
/**
* Assign an interpolated altitude to a coordinate produced by destination().
*
* When both segment endpoints carry an altitude the value is linearly
* interpolated at `fraction` (0 = at `from`, 1 = at `to`). If either
* endpoint has no altitude, any altitude that destination() may have copied
* from its origin is removed so the output remains 2-D.
*/
function setInterpolatedAltitude(
coord: Position,
from: Position,
to: Position,
fraction: number
): void {
if (from[2] !== undefined && to[2] !== undefined) {
coord[2] = from[2] + fraction * (to[2] - from[2]);
} else {
coord.splice(2);
}
}

export { lineSliceAlong };
export default lineSliceAlong;
77 changes: 77 additions & 0 deletions packages/turf-line-slice-along/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,80 @@ test("turf-line-slice-along -- start equal to line length", function (t) {
);
t.end();
});
// Issue #3007: interpolated endpoint vertices must carry interpolated altitude,
// not the far-endpoint altitude copied by destination().
test("turf-line-slice-along -- altitude interpolation at stop (issue #3007)", function (t) {
// A ~100 m segment from elevation 0 → 100.
// Slicing at the approximate midpoint (0→50 m) must yield an interpolated
// stop vertex near elevation 50, not the far endpoint's elevation of 100.
const elevLine = {
type: "Feature" as const,
geometry: {
type: "LineString" as const,
coordinates: [
[0, 0, 0],
[0, 0.0009, 100], // ≈ 100 m north, elevation 100 m
],
},
};
const sliced = lineSliceAlong(elevLine, 0, 50, { units: "meters" });
const endCoord =
sliced.geometry.coordinates[sliced.geometry.coordinates.length - 1];
t.equal(
endCoord.length,
3,
"interpolated stop vertex has altitude component"
);
t.ok(
Math.abs((endCoord[2] as number) - 50) < 2,
`stop altitude should be ~50 m, got ${endCoord[2]}`
);
t.end();
});

test("turf-line-slice-along -- altitude interpolation at start (issue #3007)", function (t) {
// Slicing a 3-D segment starting mid-segment: the interpolated start vertex
// must have altitude proportional to position, not a copy of the near endpoint.
const elevLine = {
type: "Feature" as const,
geometry: {
type: "LineString" as const,
coordinates: [
[0, 0, 0],
[0, 0.0009, 100], // ≈ 100 m, elevation 100 m
],
},
};
// Slice from ≈25 m to end — the interpolated start vertex should be ~alt 25.
const sliced = lineSliceAlong(elevLine, 25, 90, { units: "meters" });
const startCoord = sliced.geometry.coordinates[0];
t.equal(
startCoord.length,
3,
"interpolated start vertex has altitude component"
);
t.ok(
Math.abs((startCoord[2] as number) - 25) < 2,
`start altitude should be ~25 m, got ${startCoord[2]}`
);
t.end();
});

test("turf-line-slice-along -- no spurious altitude on 2-D line (issue #3007)", function (t) {
// A 2-D line must produce 2-D interpolated vertices — no altitude should appear.
const line2d = {
type: "Feature" as const,
geometry: {
type: "LineString" as const,
coordinates: [
[0, 0],
[0, 0.0009],
],
},
};
const sliced = lineSliceAlong(line2d, 0, 50, { units: "meters" });
const endCoord =
sliced.geometry.coordinates[sliced.geometry.coordinates.length - 1];
t.equal(endCoord.length, 2, "2-D line produces 2-D interpolated vertex");
t.end();
});
Loading