Chia Linestrings trên dateline với OpenLayers


9

Một vài năm trước tôi đã đăng The International Date Line quấn quanh và @jdeolive đề nghị tôi chia các tính năng tại dateLine. Vì vậy, tôi đã cố gắng.

Khi tôi cố gắng phân chia theo dõi vệ tinh của mình với splitWith trên dateline tôi sẽ quay lại null. Tôi biết tôi đang chia tách chính xác bởi vì khi tôi tách trên dòng Greenwich, tôi nhận được kết quả mong đợi.

Bất cứ ai cũng biết làm thế nào tôi có thể phân chia một Linestring đúng cách theo dòng ngày với OpenLayers? Tôi tìm mã ví dụ nếu bạn có nó.

Tôi đã thử wrapDateLinenhưng dường như nó không hoạt động trên các lớp vectơ mặc dù lớp vectơ của tôi giống như thế này:

vectorLayer = new OpenLayers.Layer.Vector("GroundTracks", {
    renderers: ['Canvas', 'VML'],
    wrapDateLine: true}); // <-- shoud be wraping.

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

Đây là mã của tôi:

var features = [];
var format = new OpenLayers.Format.WKT({
    'internalProjection': map.baseLayer.projection,
    'externalProjection': prjGeographic
});
var satTrack = format.read("LINESTRING (95.538611 13.286511, 94.730711 16.908947, 93.901095 20.528750, 93.043594 24.145177, 92.150978 27.757436, 91.214579 31.364666, 90.223791 34.965899, 89.165364 38.560019, 88.022401 42.145679, 86.772901 45.721205, 85.387568 49.284424, 83.826433 52.832413, 82.033480 56.361087, 79.927797 59.864504, 77.388419 63.333664, 74.227306 66.754285, 70.139140 70.102478, 64.605267 73.335774, 56.712904 76.373458, 44.881134 79.052803, 26.939886 81.047314, 02.704174 81.839241, -21.686285 81.101751, -39.887660 79.141947, -51.906937 76.480894, -59.912477 73.452897, -65.514482 70.225089, -69.645366 66.880243, -72.834535 63.461797, -75.393132 59.994131, -77.512464 56.491789, -79.315407 52.963919, -80.884039 49.416549, -82.275114 45.853820, -83.529088 42.278691, -84.675583 38.693355, -85.736827 35.099503, -86.729876 31.498490, -87.668095 27.891443, -88.562176 24.279331, -89.420849 20.663020, -90.251389 17.043303, -91.059999 13.420926, -91.852092 09.796602, -92.632515 06.171020, -93.405728 02.544857, -94.175960 -01.081217, -94.947343 -04.706542, -95.724045 -08.330456, -96.510402 -11.952298, -97.311065 -15.571400, -98.131162 -19.187081, -98.976502 -22.798638, -99.853829 -26.405335, -100.771148 -30.006378, -101.738172 -33.600889, -102.766925 -37.187866, -103.872602 -40.766117, -105.074803 -44.334175, -106.399366 -47.890158, -107.881153 -51.431559, -109.568417 -54.954914, -111.529886 -58.455253, -113.866668 -61.925160, -116.733085 -65.353081, -120.374635 -68.720132, -125.199754 -71.993642, -131.916790 -75.113368, -141.772276 -77.960803, -156.750096 -80.294831, -178.475596 -81.673196, 156.248392 -81.611421, 135.042323 -80.136505, 120.556535 -77.748172, 111.014840 -74.872356, 104.485504 -71.737081, 99.775637 -68.454400, 96.208126 -65.081545, 93.391438 -61.649716, 91.089380 -58.177038, 89.152970 -54.674643, 87.484294 -51.149703, 86.016609 -47.607042, 84.702947 -44.050030, 83.509299 -40.481112, 82.410411 -36.902133, 81.387093 -33.314533, 80.424442 -29.719485, 79.510644 -26.117981, 78.636145 -22.510889, 77.793053 -18.898997, 76.974710 -15.283040, 76.175371 -11.663718, 75.389950 -08.041709, 74.613831 -04.417680, 73.842693 -00.792294, 73.072378 02.833789, 72.298749 06.459907, 71.517566 10.085391, 70.724342 13.709564, 69.914194 17.331733, 69.081655 20.951185, 68.220447 24.567170, 67.323194 28.178891, 66.381031 31.785476, 65.383084 35.385943, 64.315735 38.979152, 63.161579 42.563725, 61.897893 46.137940, 60.494337 49.699551, 58.909396 53.245525, 57.084691 56.771602, 54.935577 60.271560, 52.334964 63.735923, 49.084320 67.149569, 44.859585 70.487030, 39.107498 73.702694, 30.852243 76.709182, 18.420695 79.329532, -00.339911 81.212453, -25.028018 81.831766)");

var featGreenwichLine = format.read("LINESTRING(0 -89, 0 89)");
var featDateLine = format.read("LINESTRING(180 -89, 180 89)");

features.push(featGreenwichLine);
features.push(featDateLine);
features.push(satTrack);

var resultsGreenwich = satTrack.geometry.splitWith(featGreenwichLine.geometry);
var resultsDateLine = satTrack.geometry.splitWith(featDateLine.geometry);

console.log(resultsGreenwich); //<--RETURNS EXPECTED RESULTS.
console.log(resultsDateLine);//<--RETURNS NULL.

vectorLayer.addFeatures(features);

Câu hỏi của tôi không phải là một bản sao của câu hỏi này vì họ muốn biết làm thế nào để làm điều đó trong ogr2ogr

Cập nhật:

Đây là những gì một bộ dữ liệu điển hình mà tôi làm việc trông giống như (theo dõi vệ tinh 24 giờ): Có thể tìm thấy wkt Linestring TẠI ĐÂY .

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


Phiên bản nào của openlayers bạn đang sử dụng?
Plux

@Plux 2.13.1 (Lần cuối)
CaptDragon

1
Theo API của họ, quấnDateLine chỉ nên được sử dụng trên lớp cơ sở, vì vậy không có gì lạ khi nó không hoạt động trên lớp vectơ. Tuy nhiên, tôi không biết làm thế nào để nó hoạt động trên lớp vector. Tôi đang có một vấn đề tương tự với đa hệ thống vượt qua dòng thời gian.
Plux

1
@Plux kiểm tra giải pháp
CaptDragon

Giải pháp tốt đẹp. Thật không may, không áp dụng được cho vấn đề của tôi, tôi tin rằng vấn đề của tôi nằm ở phía máy chủ địa lý nhiều hơn và đa giác của tôi chứa tọa độ nằm ở "phía bên kia" của dòng thời gian, như -180.00000000000003 90.00000190734869 tạo ra một số vấn đề trong máy chủ địa lý mà tôi tin. Tôi không có vấn đề hiển thị trên bản đồ của tôi (Tôi có một wms mà thực hiện điều này), nhưng tôi muốn sử dụng những như filterboxes trên WFS-truy vấn để geoserver :)
Plux

Câu trả lời:


2

Vấn đề là tính năng của bạn không vượt qua dòng ngày từ phối cảnh OpenLayers, vì vậy dòng chia của bạn không giao nhau với tính năng của bạn. Ví dụ từ dữ liệu của bạn:

..., -178.475596 -81.673196, 156.248392 -81.611421,...

Bạn đi từ -178 đến 156 và điều này không vượt qua dòng ngày từ phối cảnh OpenLayers. Thay vì chia nhỏ trên dòng ngày, bạn nên chia theo giá trị X tối thiểu của mình.

// Build the splitting line based on the min and max coordinates of the vector to split
var minX = 999999999;
var minY = -20037508.34 // minimum value of the spherical mercator projection
var maxY = 20037508.34  // maximum value of the spherical mercator projection
//Extract the minimum X from the data as bounds seems to be rounded.
for(var i=0; i<satTrack.geometry.components.length; i++) {
    if(satTrack.geometry.components[i].x < minX)
        minX = satTrack.geometry.components[i].x;
}
var pointList = [
    new OpenLayers.Geometry.Point(minX, minY),
    new OpenLayers.Geometry.Point(minX, maxY)
];
var featDateLine = new OpenLayers.Feature.Vector(
    new OpenLayers.Geometry.LineString(pointList)
);

Tôi đã tạo một ví dụ ở đây phân chia thành công vệ tinh của bạn thành 2 tính năng: http://jsfiddle.net/6XJ5A/

Bây giờ để sử dụng WKT với nhiều dòng trong bản cập nhật của bạn, thay vì sử dụng một đường thẳng, bạn phải đi qua toàn bộ tập dữ liệu và xây dựng đường phân chia của bạn với tất cả các tọa độ đi qua đường dữ liệu. Bằng cách xây dựng một dòng nhỏ bên trong một dòng, bạn có thể phân chia trên tất cả các tọa độ sẽ đi qua dòng thời gian. Dưới đây là ví dụ cập nhật: http://jsfiddle.net/Jc274/

Và mã:

// Build the splitting line based on the min and max coordinates of the vector to split
var pointList = [];
var lastPoint = satTrack.geometry.components[0];
//Extract the minimum X from the data as bounds seems to be rounded.
for (var i = 1; i < satTrack.geometry.components.length; i++) {
    if (Math.abs(satTrack.geometry.components[i].x - lastPoint.x) > 10000000) {
        pointList.push(satTrack.geometry.components[i]);
    }
    lastPoint = satTrack.geometry.components[i];
}

var lineList = [];
for(var i=0; i<pointList.length; i++) {
    lineList.push(new OpenLayers.Geometry.LineString([
        new OpenLayers.Geometry.Point(pointList[i].x, pointList[i].y-0.00001), 
        new OpenLayers.Geometry.Point(pointList[i].x, pointList[i].y+0.00001)
    ]));
}

var featDateLine = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.MultiLineString(lineList), null, split_style);

Điều này sẽ trả về cho bạn một đường chia tách trên tất cả các điểm "cắt ngang" đường dữ liệu

Lưu ý rằng tôi cũng lặp qua các tọa độ để xóa đường đi ngang qua bản đồ để kết nối 2 tọa độ:

for (var i = 0; i < resultsDateLine.length; i++) {
    // Remove the first (or last) point of the line, the one that cross the dateline
    if (Math.abs(resultsDateLine[i].components[0].x - resultsDateLine[i].components[1].x) > 10000000) {
        resultsDateLine[i].removeComponent(resultsDateLine[i].components[0]);
    }
    if (Math.abs(resultsDateLine[i].components[resultsDateLine[i].components.length - 1].x - resultsDateLine[i].components[resultsDateLine[i].components.length - 2].x) > 10000000) {
        resultsDateLine[i].removeComponent(resultsDateLine[i].components[resultsDateLine[i].components.length - 1]);
    }
    features.push(new OpenLayers.Feature.Vector(resultsDateLine[i], null, style_array[i]));
}

Cập nhật: Tôi đã cập nhật ví dụ đầu tiên để chỉ thêm dòng được chia. Tôi cũng cập nhật lời giải thích cho phù hợp. Cách tiếp cận này không phải là bằng chứng với bản nhạc vệ tinh 24h mà bạn cung cấp, nhưng tôi đang nghiên cứu nó.

Cập nhật 2: Tôi đã cập nhật ví dụ thứ hai. Bằng cách sử dụng multiline để phân tách và lặp qua kết quả để loại bỏ các tọa độ bổ sung được thêm bởi phần tách, chúng ta có được một tập hợp các tính năng không bao giờ đi qua đường dữ liệu.


+1 cho nỗ lực, nhưng các ví dụ bản đồ của bạn dường như không giải quyết được vấn đề. Các tuyến vệ tinh trên bản đồ ví dụ của bạn vẫn băng qua toàn bộ địa cầu thay vì đi theo đường dẫn tự nhiên của đường vệ tinh. Chắc chắn là tôi đang thiếu gì đó?
CaptDragon

Bạn có thể hiểu nhầm vấn đề vì ..., -178.475596 -81.673196, 156.248392 -81.611421,...hoàn toàn vượt qua dòng thời gian. Xem tại đây
CaptDragon

Hãy để tôi cập nhật mã và giải thích của tôi. Tôi biết nó nên vượt qua dòng dữ liệu, nhưng OpenLayers không hỗ trợ điều này. Từ quan điểm OL, nó không vượt qua dòng thời gian.
Julien-Samuel Lacroix

Đúng rồi. Đó chính là vấn đề. Tôi sẽ cần phải lừa OpenLayers và phân chia dòng để nó đi thẳng ra rìa sau đó tiếp tục ở phía bên kia nơi mà nó được cho là.
CaptDragon

2

Tôi đã tìm thấy một giải pháp tuyệt vời trên github của @Dane. Nó được gọi là Arc.js và nó để tính toán các tuyến đường vòng tròn lớn. Không chỉ vậy, nó cũng sẽ phân chia dòng trên dòng thời gian và cung cấp cho bạn hai dòng họ gặp nhau tại dòng thời gian, mà OpenLayers có thể dễ dàng ánh xạ. Tôi hy vọng anh ấy tiến lên để đòi tiền thưởng.

Đây là kết quả của tôi:

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


1

Hàm splitWith không biết về hình dạng 3 chiều của trái đất. Nó chỉ hoạt động trong một thế giới 2 chiều. Trong trường hợp của bạn, tất cả các LINESTRINGtọa độ X của bạn nằm trong khoảng -180 đến 180. Vì vậy, từ phối cảnh hai chiều của OpenLayers, chuỗi dòng thực sự không bao giờ vượt qua hình dạng phân chia của bạn (dòng ngày) và nó cho bạn biết điều đó bằng cách quay lại null.

Tôi tin rằng bạn sẽ phải viết một số mã tùy chỉnh để thực hiện việc chia tách. Tôi đang tưởng tượng một thuật toán lặp trên các đỉnh của bạn, xây dựng các chuỗi dòng đầu ra như thế này:

  • Đối với mỗi cặp đỉnh liền kề sẽ quyết định xem đoạn giữa chúng có vượt qua đường ngày không.
  • Nếu không, hãy giữ phân đoạn đó như cũ và thêm nó vào chuỗi dòng đầu ra "hiện tại".
  • Nếu , chia phân khúc thành hai phần. Thêm một phần vào chuỗi dòng "hiện tại", bắt đầu chuỗi dòng "hiện tại" mới và thêm phần khác vào chuỗi mới này.

Một phương pháp phỏng đoán hợp lý để xác định xem một cặp đỉnh có vượt qua đường ngày hay không là để xem sự khác biệt giữa các tọa độ X có lớn hơn 180 độ hay không. (Mặc dù điều này có thể khiến nó sai, ví dụ, ở các vùng cực. Có lẽ bạn đủ may mắn để không có bất kỳ vĩ độ thực sự cao nào.)

Hoạt động chia một phân đoạn thành hai phần có thể đơn giản như nội suy tuyến tính (nếu bạn không quan tâm quá nhiều đến độ chính xác của bản nhạc). Khi bạn phát hiện phân đoạn đó vượt qua dòng ngày, bạn tạo một bản sao của đỉnh thứ hai và di chuyển tọa độ X của nó (bằng cách thêm hoặc bớt 360 độ) sau đó nội suy tọa độ Y.

EDIT : Đây là một JSFiddle thể hiện thuật toán trên trên dữ liệu của bạn: http://jsfiddle.net/85vjS/


0

Nếu nó hoạt động với Greenwich, điều này là do bạn đang ở trong giới hạn của CRS. Vì vậy, trước tiên tôi sẽ đề xuất cách giải quyết tương tự như trong bài đăng mà bạn đang trỏ đến:

var featDateLine = format.read("LINESTRING(179.99 -89, 179.99 89)");

và có thể

var featDateLine = format.read("LINESTRING(-179.99 -89, -179.99 89)");

cho phía bên kia.

Một giải pháp khác là làm việc trong CRS không "vượt quá giới hạn" tại đường dữ liệu. Sau đó bạn sẽ có thể phân chia dữ liệu của bạn mà không có vấn đề.


Tôi đã thử cả hai LINESTRING(179.99 -89, 179.99 89)LINESTRING(-179.99 -89, -179.99 89)vô ích. Thật không may, về CRS, điều này không hoạt động cho mục đích của tôi vì tôi đang lập bản đồ các vệ tinh đi khắp thế giới nhiều lần. Vì vậy, tất cả các CRS được phân chia ở đâu đó và tôi sẽ có cùng một vấn đề ở bất cứ nơi nào tôi chia nó. Cảm ơn vì đầu vào của bạn.
CaptDragon
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.