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

refactor distance calculations #9202

Merged
merged 34 commits into from
Jan 31, 2020
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9c3b2b7
refactor distance calculations
Meekohi Jan 17, 2020
e8961f4
update LngLat test
Meekohi Jan 17, 2020
2ce2d77
updated render-tests
Meekohi Jan 17, 2020
f8d0055
missed one?
Meekohi Jan 17, 2020
756b094
missed a bunch
Meekohi Jan 17, 2020
e6e1f3d
Update src/geo/lng_lat.js
Meekohi Jan 19, 2020
615dced
better comments
Meekohi Jan 19, 2020
003ac59
update tests again
Meekohi Jan 19, 2020
428a861
updated inline comment
Meekohi Jan 19, 2020
2384d75
better error messages in tests
Meekohi Jan 19, 2020
87f3393
fix promoteId spec definitions (#9212)
mourner Jan 21, 2020
a13efc0
upgrade earcut to v2.2.2 (#9214)
mourner Jan 21, 2020
c09c9ec
move earthRadius definition to named export
Meekohi Jan 22, 2020
28603d1
Fix promoteId for line layers (#9210)
mourner Jan 22, 2020
980d1fb
Fix line distances breaking gradient across tile boundaries (#9220)
karimnaaji Jan 23, 2020
b7e8fb3
Update image expression SDK support table (#9228)
Jan 24, 2020
8cd474e
Refactor style._load function, move sprite loading to a private metho…
webdeb Jan 24, 2020
8c9ace1
[tests][tile mode] Add left-top-right-buttom-offset-tile-map-mode test
pozdnyakov Jan 27, 2020
be4f189
Reduce size of line atlas by removing unused channels (#9232)
karimnaaji Jan 27, 2020
99bfc7f
Fix a bug where lines with duplicate endpoint disappear on z18+ (#9218)
mourner Jan 27, 2020
c913aed
refactor distance calculations
Meekohi Jan 17, 2020
53aee40
update LngLat test
Meekohi Jan 17, 2020
4167d3e
updated render-tests
Meekohi Jan 17, 2020
2da4971
missed one?
Meekohi Jan 17, 2020
c79cd91
missed a bunch
Meekohi Jan 17, 2020
8b1dabd
Update src/geo/lng_lat.js
Meekohi Jan 19, 2020
e40b6e4
better comments
Meekohi Jan 19, 2020
74abf1d
update tests again
Meekohi Jan 19, 2020
896c33f
updated inline comment
Meekohi Jan 19, 2020
9d63de4
better error messages in tests
Meekohi Jan 19, 2020
c8edf1c
move earthRadius definition to named export
Meekohi Jan 22, 2020
c573758
Merge branch 'lnglat-distance' of github.com:Meekohi/mapbox-gl-js int…
Meekohi Jan 27, 2020
25657f0
update modified render test:
Meekohi Jan 27, 2020
d7ff0fa
wiggle room for HW differences
Meekohi Jan 31, 2020
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
34 changes: 34 additions & 0 deletions src/geo/lng_lat.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,40 @@ class LngLat {
return `LngLat(${this.lng}, ${this.lat})`;
}

/*
* Approximate radius of the earth.
* Uses the WGS-84 approximation. The radius at the equator is ~6378137 and at the poles is ~6356752. https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84
* 6371008.8 is one published "average radius" see https://en.wikipedia.org/wiki/Earth_radius#Mean_radius, or ftp://athena.fsv.cvut.cz/ZFG/grs80-Moritz.pdf p.4
*
* @returns {number} Average radius of the earth in meters.
*/
static earthRadius(): number {
return 6371008.8;
}
Meekohi marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns the approximate distance between a pair of coordinates in meters
* Uses the Haversine Formula (from R.W. Sinnott, "Virtues of the Haversine", Sky and Telescope, vol. 68, no. 2, 1984, p. 159)
*
* @param {LngLat} lngLat coordinates to compute the distance to
* @returns {number} Distance in meters between the two coordinates.
* @example
* var new_york = new mapboxgl.LngLat(-74.0060, 40.7128);
* var los_angeles = new mapboxgl.LngLat(-118.2437, 34.0522);
* new_york.distanceTo(los_angeles); // = 3935751.690893987, "true distance" using a non-spherical approximation is ~3966km
*/
distanceTo(lngLat: LngLat) {
const R = LngLat.earthRadius(); // meters

const rad = Math.PI / 180;
const lat1 = this.lat * rad;
const lat2 = lngLat.lat * rad;
const a = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos((lngLat.lng - this.lng) * rad);

const maxMeters = R * Math.acos(Math.min(a, 1));
return maxMeters;
}

/**
* Returns a `LngLatBounds` from the coordinates extended by a given `radius`. The returned `LngLatBounds` completely contains the `radius`.
*
Expand Down
11 changes: 6 additions & 5 deletions src/geo/mercator_coordinate.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import LngLat from '../geo/lng_lat';
import type {LngLatLike} from '../geo/lng_lat';

/*
* The circumference of the world in meters at the equator.
* The average circumference of the world in meters.
*/
const circumferenceAtEquator = 2 * Math.PI * 6378137;
const earthRadius = LngLat.earthRadius(); // meters
const earthCircumfrence = 2 * Math.PI * earthRadius;

/*
* The circumference of the world in meters at the given latitude.
* The circumference at a line of latitude in meters.
*/
function circumferenceAtLatitude(latitude: number) {
return circumferenceAtEquator * Math.cos(latitude * Math.PI / 180);
return earthCircumfrence * Math.cos(latitude * Math.PI / 180);
}

export function mercatorXfromLng(lng: number) {
Expand Down Expand Up @@ -142,7 +143,7 @@ class MercatorCoordinate {
*/
meterInMercatorCoordinateUnits() {
// 1 meter / circumference at equator in meters * Mercator projection scale factor at this latitude
return 1 / circumferenceAtEquator * mercatorScale(latFromMercatorY(this.y));
return 1 / earthCircumfrence * mercatorScale(latFromMercatorY(this.y));
}

}
Expand Down
19 changes: 3 additions & 16 deletions src/ui/control/scale_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ function updateScale(map, container, options) {
const maxWidth = options && options.maxWidth || 100;

const y = map._container.clientHeight / 2;
const maxMeters = getDistance(map.unproject([0, y]), map.unproject([maxWidth, y]));
const left = map.unproject([0, y]);
const right = map.unproject([maxWidth, y]);
const maxMeters = left.distanceTo(right);
// The real distance corresponding to 100px scale length is rounded off to
// near pretty number and the scale length for the same is found out.
// Default unit of the scale is based on User's locale.
Expand Down Expand Up @@ -121,21 +123,6 @@ function setScale(container, maxWidth, maxDistance, unit) {
container.innerHTML = distance + unit;
}

function getDistance(latlng1, latlng2) {
// Uses spherical law of cosines approximation.
const R = 6371000;

const rad = Math.PI / 180,
lat1 = latlng1.lat * rad,
lat2 = latlng2.lat * rad,
a = Math.sin(lat1) * Math.sin(lat2) +
Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlng2.lng - latlng1.lng) * rad);

const maxMeters = R * Math.acos(Math.min(a, 1));
return maxMeters;

}

function getDecimalRoundNum(d) {
const multiplier = Math.pow(10, Math.ceil(-Math.log(d) / Math.LN10));
return Math.round(d * multiplier) / multiplier;
Expand Down
Binary file modified test/integration/render-tests/extent/1024-symbol/expected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions test/unit/geo/lng_lat.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,33 @@ test('LngLat', (t) => {
t.end();
});

t.test('#distanceTo', (t) => {
const newYork = new LngLat(-74.0060, 40.7128);
const losAngeles = new LngLat(-118.2437, 34.0522);
const d = newYork.distanceTo(losAngeles); // 3935751.690893987, "true distance" is 3966km
t.ok(d > 3935750, "New York should be more than 3935750m from Los Angeles");
t.ok(d < 3935752, "New York should be less than 3935752m from Los Angeles");
t.end();
});

t.test('#distanceTo to pole', (t) => {
const newYork = new LngLat(-74.0060, 40.7128);
const northPole = new LngLat(-135, 90);
const d = newYork.distanceTo(northPole); // 5480494.158486183 , "true distance" is 5499km
t.ok(d > 5480493, "New York should be more than 5480493m from the North Pole");
t.ok(d < 5480495, "New York should be less than 5480495m from the North Pole");
t.end();
});

t.test('#distanceTo to Null Island', (t) => {
const newYork = new LngLat(-74.0060, 40.7128);
const nullIsland = new LngLat(0, 0);
const d = newYork.distanceTo(nullIsland); // 8667080.125666846 , "true distance" is 8661km
t.ok(d > 8667079, "New York should be more than 8667079m from Null Island");
t.ok(d < 8667081, "New York should be less than 8667081m from Null Island");
t.end();
});

t.test('#toBounds', (t) => {
t.deepEqual(new LngLat(0, 0).toBounds(10).toArray(), [[-0.00008983152770714982, -0.00008983152770714982], [0.00008983152770714982, 0.00008983152770714982]]);
t.deepEqual(new LngLat(-73.9749, 40.7736).toBounds(10).toArray(), [[-73.97501862141328, 40.77351016847229], [-73.97478137858673, 40.77368983152771]]);
Expand Down
2 changes: 1 addition & 1 deletion test/unit/geo/mercator_coordinate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ test('LngLat', (t) => {

t.test('#meterInMercatorCoordinateUnits', (t) => {
const nullIsland = new LngLat(0, 0);
t.equal(MercatorCoordinate.fromLngLat(nullIsland).meterInMercatorCoordinateUnits(), 2.495320233665337e-8, 'length of 1 meter in MercatorCoordinate units at the equator');
t.equal(MercatorCoordinate.fromLngLat(nullIsland).meterInMercatorCoordinateUnits(), 2.4981121214570498e-8, 'length of 1 meter in MercatorCoordinate units at the equator');
t.end();
});

Expand Down