Converter latitude e longitude em um ponto 2D em Java

Converter latitude e longitude em um ponto 2D em Java

 

1. Visão geral

Ao implementar aplicativos que usam mapas, geralmente encontramos o problema da conversão de coordenadas. Na maioria das vezes, precisamosconvert latitude and longitude to a 2D point to display. Felizmente, para resolver esse problema, podemos utilizar as fórmulas da projeção Mercator.

Neste tutorial, cobriremos a Projeção de Mercator e aprenderemos como implementar suas duas variantes.

2. Projeção Mercator

OMercator projection é uma projeção cartográfica introduzida pelo cartógrafo flamengo Gerardus Mercator em 1569. Uma projeção de mapa converte as coordenadas de latitude e longitude na Terra em um ponto em uma superfície plana. Em outras palavras,it translates a point on the surface of the earth to a point on a flat map.

Existem duas maneiras de implementar a projeção Mercator. The pseudo Mercator projection treats the Earth as a sphere. The true Mercator projection models the Earth as an ellipsoid. Vamos implementar as duas versões.

Vamos começar com uma classe base para ambas as implementações de projeção de 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);
}

Essa classe também fornece o raio maior e o menor da Terra medidos em metros. É sabido que a Terra não é exatamente uma esfera. Por esse motivo, precisamos de dois raios. Em primeiro lugar, omajor radius is the distance from the center of the earth to the equator. Em segundo lugar, ominor radius is the distance from the center of the earth to the north and south poles.

2.1. Projeção Esférica de Mercator

O modelo de pseudo-projeção trata a Terra como uma esfera. Em contraste com a projeção elíptica onde a Terra seria projetada em uma forma mais precisa. Essa abordagem nos permite umquick estimation para a projeção elíptica mais precisa, mas computacionalmente mais pesada. Como resultado disso, omeasurements of distances direto nesta projeção será aproximado.

Além disso, as proporções das formas no mapa serão alteradas marginalmente. Como resultado dessa latitude e proporção de formas de objetos no mapa, como países, lagos, rios, etc. não sãoprecisely preserved.

Isso também é chamado de projeçãoWeb Mercator - comumente usado em aplicativos da web, incluindo Google Maps.

Vamos implementar esta abordagem:

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;
    }
}

A primeira coisa a notar sobre esta abordagem é o fato de que ela representa oradius da terra porone constante não dois como realmente é. Em segundo lugar, podemos ver que implementamos duas funções para usar na conversão parax-axis projectioney-axis projection. Na classe acima, usamos a bibliotecaMath fornecida por java para nos ajudar a tornar nosso código mais simples.

Vamos testar uma conversão simples:

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

Vale notar que esta projeção mapeará pontos em uma caixa delimitadora (esquerda, inferior, direita, superior) de (-20037508.34, -23810769.32, 20037508.34, 23810769.32).

2.2. Elliptical Mercator Projection

A verdadeira projeção modela a terra como um elipsóide. This projection givesaccurate ratiosfor objects anywhere on Earth. Certamente,it respects objects on the map butnot 100% accurate. No entanto, essa abordagem não é a mais usada porque é computacionalmente complexa.

Vamos implementar esta abordagem:

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);
    }
}

Acima, podemos ver quão complexa é essa abordagem em relação à projeção no eixo y. Isso ocorre porque deve levar em consideração a forma de terra não redonda. Embora a verdadeira abordagem de Mercator pareça complexa, é mais precisa do que a abordagem esférica, pois utiliza o raio para representar a Terra um menor e um maior.

Vamos testar uma conversão simples:

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

Essa projeção mapeará pontos em uma caixa delimitadora de (-20037508.34, -34619289.37, 20037508.34, 34619289.37).

3. Conclusion

Se precisarmos converter coordenadas de latitude e longitude em uma superfície 2D, podemos usar a projeção de Mercator. Dependendo da precisão que precisamos para nossa implementação, podemos usar a abordagem esférica ou elíptica.

Como sempre, podemos encontrar o código deste artigoover on GitHub.