diff --git a/Sources/Turf/Geometries/LineString.swift b/Sources/Turf/Geometries/LineString.swift index 8b74d28f..6076431f 100644 --- a/Sources/Turf/Geometries/LineString.swift +++ b/Sources/Turf/Geometries/LineString.swift @@ -326,19 +326,30 @@ extension LineString { - seealso: `Turf.intersection(_:, _:)` */ public func intersections(with line: LineString) -> [LocationCoordinate2D] { - var intersections: [String : 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)) { - let key = "\(intersection.latitude),\(intersection.longitude)" - if intersections[key] == nil { - intersections[key] = intersection - } + intersections.insert(.init(intersection)) } } } - return Array(intersections.values) + return intersections.map(\.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 4139b2b9..10e79892 100644 --- a/Sources/Turf/Turf.swift +++ b/Sources/Turf/Turf.swift @@ -37,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 6c98a261..c6a9cd26 100644 --- a/Tests/TurfTests/LineStringTests.swift +++ b/Tests/TurfTests/LineStringTests.swift @@ -350,4 +350,21 @@ class LineStringTests: XCTestCase { XCTAssertEqual(slicedCoordinates?.count, 2, "no duplicated coords") XCTAssertNotEqual(slicedCoordinates?.first, slicedCoordinates?.last, "vertical slice should not collapse to first coordinate") } + + 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)]) + + let 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.") + } } 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()