国際日付変更線の折り返し


13

OpenLayersを使用して、特定の日付内にラテンアメリカの国々に配置されたポリゴン(黄色)と交差するすべてのフィーチャ(黒)を返すフィルターを備えたWFSレイヤー(GeoServer上)を追加しました。

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

ただし、マップ上で水平に交差するフィーチャは、実際にはポリゴンと交差しません。この機能は、ラテンアメリカではなく、ハワイとフィジーの間の太平洋のどこかにあります。問題は、国際日付変更線を越える代わりに、全世界を包むことで地図上にレンダリングされることです。

problamatic機能が定義されています:

POLYGON((-179.700417 14.202717、-178.687422 13.992875,179.024138 8.24716、-179.98241 8.035567、-179.700417 14.202717))

このような問題の多い日付変更機能が多数ありますが、この例ではこれに絞り込みました。私はそれらの多くを持っているので、私はちょうど私のアプリケーションでそれを無視することはできません。

ベースレイヤーとWFSレイヤーで「wrapDateLine:true」を使用して同じ結果を得ようとしました。

これがGeoServerの問題なのか、OpenLayersの問題なのかはわかりません。

私の国際日付変更線の問題の解決策を知っている人はいますか?


2
ソフトウェアがこれに関してこのような問題を抱えている理由がわかりません、世界はフラットですよね!
-DavidF

たぶん、方向パラメータがあるはずです。
CaptDragon

@CaptDragonこの問題の解決策はありますか?
アニル

@Anilまだありません。見つけたら教えてください。
CaptDragon

回答:


6

残念ながら、これは既知の問題です。問題は、このように日付変更線を横切るジオメトリがあいまいであることです。OLレンダラーとGeoServerレンダラーは、意図が世界中を「短い」方法で進むことを知る簡単な方法がないため、たとえば170から-170を「通常の」方法で解釈し、世​​界中を長い方法で移動するだけです。

残念ながら、これに対する良い解決策は、日付変更線を横切るジオメトリを分割することを除いてありません。


+1のおかげで、私は同意しますが、ジオメトリを分割できません。他の誰かが他のアイデアを持っているかどうか見てみましょう
CaptDragon

OpenLayersでそれらをうまく分割する方法を見つけました。
CaptDragon 14年

7

グリニッジ子午線(または他の場所)で分割された投影を使用するようにマップを再投影して、関心のあるポリゴンがマップの不連続点を越えないようにします。


ポリゴンは世界をかなりうまくカバーします。常に、あるラインを横切るポリゴンが存在します。しかし、このように分割されていない投影法を知っていますか?
CaptDragon

1
すべての投影は世界をどこかで分割しなければなりません、それは数学に暗示的です(あなたが私を信じないならオレンジ色をむいてください:-))。できることは、タスクに最適な投影法を選択することだけです。
イアンタートン

ええ、あなたは正しいです。これを数日開いたままにして、他のアイデアが出てくるかどうかを確認します。あなたの提案をありがとう。:-)
CaptDragon

2

ユーザーがDragBoxアクションを介して、またはユーザーが入力した範囲ポイントをプロットすることにより、関心領域の長方形を生成できるアプリケーションを開発したため、私はかなり長い間この問題を調査していました。この冒険を始めたとき、私はOpenLayersを初めて使いました。手動で入力した範囲ポイントの問題は、AOIが国際日付変更線をカバーしている場合、描かれた長方形が間違った方法で世界中に描かれることでした。多くのStackExchangeユーザーがこの問題について質問したのは、OpenLayersのレスポンダーからのみです(そして、ここで言い換えると)「OpenLayersには、描画されるポイントの方向の意図を知る方法がないため、デフォルトになります...」。ああ、OpenLayersが危険であると十分に学んでおり、この問題が私に起こっているので、私はその応答でBSフラグを上げる必要があります。彼らの応答に関する問題は、定義によって、右上の経度と緯度、および左下の経度と緯度を指定する範囲の座標を読み込むことです。右上の経度がIDLの西側にあり、左下の経度がIDLの東側にある場合、ユーザーがどちらの方法でポリゴンをプロットしたいかは明らかですが、OpenLayersは経度の値の交換と描画を主張します多角形が間違った方法で世界中を回っています。エクステント宣言と問題のあるOpenLayersメソッド呼び出しのサンプルを以下に示します。右上の経度がIDLの西側にあり、左下の経度がIDLの東側にある場合、ユーザーがどちらの方法でポリゴンをプロットしたいかは明らかですが、OpenLayersは経度の値の交換と描画を主張します多角形が間違った方法で世界中を回っています。エクステント宣言と問題のあるOpenLayersメソッド呼び出しのサンプルを以下に示します。右上の経度がIDLの西側にあり、左下の経度がIDLの東側にある場合、ユーザーがどちらの方法でポリゴンをプロットしたいかは明らかですが、OpenLayersは経度の値の交換と描画を主張します多角形が間違った方法で世界中を回っています。エクステント宣言と問題のあるOpenLayersメソッド呼び出しのサンプルを以下に示します。

// 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__: []

ご覧のとおり、縦座標が逆になっているため、完全な座標構造を作成すると、ポリゴンが作成されます。polygonFeatureを作成し、その機能をベクトルに適用して、最終的にプロットするだけで、ポリゴンが世界中を間違って進むことがわかります。

OpenLayers 4ライブラリのこのol.extent.boundingExtentメソッドを掘り下げたので、なぜこれが起こっているのかを理解する必要がありました。

/**
 * 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__: []

ユーザーが有効なサイズのAOIポリゴンを作成したかどうかを判断できるように、コードは面積を動的に計算します。DragBoxで生成された選択を処理しているとき、結果のジオメトリ構造から座標を要求しています。EPSG:4326投影では、ラップされたワールドから座標を返すときに、最初の180.0度を超える座標が増加し続けるため、lonUR計算の理由360.0-165.937 = 194.063。私の面積計算コードパスは次のIDLテストを使用し、手動で入力した座標に同じコードパスを使用するために、座標値をDragBox getGeometry呼び出しから返されたかのようにシミュレートする必要がありました。私は実際にGEOJSONポリゴン構造をテストしています。これは、1次元がリング番号である3次元配列です。

 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))) {
 .
 .
 .

この時点でこれらのテストに合格した場合、コードは私が開発したアルゴリズムを使用してIDLの面積を計算します。

次に、この範囲を使用してポリゴンを作成し、次にpolygonFeatureを作成し、そのフィーチャをベクトルに適用して、最後にプロットし、今回は正しくプロットします。そこで、私が考えていた面積計算の問題を解決するために思いついた修正は、プロットの問題も修正しました。

たぶん、この解決策は他の誰かを助けたり、別の方向に考えさせたりするでしょう。解決策は、IDLの問題を2つの問題に分割することができたときに思いつきました。実際の面積計算は1つの問題で、もう1つはIDL上のポリゴンのプロットです。


1
OLは、> =演算子を使用して、プロット時にどちらの側に行くかを知るだけです。170を与えてから190を与えると、それは短い道のりになります。170を与え、次に-170を与えると、長い道のりを歩みます。経度を常に-180〜180の範囲に「正規化」すると、情報が失われます。情報を取得する1つの方法は、ポイント間の距離が180を
超え

1

回避策:例

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


私はWFSを使用していますが、投稿のリンクは言う:「あなたは『Layer.WMS』または『Layer.MapServer』層でそれを行うことができます」
CaptDragon

両方がサポートされていて、Layer.MapServerを特に必要としない場合は、Layer.WMSを使用します(MapServerからも提供できます)。
-DavidF

@DavidF:ありがとう。でも、WFSのベクター機能を使う必要があります。
CaptDragon

1

2年後も、ベクターレイヤー上のフィーチャにこの問題が続きました。エンドポイントが日付変更線を超えた場合にエンドポイントを反転する方法を示すコードのスニペットを含むこのファイルを見つけました。

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

更新:

実際、上記は世界中で複数の革命のために機能しませんでした。私がやってしまっTHISを

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


1

私はあなたのために働くかもしれないし、そうでないかもしれない私自身のプロジェクトでこれのための解決策を考え出しました。LineStringsで機能することは知っていますが、他のジオメトリタイプについてはわかりません。

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

dateLineFix関数は、日付変更線と交差するすべてのセグメントについて、指定されたLineStringを再帰的に走査します。次に、日付行でそれらを2つに分割し、結果のすべてのセグメントをMultiLineStringとして返します。

私の目的には完全に機能しました(極緯度経度グリッドを描く)。


0

私は日付変更線に関する問題がほとんどなく、それらすべてを修正することができました。あなたは以下を試すことができます。

  1. GeoServerレイヤーのバウンディングボックスの値を手動で更新して、ポリゴンを壊さずにカバーし、問題が解決するかどうかを確認します。

  2. Openlayersで行った修正の1つは、日付線を+ ve経度から-veに渡すときにタイルが見つからないことです。 http://trac.osgeo.org/openlayers/ticket/2754 WFSに適用できるかどうかわからない。最新のopenlayers開発バージョンを入手して試してみてください。


0

LineStringsでこの問題に遭遇し、その解決策を作成しました。ポリゴンに役立つかどうかはわかりません。私のrepl.itでそれを見ることができます:https ://repl.it/@gpantic/OpenLayersSplitRouteOverPacific


1
質問に回答する場合は、リンクを提供する代わりに、すべての情報を回答に追加してください。
BERA

0

EPSG:3832(WGS84 PDC)は、太平洋を中心とした投影です。これにより、IDLクロッシング問題とプライムメリディアンクロッシング問題が交換されます。これは、何を描いているかによっては問題にならない場合があります。北極圏と南極圏の近くでも問題を発見しました。

クレジットはこの記事にあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.