PostGISのST_Areaはどのように機能しますか?


8

面積が約6226 km ^ 2であることがわかっているポリゴンに対して単純な計算を実行しています。これは、地理(WGS84 SRID)列に格納されます。

クエリは次のとおりです。

select st_astext(col), st_area(col) area from table

そして返す:

"POLYGON((-180 58.282525588539,-178.916399160189 57.4759784390599,-178.191728834624 58.5761461944577,-180 58.282525588539))" | 5807028547.33813

返される領域(5807028547.33813)は、km ^ 2ではなくmm ^ 2のように見えますか?ドキュメントhttp://postgis.net/docs/ST_Area.htmlは、「デフォルトでは、面積は平方メートルの単位を持つ回転楕円体で決定される」と述べています。

これはドキュメントのエラーですか、それとも上記は正しいのですか?機能が根本的に誤解していますか?

回答:


4

計算により正しい出力が得られます。あなたが引用したように、ドキュメントは「デフォルトでは面積は平方メートルの単位を持つ回転楕円体で決定されます」と述べています。

クエリの結果は5807028547.33813 m ^ 2です。面積をkm ^ 2で取得するには、結果を1,000,000で割る必要があります。

5807028547.33813 m^2 / 1,000,000 = 5807.02854733813 km^2

5807.02854733813 km ^ 2は、予想される6226 km ^ 2にほぼ対応します。


これは正しいです。参考までに:postgis.net/docs/ST_Area.html
alphabetasoup

しかし、10万で除算する根拠は何でしょうか。km ^ 2 = m ^ 2 / 1,000,000
J Tileson 2015年

それはタイプミスです。値は1.0e + 006である必要がありますが、結果は正しかった(5807 km ^ 2)。
Vince

@Vinceあなたは正しい。タイプミスを修正しました。
yxcv 2015年

@ J Tilesoneあなたがmath.stackexchange.comで尋ねることができるその部門の基礎の質問。
yxcv 2015年

5

SELECT
     st_astext(col)
    、st_area(col、false)ASエリア
FROMテーブル

ST_Areaは(ジオメトリ)は、WGS1984としてのポリゴン面積を計算なしに等しい面積球/省略記号(かわり地理のSQL型のジオメトリを使用している場合)に突出します。結果は、ジオメトリのSRIDの単位で測定されます。

ST_Areaは(地理)は、WGS1984としてのポリゴン面積を算出WITH(あなたは、SQL型の代わりにジオメトリの地理学を使用している場合)に等しい面積球/省略記号に突出します。結果は平方メートルで測定されます。m 2からkm 2に移動するには、m 2を1000 2で除算する必要があります(1000メートルは1キロメートルです。これは、面積であるため平方するため、1000 * 1000別名1000 2です)。

ST_Area(geometry、true / false)は、CylindricalEqualAreaworld座標系に投影された座標で面積(m 2単位)を計算します(面積を保持-面積を計算する場合に意味があります)。

真/偽の違いは精度です。
ST_Area(geog、false)は、高速ですが精度の低い球を使用します。

このポリゴンを使用すると、次のようになります。

var poly = [
    [47.3612503, 8.5351944],
    [47.3612252, 8.5342631],
    [47.3610145, 8.5342755],
    [47.3610212, 8.5345227],
    [47.3606405, 8.5345451],
    [47.3606350, 8.5343411],
    [47.3604067, 8.5343545],
    [47.3604120, 8.5345623],
    [47.3604308, 8.5352457],
    [47.3606508, 8.5352328],
    [47.3606413, 8.5348784],
    [47.3610383, 8.5348551],
    [47.3610477, 8.5352063],
    [47.3612503, 8.5351944]
];

次の結果が得られます。

ST_Area(g) =             5.21556075001092E-07
ST_Area(g, false)     6379.25032051953
ST_Area(g, true)      6350.65051177517

私はドキュメントから取られるべき重要な部分はこれだと思います:

geo metryの場合、2Dデカルト領域はSRIDで指定された単位 で決定されます。
GEOためグラフィー、既定の面積で有する回転楕円体上で決定された平方メートル単位

あなたが選択することに注意する必要があるので、地理、およびNOTジオメトリ。
ジオメトリを使用する場合は、ST_Areaのtrue / falseオーバーロードを使用する必要があります。

C#では、KnownCoordinateSystems.Projected.World.CylindricalEqualAreaworldでtrueとほぼ同じになるが、falseは地球の平均半径の世界、WorldSpheroid.CylindricalEqualAreasphereまたはWorldSpheroid.EckertIVsphereに近いもののようだが、それは2m 2だけ離れているので、それは独自のことをしているようです。

using DotSpatial.Projections;
using DotSpatial.Topology;


namespace TestSpatial
{


    static class Program
    {

        // https://stackoverflow.com/questions/46159499/calculate-area-of-polygon-having-wgs-coordinates-using-dotspatial
        // pfff wrong...
        public static void TestPolygonArea()
        {
            // this feature can be see visually here http://www.allhx.ca/on/toronto/westmount-park-road/25/
            string feature = "-79.525542519049552,43.691278124243432 -79.525382520578987,43.691281097414787 -79.525228855617627,43.69124858593392 -79.525096151437353,43.691183664769774 -79.52472799258571,43.690927163079735 -79.525379447437814,43.690771996666641 -79.525602330675355,43.691267524226838 -79.525542519049552,43.691278124243432";
            feature = "47.3612503,8.5351944 47.3612252,8.5342631 47.3610145,8.5342755 47.3610212,8.5345227 47.3606405,8.5345451 47.3606350,8.5343411 47.3604067,8.5343545 47.3604120,8.5345623 47.3604308,8.5352457 47.3606508,8.5352328 47.3606413,8.5348784 47.3610383,8.5348551 47.3610477,8.5352063 47.3612503,8.5351944";

            string[] coordinates = feature.Split(' ');
            // System.Array.Reverse(coordinates);


            // dotspatial takes the x,y in a single array, and z in a separate array.  I'm sure there's a 
            // reason for this, but I don't know what it is.'
            double[] xy = new double[coordinates.Length * 2];
            double[] z = new double[coordinates.Length];
            for (int i = 0; i < coordinates.Length; i++)
            {
                double lon = double.Parse(coordinates[i].Split(',')[0]);
                double lat = double.Parse(coordinates[i].Split(',')[1]);
                xy[i * 2] = lon;
                xy[i * 2 + 1] = lat;
                z[i] = 0;
            }

            double area = CalculateArea(xy);
            System.Console.WriteLine(area);
        }



        public static double CalculateArea(double[] latLonPoints)
        {
            // source projection is WGS1984
            ProjectionInfo projFrom = KnownCoordinateSystems.Geographic.World.WGS1984;
            // most complicated problem - you have to find most suitable projection
            ProjectionInfo projTo = KnownCoordinateSystems.Projected.UtmWgs1984.WGS1984UTMZone37N;
            projTo = KnownCoordinateSystems.Projected.Europe.EuropeAlbersEqualAreaConic; // 6350.9772005155683
            // projTo= KnownCoordinateSystems.Geographic.World.WGS1984; // 5.215560750019806E-07
            projTo = KnownCoordinateSystems.Projected.WorldSpheroid.EckertIVsphere; // 6377.26664171461
            projTo = KnownCoordinateSystems.Projected.World.EckertIVworld; // 6391.5626849671826
            projTo = KnownCoordinateSystems.Projected.World.CylindricalEqualAreaworld; // 6350.6506013739854
            projTo = KnownCoordinateSystems.Projected.WorldSpheroid.CylindricalEqualAreasphere; // 6377.2695087222382
            projTo = KnownCoordinateSystems.Projected.WorldSpheroid.EquidistantCylindricalsphere; // 6448.6818862780929
            projTo = KnownCoordinateSystems.Projected.World.Polyconicworld; // 8483.7701716953889
            projTo = KnownCoordinateSystems.Projected.World.EquidistantCylindricalworld; // 6463.1380225215107
            projTo = KnownCoordinateSystems.Projected.World.EquidistantConicworld; // 8197.4427198320627
            projTo = KnownCoordinateSystems.Projected.World.VanderGrintenIworld; // 6537.3942984174937
            projTo = KnownCoordinateSystems.Projected.World.WebMercator; // 6535.5119516421109
            projTo = KnownCoordinateSystems.Projected.World.Mercatorworld; // 6492.7180733950809
            projTo = KnownCoordinateSystems.Projected.SpheroidBased.Lambert2; // 9422.0631835013628
            projTo = KnownCoordinateSystems.Projected.SpheroidBased.Lambert2Wide; // 9422.0614012926817
            projTo = KnownCoordinateSystems.Projected.TransverseMercator.WGS1984lo33; // 6760.01638841012
            projTo = KnownCoordinateSystems.Projected.Europe.EuropeAlbersEqualAreaConic; // 6350.9772005155683
            projTo = KnownCoordinateSystems.Projected.UtmOther.EuropeanDatum1950UTMZone37N; // 6480.7883094931021


            // ST_Area(g, false)     6379.25032051953
            // ST_Area(g, true)      6350.65051177517
            // ST_Area(g)            5.21556075001092E-07


            // prepare for ReprojectPoints (it's mutate array)
            double[] z = new double[latLonPoints.Length / 2];
            // double[] pointsArray = latLonPoints.ToArray();

            Reproject.ReprojectPoints(latLonPoints, z, projFrom, projTo, 0, latLonPoints.Length / 2);

            // assemblying new points array to create polygon
            System.Collections.Generic.List<Coordinate> points = 
                new System.Collections.Generic.List<Coordinate>(latLonPoints.Length / 2);

            for (int i = 0; i < latLonPoints.Length / 2; i++)
                points.Add(new Coordinate(latLonPoints[i * 2], latLonPoints[i * 2 + 1]));

            Polygon poly = new Polygon(points);
            return poly.Area;
        }


        [System.STAThread]
        static void Main(string[] args)
        {
            TestPolygonArea();

            System.Console.WriteLine(System.Environment.NewLine);
            System.Console.WriteLine(" --- Press any key to continue --- ");
            System.Console.ReadKey();
        }
    }
}

例えば、あなたは平均半径で偽に近い適合を得ます:

// https://gis.stackexchange.com/a/816/3997
function polygonArea()
{
    var poly = [
        [47.3612503, 8.5351944],
        [47.3612252, 8.5342631],
        [47.3610145, 8.5342755],
        [47.3610212, 8.5345227],
        [47.3606405, 8.5345451],
        [47.3606350, 8.5343411],
        [47.3604067, 8.5343545],
        [47.3604120, 8.5345623],
        [47.3604308, 8.5352457],
        [47.3606508, 8.5352328],
        [47.3606413, 8.5348784],
        [47.3610383, 8.5348551],
        [47.3610477, 8.5352063],
        [47.3612503, 8.5351944]
    ];


    var area = 0.0;
    var len = poly.length;

    if (len > 2)
    {

        var p1, p2;

        for (var i = 0; i < len - 1; i++)
        {

            p1 = poly[i];
            p2 = poly[i + 1];

            area += Math.radians(p2[0] - p1[0]) *
                (
                    2
                    + Math.sin(Math.radians(p1[1]))
                    + Math.sin(Math.radians(p2[1]))
                );
        }

        // https://en.wikipedia.org/wiki/Earth_radius#Equatorial_radius
        // https://en.wikipedia.org/wiki/Earth_ellipsoid
        // The radius you are using, 6378137.0 m corresponds to the equatorial radius of the Earth.
        var equatorial_radius = 6378137; // m
        var polar_radius = 6356752.3142; // m
        var mean_radius = 6371008.8; // m
        var authalic_radius = 6371007.2; // m (radius of perfect sphere with same surface as reference ellipsoid)
        var volumetric_radius = 6371000.8 // m (radius of a sphere of volume equal to the ellipsoid)
        // geodetic latitude φ
        var siteLatitude = Math.radians(poly[0][0]);


        // https://en.wikipedia.org/wiki/Semi-major_and_semi-minor_axes
        // https://en.wikipedia.org/wiki/World_Geodetic_System
        var a = 6378137; // m
        var b = 6356752.3142; // m
        // where a and b are, respectively, the equatorial radius and the polar radius.

        var R1 = Math.pow(a * a * Math.cos(siteLatitude), 2) + Math.pow(b * b * Math.sin(siteLatitude), 2)
        var R2 = Math.pow(a * Math.cos(siteLatitude), 2) + Math.pow(b * Math.sin(siteLatitude), 2);

        // https://en.wikipedia.org/wiki/Earth_radius#Radius_at_a_given_geodetic_latitude
        // Geocentric radius
        var R = Math.sqrt(R1 / R2);
        // var merid_radius = ((a * a) * (b * b)) / Math.pow(Math.pow(a * Math.cos(siteLatitude), 2) + Math.pow(b * Math.sin(siteLatitude), 2), 3/2)



        // console.log(R);
        // var hrad = polar_radius + (90 - Math.abs(siteLatitude)) / 90 * (equatorial_radius - polar_radius);
        var radius = mean_radius;

        area = area * radius * radius / 2.0;
    } // End if len > 0

    // equatorial_radius: 6391.565558418869 m2
    // mean_radius:       6377.287126172337m2
    // authalic_radius:   6377.283923019292 m2
    // volumetric_radius: 6377.271110415153 m2
    // merid_radius:      6375.314923754325 m2
    // polar_radius:      6348.777989748668 m2
    // R:                 6368.48180842528 m2
    // hrad:              6391.171919886588 m2

    // http://postgis.net/docs/doxygen/2.2/dc/d52/geography__measurement_8c_a1a7c48d59bcf4ed56522ab26c142f61d.html
    // ST_Area(false)     6379.25032051953
    // ST_Area(true)      6350.65051177517

    // return area;
    return area.toFixed(2);
}

WebMercatorは、Googleマップで使用される座標系です。
この座標系の正式名称はEPSG:3857です。

PostGISが正確に行うことは、ここに文書化されています:https :
//postgis.net/docs/ST_Area.html

そして、ソースコードの詳細はここにあります:http :
//postgis.net/docs/doxygen/2.2/dc/d52/geography__measurement_8c_a1a7c48d59bcf4ed56522ab26c142f61d.html

そしてここ:http :
//postgis.net/docs/doxygen/2.2/d1/dc0/lwspheroid_8c_a29d141c632f6b46587dec3a1dbe3d176.html#a29d141c632f6b46587dec3a1dbe3d176

アルバース-プロジェクション: アルバース-プロジェクション アルバース-プロジェクション2

円筒形の等面積投影: 円筒形 円筒2


ステファン、これは変だ。「ST_Area(geography)」の場合の発言と実際の計算結果は、「use_spheroid」ブール値を指定しないと、公式のPostGISドキュメントと矛盾するようです。ドキュメントでは、「地理の場合、デフォルトでは面積は平方メートル単位の回転楕円体で決定されます。」と書かれているため、ブール値を指定せずに、回転楕円体に基づいてデフォルトで面積をm2で指定する必要があります。また、これは何のブールは、ST_Areaはコマンドで使用されていない明確にヘルプページ、上の灰色のボックス内の最後の例で示した結果である、まだ結果が示す「sqm_spheroid」..?
Marco_B

1
ステファン、あなたのソースデータは実際に地理にありましたか、それとも地理に変換しましたか、それともWGS1984の緯度/経度にあるジオメトリだけですか?
Marco_B

1
@Marco_B:間違いなくジオメトリ。そうしないと、5.21556075001092E-07を説明できません。ええ、私はジオメトリの代わりに地理を使うべきでした。github.com/ststeiger/AnySqlWebAdmin/blob/master/AnySqlWebAdmin/…を
Stefan Steiger

応答をありがとう、それはそれをそれで説明します。たぶん、最初の投稿を編集して、「ST_Area(geography)がポリゴンエリアをWGS1984として計算し、等しい面積の球/省略記号に投影しないでください」という今ややや不正確なステートメントを変更するとよいでしょう。このステートメントは、図形がGeographyストレージではなくGeometryにある状況、およびGeographyの場合、図形は回転楕円体/球体を使用します。
Marco_B

1
@Marco_B:あなたがそのコメントを書いたとき、私はすでにそうし始めていました。これで完了です。
Stefan Steiger
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.