Международная дата линия обернуть вокруг

13

Используя OpenLayers, я добавил слой WFS (на GeoServer) с фильтром, который возвращает все объекты (черные), которые пересекают мой многоугольник (желтый), размещенный над некоторыми странами Латинской Америки в определенные даты.

введите описание изображения здесь

Однако объект, который горизонтально пересекает карту, на самом деле НЕ пересекает мой многоугольник. Эта особенность находится где-то в Тихом океане между Гавайями и Фиджи, а НЕ в Латинской Америке. Проблема в том, что вместо пересечения Международной линии дат она отображается на карте, охватывая весь мир.

Пробламатическая особенность определяется:

POLYGON ((- 179,700417, 14,201717, -178,687422, 13,9975, 179,024138, 8,24716, -179,98241, 8,035567, -179,700417, 14,202717))

У меня есть много проблемных функций линии даты, подобных этой, но я сузил их до этого для этого примера. Я не могу просто игнорировать это в своем заявлении, потому что у меня их много.

Я попытался использовать «wrapDateLine: true» в базовом слое и слое WFS с одинаковыми результатами.

Не уверен, будет ли это проблемой GeoServer или OpenLayers.

Кто-нибудь знает решение моей международной проблемы с датой?

CaptDragon
источник
2
Я не знаю, почему у программного обеспечения такая проблема с этим, мир плоский, верно ?!
DavidF
Может быть, должен быть параметр направления.
CaptDragon
@CaptDragon Есть ли решение этой проблемы?
Анил
@Anil Пока нет. Пожалуйста, дайте мне знать, если найдете.
CaptDragon

Ответы:

6

К сожалению, это известная проблема. Проблема в том, что геометрии, которые пересекают линию даты, являются неоднозначными. Рендереры OL и GeoServer не имеют простого способа узнать, что цель состоит в том, чтобы пройти «короткий» путь по всему миру, поэтому они просто интерпретируют, например, 170–170 «обычный» путь и идут по всему миру.

К сожалению, нет хорошего решения для этого, кроме как разделить ваши геометрии, которые лежат на линии времени.

jdeolive
источник
Спасибо +1, я согласен, но я не могу разделить свою геометрию. Посмотрим, есть ли у кого-нибудь еще идеи.
CaptDragon
Я нашел способ красиво разделить их на OpenLayers.
CaptDragon
7

Перепроектируйте вашу карту, чтобы использовать проекцию, которая разделена на меридиане Гринвича (или где-либо еще), чтобы интересующие вас многоугольники не пересекали разрыв на вашей карте.

Ян Тертон
источник
полигоны покрывают мир довольно хорошо, всегда найдутся полигоны, которые пересекут некоторую линию. Хотя знаете ли вы какие-либо прогнозы, которые не разделяются таким образом?
CaptDragon
1
Все прогнозы должны где-то разделить мир, это подразумевается в математике (очистите апельсин, если вы мне не верите :-)). Все, что вы можете сделать, это выбрать лучший прогноз для вашей задачи.
Ян Тертон
Да, ты прав. Я оставлю это открытым несколько дней и посмотрю, появятся ли какие-нибудь другие идеи. Спасибо за ваше предложение. :-)
CaptDragon
2

Я довольно долго изучал эту проблему, так как разработал приложение, которое позволяет пользователю создавать прямоугольник области интереса либо с помощью действия DragBox, либо с помощью построения точек экстента, введенных пользователем. Когда я начал это приключение, я был совершенно новым для OpenLayers. Проблема с введенными вручную точками экстента заключалась в том, что если бы AOI покрывал международную линию дат, нарисованный прямоугольник был бы нарисован неверно по всему миру. Многочисленные пользователи StackExchange спрашивали об этой проблеме только после того, как респондент OpenLayers сказал (и я здесь перефразирую): «OpenLayers не может знать направленное намерение точек, которые нужно нарисовать, поэтому он по умолчанию ...». Я должен поднять флаг BS для этого ответа, так как теперь я достаточно узнал об OpenLayers, чтобы быть опасным, и эта проблема случается со мной. Проблема, с которой я столкнулся, заключается в том, что я загружаю координаты для экстента, который по определению определяет верхнюю правую долготу и широту, а также нижнюю левую долготу и широту. Если верхняя правая долгота лежит на западной стороне IDL, а нижняя левая долгота лежит на восточной стороне IDL, то совершенно очевидно, каким образом пользователь хочет построить полигон, и все же OpenLayers настаивает на обмене продольных значений и отрисовке полигон неправильный путь по всему миру. Пример объявления экстента и проблемного вызова метода OpenLayers показан ниже. Если верхняя правая долгота лежит на западной стороне IDL, а нижняя левая долгота лежит на восточной стороне IDL, то совершенно очевидно, каким образом пользователь хочет построить полигон, и все же OpenLayers настаивает на обмене продольных значений и отрисовке полигон неправильный путь по всему миру. Пример объявления экстента и проблемного вызова метода OpenLayers показан ниже. Если верхняя правая долгота лежит на западной стороне IDL, а нижняя левая долгота лежит на восточной стороне IDL, то совершенно очевидно, каким образом пользователь хочет построить полигон, и все же OpenLayers настаивает на обмене продольных значений и отрисовке полигон неправильный путь по всему миру. Пример объявления экстента и проблемного вызова метода OpenLayers показан ниже.

// 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__: []

Как вы можете видеть, продольные координаты меняются местами, и после создания полной структуры координат создается многоугольник. a polygonFeature, а затем примените эту особенность к вектору и, наконец, нанесите ее на график, только чтобы обнаружить, что многоугольник движется в неправильном направлении по всему миру.

Мне нужно было выяснить, почему это происходит, поэтому я углубился в этот метод ol.extent.boundingExtent в библиотеке 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__: []

Мой код вычисляет площадь динамически, чтобы я мог определить, создал ли пользователь полигон AOI действительного размера. Когда я обрабатываю сгенерированный DragBox выбор, я запрашиваю координаты полученной геометрической структуры и для проекции EPSG: 4326, когда она возвращает координаты из обернутого мира, координаты после первых 180,0 градусов продолжают увеличиваться, таким образом, причина для вычисления lonUR 360,0 - 165,937 = 194,063. Мой кодовый путь вычисления площади использует следующий тест IDL, и для того, чтобы использовать тот же кодовый путь для введенных вручную координат, мне нужно было смоделировать значение координаты, как если бы оно было возвращено из вызова DragBox getGeometry. Я на самом деле тестирую многоугольную структуру GEOJSON, которая является трехмерным массивом, а 1-е измерение - это число кольца,

 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))) {
 .
 .
 .

Если эти тесты пройдут в этот момент, код использует алгоритм, который я разработал для вычисления площади по IDL, в противном случае он просто вычисляет его как нормальный везде.

Затем я использую этот экстент для создания многоугольника, затем polygonFeature, затем применяю этот элемент к вектору и, наконец, строю его, и на этот раз он отображается правильно. Итак, исправление, которое я придумал, чтобы помочь решить проблему вычисления площади, я также исправил проблему построения.

Возможно, это решение поможет кому-то другому или заставит их думать в другом направлении. Решение пришло ко мне, когда я наконец смог разделить проблему IDL на две проблемы. Фактическое вычисление площади было одной проблемой с другой, являющейся изображением полигона по IDL.

user1593611
источник
1
OL просто использует оператор> =, чтобы знать, на какую сторону идти при построении графика. Если вы дадите 170, то 190 пойдет коротким путем; если вы дадите 170, то -170, это будет далеко. Если вы всегда «нормализуете» долготу между -180 и 180, вы потеряете информацию. Один из способов вернуть информацию - это диктовать, что расстояние между точками не должно превышать> 180
Rivenfall
1

Workround: пример

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

Mapperz
источник
Я использую WFS по ссылке, которую вы разместили: «Вы можете сделать это с помощью слоя« Layer.WMS »или« Layer.MapServer »»
CaptDragon
Если оба поддерживаются, и у вас нет особой необходимости в Layer.MapServer, перейдите к Layer.WMS (который все еще может обслуживаться из MapServer).
DavidF
@DavidF: Спасибо, но мне нужно использовать векторные возможности WFS.
CaptDragon
1

Два года спустя у меня все еще была проблема с векторным слоем. Я нашел этот файл, содержащий фрагмент кода, который показывает, как перевернуть конечную точку, если она пересекла линию даты:

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

Обновить:

На самом деле вышесказанное не сработало более чем на одну революцию в мире. Я в конечном итоге делает ЭТО .

введите описание изображения здесь

CaptDragon
источник
1

Я придумал решение для этого в моих собственных проектах, которые могут или не могут работать для вас. Я точно знаю, что он работает с LineStrings, но я не уверен насчет других типов геометрии.

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

Функция dateLineFix рекурсивно пересекает заданную LineString для любых сегментов, которые пересекают линию даты. Затем он разрезает их пополам на линии даты и возвращает все результирующие сегменты в виде MultiLineString.

Это отлично работало для моей цели (рисование полярной решетки).

Скотт Одл
источник
0

У меня было несколько проблем с датой и мне удалось все их исправить. Вы можете попробовать следующее.

  1. Обновите значения ограничивающего прямоугольника слоя GeoServer вручную, чтобы охватить полигон, не ломая его, и посмотрите, решит ли он проблему.

  2. Одно из исправлений, которое я сделал в Openlayers, - это отсутствие тайлов при передаче линии даты от + ve долготы до -ve. http://trac.osgeo.org/openlayers/ticket/2754 Не уверен, применимо ли это для WFS. Вы можете получить последнюю версию openlayers и попробовать.

Senthil
источник
0

Я столкнулся с этой проблемой с LineStrings и создал решение для нее. Я не уверен, поможет ли это вам с полигонами. Вы можете увидеть это на моем repl.it здесь: https://repl.it/@gpantic/OpenLayersSplitRouteOverPacific

gpantic
источник
1
Если он отвечает на вопрос, пожалуйста, добавьте всю информацию в свой ответ вместо предоставления ссылки.
BERA
0

EPSG: 3832 (WGS84 PDC) - это центрированная проекция Тихого океана. Это поменяет проблемы пересечения IDL на проблемы пересечения Prime Meridian. Это не может быть проблемой в зависимости от того, что вы изображаете. Я также обнаружил проблемы возле полярных и антарктических кругов.

Кредит идет к этой статье.

Будет
источник