Skip to content

Commit

Permalink
Add method of LineString.trimmed(from:to:) (#166)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShanMa1991 authored Nov 4, 2021
1 parent 21e9646 commit 1806393
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Turf.js | Turf for Swift
[turf-length#length](https://turfjs.org/docs/#length) | `LineString.distance(from:to:)`
[turf-line-intersect#lineIntersect](https://turfjs.org/docs/#lineIntersect) | `intersection(_:_:)`
[turf-line-slice#lineSlice](https://turfjs.org/docs/#lineSlice) | `LineString.sliced(from:to:)`
[turf-line-slice-along#lineSliceAlong](https://turfjs.org/docs/#lineSliceAlong) | `LineString.trimmed(from:distance:)`
[turf-line-slice-along#lineSliceAlong](https://turfjs.org/docs/#lineSliceAlong) | `LineString.trimmed(from:to:)`
[turf-midpoint#midpoint](https://turfjs.org/docs/#midpoint) | `mid(_:_:)`
[turf-nearest-point-on-line#nearestPointOnLine](https://turfjs.org/docs/#nearestPointOnLine) | `LineString.closestCoordinate(to:)`
[turf-polygon-to-line#polygonToLine](https://turfjs.org/docs/#polygonToLine) | `LineString(_:)`<br>`MultiLineString(_:)`
Expand Down
60 changes: 58 additions & 2 deletions Sources/Turf/Geometries/LineString.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,65 @@ extension LineString {
}

/**
Returns the portion of the line string that begins at the given coordinate and extends the given distance along the line string.
Returns the portion of the line string that begins at the given start distance and extends the given stop distance along the line string.

This method is roughly equivalent to the [turf-line-slice-along](https://turfjs.org/docs/#lineSliceAlong) package of Turf.js ([source code](https://github.com/Turfjs/turf/tree/master/packages/turf-line-slice-along/)), except that it accepts a starting position instead of a starting distance along the line string.
This method is equivalent to the [turf-line-slice-along](https://turfjs.org/docs/#lineSliceAlong) package of Turf.js ([source code](https://github.com/Turfjs/turf/tree/master/packages/turf-line-slice-along/)).
*/
public func trimmed(from startDistance: LocationDistance, to stopDistance: LocationDistance) -> LineString? {
// The method is porting from https://github.com/Turfjs/turf/blob/5375941072b90d489389db22b43bfe809d5e451e/packages/turf-line-slice-along/index.js
guard startDistance >= 0.0 && stopDistance >= startDistance else { return nil }
let coordinates = self.coordinates
var traveled: LocationDistance = 0
var slice = [LocationCoordinate2D]()

for i in 0..<coordinates.endIndex {
if startDistance >= traveled && i == coordinates.endIndex - 1 {
break
} else if traveled > startDistance && slice.isEmpty {
let overshoot = startDistance - traveled
if overshoot == 0.0 {
slice.append(coordinates[i])
return LineString(slice)
}
let direction = coordinates[i].direction(to: coordinates[i - 1]) - 180
let interpolated = coordinates[i].coordinate(at: overshoot, facing: direction)
slice.append(interpolated)
}

if traveled >= stopDistance {
let overshoot = stopDistance - traveled
if overshoot == 0.0 {
slice.append(coordinates[i])
return LineString(slice)
}
let direction = coordinates[i].direction(to: coordinates[i - 1]) - 180
let interpolated = coordinates[i].coordinate(at: overshoot, facing: direction)
slice.append(interpolated)
return LineString(slice)
}

if traveled >= startDistance {
slice.append(coordinates[i])
}

if i == coordinates.count - 1 {
return LineString(slice)
}

traveled += distance(from: coordinates[i], to: coordinates[i + 1]) ?? 0.0
}

if traveled < startDistance { return nil }

if let last = coordinates.last {
return LineString([last, last])
}

return nil
}

/**
Returns the portion of the line string that begins at the given coordinate and extends the given distance along the line string.
*/
public func trimmed(from coordinate: LocationCoordinate2D, distance: LocationDistance) -> LineString? {
let startVertex = closestCoordinate(to: coordinate)
Expand Down
60 changes: 60 additions & 0 deletions Tests/TurfTests/LineStringTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -350,4 +350,64 @@ class LineStringTests: XCTestCase {
XCTAssertEqual(slicedCoordinates?.count, 2, "no duplicated coords")
XCTAssertNotEqual(slicedCoordinates?.first, slicedCoordinates?.last, "vertical slice should not collapse to first coordinate")
}

func testTrimmed() {
// https://github.com/Turfjs/turf/blob/5375941072b90d489389db22b43bfe809d5e451e/packages/turf-line-slice-along/test.js

// turf-line-slice-along -- line1
let 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]
]
let line1 = LineString(coordinates.map{
CLLocationCoordinate2D(latitude: $0.last!, longitude: $0.first!)
})

var startDistance = 804672.0
var stopDistance = 1207008.0

var startPoint = line1.coordinateFromStart(distance: startDistance)
var endPoint = line1.coordinateFromStart(distance: stopDistance)
var sliced = line1.trimmed(from: startDistance, to: stopDistance)
XCTAssertNotNil(sliced, "should return valid lineString")
XCTAssertEqual(sliced!.coordinates.first!, startPoint)
XCTAssertEqual(sliced!.coordinates.last!, endPoint)

stopDistance = 2414016.0
endPoint = line1.coordinateFromStart(distance: stopDistance)
sliced = line1.trimmed(from: startDistance, to: stopDistance)
XCTAssertNotNil(sliced, "should return valid lineString")
XCTAssertEqual(sliced!.coordinates.first!, startPoint)
XCTAssertEqual(sliced!.coordinates.last!, endPoint)

startDistance = 8046720
stopDistance = 12874752.0
sliced = line1.trimmed(from: startDistance, to: stopDistance)
XCTAssertNil(sliced, "should return nil")

startDistance = line1.distance()!
stopDistance = startDistance + 100.0
startPoint = line1.coordinateFromStart(distance: startDistance)
endPoint = line1.coordinateFromStart(distance: stopDistance)
sliced = line1.trimmed(from: startDistance, to: stopDistance)
XCTAssertNotNil(sliced, "should return valid lineString")
XCTAssertEqual(sliced!.coordinates.first!, startPoint)
XCTAssertEqual(sliced!.coordinates.last!, endPoint)

startDistance = -0.376
stopDistance = 543.0
sliced = line1.trimmed(from: startDistance, to: stopDistance)
XCTAssertNil(sliced, "should return nil")
}
}

0 comments on commit 1806393

Please sign in to comment.