OpenLayersを使用した日付ラインの折れ線の分割


9

数年前、私は投稿の周り日付変更線ラップをし、@jdeoliveは、私は機能を分割提案日付変更線で。だから私は試しました。

日付変更線でsplitWithを使用して衛星トラックを分割しようとすると、戻りnullます。グリニッジラインで分割すると期待どおりの結果が得られるため、正しく分割していることがわかります。

OpenLayersを使用して、プログラムでLinestringを日付ラインに沿って適切に分割する方法を知っている人はいますか?もしあれば、サンプルコードを探します。

私は試しました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時間の衛星トラック)。Linestringwktはここにあります。

ここに画像の説明を入力してください


どのバージョンのopenlayersを使用していますか?
Plux、2014年

@Plux 2.13.1(最新)
CaptDragon 2014年

1
APIによると、wrapDateLineはベースレイヤーでのみ使用する必要があるため、ベクターレイヤーでは機能しないのも不思議ではありません。ただし、ベクターレイヤーでどのように機能させるかはわかりません。日付変更線と交差するマルチポリゴンで同様の問題が発生しています。
Plux、2014年


素晴らしい解決策。残念ながら、これは私の問題には当てはまりません。私の問題はジオサーバー側にあると考えています。ポリゴンには、-180.00000000000003 90.00000190734869のような日付線の「反対側」にある座標が含まれているため、ジオサーバーに問題が発生すると思います。:)私は(私はこれを行うWMSを持っている)私の地図上に表示の問題を持っていないんだけど、私はgeoserverにWFS-クエリにfilterboxesとしてこれらを使用したい
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)
);

ここでは、衛星トラックを2つの機能に正常に分割する例を作成しました: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);

これにより、日付変更線を「横切る」すべてのポイントで分割された線が返されます

2つの座標を接続するためにマップを横切る線を削除するために、座標もループすることに注意してください。

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: 2番目の例を更新しました。マルチラインを使用して分割し、結果をループして分割によって追加された余分な座標を削除することにより、日付線を越えない一連の機能を取得します。


努力のために+1しますが、マップの例では問題を解決できないようです。サンプルマップ上の衛星トラックは、衛星トラックの自然な経路をたどるのではなく、地球全体を横切ります。私は何かを逃しているに違いありませんか?
CaptDragon 2014年

..., -178.475596 -81.673196, 156.248392 -81.611421,...日付変更線を完全に横切るため、問題を誤解している可能性があります。こちらをご覧ください
CaptDragon 2014年

コードと説明を更新しましょう。データラインを横切る必要があることはわかっていますが、OpenLayersはこれをサポートしていません。OLの観点からは、日付変更線を越えていません。
Julien-Samuel Lacroix

そのとおり。それが問題です。OpenLayersをだましてラインを分割し、エッジまでまっすぐ進み、本来あるべき反対側に続くようにする必要があります。
CaptDragon 2014年

2

@Daneのgithubで素晴らしい解決策を見つけました。これはArc.jsと呼ばれ、大圏ルートを計算するためのものです。それだけでなく、日付ラインで行を分割し、日付ラインで交わる2つの折れ線を提供します。OpenLayersは簡単にマップできます。が賞金を受け取ること楽しみにしています。

これが私の結果です:

ここに画像の説明を入力してください ここに画像の説明を入力してください


1

splitWithの機能は、地球の3次元形状を認識していません。2次元の世界でのみ動作します。あなたの場合、すべてのLINESTRINGX座標は-180から180の間です。したがって、OpenLayersの2次元の観点から、ライン文字列は実際には分割されたジオメトリ(日付線)を横切ることはなく、を返すことでそれを伝えますnull

分割を行うには、カスタムコードを記述する必要があると思います。私はあなたの頂点をループして、次のような出力ライン文字列を構築するアルゴリズムを想像しています:

  • 隣接する頂点のペアごとに、頂点間のセグメントが日付変更線と交差するかどうかを決定します。
  • そうでない場合は、そのセグメントをそのままにして、「現在の」出力行ストリングに追加します。
  • ある場合、セグメントを2つの部分に分割します。「現在の」ラインストリングに1つのパーツを追加し、新しい「現在の」ラインストリングを開始して、この新しいパーツに他のパーツを追加します。

頂点のペアが日付変更線と交差するかどうかを判断するための1つの合理的なヒューリスティックは、X座標間の差が180度を超えるかどうかを確認することです。(これは、たとえば極地でそれを誤解する可能性があります。多分、あなたは本当に高い緯度を持たないほど幸運であるかもしれません。)

セグメントを2つの部分に分割する操作は、線形補間と同じくらい簡単です(トラックの精度をあまり気にしない場合)。セグメントが日付線と交差していることを検出したら、2番目の頂点のコピーを作成し、そのX座標を(360度加算または減算して)移動してから、Y座標を補間します。

編集:データの上記のアルゴリズムを示すJSFiddleは次のとおりです:http ://jsfiddle.net/85vjS/


0

グリニッジで動作する場合、これは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 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.