Міжнародна лінія дати обгортається


13

Використовуючи OpenLayers, я додав шар WFS (на GeoServer) з фільтром, який повертає всі функції (чорні), які перетинають мій багатокутник (жовтий), розміщений над деякими країнами Латинської Америки протягом певних дат.

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

Однак функція, яка перетинається горизонтально через карту, НЕ насправді перетинає мій багатокутник. Ця особливість є десь у тихому океані між Гаваями та Фіджі, а НЕ в Латинській Америці. Проблема полягає в тому, що замість того, щоб перетинати Міжнародну дату, вона відображається на карті, обертаючись по всьому світу.

Проблематична ознака визначається:

ПОЛІГОН ((- 179.700417 14.202717, -178.687422 13.992875,179.024138 8.24716, -179.98241 8.035567, -179.700417 14.202717))

У мене є багато проблемних особливостей рядка дати, як ця, але звузили її до цієї для цього прикладу. Я не можу просто проігнорувати це у своїй заявці, бо їх у мене багато.

Я намагався використовувати "wrapDateLine: true" в базовому шарі та WFS-шарі з однаковими результатами.

Не впевнений, чи це буде проблема GeoServer чи проблема OpenLayers.

Хтось знає рішення моєї міжнародної проблеми з датою?


2
Я не знаю, чому з цим програмним забезпеченням виникає така проблема, світ рівний, правда ?!
DavidF

Можливо, має бути параметр напрямку.
CaptDragon

@CaptDragon Будь-яке рішення цієї проблеми?
Аніль

@Anil Ще немає. Будь ласка, повідомте мене, якщо ви знайдете його.
CaptDragon

Відповіді:


6

На жаль, це відома проблема. Проблема полягає в тому, що геометрії, які перетинають лінію дати, як це, неоднозначні. Провайдери OL та GeoServer не мають простого способу знати, що наміром є пройти "коротким" шляхом по всьому світу, щоб вони просто інтерпретували, наприклад, 170-170 "звичайний" шлях і пройшли довгий шлях світу.

На жаль, для цього немає гарного рішення, окрім того, як розділити геометрії, що лежать поперек дателі.


Дякую +1, я згоден, але я не можу розділити свої геометрії. Давайте подивимось, чи є ще хтось із інших ідей.
CaptDragon

Я придумав спосіб їх гарного поділу на OpenLayers.
CaptDragon

7

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


багатокутники досить добре висвітлюють світ. Завжди знайдуться багатокутники, які перетнуть якусь лінію. Хоча, чи знаєте ви якісь прогнози, які не розщеплені так?
CaptDragon

1
Усі прогнози повинні десь розколоти світ, це міститься в математиці (очистіть апельсин, якщо ви мені не вірите :-)). Все, що ви можете зробити - це вибрати найкращу проекцію для свого завдання.
Ян Тертон

так, ти маєш рацію. Я залишу це відкритим на кілька днів і побачу, чи з’являться якісь інші ідеї. Дякую за вашу пропозицію. :-)
CaptDragon

2

Я досить довго досліджував цю проблему, оскільки розробив програму, яка дозволяє користувачеві генерувати прямокутник «Область інтересу» або за допомогою дії DragBox, або намічаючи, що користувач вводив точки балів. Коли я розпочав цю пригоду, я був абсолютно новим для OpenLayers. Проблема з введеними вручну точками міри полягала в тому, що якби AOI покривав Міжнародну дателі, намальований прямокутник буде намальований неправильним шляхом по всьому світу. Численні користувачі StackExchange попросили про цю проблему лише відповісти респонденту OpenLayers про те, що (і я перефразовуючи тут) "OpenLayers не має можливості знати спрямованість наміченого пункту, щоб він був заздалегідь ...". Ага, я маю підняти прапор BS на цю відповідь, тому що зараз я достатньо дізнався про OpenLayers, щоб бути небезпечним, і ця проблема трапляється зі мною. Проблема, яку я маю з їхньою відповіддю, полягає в тому, що я завантажую координати настільки, що за визначенням визначає верхню праву довготу та широту, а також нижню ліву довготу та широту. Якщо верхня права довжина лежить на західній стороні ІДЛ, а нижня ліва довгота лежить на східній стороні ІДЛ, то цілком очевидно, яким способом користувач хоче побудувати полігон, і все ж OpenLayers наполягає на заміні поздовжніх значень та малюванні полігон неправильний шлях по всьому світу. Зразок декларації про масштаби та проблемний виклик методу OpenLayers показаний нижче. Якщо верхня права довжина лежить на західній стороні ІДЛ, а нижня ліва довгота лежить на східній стороні ІДЛ, то цілком очевидно, яким способом користувач хоче побудувати полігон, і все ж OpenLayers наполягає на заміні поздовжніх значень та малюванні полігон неправильний шлях по всьому світу. Зразок декларації про масштаби та проблемний виклик методу OpenLayers показаний нижче. Якщо верхня права довжина лежить на західній стороні ІДЛ, а нижня ліва довгота лежить на східній стороні ІДЛ, то цілком очевидно, яким способом користувач хоче побудувати полігон, і все ж 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__: []

Як ви бачите, що поздовжні координати повертаються назад, і тому після того, як ви створите повну структуру координат, багатокутник. а потім застосувати цю функцію до вектора і, нарешті, побудувати її лише для того, щоб виявити, що багатокутник йде неправильним шляхом у всьому світі.

Мені потрібно було з'ясувати, чому це відбувається, тому я занурився в цей метод 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, інакше він просто обчислює його як звичайне скрізь.

Потім я використовую цю міру, щоб створити багатокутник, потім полігонФеатура, потім застосував цю функцію до вектора і, нарешті, побудував її, і цього разу правильно побудував її. Тож виправлення, яке я придумав, щоб допомогти вирішити проблему обчислення площі, я також виправив проблему побудови графіків.

Можливо, це рішення допоможе комусь іншому або змусить їх задуматися в іншому напрямку. Рішення прийшло до мене, коли я нарешті зміг розбити проблему ІДЛ на два питання. Фактичним розрахунком площі було одне питання, а інше - побудова полігона над ІДЛ.


1
OL просто використовує оператор> =, щоб знати, в яку сторону піти, коли планується. Якщо ви дасте 170, то 190 піде коротким шляхом; якщо дати 170, то -170, це піде довгим шляхом. Якщо ви завжди «нормалізуєте» довготу між -180 і 180, ви втрачаєте інформацію. Один із способів повернути інформацію
продиктувати,

1

Робочий круг: Приклад

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


Я використовую 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;
  }
}

Оновлення:

Насправді вищезазначене не працювало протягом більше однієї революції у всьому світі. Я в кінцевому підсумку робить ЦЕ .

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


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.

Це прекрасно спрацювало з моїми цілями (малювання полярної сіткою lat-lon).


0

У мене було небагато проблем із дателіном і мені вдалося виправити їх усі. Ви можете спробувати наступне.

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

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


0

Я зіткнувся з цією проблемою з LineStrings і створив її рішення. Я не впевнений, чи допоможе вам це на Полігонах. Ви можете побачити це на моїй repl.it тут: https://repl.it/@gpantic/OpenLayersSplitRouteOverPacific


1
Якщо він відповідає на запитання, будь-ласка, додайте всю інформацію до своєї відповіді, а не надайте посилання.
БЕРА

0

EPSG: 3832 (WGS84 PDC) - проекція, орієнтована на Тихий океан. Це торгуватиме проблемами перетину ІДЛ для проблем, що перетинаються. Це може бути проблемою не залежно від того, що ви зображуєте. Я також виявив проблеми біля Полярного та Антарктичного кіл.

Кредит стосується цієї статті.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.