我已经研究了这个问题很长时间了,因为我开发了一个应用程序,该应用程序允许用户通过DragBox动作或绘制用户输入的范围点来生成“关注区域”矩形。当我开始这个冒险时,我对OpenLayers完全陌生。手动输入的范围点的问题是,如果AOI覆盖了国际日期变更线,则绘制的矩形将在世界范围内以错误的方式绘制。众多StackExchange用户问到这个问题,只是被OpenLayers响应者告知(并且我在这里释义):“ OpenLayers无法知道要绘制的点的方向意图,因此它默认为...”。嗯,由于我现在对OpenLayers的了解已经足够危险了,所以我必须在响应中举起BS标志,这个问题已经发生在我身上。我的响应有一个问题,就是我在一定程度上加载了坐标,根据定义,该范围指定了右上经度和纬度以及左下经度和纬度。如果右上经度位于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__: []
如您所见,纵向坐标反转了,因此在创建完整的坐标结构后即为多边形。将polygonFeature应用于特征,然后将该特征应用于矢量,最后对其进行绘制,以发现多边形在世界范围内走错了方向。
我需要弄清楚为什么会这样,所以我在OpenLayers 4库中钻研了这个ol.extent.boundingExtent方法。
/**
* 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多边形结构,该结构是3维数组,第1维是Ring编号,
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上绘制多边形。