ユーザーが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上のポリゴンのプロットです。