OpenLayers를 사용하여 날짜 줄에 줄 문자열 나누기


9

몇 년 전 International Date Line 랩을 게시 하고 @jdeolive dateLine 에서 기능분할하도록 제안 했습니다. 그래서 시도했습니다.

날짜 표시 줄에 splitWith로 위성 트랙을 분할하려고 하면 다시 돌아옵니다 null. 그리니치 라인에서 분할 할 때 예상되는 결과를 얻으므로 올바르게 분할하는 것을 알고 있습니다.

누구나 OpenLayers를 사용하여 날짜 줄을 따라 프로그래밍 방식으로 줄 문자열을 올바르게 분할하는 방법을 알고 있습니까? 예제 코드가 있으면 찾으십시오.

시도 wrapDateLine했지만 벡터 레이어가 다음과 같음에도 불구하고 벡터 레이어에서 작동하지 않는 것 같습니다.

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

여기에 이미지 설명을 입력하십시오

내 코드는 다음과 같습니다.

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

내 질문은 ogr2ogr에서 어떻게하는지 알고 싶어하기 때문에이 질문과 중복되지 않습니다.

최신 정보:

이것은 내가 작업하는 일반적인 데이터 세트 (24 시간 위성 트랙)와 같습니다. Linestring wkt는 여기 에서 찾을 수 있습니다 .

여기에 이미지 설명을 입력하십시오


어떤 버전의 오픈 레이어를 사용하고 있습니까?
Plux

@Plux 2.13.1 (최신)
CaptDragon

1
API에 따르면 wrapDateLine은 기본 레이어에서만 사용해야하므로 벡터 레이어에서는 작동하지 않습니다. 그러나 벡터 레이어에서 어떻게 작동하게하는지 모르겠습니다. 날짜 표시 줄을 지나는 다중 다각형과 비슷한 문제가 있습니다.
Plux

1
@Plux 내 솔루션을
CaptDragon

좋은 해결책. 불행히도 내 문제에는 적용 할 수 없으며 내 문제는 지오 서버 측에 더 가깝고 다각형에는 날짜 줄의 "다른 쪽"에있는 좌표가 포함되어 있습니다 (예 : -180.00000000000003 90.00000190734869). 내지도에 표시 문제가 아니에요 (I이를 수행하는 WMS를),하지만 난에 filterboxes 이러한를 사용하려면 WFS 쿼리에 geoserver :
Plux

답변:


2

문제는 기능이 OpenLayers 관점에서 날짜 줄과 교차하지 않으므로 분할 선이 기능과 교차하지 않는다는 것입니다. 데이터의 예 :

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

-178에서 156으로 이동하면 OpenLayers 관점에서 날짜 줄을 넘지 않습니다. 날짜 줄을 나누는 대신 최소 X 값으로 나누어야합니다.

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

위성 트랙을 두 가지 기능으로 성공적으로 분할하는 예제를 작성했습니다. http://jsfiddle.net/6XJ5A/

이제 직선을 사용하는 대신 업데이트에서 여러 줄로 WKT를 사용하려면 전체 데이터 세트를 거쳐 날짜 선을 가로 지르는 모든 좌표로 분할 선을 작성해야합니다. 여러 줄 안에 작은 선을 작성하면 날짜 표시 줄을 가로 지르는 모든 좌표를 분할 할 수 있습니다. 업데이트 된 예는 다음과 같습니다. http://jsfiddle.net/Jc274/

그리고 코드 :

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

이렇게하면 날짜 표시 줄을 "교차"하는 모든 지점에서 분할 된 선이 반환됩니다.

또한 좌표를 반복하여 두 좌표를 연결하기 위해 맵을 가로 지르는 선을 제거합니다.

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

업데이트 : 분할 된 줄만 추가하도록 첫 번째 예제를 업데이트했습니다. 또한 그에 따라 설명을 업데이트했습니다. 이 방법은 귀하가 제공 한 24 시간 위성 트랙에 대한 증거는 아니지만, 현재 작업 중입니다.

업데이트 2 : 두 번째 예를 업데이트했습니다. 여러 줄을 사용하여 결과를 분할하고 반복하여 분할에 의해 추가 된 추가 좌표를 제거함으로써 날짜 표시 줄을 넘지 않는 일련의 기능을 얻게됩니다.


노력 +1하지만지도 예제로 문제를 해결하지 못하는 것 같습니다. 예제지도의 위성 트랙은 위성 트랙의 자연 경로를 따르지 않고 지구 전체를 여전히 가로지 릅니다. 뭔가 빠졌어야합니까?
CaptDragon

..., -178.475596 -81.673196, 156.248392 -81.611421,...날짜를 절대적으로 넘기 때문에 문제를 오해하고있을 수 있습니다 . 여기를보십시오
CaptDragon

코드와 설명을 업데이트하겠습니다. 데이터 라인을 교차해야한다는 것을 알고 있지만 OpenLayers는 이것을 지원하지 않습니다. OL 관점에서 볼 때 날짜 줄을 넘지 않습니다.
Julien-Samuel Lacroix

맞습니다. 그것이 문제이다. OpenLayers를 속이고 라인을 분할하여 가장자리까지 올라간 다음 반대쪽에서 계속해야합니다.
CaptDragon

2

@Dane의 github에 대한 훌륭한 솔루션을 찾았습니다. 이것을 Arc.js 라고 하며 Great circle route를 계산하기위한 것입니다. 뿐만 아니라, 날짜 표시 줄에서 줄을 분할하고 날짜 표시 줄에서 만나는 두 개의 줄 문자열을 제공하므로 OpenLayers가 쉽게 매핑 할 수 있습니다. 그가 현상금을 청구하기 위해 앞으로 나아 오기를 바랍니다 .

내 결과는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오


1

splitWith의 기능은 지구의 3 차원 형상에 대해 알고하지 않습니다. 2 차원 세계에서만 작동합니다. 귀하의 경우 모든 LINESTRINGX 좌표는 -180과 180 사이입니다. 따라서 OpenLayers의 2 차원 관점에서 라인 문자열은 실제로 분할 형상 (날짜 라인)을 교차하지 않으며을 반환하여 알려줍니다 null.

분할을 수행하기 위해 사용자 지정 코드를 작성해야한다고 생각합니다. 정점을 반복하여 다음과 같이 출력 줄 문자열을 작성하는 알고리즘을 상상합니다.

  • 인접한 각 정점 쌍에 대해 그 사이의 세그먼트가 날짜 줄을 통과하는지 여부를 결정합니다.
  • 그렇지 않은 경우 해당 세그먼트를 그대로 유지하고 "현재"출력 라인 문자열에 추가하십시오.
  • 이 경우 않습니다 , 두 부분으로 세그먼트를 분할합니다. "현재"행 문자열에 한 부분을 추가하고 새로운 "현재"행 문자열을 시작한 다음이 새 행에 다른 부분을 추가하십시오.

한 쌍의 꼭짓점이 날짜 선을 통과하는지 여부를 결정하기위한 하나의 합리적인 휴리스틱은 X 좌표 간의 차이가 180도 이상인지 확인하는 것입니다. (예를 들어 극지방에서는 잘못 될 수 있습니다. 실제로 위도가 높지 않을 정도로 운이 좋을 수도 있습니다.)

세그먼트를 두 부분으로 나누는 작업은 선형 보간만큼 간단 할 수 있습니다 (트랙의 정확도에 너무 신경 쓰지 않는 경우). 세그먼트가 날짜 선을 지나는 것을 감지하면 두 번째 정점의 사본을 만들고 360도를 더하거나 빼서 X 좌표를 이동 한 다음 Y 좌표를 보간합니다.

편집 : 다음은 데이터에서 위의 알고리즘을 보여주는 JSFiddle입니다. http://jsfiddle.net/85vjS/


0

Greenwich와 함께 작동하는 경우 CRS 경계 안에 있기 때문입니다. 따라서 먼저 게시물에서와 동일한 해결 방법을 제안합니다.

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

그리고 아마도

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

다른 쪽을 위해.

다른 해결책은 날짜 표시 줄에 "범위를 벗어난"CRS에서 작업하는 것입니다. 그런 다음 문제없이 데이터를 분할 할 수 있어야합니다.


난 이미 모두를 시도했습니다 LINESTRING(179.99 -89, 179.99 89)LINESTRING(-179.99 -89, -179.99 89)아무 소용. CRS와 관련하여 불행히도 전 세계 여러 번 이동하는 위성 트랙을 매핑하기 때문에 이것이 내 목적으로는 작동하지 않습니다. 따라서 모든 CRS는 어딘가에서 나뉘어져 있으며 나누는 곳마다 같은 문제가 있습니다. 입력 해 주셔서 감사합니다.
CaptDragon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.