Tôi đã nghiên cứu vấn đề này khá lâu khi tôi đã phát triển một ứng dụng cho phép người dùng tạo hình chữ nhật Khu vực yêu thích thông qua hành động DragBox hoặc vẽ điểm phạm vi của Người dùng. Khi tôi bắt đầu cuộc phiêu lưu này, tôi hoàn toàn mới với OpenLayers. Vấn đề với các điểm phạm vi được nhập thủ công là nếu AOI bao phủ Đường dữ liệu quốc tế, hình chữ nhật được vẽ sẽ bị vẽ sai trên toàn thế giới. Nhiều người dùng StackExchange đã hỏi về vấn đề này chỉ được trả lời bởi một người trả lời OpenLayers rằng (và tôi đang diễn giải ở đây) "OpenLayers không có cách nào biết được mục đích định hướng của các điểm sẽ được rút ra để nó mặc định ...". Uh, tôi phải giơ cờ BS về phản hồi đó vì giờ tôi đã biết đủ về OpenLayers để trở nên nguy hiểm và vấn đề này đã xảy ra với tôi. Vấn đề tôi gặp phải với phản ứng của họ là tôi tải tọa độ trong một phạm vi, theo định nghĩa, chỉ định Kinh độ và Vĩ độ trên bên phải cũng như Kinh độ và Vĩ độ dưới bên trái. Nếu Kinh độ trên bên phải nằm ở phía Tây của IDL và Kinh độ dưới bên trái nằm ở phía đông của IDL thì rõ ràng là cách người dùng muốn vẽ đa giác và OpenLayers khăng khăng hoán đổi các giá trị theo chiều dọc và vẽ đa giác sai cách trên khắp thế giới. Một mẫu của khai báo phạm vi và cuộc gọi phương thức OpenLayers có vấn đề được hiển thị bên dưới. Nếu Kinh độ trên bên phải nằm ở phía Tây của IDL và Kinh độ dưới bên trái nằm ở phía đông của IDL thì rõ ràng là cách người dùng muốn vẽ đa giác và OpenLayers khăng khăng hoán đổi các giá trị theo chiều dọc và vẽ đa giác sai cách trên khắp thế giới. Một mẫu của khai báo phạm vi và cuộc gọi phương thức OpenLayers có vấn đề được hiển thị bên dưới. Nếu Kinh độ trên bên phải nằm ở phía Tây của IDL và Kinh độ dưới bên trái nằm ở phía đông của IDL thì rõ ràng là cách người dùng muốn vẽ đa giác và OpenLayers khăng khăng hoán đổi các giá trị theo chiều dọc và vẽ đa giác sai cách trên khắp thế giới. Một mẫu của khai báo phạm vi và cuộc gọi phương thức OpenLayers có vấn đề được hiển thị bên dưới.
// 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__: []
Như bạn có thể thấy các tọa độ theo chiều dọc được đảo ngược và do đó sau khi bạn tạo cấu trúc tọa độ đầy đủ, một đa giác. một đa giácFeature và sau đó áp dụng tính năng đó cho một vectơ và cuối cùng chỉ vẽ nó để thấy rằng đa giác đi sai đường trên khắp thế giới.
Tôi cần phải tìm ra lý do tại sao điều này xảy ra vì vậy tôi đã tìm hiểu phương thức ol.extent.boundingExtent này trong thư viện 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__: []
Mã của tôi tính toán diện tích một cách linh hoạt để tôi có thể xác định xem Người dùng có tạo đa giác AOI có kích thước hợp lệ hay không. Khi tôi đang xử lý lựa chọn được tạo bởi DragBox, tôi yêu cầu tọa độ từ cấu trúc hình học kết quả và đối với phép chiếu EPSG: 4326 khi nó trả về tọa độ từ một thế giới được bao bọc, các tọa độ vượt qua 180 độ đầu tiên tiếp tục tăng, do đó, lý do cho phép tính đơn giản của 360.0 - 165.937 = 194.063. Codepath tính toán khu vực của tôi sử dụng thử nghiệm IDL sau đây và để sử dụng cùng một loại tiền mã hóa cho các tọa độ được nhập thủ công, tôi cần mô phỏng giá trị tọa độ như thể nó đã được trả về từ lệnh gọi DragBox getGeometry. Tôi thực sự đang thử nghiệm cấu trúc đa giác GEOJSON, đó là mảng 3 chiều với chiều thứ 1 là số 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))) {
.
.
.
Nếu các thử nghiệm này vượt qua tại thời điểm này, mã sử dụng thuật toán mà tôi đã phát triển để tính diện tích trên IDL nếu không nó chỉ tính toán như bình thường ở mọi nơi khác.
Sau đó, tôi sử dụng phạm vi này để tạo ra một đa giác, sau đó là một đa giácFeature, sau đó áp dụng tính năng đó cho một vectơ và cuối cùng vẽ nó và lần này nó được vẽ chính xác. Vì vậy, bản sửa lỗi tôi đã đưa ra để giúp giải quyết vấn đề tính toán diện tích mà tôi cũng đã khắc phục được vấn đề vẽ đồ thị.
Có thể giải pháp này sẽ giúp người khác hoặc khiến họ suy nghĩ theo một hướng khác. Giải pháp đã đến với tôi khi cuối cùng tôi đã có thể chia vấn đề của IDL thành hai vấn đề. Tính toán diện tích thực tế là một vấn đề với vấn đề còn lại là âm mưu của đa giác trên IDL.