web-dev-qa-db-ja.com

地球の表面上の任意のポリゴンで囲まれた面積を計算する

単純な閉じた曲線上の点を表す緯度と経度のペアの任意のセットがあるとします。デカルト空間では、グリーンの定理を使用して、このような曲線で囲まれた面積を簡単に計算できました。球の表面の面積を計算するための類似のアプローチは何ですか?私が求めているのは、 Matlabのareaint関数 の背後にあるアルゴリズム(の近似値でさえ)だと思います。

22
Paul A. Hoadley

これを行うにはいくつかの方法があります。

1)緯度帯からの寄与を統合します。ここで、各ストリップの面積は(Rcos(A)(B1-B0))(RdA)になります。ここで、Aは緯度、B1とB0は開始経度と終了経度、すべての角度はラジアンです。

2)表面を 球面三角形 に分割し、 ジラールの定理 を使用して面積を計算し、これらを合計します。

3)ここでJames Schekが提案したように、GIS作業では、平坦な空間への射影を維持する面積を使用して、そこでの面積を計算します。

データの説明から、最初の方法が最も簡単なように聞こえます。 (もちろん、私が知らない他のもっと簡単な方法があるかもしれません。)

編集–これら2つの方法の比較:

最初の検査では、球面三角形アプローチが最も簡単に見えるかもしれませんが、一般的にはそうではありません。問題は、領域を三角形に分割するだけでなく、球面三角形、つまり辺が大円弧である三角形に分割する必要があることです。たとえば、緯度の境界は修飾されないので、これらの境界は大円の弧によりよく近似するエッジに分割する必要があります。そして、これは、大円が球面角度の特定の組み合わせを必要とする任意のエッジに対して行うのがより困難になります。たとえば、球の周りの中央のバンドをどのように分割するかを考えてみましょう。たとえば、緯度0から45度までのすべての領域を球面三角形に分割します。

結局、各方法で同様のエラーを使用してこれを適切に行う場合、方法2では三角形の数は少なくなりますが、三角形を決定するのは困難になります。方法1はより多くのストリップを提供しますが、それらを決定するのは簡単です。したがって、より良いアプローチとして方法1をお勧めします。

11
tom10

私はJavaでMATLABの「areaint」関数を書き直しました。これはまったく同じ結果になります。 「areaint」は「単位あたりの表面」を計算するので、答えに地球の表面積(5.10072e14平方メートル)を掛けました。

private double area(ArrayList<Double> lats,ArrayList<Double> lons)
{       
    double sum=0;
    double prevcolat=0;
    double prevaz=0;
    double colat0=0;
    double az0=0;
    for (int i=0;i<lats.size();i++)
    {
        double colat=2*Math.atan2(Math.sqrt(Math.pow(Math.sin(lats.get(i)*Math.PI/180/2), 2)+ Math.cos(lats.get(i)*Math.PI/180)*Math.pow(Math.sin(lons.get(i)*Math.PI/180/2), 2)),Math.sqrt(1-  Math.pow(Math.sin(lats.get(i)*Math.PI/180/2), 2)- Math.cos(lats.get(i)*Math.PI/180)*Math.pow(Math.sin(lons.get(i)*Math.PI/180/2), 2)));
        double az=0;
        if (lats.get(i)>=90)
        {
            az=0;
        }
        else if (lats.get(i)<=-90)
        {
            az=Math.PI;
        }
        else
        {
            az=Math.atan2(Math.cos(lats.get(i)*Math.PI/180) * Math.sin(lons.get(i)*Math.PI/180),Math.sin(lats.get(i)*Math.PI/180))% (2*Math.PI);
        }
        if(i==0)
        {
             colat0=colat;
             az0=az;
        }           
        if(i>0 && i<lats.size())
        {
            sum=sum+(1-Math.cos(prevcolat  + (colat-prevcolat)/2))*Math.PI*((Math.abs(az-prevaz)/Math.PI)-2*Math.ceil(((Math.abs(az-prevaz)/Math.PI)-1)/2))* Math.signum(az-prevaz);
        }
        prevcolat=colat;
        prevaz=az;
    }
    sum=sum+(1-Math.cos(prevcolat  + (colat0-prevcolat)/2))*(az0-prevaz);
    return 5.10072E14* Math.min(Math.abs(sum)/4/Math.PI,1-Math.abs(sum)/4/Math.PI);
}
9
user2548538

タグの1つで「地理」について言及しているので、ジオイドの表面上のポリゴンの領域の後にいるとしか思えません。通常、これは地理座標系(lon/lat)ではなく投影座標系を使用して行われます。 lon/latで行う場合、返される測定単位は球の表面のパーセントになると思います。

より「GIS」フレーバーでこれを実行したい場合は、エリアの測定単位を選択し、エリアを保持する適切な投影法を見つける必要があります(すべてがそうするわけではありません)。任意のポリゴンの計算について話しているので、 ランベルト正積方位図法 射影のようなものを使用します。投影の原点/中心をポリゴンの中心に設定し、ポリゴンを新しい座標系に投影してから、標準の平面手法を使用して面積を計算します。

地理的領域で多くのポリゴンを作成する必要がある場合は、機能する(または十分に近い)他の投影法が存在する可能性があります。たとえば、UTMは、すべてのポリゴンが1つの子午線の周りに集まっている場合に優れた近似値です。

これがMatlabのareaint関数の動作と関係があるかどうかはわかりません。

8
James Schek