Я довольно долго изучал эту проблему, так как разработал приложение, которое позволяет пользователю создавать прямоугольник области интереса либо с помощью действия 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.