diff --git a/README.md b/README.md
index ac08df76..ec18b569 100644
--- a/README.md
+++ b/README.md
@@ -87,7 +87,7 @@ Turf.js | Turf for Swift
[turf-helpers#radiansToDegrees](https://turfjs.org/docs/#radiansToDegrees) | `CLLocationDegrees.toDegrees()`
`LocationDegrees.toDegrees()` on Linux
[turf-helpers#convertLength](https://turfjs.org/docs/#convertLength)
[turf-helpers#convertArea](https://turfjs.org/docs/#convertArea) | `Measurement.converted(to:)`
[turf-length#length](https://turfjs.org/docs/#length) | `LineString.distance(from:to:)`
-[turf-line-intersect#lineIntersect](https://turfjs.org/docs/#lineIntersect) | `intersection(_:_:)`
+[turf-line-intersect#lineIntersect](https://turfjs.org/docs/#lineIntersect) | `LineString.intersections(with:)`
[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:to:)`
[turf-midpoint#midpoint](https://turfjs.org/docs/#midpoint) | `mid(_:_:)`
diff --git a/Sources/Turf/Geometries/LineString.swift b/Sources/Turf/Geometries/LineString.swift
index 09afb02b..614c2c33 100644
--- a/Sources/Turf/Geometries/LineString.swift
+++ b/Sources/Turf/Geometries/LineString.swift
@@ -31,6 +31,13 @@ public struct LineString: Equatable {
public init(_ ring: Ring) {
self.coordinates = ring.coordinates
}
+
+ /**
+ Representation of current `LineString` as an array of `LineSegment`s.
+ */
+ var segments: [LineSegment] {
+ return zip(coordinates.dropLast(), coordinates.dropFirst()).map { LineSegment($0.0, $0.1) }
+ }
}
extension LineString: Codable {
@@ -308,7 +315,7 @@ extension LineString {
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 intersectionPoint = Turf.intersection((perpendicularPoint1, perpendicularPoint2), segment)
let intersectionDistance: LocationDistance? = intersectionPoint != nil ? coordinate.distance(to: intersectionPoint!) : nil
if distances.0 < closestDistance ?? .greatestFiniteMagnitude {
@@ -364,4 +371,41 @@ extension LineString {
// Ported from https://github.com/Turfjs/turf/blob/4e8342acb1dbd099f5e91c8ee27f05fb2647ee1b/packages/turf-simplify/lib/simplify.js
coordinates = Simplifier.simplify(coordinates, tolerance: tolerance, highestQuality: highestQuality)
}
+
+ /**
+ Returns all intersections with another `LineString`.
+
+ This function is roughly equivalent to the [turf-line-intersect](https://turfjs.org/docs/#lineIntersect) package of Turf.js ([source code](https://github.com/Turfjs/turf/tree/master/packages/turf-line-intersect/)). Order of found intersections is not determined.
+
+ You can also use `Turf.intersection(_:, _:)` if you need to find intersection of individual `LineSegment`s.
+
+ - seealso: `Turf.intersection(_:, _:)`
+ */
+ public func intersections(with line: LineString) -> [LocationCoordinate2D] {
+ var intersections = Set()
+ for segment1 in segments {
+ for segment2 in line.segments {
+ if let intersection = Turf.intersection(LineSegment(segment1.0, segment1.1),
+ LineSegment(segment2.0, segment2.1)) {
+ intersections.insert(.init(intersection))
+ }
+ }
+ }
+ return intersections.map { $0.locationCoordinate }
+ }
+
+ private struct HashableCoordinate: Hashable {
+ let latitude: Double
+ let longitude: Double
+
+ var locationCoordinate: LocationCoordinate2D {
+ return LocationCoordinate2D(latitude: latitude,
+ longitude: longitude)
+ }
+
+ init(_ coordinate: LocationCoordinate2D) {
+ self.latitude = coordinate.latitude
+ self.longitude = coordinate.longitude
+ }
+ }
}
diff --git a/Sources/Turf/Turf.swift b/Sources/Turf/Turf.swift
index 8129d7a1..10e79892 100644
--- a/Sources/Turf/Turf.swift
+++ b/Sources/Turf/Turf.swift
@@ -14,6 +14,8 @@ public typealias LineSegment = (LocationCoordinate2D, LocationCoordinate2D)
Returns the intersection of two line segments.
This function is roughly equivalent to the [turf-line-intersect](https://turfjs.org/docs/#lineIntersect) package of Turf.js ([source code](https://github.com/Turfjs/turf/tree/master/packages/turf-line-intersect/)), except that it only accepts individual line segments instead of whole line strings.
+
+ - seealso: `LineString.intersection(with:)`
*/
public func intersection(_ line1: LineSegment, _ line2: LineSegment) -> LocationCoordinate2D? {
// Ported from https://github.com/Turfjs/turf/blob/142e137ce0c758e2825a260ab32b24db0aa19439/packages/turf-point-on-line/index.js, in turn adapted from http://jsfiddle.net/justin_c_rounds/Gd2S2/light/
@@ -35,9 +37,9 @@ public func intersection(_ line1: LineSegment, _ line2: LineSegment) -> Location
longitude: line1.0.longitude + a * (line1.1.longitude - line1.0.longitude))
/// True if line 1 is finite and line 2 is infinite.
- let intersectsWithLine1 = a > 0 && a < 1
+ let intersectsWithLine1 = a >= 0 && a <= 1
/// True if line 2 is finite and line 1 is infinite.
- let intersectsWithLine2 = b > 0 && b < 1
+ let intersectsWithLine2 = b >= 0 && b <= 1
return intersectsWithLine1 && intersectsWithLine2 ? intersection : nil
}
diff --git a/Tests/TurfTests/LineStringTests.swift b/Tests/TurfTests/LineStringTests.swift
index 8446925b..c0d047c1 100644
--- a/Tests/TurfTests/LineStringTests.swift
+++ b/Tests/TurfTests/LineStringTests.swift
@@ -410,4 +410,35 @@ class LineStringTests: XCTestCase {
sliced = line1.trimmed(from: startDistance, to: stopDistance)
XCTAssertNil(sliced, "should return nil")
}
+
+ func testIntersections() {
+ let lineString = LineString([.init(latitude: 2, longitude: 1),
+ .init(latitude: 2, longitude: 5),
+ .init(latitude: 2, longitude: 9)])
+
+ let intersectingLineString = LineString([.init(latitude: 4, longitude: 1),
+ .init(latitude: 0, longitude: 5),
+ .init(latitude: 2, longitude: 9)])
+
+ var intersections = lineString.intersections(with: intersectingLineString)
+
+ XCTAssertEqual(intersections.sorted(by: { $0.longitude < $1.longitude }),
+ [.init(latitude: 2, longitude: 3),
+ .init(latitude: 2, longitude: 9)],
+ accuracy: 0, "LineString intersections are not correct.")
+
+ let notIntersectingLineString = LineString([.init(latitude: 1, longitude: 1),
+ .init(latitude: 1, longitude: 5),
+ .init(latitude: 1, longitude: 9)])
+
+ intersections = lineString.intersections(with: notIntersectingLineString)
+
+ XCTAssertTrue(intersections.isEmpty, "Found impossible LineString intersection(s).")
+
+ let emptyLineString = LineString([])
+
+ intersections = lineString.intersections(with: emptyLineString)
+
+ XCTAssertTrue(intersections.isEmpty, "Found impossible LineString intersection(s).")
+ }
}
diff --git a/Tests/TurfTests/TurfTests.swift b/Tests/TurfTests/TurfTests.swift
index 8e3681a0..5344870d 100644
--- a/Tests/TurfTests/TurfTests.swift
+++ b/Tests/TurfTests/TurfTests.swift
@@ -40,6 +40,13 @@ class TurfTests: XCTestCase {
XCTAssertEqual(a, coord1)
}
+ func testIntersectionOnEnd() {
+ let coord1 = LocationCoordinate2D(latitude: 20, longitude: 20)
+ let a = intersection((LocationCoordinate2D(latitude: 20, longitude: 20), LocationCoordinate2D(latitude: 40, longitude: 40)),
+ (LocationCoordinate2D(latitude: 20, longitude: 20), LocationCoordinate2D(latitude: 40, longitude: 20)))
+ XCTAssertEqual(a, coord1)
+ }
+
func testCLLocationDegrees() {
let degree: CLLocationDegrees = 100
let a = degree.toRadians()