Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent results from Polyline.distance #27

Closed
systemed opened this issue Jan 2, 2018 · 4 comments · Fixed by #74
Closed

Inconsistent results from Polyline.distance #27

systemed opened this issue Jan 2, 2018 · 4 comments · Fixed by #74
Assignees

Comments

@systemed
Copy link

systemed commented Jan 2, 2018

I'm getting small inconsistencies from Polyline.distance. By tracing intermediate points along a polyline from start to end - including between vertices - the resulting distance(to: point) doesn't consistently increment from 0 to (total distance), but jumps up and down.

My suspicion is that there's something screwy going on with the interaction with closestCoordinate but I've not been able to nail it down.

For my purposes I only need the distance to a point from the start of the polyline, so I was able to get round it by hacking a baseIndex property onto closestCoordinate which always contains the value of index (not index+1) and then building this round it:

let slice = polyline.coordinates[0 ... coord.baseIndex]
let zipped = zip(slice.prefix(upTo: slice.count - 1), slice.suffix(from: 1))
return zipped.map { $0.distance(to: $1) }.reduce(0, +) +
	polyline.coordinates[coord.baseIndex].distance(to: coord.coordinate)

but I thought it worth flagging in case anyone else encounters this.

@1ec5
Copy link
Contributor

1ec5 commented Jan 12, 2018

I wonder if this is related to the Earth radius constant we’re using: #26.

/cc @frederoni @bsudekum

@KaterGreg
Copy link

I'm having the same issue in 0.2.0.

Calculating distance from 2 different points less than 1 meter apart are giving me results that are 90 meters apart.

Original PolyLine:
49.119869999999999, -122.65477
49.119949999999996, -122.65477
49.120129999999996, -122.65477
49.120129999999996, -122.65401
49.12032, -122.65401
49.120689999999996, -122.65401
49.120619999999995, -122.65352 - 183.04443165794757
49.120189999999994, -122.65237 - 279.46026229062824
49.120149999999995, -122.65227 - 287.99193938810771
49.119779999999999, -122.65275 - 341.98021101023426
49.119639999999997, -122.65293 - 362.33204275778985
— more data points follow, but are irrelevant for this example —

Location = 49.120403526377203, -122.6529443631224
polyline.distance(from: polyline.coordinates.first, to: location.coordinate) = 327.54650624173649

polylineIndex = polyline.closestCoordinate(to: location.coordinate)!
polylineIndex.coordinate = 49.120404457012796, -122.65294354782493
polyline.distance(from: polyline.coordinates.first, to: polylineIndex.coordinate) = 327.54632204561312

Fake Point (calculated mid-point between points 7 & 8) = 49.120405, -122.652945
polyline.distance(from: polyline.coordinates.first, to: CLLocationCoordinate2DMake(49.120405, -122.652945)) = 231.25245146525631

The coordinates all share 5 decimal places of accuracy (49.12040xxx, -122.65294xxx), so these distances are minuscule.

So, the ultimate test:
polyline.distance(from: location.coordinate, to: polylineIndex.coordinate) = 0.00018419612339527888

polyline.distance(from: location.coordinate, to: (49.120405, -122.652945)) = 96.294054777557619

polyline.distance(from: polylineIndex.coordinate, to: (49.120405, -122.652945)) = 96.29387058143422

I removed the variable and tested some data directly, and narrowed down the miscalculation to a very small area:
polyline.distance(from: (49.120405, -122.652945), to: (49.120405, -122.652943)) = 96.289203671890107
polyline.distance(from: (49.120405, -122.652945), to: (49.120405, -122.652944)) = 96.352412662880823
polyline.distance(from: (49.120405, -122.65294499876), to: (49.120405, -122.65294499875)) =
96.415464260856965
polyline.distance(from: (49.120405, -122.652945), to: (49.120405, -122.652945)) = 0.0
polyline.distance(from: (49.120405, -122.652945), to: (49.120405, -122.652946)) = 0.063208025878338778
polyline.distance(from: (49.120405, -122.652945), to: (49.120405, -122.652947)) = 0.12641605148581697

I have no idea what causes a significant distance change between -122.65294499876 & -122.65294499875, but it's definitely wrong.

@1ec5 1ec5 self-assigned this Dec 11, 2018
@1ec5
Copy link
Contributor

1ec5 commented Dec 14, 2018

Here’s a subset of the polyline above:

let polyline = Polyline([
    CLLocationCoordinate2D(latitude: 49.119869999999999, longitude: -122.65477),
    CLLocationCoordinate2D(latitude: 49.119949999999996, longitude: -122.65477),
    CLLocationCoordinate2D(latitude: 49.120129999999996, longitude: -122.65477),
    CLLocationCoordinate2D(latitude: 49.120129999999996, longitude: -122.65401),
    CLLocationCoordinate2D(latitude: 49.12032, longitude: -122.65401),
    CLLocationCoordinate2D(latitude: 49.120689999999996, longitude: -122.65401),
    CLLocationCoordinate2D(latitude: 49.120689999999996, longitude: -122.65401),
    CLLocationCoordinate2D(latitude: 49.120619999999995, longitude: -122.65352),
])

let start = CLLocationCoordinate2D(latitude: 49.120403526377203, longitude: -122.6529443631224)
let end = CLLocationCoordinate2D(latitude: 49.120405, longitude: -122.652945)
XCTAssertLessThan(start.distance(to: end), 1)

XCTAssertLessThan(polyline.distance(from: start, to: end), 1)

Here’s what polyline, start, and end look like – start and end are nearly coincidental:

short

CLLocationCoordinate2D.distance(to:) returns 17 centimeters, while Polyline.distance(from:to:) returns 0, as expected, since both points lie beyond the end of the polyline.

When appending the following coordinate onto the polyline, causing the polyline to go through both points, things get weird:

CLLocationCoordinate2D(latitude: 49.120189999999994, longitude: -122.65237)

long

CLLocationCoordinate2D.distance(to:) still returns 17 centimeters, while Polyline.distance(from:to:) returns 96 meters, which is the distance from start to the end of the polyline to end, as returned by LineString.sliced(from:to:).

@1ec5
Copy link
Contributor

1ec5 commented Dec 14, 2018

The following line in LineString.sliced(from:to:) is responsible for adding the extraneous coordinates to the slice:

var coords = ends.0.index == ends.1.index ? [] : Array(coordinates[ends.0.index + 1...ends.1.index])

ends.0.index and ends.1.index are 8 and 7, respectively. I suspect the issue is that we’re rounding the index up for ends.0 due to mapbox/mapbox-navigation-ios#284. This change was known to differ from Turf.js (unlike mapbox/mapbox-navigation-ios#39, which was backported to JavaScript), but the thought was that always rounding the index up would be more internally consistent. It turns out that LineString.sliced(from:to:) relies on LineString.closestCoordinate(to:) to not round up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants