Я досить довго досліджував цю проблему, оскільки розробив програму, яка дозволяє користувачеві генерувати прямокутник «Область інтересу» або за допомогою дії 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, інакше він просто обчислює його як звичайне скрізь.
Потім я використовую цю міру, щоб створити багатокутник, потім полігонФеатура, потім застосував цю функцію до вектора і, нарешті, побудував її, і цього разу правильно побудував її. Тож виправлення, яке я придумав, щоб допомогти вирішити проблему обчислення площі, я також виправив проблему побудови графіків.
Можливо, це рішення допоможе комусь іншому або змусить їх задуматися в іншому напрямку. Рішення прийшло до мене, коли я нарешті зміг розбити проблему ІДЛ на два питання. Фактичним розрахунком площі було одне питання, а інше - побудова полігона над ІДЛ.