Skip to content

Commit

Permalink
Move intersection/2 to GeoJSON.LineString.intersection(with:) method
Browse files Browse the repository at this point in the history
  • Loading branch information
nighthawk committed Jun 1, 2022
1 parent 3d131ef commit 0c2cebe
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Turf.js | Turf-swift
[turf-helpers#radiansToDegrees](https://github.com/Turfjs/turf/tree/master/packages/turf-helpers/#radiansToDegrees) | `GeoJSON.DegreesRadians.toDegrees()`
[turf-helpers#convertLength](https://github.com/Turfjs/turf/tree/master/packages/turf-helpers#convertlength)<br>[turf-helpers#convertArea](https://github.com/Turfjs/turf/tree/master/packages/turf-helpers#convertarea) | `Measurement.converted(to:)`
[turf-length](https://github.com/Turfjs/turf/tree/master/packages/turf-length/) | `GeoJSON.LineString.distance(from:to:)`
[turf-line-intersect](https://github.com/Turfjs/turf/tree/master/packages/turf-line-intersect/) | `intersection(_:_:)`
[turf-line-intersect](https://github.com/Turfjs/turf/tree/master/packages/turf-line-intersect/) | `GeoJSON.LineString.intersection(with:)`
[turf-line-slice](https://github.com/Turfjs/turf/tree/master/packages/turf-line-slice/) | `GeoJSON.LineString.sliced(from:to:)`
[turf-line-slice-along](https://github.com/Turfjs/turf/tree/master/packages/turf-line-slice-along/) | `GeoJSON.LineString.trimmed(from:distance:)`, `GeoJSON.LineString.trimmed(from:to:)`
[turf-midpoint](https://github.com/Turfjs/turf/blob/master/packages/turf-midpoint/index.js) | `mid(_:_:)`
Expand Down
26 changes: 26 additions & 0 deletions Sources/GeoJSONKitTurf/Turf+LineString.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import GeoJSONKit
extension GeoJSON.LineString {
var coordinates: [GeoJSON.Position] { positions }

/**
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) }
}

/// Returns a new line string based on bezier transformation of the input line.
///
/// ported from https://github.com/Turfjs/turf/blob/1ea264853e1be7469c8b7d2795651c9114a069aa/packages/turf-bezier-spline/index.ts
Expand Down Expand Up @@ -261,5 +268,24 @@ extension GeoJSON.LineString {

return closestCoordinate
}


/**
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.
*/
public func intersections(with line: GeoJSON.LineString) -> Set<GeoJSON.Position> {
var intersections = Set<GeoJSON.Position>()
for segment1 in segments {
for segment2 in line.segments {
if let intersection = intersection(LineSegment(segment1.0, segment1.1),
LineSegment(segment2.0, segment2.1)) {
intersections.insert(intersection)
}
}
}
return intersections
}

}
8 changes: 4 additions & 4 deletions Sources/GeoJSONKitTurf/Turf.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ let metersPerRadian: GeoJSON.Distance = 6_373_000.0
// WGS84 equatorial radius as specified by the International Union of Geodesy and Geophysics
let equatorialRadius: GeoJSON.Distance = 6_378_137

public typealias LineSegment = (GeoJSON.Position, GeoJSON.Position)
typealias LineSegment = (GeoJSON.Position, GeoJSON.Position)

/**
Returns the intersection of two line segments.
*/
public func intersection(_ line1: LineSegment, _ line2: LineSegment) -> GeoJSON.Position? {
func intersection(_ line1: LineSegment, _ line2: LineSegment) -> GeoJSON.Position? {
// 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/
let denominator = ((line2.1.latitude - line2.0.latitude) * (line1.1.longitude - line1.0.longitude))
- ((line2.1.longitude - line2.0.longitude) * (line1.1.latitude - line1.0.latitude))
Expand All @@ -31,9 +31,9 @@ public func intersection(_ line1: LineSegment, _ line2: LineSegment) -> GeoJSON.
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
}

Expand Down
30 changes: 30 additions & 0 deletions Tests/GeoJSONKitTurfTests/LineStringTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -392,4 +392,34 @@ class LineStringTests: XCTestCase {
sliced = line1.trimmed(from: startDistance, to: stopDistance)
XCTAssertNil(sliced, "should return nil")
}

func testIntersections() {
let lineString = GeoJSON.LineString(positions: [.init(latitude: 2, longitude: 1),
.init(latitude: 2, longitude: 5),
.init(latitude: 2, longitude: 9)])

let intersectingLineString = GeoJSON.LineString(positions: [.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)], "LineString intersections are not correct.")

let notIntersectingLineString = GeoJSON.LineString(positions: [.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 = GeoJSON.LineString(positions: [])

intersections = lineString.intersections(with: emptyLineString)

XCTAssertTrue(intersections.isEmpty, "Found impossible LineString intersection(s).")
}
}
7 changes: 7 additions & 0 deletions Tests/GeoJSONKitTurfTests/TurfTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ class TurfTests: XCTestCase {
XCTAssertEqual(a, coord1)
}

func testIntersectionOnEnd() {
let coord1 = GeoJSON.Position(latitude: 20, longitude: 20)
let a = intersection((GeoJSON.Position(latitude: 20, longitude: 20), GeoJSON.Position(latitude: 40, longitude: 40)),
(GeoJSON.Position(latitude: 20, longitude: 20), GeoJSON.Position(latitude: 40, longitude: 20)))
XCTAssertEqual(a, coord1)
}

func testDegreeesToRadians() {
let degree: GeoJSON.Degrees = 100
let a = degree.toRadians()
Expand Down

0 comments on commit 0c2cebe

Please sign in to comment.