-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add initial line_slice_along implementation (#190)
- Loading branch information
Showing
8 changed files
with
30,786 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
library turf_line_slice_along; | ||
|
||
export 'package:geotypes/geotypes.dart'; | ||
export "src/line_slice_along.dart"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import 'package:turf/bearing.dart'; | ||
import 'package:turf/destination.dart'; | ||
import 'package:turf/distance.dart'; | ||
import 'package:turf/helpers.dart'; | ||
|
||
/// Takes a [line], at a start distance [startDist] and a stop distance [stopDist] | ||
/// and returns a subsection of the line in-between those distances. | ||
/// | ||
/// If [startDist] and [stopDist] resolve to the same point on [line], null is returned | ||
/// as the resolved line would only contain one point which isn't supported by LineString. | ||
/// | ||
/// This can be useful for extracting only the part of a route between distances on the route. | ||
LineString lineSliceAlongRaw( | ||
LineString line, | ||
double startDist, | ||
double stopDist, [ | ||
Unit unit = Unit.kilometers, | ||
]) { | ||
List<Position> coords = line.coordinates; | ||
var slice = <Position>[]; | ||
|
||
var origCoordsLength = coords.length; | ||
double travelled = 0; | ||
double? overshot; | ||
double direction = 0; | ||
Position? interpolated; | ||
for (var i = 0; i < coords.length; i++) { | ||
if (startDist >= travelled && i == coords.length - 1) { | ||
break; | ||
} else if (travelled > startDist && slice.isEmpty) { | ||
overshot = startDist - travelled; | ||
if (overshot == 0) { | ||
slice.add(coords[i]); | ||
return LineString(coordinates: slice); | ||
} | ||
direction = bearingRaw(coords[i], coords[i - 1]) - 180; | ||
interpolated = destinationRaw(coords[i], overshot, direction, unit); | ||
slice.add(interpolated); | ||
} | ||
|
||
if (travelled >= stopDist) { | ||
overshot = stopDist - travelled; | ||
if (overshot == 0) { | ||
slice.add(coords[i]); | ||
return LineString(coordinates: slice); | ||
} | ||
direction = bearingRaw(coords[i], coords[i - 1]) - 180; | ||
interpolated = destinationRaw(coords[i], overshot, direction, unit); | ||
slice.add(interpolated); | ||
return LineString(coordinates: slice); | ||
} | ||
|
||
if (travelled >= startDist) { | ||
slice.add(coords[i]); | ||
} | ||
|
||
if (i == coords.length - 1) { | ||
return LineString(coordinates: slice); | ||
} | ||
|
||
travelled += distanceRaw(coords[i], coords[i + 1], unit); | ||
} | ||
|
||
if (travelled < startDist && coords.length == origCoordsLength) { | ||
throw Exception("Start position is beyond line"); | ||
} | ||
|
||
final last = coords[coords.length - 1]; | ||
return LineString(coordinates: [last, last]); | ||
} | ||
|
||
/// Takes a [line], at a start distance [startDist] and a stop distance [stopDist] | ||
/// and returns a subsection of the line in-between those distances. | ||
/// | ||
/// If [startDist] and [stopDist] resolve to the same point on [line], null is returned | ||
/// as the resolved line would only contain one point which isn't supported by LineString. | ||
/// | ||
/// This can be useful for extracting only the part of a route between distances on the route. | ||
Feature<LineString> lineSliceAlong( | ||
Feature<LineString> line, | ||
double startDist, | ||
double stopDist, [ | ||
Unit unit = Unit.kilometers, | ||
]) { | ||
return Feature<LineString>( | ||
geometry: lineSliceAlongRaw(line.geometry!, startDist, stopDist, unit), | ||
properties: line.properties, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import 'package:test/test.dart'; | ||
import 'package:turf/turf.dart'; | ||
|
||
import '../context/load_test_cases.dart'; | ||
|
||
void main() { | ||
loadGeoJson('./test/examples/line_slice_along/fixtures/line1.geojson', | ||
(path, geoJson) { | ||
final line1 = Feature<LineString>( | ||
geometry: (geoJson as Feature).geometry as LineString, | ||
); | ||
|
||
test('turf-line-slice-along -- line1', () { | ||
const start = 500.0; | ||
const stop = 750.0; | ||
const options = Unit.miles; | ||
|
||
final startPoint = along(line1, start, options); | ||
final endPoint = along(line1, stop, options); | ||
final sliced = lineSliceAlong(line1, start, stop, options); | ||
|
||
expect(sliced, isA<Feature<LineString>>()); | ||
expect(sliced.type, GeoJSONObjectType.feature); | ||
expect(sliced.geometry?.type, GeoJSONObjectType.lineString); | ||
expect(sliced.geometry?.coordinates[0], | ||
equals(startPoint.geometry!.coordinates)); | ||
expect( | ||
sliced.geometry?.coordinates[sliced.geometry!.coordinates.length - 1], | ||
equals(endPoint.geometry!.coordinates), | ||
); | ||
}); | ||
|
||
test('turf-line-slice-along -- line1 overshoot', () { | ||
const start = 500.0; | ||
const stop = 1500.0; | ||
const options = Unit.miles; | ||
|
||
final startPoint = along(line1, start, options); | ||
final endPoint = along(line1, stop, options); | ||
final sliced = lineSliceAlong(line1, start, stop, options); | ||
|
||
expect(sliced, isA<Feature<LineString>>()); | ||
expect(sliced.type, GeoJSONObjectType.feature); | ||
expect(sliced.geometry?.type, GeoJSONObjectType.lineString); | ||
expect(sliced.geometry?.coordinates[0], | ||
equals(startPoint.geometry!.coordinates)); | ||
expect( | ||
sliced.geometry?.coordinates[sliced.geometry!.coordinates.length - 1], | ||
equals(endPoint.geometry!.coordinates), | ||
); | ||
}); | ||
|
||
test('turf-line-slice-along -- start longer than line length', () { | ||
const start = 500000.0; | ||
const stop = 800000.0; | ||
const options = Unit.miles; | ||
|
||
expect( | ||
() => lineSliceAlong(line1, start, stop, options), | ||
throwsA(isA<Exception>().having( | ||
(e) => e.toString(), | ||
'message', | ||
contains('Start position is beyond line'), | ||
)), | ||
); | ||
}); | ||
|
||
test('turf-line-slice-along -- start equal to line length', () { | ||
const options = Unit.miles; | ||
final start = length(line1, options); | ||
final stop = start + 100; | ||
|
||
final startPoint = along(line1, start, options); | ||
final endPoint = along(line1, stop, options); | ||
final sliced = | ||
lineSliceAlong(line1, start.toDouble(), stop.toDouble(), options); | ||
|
||
expect(sliced, isA<Feature<LineString>>()); | ||
expect(sliced.type, GeoJSONObjectType.feature); | ||
expect(sliced.geometry?.type, GeoJSONObjectType.lineString); | ||
expect(sliced.geometry?.coordinates[0], | ||
equals(startPoint.geometry!.coordinates)); | ||
expect( | ||
sliced.geometry?.coordinates[sliced.geometry!.coordinates.length - 1], | ||
endPoint.geometry!.coordinates, | ||
); | ||
}); | ||
}); | ||
|
||
loadGeoJson('./test/examples/line_slice_along/fixtures/route1.geojson', | ||
(path, geoJson) { | ||
final route1 = Feature<LineString>( | ||
geometry: (geoJson as Feature).geometry as LineString, | ||
); | ||
|
||
test('turf-line-slice-along -- route1', () { | ||
const start = 500.0; | ||
const stop = 750.0; | ||
const options = Unit.miles; | ||
|
||
final startPoint = along(route1, start, options); | ||
final endPoint = along(route1, stop, options); | ||
final sliced = lineSliceAlong(route1, start, stop, options); | ||
|
||
expect(sliced, isA<Feature<LineString>>()); | ||
expect(sliced.type, GeoJSONObjectType.feature); | ||
expect(sliced.geometry?.type, GeoJSONObjectType.lineString); | ||
expect(sliced.geometry?.coordinates[0], | ||
equals(startPoint.geometry!.coordinates)); | ||
expect( | ||
sliced.geometry?.coordinates[sliced.geometry!.coordinates.length - 1], | ||
equals(endPoint.geometry!.coordinates), | ||
); | ||
}); | ||
}); | ||
|
||
loadGeoJson('./test/examples/line_slice_along/fixtures/route2.geojson', | ||
(path, geoJson) { | ||
final route2 = Feature<LineString>( | ||
geometry: (geoJson as Feature).geometry as LineString, | ||
); | ||
|
||
test('turf-line-slice-along -- route2', () { | ||
const start = 25.0; | ||
const stop = 50.0; | ||
const options = Unit.miles; | ||
|
||
final startPoint = along(route2, start, options); | ||
final endPoint = along(route2, stop, options); | ||
final sliced = lineSliceAlong(route2, start, stop, options); | ||
|
||
expect(sliced, isA<Feature<LineString>>()); | ||
expect(sliced.type, GeoJSONObjectType.feature); | ||
expect(sliced.geometry?.type, GeoJSONObjectType.lineString); | ||
expect(sliced.geometry?.coordinates[0], | ||
equals(startPoint.geometry!.coordinates)); | ||
expect( | ||
sliced.geometry?.coordinates[sliced.geometry!.coordinates.length - 1], | ||
equals(endPoint.geometry!.coordinates), | ||
); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"type": "Feature", | ||
"properties": {}, | ||
"geometry": { | ||
"type": "LineString", | ||
"coordinates": [ | ||
[113.99414062499999, 22.350075806124867], | ||
[116.76269531249999, 23.241346102386135], | ||
[117.7734375, 24.367113562651276], | ||
[118.828125, 25.20494115356912], | ||
[119.794921875, 26.78484736105119], | ||
[120.80566406250001, 28.110748760633534], | ||
[121.59667968749999, 29.49698759653577], | ||
[121.59667968749999, 31.12819929911196], | ||
[120.84960937499999, 32.84267363195431], | ||
[119.83886718750001, 34.125447565116126], | ||
[118.69628906249999, 35.31736632923788], | ||
[121.4208984375, 36.80928470205937], | ||
[122.82714843749999, 37.37015718405753] | ||
] | ||
} | ||
} |
Oops, something went wrong.