A Linha Internacional de Data envolve


13

Usando o OpenLayers, adicionei uma camada WFS (no GeoServer) com um filtro que retorna todos os recursos (pretos) que cruzam meu polígono (amarelo) colocado sobre alguns países da América Latina em determinadas datas.

insira a descrição da imagem aqui

No entanto, o recurso que cruza horizontalmente o mapa NÃO cruza meu polígono. Esse recurso está em algum lugar no oceano pacífico entre o Havaí e Fiji e NÃO na América Latina. O problema é que, em vez de cruzar a Linha Internacional de Data, ela está sendo renderizada no mapa, envolvendo todo o mundo.

O recurso problamatic é definido:

POLYGON ((- 179.700417 14.202717, -178.687422 13.992875,179.024138 8.24716, -179.98241 8.035567, -179.700417 14.202717))

Eu tenho muitos recursos problemáticos de linhas de data como essa, mas a reduzi a esta neste exemplo. Não posso simplesmente ignorá-lo no meu aplicativo porque tenho muitos deles.

Eu tentei usar "wrapDateLine: true" na camada base e na camada WFS com os mesmos resultados.

Não tenho certeza se isso seria um problema do GeoServer ou um problema do OpenLayers.

Alguém conhece uma solução para o meu problema internacional de linha de data?


2
Não sei por que o software tem um problema com isso, o mundo é plano, certo ?!
davidf

Talvez deva haver um parâmetro de direção.
CaptDragon

@CaptDragon Alguma solução para este problema?
Anil

@ Anil Ainda não. Por favor, deixe-me saber se você encontrar um.
CaptDragon

Respostas:


6

Infelizmente, este é um problema conhecido. A questão é que as geometrias que cruzam a linha da data são ambíguas. Os renderizadores OL e GeoServer não têm uma maneira fácil de saber que a intenção é seguir o caminho "mais curto" ao redor do mundo, de modo que eles apenas interpretem, por exemplo, 170 a -170 o caminho "regular" e o caminho mais longo ao redor do mundo.

Infelizmente, não há uma boa solução para isso, exceto dividir suas geometrias que se estendem pela linha de dados.


Obrigado +1, eu concordo, mas não posso dividir minhas geometrias. Vamos ver se mais alguém tem outras idéias.
CaptDragon

Eu descobri uma maneira de dividi-los muito bem no OpenLayers.
precisa saber é o seguinte

7

Reprojete seu mapa para usar uma projeção dividida no meridiano de Greenwich (ou em outro lugar) para que os polígonos nos quais você está interessado não cruzem a descontinuidade em seu mapa.


os polígonos cobrem o mundo muito bem, sempre haverá polígonos que cruzarão alguma linha. No entanto, você conhece alguma projeção que não seja dividida assim?
CaptDragon

1
Todas as projeções devem dividir o mundo em algum lugar, isso está implícito na matemática (descasque uma laranja se você não acredita em mim :-)). Tudo o que você pode fazer é escolher a melhor projeção para sua tarefa.
Ian Turton

Sim você está certo. Vou deixar isso em aberto alguns dias e ver se há outras idéias. Obrigado pela sua sugestão. :-)
CaptDragon

2

Eu estava pesquisando esse problema há algum tempo, pois desenvolvi um aplicativo que permite ao usuário gerar um retângulo da área de interesse por meio de uma ação DragBox ou plotando pontos de extensão inseridos pelo usuário. Quando comecei essa aventura, eu era completamente novo no OpenLayers. O problema com os pontos de extensão inseridos manualmente era que, se a AOI cobrisse a Linha de Dados Internacional, o retângulo desenhado seria traçado de maneira errada em todo o mundo. Vários usuários do StackExchange perguntaram sobre esse problema apenas para serem informados por um respondente do OpenLayers que (e estou parafraseando aqui) "O OpenLayers não tem como saber a intenção direcional dos pontos a serem desenhados, por padrão ...". Tenho que levantar a bandeira da BS nessa resposta, pois agora aprendi o suficiente sobre o OpenLayers para ser perigoso e esse problema está acontecendo comigo. O problema que tenho com a resposta deles é que carrego as coordenadas em uma extensão que, por definição, especifica a longitude e a latitude superiores direita, bem como a longitude e latitude inferior esquerda. Se a longitude superior direita fica no lado ocidental do IDL e a longitude inferior esquerda fica no lado oriental do IDL, é bastante óbvio de que maneira o usuário deseja plotar o polígono e ainda assim o OpenLayers insiste em trocar os valores longitudinais e desenhar o polígono da maneira errada ao redor do mundo. Uma amostra da declaração de extensão e da chamada problemática do método OpenLayers é mostrada abaixo. Se a longitude superior direita fica no lado ocidental do IDL e a longitude inferior esquerda fica no lado oriental do IDL, é bastante óbvio de que maneira o usuário deseja plotar o polígono e ainda assim o OpenLayers insiste em trocar os valores longitudinais e desenhar o polígono da maneira errada ao redor do mundo. Uma amostra da declaração de extensão e da chamada problemática do método OpenLayers é mostrada abaixo. Se a longitude superior direita fica no lado ocidental do IDL e a longitude inferior esquerda fica no lado oriental do IDL, é bastante óbvio de que maneira o usuário deseja plotar o polígono e ainda assim o OpenLayers insiste em trocar os valores longitudinais e desenhar o polígono da maneira errada ao redor do mundo. Uma amostra da declaração de extensão e da chamada problemática do método OpenLayers é mostrada abaixo.

// I would start out with the following entered values as an example
lonLL = 175.781; // minX
latLL = 13.992;  // minY
lonUR = -165.937;// maxX
latUR = 25.945;  // maxY

// I would then make the following call
var manCoordEntryExtent = ol.extent.boundingExtent([[lonLL,latLL], [lonUR, latUR]]);

// Looking at the resulting structure in the debugger I get:
0: -165.937   // minX
1: 13.992     // minY
2: 175.781    // maxX
3: 25.945     // maxY
length: 4
__proto__: []

Como você pode ver, as coordenadas longitudinais são invertidas e, depois, você cria toda a estrutura de coordenadas, um polígono. a polygonFeature e, em seguida, aplique esse recurso a um vetor e, finalmente, plote-o apenas para descobrir que o polígono segue o caminho errado em todo o mundo.

Eu precisava descobrir por que isso estava acontecendo, então procurei esse método ol.extent.boundingExtent na biblioteca do OpenLayers 4.

/**
 * Build an extent that includes all given coordinates.
 *
 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
 * @return {ol.Extent} Bounding extent.
 * @api
 */
ol.extent.boundingExtent = function(coordinates) {
  var extent = ol.extent.createEmpty();
  for (var i = 0, ii = coordinates.length; i < ii; ++i) {
    ol.extent.extendCoordinate(extent, coordinates[i]);
  }
  return extent;
};

It first calls ol.extent.createEmpty to initially create an extent structure

/**
 * Create an empty extent.
 * @return {ol.Extent} Empty extent.
 * @api
 */
ol.extent.createEmpty = function() {
  return [Infinity, Infinity, -Infinity, -Infinity];
};

// It then iterates thru the number of coordinates and fills in the extent   structure values, however...
// Here is where the problem is.  Notice the complete lack of any explanation as to what the hell this
// method is doing.  Why is it doing what it does?  All I know is that it cannot handle plots across 
// the IDL and it corrupts your extent structure if you try.

/**
 * @param {ol.Extent} extent Extent.
 * @param {ol.Coordinate} coordinate Coordinate.
 */
ol.extent.extendCoordinate = function(extent, coordinate) {
  if (coordinate[0] < extent[0]) {
    extent[0] = coordinate[0];
  }
  if (coordinate[0] > extent[2]) {
    extent[2] = coordinate[0];
  }
  if (coordinate[1] < extent[1]) {
    extent[1] = coordinate[1];
  }
  if (coordinate[1] > extent[3]) {
    extent[3] = coordinate[1];
  }
};

// The solution was for me to test for IDL myself and if found then create an empty extent and populate it myself manually.

// Using the same extent coordinates as before
lonLL = 175.781; // minX
latLL = 13.992;  // minY
lonUR = -165.937;// maxX
latUR = 25.945;  // maxY

// I test for Dateline instance (Dont have to worry about the potential of there being a polygon covering both Meridian 
// and Anti-meridian as a valid polygon is limited to a maximum size of just over 12 million square kilometers.)
if ((lonLL > 0.0) && (lonUR < 0.0)) {
    // Manually build the coordinates for the Area calculation as the boundingExtent 
    // codepath corrupts an extent to be plotted across the Dateline
    var manCoordEntryExtent = ol.extent.createEmpty();
    manCoordEntryExtent[0] = lonLL;
    manCoordEntryExtent[1] = latLL;
    manCoordEntryExtent[2] = lonUR + 360.0;
    manCoordEntryExtent[3] = latUR;
} else {
    var manCoordEntryExtent = ol.extent.boundingExtent([[lonLL,latLL], [lonUR, latUR]]);
}

// Looking at the resulting structure in the debugger I get:
0: 175.781 // minX
1: 13.992  // minY
2: 194.063 // maxX
3: 25.945  // maxY
length: 4
__proto__: []

Meu código calcula a área dinamicamente para que eu possa determinar se o usuário criou um polígono AOI de tamanho válido. Quando estou processando uma seleção gerada pelo DragBox, solicito as coordenadas da estrutura geométrica resultante e para uma projeção EPSG: 4326 quando ela retorna coordenadas de um mundo empacotado, as coordenadas após os primeiros 180,0 graus continuam incrementando, portanto, o motivo para o cálculo da longitude de 360,0 - 165,937 = 194,063. Meu caminho de código de cálculo de área usa o seguinte teste IDL e, para usar o mesmo caminho de código para as coordenadas inseridas manualmente, eu precisava simular o valor da coordenada como se tivesse sido retornado da chamada dragBox getGeometry. Na verdade, estou testando uma estrutura de polígono GEOJSON que é uma matriz tridimensional com a 1ª dimensão sendo o número do anel,

 function getArea(coords, extent) {

  // Test for Western side of Dateline instance
  if (((coords[0][0][0] <= -180.0) && (coords[0][2][0] > -180.0)) ||
      // Test for Eastern side of Dateline instance
      ((coords[0][0][0] < 180.0) && (coords[0][2][0] >= 180.0))) {
 .
 .
 .

Se esses testes forem aprovados nesse momento, o código usará o algoritmo que desenvolvi para calcular a área sobre o IDL, caso contrário, apenas o calculará como normal em qualquer outro lugar.

Em seguida, uso essa extensão para criar um polígono, depois um polygonFeature, depois aplico esse recurso a um vetor e, finalmente, plotei-o e, desta vez, plotamos corretamente. Portanto, a correção que surgiu para ajudar a resolver o problema de cálculo de área que eu estava tendo também corrigiu o problema de plotagem.

Talvez essa solução ajude outras pessoas ou as faça pensar em uma direção diferente. A solução veio a mim quando finalmente consegui dividir o problema da IDL em duas questões. O cálculo da área real era um problema, com o outro sendo a plotagem do polígono sobre o IDL.


1
O OL apenas usa o operador> = para saber para qual lado ir ao plotar. Se você der 170, então 190 ele seguirá o caminho mais curto; se você der 170 então -170, irá percorrer o longo caminho. Se você sempre "normaliza" a longitude entre -180 e 180, você perde informações. Uma maneira de recuperar as informações é ditando que as distâncias entre os pontos não podem ser
maiores que

1

Solução: Exemplo

var mapserv = new OpenLayers.Layer.MapServer( "OpenLayers Basic",
                "http://vmap0.tiles.osgeo.org/wms/vmap0",
                {layers: 'basic'},
                {wrapDateLine: true} );

http://openlayers.org/dev/examples/wrapDateLine.html


Estou usando o WFS, o link que você postou diz: "Você pode fazer isso com uma camada 'Layer.WMS' ou 'Layer.MapServer'"
CaptDragon

Se ambos forem suportados e você não tiver uma necessidade específica do Layer.MapServer, vá com o Layer.WMS (que ainda pode ser veiculado no MapServer).
davidf

@ DavidDF: Obrigado, mas eu preciso usar os recursos de vetor de WFS.
CaptDragon

1

Dois anos depois, eu continuava tendo esse problema com recursos em uma camada vetorial. Encontrei este arquivo contendo um trecho de código que mostra como inverter um ponto de extremidade se ele cruzasse a linha de dados:

if(Math.abs(startPoint.x-endPoint.x) > 180) {
  if(startPoint.x < endPoint.x) {
    endPoint.x -= 360;
  } else {
    endPoint.x += 360;
  }
}

Atualizar:

Na verdade, o que foi dito acima não funcionou por mais de uma revolução em todo o mundo. Acabei fazendo ESTA .

insira a descrição da imagem aqui


1

Eu encontrei uma solução para isso em meus próprios projetos que podem ou não funcionar para você. Sei que funciona com LineStrings, mas não tenho certeza sobre outros tipos de geometria.

OpenLayers.Geometry.prototype.crossesDateLine = function() {
    var lastX = this.components[0];
    for (var i=0; i < this.components.length; i++) {
        if (Math.abs(this.components[i].x - lastX) > 180) return i;
        lastX = this.components[i].x;
    }
    return false;
};
OpenLayers.Geometry.prototype.dateLineFix = function() {
    var linestrings = [];
    if (this.crossesDateLine()) {
        var string1 = [];
        for (var i = 0; i < this.crossesDateLine(); i++)
            string1.push(this.components[i]);
        var ls1 = new OpenLayers.Geometry.LineString(string1);
        var string2 = [];
        for (var i = this.crossesDateLine(); i < this.components.length; i++)
            string2.push(this.components[i]);
        var ls2 = new OpenLayers.Geometry.LineString(string2);

        if (!ls1.crossesDateLine()) {
            linestrings.push(ls1);
        } else {
            var split = ls1.dateLineFix();
            for (var i = 0; i < split.components.length; i++)
                linestrings.push(split.components[i]);
        }
        if (!ls2.crossesDateLine()) {
            linestrings.push(ls2);
        } else {
            var split = ls2.dateLineFix();
            for (var i = 0; i < split.components.length; i++)
                linestrings.push(split.components[i]);
        }
    } else {
        linestrings.push(this);
    }
    return new OpenLayers.Geometry.MultiLineString(linestrings);
};

A função dateLineFix percorre recursivamente a LineString fornecida para quaisquer segmentos que cruzam a linha da data. Em seguida, os divide em dois na linha de dados e retorna todos os segmentos resultantes como um MultiLineString.

Funcionou perfeitamente para o meu propósito (desenhar uma grade lat-lon polar).


0

Eu tive alguns problemas com a linha de dados e consegui consertar todos eles. Você pode tentar seguir.

  1. Atualize os valores da caixa delimitadora da camada GeoServer manualmente para cobrir seu polígono sem quebrar e ver se ele resolve o problema.

  2. Uma das correções que fiz nos Openlayers está faltando blocos ao passar a linha de dados de + ve longitude para -ve. http://trac.osgeo.org/openlayers/ticket/2754 Não tenho certeza se é aplicável ao WFS. Você pode obter a versão mais recente do desenvolvimento de openlayers e experimentar.



0

EPSG: 3832 (WGS84 PDC) é uma projeção centrada no Oceano Pacífico. Isso trocará os problemas de travessia de IDL por problemas de travessia do Meridiano Prime. Isso pode não ser um problema, dependendo do que você está representando. Também encontrei problemas perto dos Círculos Ártico e Antártico.

O crédito vai para este artigo.

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.