Skip to content

Commit

Permalink
Implement lineSlice with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
leiflinse-trivector committed Jan 26, 2024
1 parent c123163 commit ec03d7a
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lib/line_slice.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
library turf_along;

export "src/line_slice.dart";
36 changes: 36 additions & 0 deletions lib/src/line_slice.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'package:turf/helpers.dart';
import 'package:turf/nearest_point_on_line.dart';
import 'package:turf/src/invariant.dart';

/// Takes a [line], at a start point [startPt], and a stop point [stopPt]
/// and returns a subsection of the line in-between those points.
/// The start & stop points don't need to fall exactly on the line.
///
/// This can be useful for extracting only the part of a route between waypoints.
Feature<LineString> lineSlice(
Point startPt, Point stopPt, Feature<LineString> line) {
final coords = line.geometry;
if (coords == null) {
throw Exception('line has no geometry');
}

final startVertex = nearestPointOnLine(coords, startPt);
final stopVertex = nearestPointOnLine(coords, stopPt);
late final List<Feature<Point>> ends;
if (startVertex.properties!['index'] <= stopVertex.properties!['index']) {
ends = [startVertex, stopVertex];
} else {
ends = [stopVertex, startVertex];
}
final List<Position> clipCoords = [getCoord(ends[0])];
for (var i = ends[0].properties!['index'] + 1;
i < ends[1].properties!['index'] + 1;
i++) {
clipCoords.add(coords.coordinates[i]);
}
clipCoords.add(getCoord(ends[1]));
return Feature<LineString>(
geometry: LineString(coordinates: clipCoords),
properties: line.properties,
);
}
73 changes: 73 additions & 0 deletions test/components/line_slice_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'package:test/test.dart';
import 'package:turf/along.dart';
import 'package:turf/distance.dart';
import 'package:turf/helpers.dart';
import 'package:turf/length.dart';
import 'package:turf/src/line_slice.dart';

void main() {
test('lineSlice - exact points', () {
final slice = lineSlice(
Point(coordinates: start), Point(coordinates: via), lineFeature);
expect(slice.properties, isNotNull);
expect(slice.properties!.keys, contains(propName));
expect(slice.properties![propName], equals(propValue));

final expectedLineFeature = Feature<LineString>(
geometry: LineString(coordinates: [start, via]),
);
expect(slice.geometry, isNotNull);
expect(length(slice).round(), equals(length(expectedLineFeature).round()));
});
test('lineSlice - interpolation', () {
const skipDist = 10;

final startPt = along(lineFeature, skipDist, Unit.meters);
expect(startPt, isNotNull);

final slice = lineSlice(startPt, Point(coordinates: via), lineFeature);
expect(slice.properties, isNotNull);
expect(slice.properties!.keys, contains(propName));
expect(slice.properties![propName], equals(propValue));

final expectedLine = Feature<LineString>(
geometry: LineString(coordinates: [start, via]),
);
expect(slice.geometry, isNotNull);
expect(
length(slice, Unit.meters).round(),
equals(length(expectedLine, Unit.meters).round() - skipDist),
);

// Sanity check of test data. No interpolation occurs if start and via are skipDist apart.
expect(distance(Point(coordinates: start), Point(coordinates: via)).round(),
isNot(equals(skipDist)));
});
}

final start = Position.named(
lat: 55.7090430186194,
lng: 13.184645393920405,
);
final via = Position.named(
lat: 55.70901279569489,
lng: 13.185546616182755,
);
final end = Position.named(
lat: 55.70764669578079,
lng: 13.187563637197076,
);
const propName = 'prop1';
const propValue = 1;
final lineFeature = Feature<LineString>(
geometry: LineString(
coordinates: [
start,
via,
end,
],
),
properties: {
propName: propValue,
},
);

0 comments on commit ec03d7a

Please sign in to comment.