Shapely: Le calcul de la surface du polygone ne correspond pas à d'autres outils comme le moteur Google Earth ou geojson.io

Créé le 5 juin 2019  ·  8Commentaires  ·  Source: Toblerity/Shapely

Le calcul de la surface polygonale ne semble pas correspondre à d'autres outils similaires tels que Geojson.io ou Google Earth Engine. Par example:

coords = [(-97.59238135821987, 43.47456565304017),
 (-97.59244690469288, 43.47962399877412),
 (-97.59191951546768, 43.47962728271748),
 (-97.59185396090983, 43.47456565304017),
 (-97.59238135821987, 43.47456565304017)]

projection = partial(pyproj.transform, pyproj.Proj(init='epsg:4326'), pyproj.Proj(init='epsg:3857'))
shapely.ops.transform(projection, shapely.geometry.Polygon(sample_coords)).area

donne une superficie de 45573.993884405005 m^2 tandis que Google Earth Engine et Geojson.io rapportent 23944.14737277293 et 23997.77 .

La zone en shapely est calculée ici en citant une méthode dont le lien est rompu, tandis que le Geojson.io est calculé ici via une méthode décrite à partir de la page 3 de ce document .

J'ai brièvement converti ceci en python avec l'argument attendant le même schéma de coordonnées que ci-dessus (liste des coordonnées):

def ringArea(coords):
    #var p1, p2, p3, lowerIndex, middleIndex, upperIndex, i,
    area = 0
    wgs84_radius = 6378137 # earth's equitorial radius in wgs84 = espg 4326
    coordsLength = len(coords)

    if coordsLength > 2:
        for i in range(coordsLength):
            if i == coordsLength - 2:
                lowerIndex = coordsLength - 2
                middleIndex = coordsLength - 1
                upperIndex = 0
            elif i == coordsLength - 1:
                lowerIndex = coordsLength - 1
                middleIndex = 0
                upperIndex = 1
            else:
                lowerIndex = i
                middleIndex = i + 1
                upperIndex = i + 2

            p1 = coords[lowerIndex]
            p2 = coords[middleIndex]
            p3 = coords[upperIndex]
            area += (np.deg2rad(p3[0]) - np.deg2rad(p1[0]) ) * np.sin(np.deg2rad(p2[1]))

        area = area * wgs84_radius * wgs84_radius / 2
    return area

Cette méthode renvoie une zone de 23997.769250450423 m^2.

Ma principale question est la suivante : la méthode actuelle est-elle préférée pour une raison quelconque ? Si tel est le cas, le lien vers le cité peut-il être corrigé (je ne sais pas où il est censé aller). Si non, est-il possible de se conformer (ou d'ajouter l'option) à la méthode décrite dans la doc JPL ?

Je serais heureux de contribuer à cela si l'option pour cette autre méthode souhaite être ajoutée, mais je n'ai vu aucune directive de contribution.

Commentaire le plus utile

Autant que je sache, shapely suppose que tous les points sont cartésiens et calcule la surface dans toutes les coordonnées qui lui sont données; dans l'exemple ci-dessus, les coordonnées wgs sont converties en web mercator epsg3857 pour calculer la surface, mais web mercator n'est pas une projection à surface égale.

Si nous remplaçons la conversion par un système de coordonnées à aire égale tel que world mollweide (https://spatialreference.org/ref/esri/54009/), le calcul de l'aire est effectué comme prévu :

coords = [(-97.59238135821987, 43.47456565304017),
 (-97.59244690469288, 43.47962399877412),
 (-97.59191951546768, 43.47962728271748),
 (-97.59185396090983, 43.47456565304017),
 (-97.59238135821987, 43.47456565304017)]

projection = partial(pyproj.transform, pyproj.Proj(init='epsg:4326'), pyproj.Proj(init='esri:54009'))
shapely.ops.transform(projection, shapely.geometry.Polygon(coords)).area

Ce qui donne 23997.775332830173 .

Nous l'utilisons dans https://github.com/mapbox/fio-area. J'espère que cela t'aides!

Tous les 8 commentaires

Autant que je sache, shapely suppose que tous les points sont cartésiens et calcule la surface dans toutes les coordonnées qui lui sont données; dans l'exemple ci-dessus, les coordonnées wgs sont converties en web mercator epsg3857 pour calculer la surface, mais web mercator n'est pas une projection à surface égale.

Si nous remplaçons la conversion par un système de coordonnées à aire égale tel que world mollweide (https://spatialreference.org/ref/esri/54009/), le calcul de l'aire est effectué comme prévu :

coords = [(-97.59238135821987, 43.47456565304017),
 (-97.59244690469288, 43.47962399877412),
 (-97.59191951546768, 43.47962728271748),
 (-97.59185396090983, 43.47456565304017),
 (-97.59238135821987, 43.47456565304017)]

projection = partial(pyproj.transform, pyproj.Proj(init='epsg:4326'), pyproj.Proj(init='esri:54009'))
shapely.ops.transform(projection, shapely.geometry.Polygon(coords)).area

Ce qui donne 23997.775332830173 .

Nous l'utilisons dans https://github.com/mapbox/fio-area. J'espère que cela t'aides!

Shapely ne fait que des calculs cartésiens, donc ce problème est principalement hors sujet.

Je viens de réparer le lien brisé dans shapely/algorithms/cga.py vers https://web.archive.org/web/20080209143651/http ://cgafaq. info:80/wiki/Polygon_Area

Il existe plusieurs façons différentes de calculer des zones à partir de coordonnées géodésiques, et elles donneront chacune un résultat légèrement différent. Pour ajouter une autre méthode, utilisez Planimeter sur WGS84 pour l' exemple pour obtenir 23988,9 m ^ 2 avec une erreur d'environ 0,2 m ^ 2, donc j'appellerais cela la "meilleure réponse". Cette méthode est également utilisée dans PostGIS sur les types géographiques.

Merci @dnomadb @mwtoews !

J'apprécie la contribution de chacun. Je suis assez nouveau dans le monde SIG donc tout est utile, merci !

@dnomadb en essayant la méthode suggérée, j'ai eu l'erreur suivante :

CRSError: Invalid projection: +init=epsg:54009 +type=crs: (Internal Proj Error: proj_create: crs not found)

Avez-vous rencontré cela?

@ brentonmallen1 , il semble que vous ayez epsg:54009 là où il devrait être esri:54009 (comme dans l'exemple ici : https://github.com/Toblerity/Shapely/issues/726#issuecomment-499252744 -- c'est une chose facile à mélanger)

C'était une faute de frappe de ma part en essayant différentes choses pour voir si je pouvais le faire fonctionner. J'obtiens toujours l'erreur avec esri:54009 :

projection = partial(pyproj.transform, pyproj.Proj(init='epsg:4326'), pyproj.Proj(init='esri:54009'))

```-------------------------------------------------------------- -------------------------------------
CRSError Traceback (appel le plus récent en dernier)
dans
5 (-97,59238135821987, 43,47456565304017)]
6
----> 7 projection = partiel(pyproj.transform, pyproj.Proj(init='epsg:4326'), pyproj.Proj(init='esri:54009'))
8 shapely.ops.transform(projection, shapely.geometry.Polygon(coords)).area

~/miniconda3/envs/fs-ml/lib/python3.6/site-packages/pyproj/proj.py dans __init__(self, projparams, preserve_units, **kwargs)
145 '116.366 39.867'
146 """
--> 147 self.crs = CRS.from_user_input(projparams si projparams n'est pas None else kwargs)
148 # assurez-vous que les unités sont des mètres si preserve_units est False.
149 sinon preserve_units et "foot" dans self.crs.axis_info[0].unit_name :

~/miniconda3/envs/fs-ml/lib/python3.6/site-packages/pyproj/crs.py dans from_user_input(cls, value)
389 si estinstance(valeur, _CRS):
390 valeur de retour
--> 391 retour cls(valeur)
392
393 def get_geod(self):

~/miniconda3/envs/fs-ml/lib/python3.6/site-packages/pyproj/crs.py dans __init__(self, projparams, **kwargs)
258 raise CRSError("Entrée CRS invalide : {!r}".format(projparams))
259
--> 260 super(CRS, self).__init__(projstring)
261
262 @méthodedeclasse

pyproj/_crs.pyx dans pyproj._crs._CRS.__init__()

CRSError : Projection non valide : +init= esri:54009 +type=crs : (Erreur de projet interne : proj_create : impossible de développer +init=esri:54009 +type=crs)```

Au cas où quelqu'un d'autre rencontrerait le problème ci-dessus lors de la re-projection vers ESRI:54009 , voici une solution https://github.com/pyproj4/pyproj/issues/341

Cette page vous a été utile?
0 / 5 - 0 notes