Dòng ngày quốc tế bao quanh


13

Sử dụng OpenLayers, tôi đã thêm một lớp WFS (trên GeoServer) với bộ lọc trả về tất cả các tính năng (màu đen) giao với đa giác của tôi (màu vàng) được đặt trên một số quốc gia Mỹ Latinh trong một số ngày nhất định.

nhập mô tả hình ảnh ở đây

Tuy nhiên, tính năng vượt qua theo chiều ngang trên bản đồ KHÔNG thực sự giao với đa giác của tôi. Tính năng này nằm ở đâu đó trong đại dương Thái Bình Dương giữa Hawaii và Fiji và KHÔNG ở Mỹ Latinh. Vấn đề là thay vì vượt qua Ngày Quốc tế, nó đang được hiển thị trên bản đồ bằng cách đi vòng quanh toàn thế giới.

Tính năng kỳ lạ được xác định:

POLYGON ((- 179.700417 14.202717, -178.687422 13,992875,179.024138 8.24716, -179,9841

Tôi có nhiều tính năng dòng ngày có vấn đề như thế này nhưng đã thu hẹp nó xuống ví dụ này cho ví dụ này. Tôi không thể bỏ qua nó trong ứng dụng của mình vì tôi có nhiều người trong số họ.

Tôi đã thử sử dụng "quấnDateLine: true" trong lớp cơ sở và lớp WFS với cùng kết quả.

Không chắc đây là sự cố GeoServer hay sự cố OpenLayers.

Có ai biết một giải pháp cho vấn đề dòng ngày quốc tế của tôi?


2
Tôi không biết tại sao phần mềm có vấn đề như vậy với điều này, thế giới phẳng, phải không?!
DavidF

Có lẽ nên có một tham số hướng.
CaptDragon

@CaptDragon Có giải pháp nào cho vấn đề này không?
Anil

@Anil Chưa có. Xin vui lòng cho tôi biết nếu bạn tìm thấy một.
CaptDragon

Câu trả lời:


6

Thật không may đây là một vấn đề được biết đến. Vấn đề là hình học vượt qua dòng ngày như thế này là mơ hồ. Các trình kết xuất OL và GeoServer không có cách nào dễ dàng để biết rằng ý định là đi theo con đường "ngắn" trên khắp thế giới để họ chỉ diễn giải từ 170 đến -170 theo cách "thông thường" và đi theo con đường dài trên toàn thế giới.

Thật không may, không có giải pháp tốt cho việc này ngoại trừ việc phân chia hình học của bạn nằm trên đường dữ liệu.


Cảm ơn +1, tôi đồng ý nhưng tôi không thể chia hình học của mình. Hãy xem liệu có ai có ý tưởng nào khác không.
CaptDragon

Tôi đã tìm ra một cách để phân chia chúng độc đáo trên OpenLayers.
CaptDragon

7

Xác định lại bản đồ của bạn để sử dụng phép chiếu được phân chia tại kinh tuyến Greenwich (hoặc các nơi khác) để các đa giác bạn quan tâm không vượt qua sự gián đoạn trong bản đồ của bạn.


các đa giác bao phủ thế giới khá tốt, sẽ luôn có các đa giác vượt qua một số dòng. Mặc dù, bạn có biết bất kỳ dự đoán nào không được phân chia như thế này không?
CaptDragon

1
Tất cả các phép chiếu phải phân chia thế giới ở đâu đó, nó ẩn chứa trong toán học (bóc một quả cam nếu bạn không tin tôi :-)). Tất cả những gì bạn có thể làm là chọn hình chiếu tốt nhất cho nhiệm vụ của bạn.
Ian Turton

Uh, đúng vậy. Tôi sẽ để nó mở một vài ngày và xem có ý tưởng nào khác xuất hiện không. Cảm ơn lời đề nghị của bạn. :-)
CaptDragon

2

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.


1
OL chỉ sử dụng toán tử> = để biết bên nào sẽ đi khi vẽ sơ đồ. Nếu bạn cho 170 thì 190 nó sẽ đi theo con đường ngắn; nếu bạn cho 170 rồi -170, nó sẽ đi được một chặng đường dài. Nếu bạn luôn "bình thường hóa" kinh độ trong khoảng từ -180 đến 180, bạn sẽ mất thông tin. Một cách để lấy lại thông tin là bằng cách ra lệnh rằng khoảng cách giữa các điểm không được phép> 180
Rivenfall

1

Workround: Ví dụ

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


Tôi đang sử dụng WFS, liên kết bạn đã đăng có nội dung: "Bạn có thể làm điều đó với một lớp 'Layer.WMS' hoặc 'Layer.MapServer'"
CaptDragon

Nếu cả hai đều được hỗ trợ và bạn không có nhu cầu cụ thể đối với Layer.MapServer, hãy đi với Layer.WMS (vẫn có thể được phục vụ từ MapServer).
DavidF

@DavidF: Cảm ơn, nhưng tôi cần sử dụng các khả năng của vectơ của WFS.
CaptDragon

1

Hai năm sau, tôi tiếp tục gặp vấn đề này với các tính năng trên một lớp vectơ. Tôi tìm thấy tệp này chứa một đoạn mã cho biết cách lật điểm cuối nếu nó vượt qua đường dữ liệu:

if(Math.abs(startPoint.x-endPoint.x) > 180) {
  if(startPoint.x < endPoint.x) {
    endPoint.x -= 360;
  } else {
    endPoint.x += 360;
  }
}

Cập nhật:

Trên thực tế, những điều trên đã không làm việc cho nhiều hơn một cuộc cách mạng trên toàn thế giới. Tôi đã kết thúc việc này .

nhập mô tả hình ảnh ở đây


1

Tôi đã đưa ra một giải pháp cho vấn đề này trong các dự án của riêng tôi mà có thể hoặc không thể làm việc cho bạn. Tôi biết thực tế là nó hoạt động với LineStrings nhưng tôi không chắc về các loại hình học khác.

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);
};

Hàm dateLineFix đi qua đệ quy LineString đã cho cho bất kỳ phân đoạn nào vượt qua dòng ngày. Sau đó, nó cắt chúng thành hai tại dateline và trả về tất cả các phân đoạn kết quả dưới dạng MultiLineString.

Nó hoạt động hoàn hảo cho mục đích của tôi (vẽ một lưới lat-lon cực).


0

Tôi đã có một vài vấn đề với dateline và quản lý để sửa tất cả chúng. Bạn có thể thử làm theo.

  1. Cập nhật các giá trị hộp giới hạn lớp GeoServer theo cách thủ công để che đi đa giác của bạn mà không phá vỡ và xem liệu nó có giải quyết được vấn đề không.

  2. Một trong những cách khắc phục tôi đã thực hiện trong Openlayers là thiếu các ô khi chuyển dòng dữ liệu từ + ve kinh độ sang -ve. http://trac.osgeo.org/openlayers/ticket/2754 Không chắc chắn liệu nó có áp dụng cho WFS hay không. Bạn có thể lấy phiên bản phát triển openlayers mới nhất và thử.


0

Tôi đã gặp vấn đề này với LineStrings và tạo ra một giải pháp cho nó. Tôi không chắc liệu nó có giúp bạn với Đa giác không. Bạn có thể thấy nó trên repl.it của tôi ở đây: https://repl.it/@gpantic/OpenLayersSplitRouteOverPacific


1
Nếu nó trả lời câu hỏi, vui lòng thêm tất cả thông tin vào câu trả lời của bạn thay vì cung cấp một liên kết.
BERA

0

EPSG: 3832 (WGS84 PDC) là một hình chiếu tập trung ở Thái Bình Dương. Điều này sẽ giao dịch các vấn đề vượt IDL cho các vấn đề vượt qua Prime Meridian. Đây có thể không phải là một vấn đề tùy thuộc vào những gì bạn đang mô tả. Tôi cũng tìm thấy các vấn đề gần Vòng Bắc Cực và Nam Cực.

Tín dụng đi vào này bài viết.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.