Skip to content
Merged
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
46 changes: 29 additions & 17 deletions Sources/GeoJSONKitTurf/ClosestCoordinate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ extension GeoJSON.LineString {
public struct IndexedCoordinate {
/// The coordinate
public let coordinate: Array<GeoJSON.Position>.Element

/// The index of the coordinate
public let index: Array<GeoJSON.Position>.Index
/// The coordinate’s distance from the start of the polyline

/// The coordinate’s distance along the polyline from the start of the polyline
public let distance: GeoJSON.Distance
}

Expand All @@ -36,37 +38,47 @@ extension GeoJSON.LineString.IndexedCoordinate {
}

var closestCoordinate: GeoJSON.LineString.IndexedCoordinate?
var closestDistance: GeoJSON.Distance?
var closestDistance: GeoJSON.Distance = .greatestFiniteMagnitude
var cumulativeDistance: GeoJSON.Distance = 0

for index in 0..<coordinates.count - 1 {
let segment = (coordinates[index], coordinates[index + 1])
let segmentDistance = segment.0.distance(to: segment.1)
let distances = (coordinate.distance(to: segment.0), coordinate.distance(to: segment.1))

let maxDistance = max(distances.0, distances.1)
let direction = segment.0.direction(to: segment.1)
let perpendicularPoint1 = coordinate.coordinate(at: maxDistance, facing: direction + 90)
let perpendicularPoint2 = coordinate.coordinate(at: maxDistance, facing: direction - 90)
let intersectionPoint = intersection((perpendicularPoint1, perpendicularPoint2), segment)
let intersectionDistance: GeoJSON.Distance? = intersectionPoint != nil ? coordinate.distance(to: intersectionPoint!) : nil


if distances.0 < closestDistance ?? .greatestFiniteMagnitude {
closestCoordinate = GeoJSON.LineString.IndexedCoordinate(coordinate: segment.0,
index: index,
distance: startCoordinate.distance(to: segment.0))

if distances.0 < closestDistance {
closestCoordinate = GeoJSON.LineString.IndexedCoordinate(
coordinate: segment.0,
index: index,
distance: cumulativeDistance)
closestDistance = distances.0
}
if distances.1 < closestDistance ?? .greatestFiniteMagnitude {
closestCoordinate = GeoJSON.LineString.IndexedCoordinate(coordinate: segment.1,
index: index + 1,
distance: startCoordinate.distance(to: segment.1))
if distances.1 < closestDistance {
closestCoordinate = GeoJSON.LineString.IndexedCoordinate(
coordinate: segment.1,
index: index + 1,
distance: cumulativeDistance + segmentDistance)
closestDistance = distances.1
}
if intersectionDistance != nil && intersectionDistance! < closestDistance ?? .greatestFiniteMagnitude {
closestCoordinate = GeoJSON.LineString.IndexedCoordinate(coordinate: intersectionPoint!,
index: index,
distance: startCoordinate.distance(to: intersectionPoint!))
closestDistance = intersectionDistance!
if let intersectionPoint = intersection((perpendicularPoint1, perpendicularPoint2), segment) {
let intersectionDistance = coordinate.distance(to: intersectionPoint)
if intersectionDistance < closestDistance {
closestCoordinate = GeoJSON.LineString.IndexedCoordinate(
coordinate: intersectionPoint,
index: index,
distance: cumulativeDistance + intersectionDistance)
closestDistance = intersectionDistance
}
}

cumulativeDistance += segmentDistance
}

return closestCoordinate
Expand Down
10 changes: 6 additions & 4 deletions Sources/GeoJSONKitTurf/Turf+LineString.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ extension GeoJSON.LineString {
*/
public func trimmed(from startDistance: GeoJSON.Distance, to stopDistance: GeoJSON.Distance) -> GeoJSON.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 }
guard startDistance >= 0, stopDistance >= startDistance else { return nil }
let positions = self.coordinates
var traveled: GeoJSON.Distance = 0
var slice = [GeoJSON.Position]()

for i in 0..<positions.endIndex {
if startDistance >= traveled && i == positions.endIndex - 1 {
if startDistance >= traveled, i == positions.endIndex - 1 {
break
} else if traveled > startDistance && slice.isEmpty {
} else if traveled > startDistance, slice.isEmpty {
let overshoot = startDistance - traveled
if overshoot == 0.0 {
slice.append(positions[i])
Expand Down Expand Up @@ -77,7 +77,9 @@ extension GeoJSON.LineString {
traveled += positions[i].distance(to: positions[i + 1])
}

if traveled < startDistance { return nil }
if traveled < startDistance {
return nil
}

if let last = positions.last {
return GeoJSON.LineString(positions: [last, last])
Expand Down