简体   繁体   中英

Entity Framework DbGeography not calculating the Area correctly?

If I define the polygon in WKT format as this (longitude/latitude):

string wkt = "POLYGON ((15.981800258159638 45.810693408924287, 15.983624160289764 45.810783148865241, 15.983688533306122 45.809844611497965, 15.981843173503876 45.8096838246252, 15.981800258159638 45.810693408924287))"

and I create the DbGeography object as this:

var polygon = System.Data.Entity.Spatial.DbGeography.FromText(wkt);

the value of the Area property is 510065621695499.69

If I do the same thing using Postgres and PostGis like this:

select ST_Area(ST_GeographyFromText(wkt))

the result is 15496.7483872527 which should be the correct value.

If I create the polygon by reversing coordinates (latitude/longitude), both DbGeography and ST_Area return the same value (21247.6269483712)

Can anybody explain what is going on here?

PS: the polygon is located in Zagreb, Croatia.

This is to do with polygon orientation . For these spatial data types, "The interior of the polygon in an ellipsoidal system is defined by the left-hand rule", to quote the documentation . See eg this question and no doubt many others for further reading and approaches to address this.

If you reverse the order of the points in your WKT, you will get an area 15496.7447813973 (using a SRID of 4326 corresponding to WGS84 ), which is very close to what your other GIS systems are giving you. The difference I would guess might be due to a different SRID, but I'm far from an expert.

Note that the erroneous result you are getting is very close to 510,072,000 km², the surface area of the entire Earth - since DbGeography uses the orientation protocol it does, it has constructed the outside of the polygon you intended.

To add to AakashM 's answer, if you always want the smaller area you can do this:

    public double GetArea(string wellKnownText)
    {
        var sqlGeo = SqlGeography.Parse(wellKnownText);
        var normalArea = sqlGeo.STArea().Value;
        var reorientedArea = sqlGeo.ReorientObject().STArea().Value;
        // just trying to not return almost the whole area of our beloved planet...
        return Math.Min(normalArea, reorientedArea);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM