Converti latitudine e longitudine in un punto 2D in Java

1. Panoramica

Quando si implementano applicazioni che utilizzano mappe, normalmente ci imbatteremo nel problema della conversione delle coordinate. La maggior parte delle volte, dobbiamo convertire la latitudine e la longitudine in un punto 2D da visualizzare . Fortunatamente, per risolvere questo problema, possiamo utilizzare le formule della proiezione di Mercatore.

In questo tutorial tratteremo la proiezione di Mercator e impareremo come implementare le sue due varianti.

2. Proiezione di Mercatore

La proiezione di Mercatore è una proiezione cartografica introdotta dal cartografo fiammingo Gerardus Mercator nel 1569. Una proiezione cartografica converte le coordinate di latitudine e longitudine sulla Terra in un punto su una superficie piana. In altre parole, traduce un punto sulla superficie della terra in un punto su una mappa piatta .

Esistono due modi per implementare la proiezione di Mercatore. La pseudo proiezione di Mercatore tratta la Terra come una sfera. La vera proiezione di Mercatore modella la Terra come un ellissoide . Implementeremo entrambe le versioni.

Cominciamo con una classe base per entrambe le implementazioni di proiezione di Mercator:

abstract class Mercator { final static double RADIUS_MAJOR = 6378137.0; final static double RADIUS_MINOR = 6356752.3142; abstract double yAxisProjection(double input); abstract double xAxisProjection(double input); }

Questa classe fornisce anche il raggio maggiore e minore della Terra misurato in metri. È noto che la Terra non è esattamente una sfera. Per questo motivo, abbiamo bisogno di due raggi. In primo luogo, il raggio maggiore è la distanza dal centro della terra all'equatore . In secondo luogo, il raggio minore è la distanza dal centro della terra ai poli nord e sud .

2.1. Proiezione sferica di Mercatore

Il modello di pseudo-proiezione tratta la terra come una sfera. In contrasto con la proiezione ellittica in cui la Terra sarebbe proiettata su una forma più accurata. Questo approccio ci consente una rapida stima della proiezione ellittica più precisa, ma computazionale più pesante. Di conseguenza, le misurazioni dirette delle distanze in questa proiezione saranno approssimative.

Inoltre, le proporzioni delle forme sulla mappa cambieranno marginalmente. Come risultato di tale latitudine e rapporti tra le forme degli oggetti sulla mappa come paesi, laghi, fiumi, ecc. Non vengono preservati con precisione .

Questa è anche chiamata proiezione Web Mercator, comunemente utilizzata nelle applicazioni web tra cui Google Maps.

Implementiamo questo approccio:

public class SphericalMercator extends Mercator { @Override double xAxisProjection(double input) { return Math.toRadians(input) * RADIUS_MAJOR; } @Override double yAxisProjection(double input) { return Math.log(Math.tan(Math.PI / 4 + Math.toRadians(input) / 2)) * RADIUS_MAJOR; } }

La prima cosa da notare su questo approccio è il fatto che questo approccio rappresenta il raggio della terra con una costante e non due come è realmente. In secondo luogo, possiamo vedere che abbiamo implementato due funzioni ad uso per la conversione di proiezione asse X e proiezione asse y . Nella classe sopra abbiamo usato la libreria Math fornita da java per aiutarci a rendere il nostro codice più semplice.

Testiamo una semplice conversione:

Assert.assertEquals(2449028.7974520186, sphericalMercator.xAxisProjection(22)); Assert.assertEquals(5465442.183322753, sphericalMercator.yAxisProjection(44));

Vale la pena notare che questa proiezione mapperà i punti in un riquadro di delimitazione (sinistro, inferiore, destro, superiore) di (-20037508.34, -23810769.32, 20037508.34, 23810769.32).

2 .2. Proiezione ellittica di Mercatore

La vera proiezione modella la terra come un ellissoide. Questa proiezione fornisce rapporti accurati per gli oggetti ovunque sulla Terra . Certamente, rispetta gli oggetti sulla mappa ma non è accurato al 100% . Tuttavia, questo approccio non è il più utilizzato perché è computazionalmente complesso.

Implementiamo questo approccio:

class EllipticalMercator extends Mercator { @Override double yAxisProjection(double input) { input = Math.min(Math.max(input, -89.5), 89.5); double earthDimensionalRateNormalized = 1.0 - Math.pow(RADIUS_MINOR / RADIUS_MAJOR, 2); double inputOnEarthProj = Math.sqrt(earthDimensionalRateNormalized) * Math.sin( Math.toRadians(input)); inputOnEarthProj = Math.pow(((1.0 - inputOnEarthProj) / (1.0+inputOnEarthProj)), 0.5 * Math.sqrt(earthDimensionalRateNormalized)); double inputOnEarthProjNormalized = Math.tan(0.5 * ((Math.PI * 0.5) - Math.toRadians(input))) / inputOnEarthProj; return (-1) * RADIUS_MAJOR * Math.log(inputOnEarthProjNormalized); } @Override double xAxisProjection(double input) { return RADIUS_MAJOR * Math.toRadians(input); } }

Sopra possiamo vedere quanto sia complesso questo approccio per quanto riguarda la proiezione sull'asse y. Questo perché dovrebbe prendere in considerazione la forma della terra non rotonda. Sebbene il vero approccio di Mercatore sembri complesso, è più accurato dell'approccio sferico in quanto utilizza il raggio per rappresentare la terra uno minore e uno maggiore.

Testiamo una semplice conversione:

Assert.assertEquals(2449028.7974520186, ellipticalMercator.xAxisProjection(22)); Assert.assertEquals(5435749.887511954, ellipticalMercator.yAxisProjection(44));

Questa proiezione mapperà i punti in un riquadro di delimitazione di (-20037508.34, -34619289.37, 20037508.34, 34619289.37).

3 . Conclusione

Se abbiamo bisogno di convertire le coordinate di latitudine e longitudine su una superficie 2D, possiamo usare la proiezione di Mercatore. A seconda della precisione di cui abbiamo bisogno per la nostra implementazione, possiamo utilizzare l'approccio sferico o ellittico.

Come sempre, possiamo trovare il codice di questo articolo su GitHub.