Cálculo de caixa delimitadora por centro e escala fornecidos no Android?


8

Dadas estas condições:

  • uma escala como 1:50000
  • o centro da janela é 100°E, 20°N
  • o tamanho da viewport é 400x600

Como posso calcular a caixa delimitadora da janela de exibição?


O sistema de coordenadas geográficas do mapa é EPSG: 4490.

Queremos exibi-los em uma projeção diferente, como Mercator ou latitude_longitude_projection (talvez este seja o chamado não-projetado).

O tamanho da janela de exibição está em pixels.


Em que projeção está o seu mapa? Web Mercator? Ou você exibe um mapa não projetado em lat / lon? E o tamanho da sua janela de visualização é em pixels? A escala está em piels? Você usa alguma estrutura / biblioteca de mapeamento que possa ter uma função para isso?
— Atlefren

Qual software e versão do GIS você está usando para tentar fazer isso?
— PolyGeo

@atlefren: Eu atualizo o post.
— giser 15/05

@ PolyGeo: Nenhum, tentamos exibir os dados do mapa no Android. E não encontramos nenhuma biblioteca.
— Giser 15/05

1
Android, você está usando a API do Google Maps ou simplesmente exibe uma imagem? Eu também recomendaria não usar um sistema de coordenadas não projetado para exibir seu mapa, pois ele parecerá muito distorcido.
— Atlefren

Respostas:


9

Ok, com alguns problemas iniciais resolvidos, a tarefa é relativamente simples.

Escala, representada como f.ex 1: 50000, significa que uma unidade no mapa corresponde a 50.000 unidades no mundo real.

Para um mapa em papel impresso em uma escala de 1: 50000, isso significa que 1 metro no mapa corresponde a 50.000 metros no mundo real, ou para facilitar: 1 cm no mapa corresponde a 50 metros no mundo real. Por enquanto, tudo bem.

Quando o computador (ou a tela do telefone) entra no programa, é muito mais difícil: a unidade de medida na tela é um pixel, que não é mapeado diretamente em centímetros. Os OpenLayers estão (ou pelo menos onde) usando os "Pontos por polegada" e assumem que uma polegada corresponde a 72 pixels (isso faz algum sentido em telas de 72 dpi, mas está errado em, por exemplo, Retina Displays. Mas, por enquanto, vamos nos ater ao 72 dpi (como é o que a maioria das bibliotecas de mapeamento faz (acho, as correções são bem-vindas)).

OpenLayers tem uma função OpenLayers.Util.getResolutionFromScale (consulte a fonte ):

OpenLayers.Util.getResolutionFromScale = function (scale, units) {
    var resolution;
    if (scale) {
        if (units == null) {
            units = "degrees";
        }
        var normScale = OpenLayers.Util.normalizeScale(scale);
        resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
                                        * OpenLayers.DOTS_PER_INCH);
    }
    return resolution;
};
  • Com units = "degrees" (que é EPSG: 4490, pelo que eu deduzo), obtemos inches_per unit = 4374754 (OpenLayers.INCHES_PER_UNIT ["degrees"])

  • uma escala de 1: 50000 (que corresponde a 1/50000 = 0,00002) (é o que penLayers.Util.normalizeScale calcula) fornece normScale = 0,00002

  • OpenLayers.DOTS_PER_INCH = 72

Podemos então calcular a resolução como

1 / (0.00002 * 4374754 * 72) = 0.00015873908440210453

Sabendo o ponto central (lon = 100, lat = 30), o tamanho de pixel da viewport (w = 400, h = 600) e a resolução, podemos usar a função calculBounds do OpenLayers.Map (consulte a fonte ):

calculateBounds: function(center, resolution) {

        var extent = null;

        if (center == null) {
            center = this.getCachedCenter();
        }
        if (resolution == null) {
            resolution = this.getResolution();
        }

        if ((center != null) && (resolution != null)) {
            var halfWDeg = (this.size.w * resolution) / 2;
            var halfHDeg = (this.size.h * resolution) / 2;

            extent = new OpenLayers.Bounds(center.lon - halfWDeg,
                                           center.lat - halfHDeg,
                                           center.lon + halfWDeg,
                                           center.lat + halfHDeg);
        }

        return extent;
    },

que podemos reduzir para:

function calculateBounds(center, resolution, size) {       
    var halfWDeg = (size.w * resolution) / 2;
    var halfHDeg = (size.h * resolution) / 2;
    return {
        "left": center.lon - halfWDeg,
        "bottom": center.lat - halfHDeg,
        "right": center.lon + halfWDeg,
        "top": center.lat + halfHDeg
    };
}

Chamar isso com nossos valores fornece:

calculateBounds({"lon": 100, "lat": 30}, 0.00015873908440210453, {"w": 400, "h":600});
{ 
    left: 99.96825218311957, 
    bottom: 29.95237827467937,
    right: 100.03174781688043,
    top: 30.04762172532063
}

Podemos então combinar tudo isso a uma função que funciona em graus com denominador de escala, dado:

function calculateBounds(center, scaleDenominator, size) {       
    var resolution = 1 / ((1 / scaleDenominator) * 4374754 * 72)
    var halfWDeg = (size.w * resolution) / 2;
    var halfHDeg = (size.h * resolution) / 2;
    return {
        "left": center.lon - halfWDeg,
        "bottom": center.lat - halfHDeg,
        "right": center.lon + halfWDeg,
        "top": center.lat + halfHDeg
    };
}

Resposta maravilhosa. De fato, parece que o ponto principal aqui é o dpivalor. Não é?
— Giser # 15/13

Ah, e a projeção? Parece que os códigos acima são usados ​​para calcular o grau diretamente.
— giser 15/05

Sim, está correto. Enquanto os usuários não espera usar o mapa da mesma forma como um mapa de papel (ou seja, medindo nele) qualquer valor pode ser usado (e eu acho que a maioria das bibliotecas de mapeamento usar 72 ou 96)
— atlefren

a única coisa que você precisa saber sobre a projeção são suas unidades, o OpenLayers usa o array OpenLayers.INCHES_PER_UNIT [units] no Utils.js. web Mercator usos metros, como unidade, o que significa 39,37 em vez de 4.374.754 para a resolução de calcular
— atlefren

@ atlerfren: Oi, parece que você é um especialista em openlayers, eu encontro alguns problemas relacionados a ele. Você pode poupar algum tempo para dar uma olhada neste post? gis.stackexchange.com/q/61256/12681
— giser
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.