Shapely: Fügen Sie die Funktionalität hinzu, um die 3. Dimension fallen zu lassen

Erstellt am 5. Mai 2019  ·  3Kommentare  ·  Quelle: Toblerity/Shapely

Auf GIS Stack Exchange gibt es eine alte Frage zum Konvertieren von 3D-Geometrien in 2D: Convert 3D WKT to 2D Shapely Geometry . Ich denke, diese Funktionalität sollte in Shapely enthalten sein, damit wir sie zum Beispiel wie folgt verwenden könnten:

>>> from shapely.geometry import Polygon
>>> p = Polygon([(0, 0, 0), (1, 0, 0), (1, 1, 0)])
>>> p.wkt
'POLYGON Z ((0 0 0, 1 0 0, 1 1 0, 0 0 0))'
>>> p2 = p.drop_z
>>> p2.wkt
'POLYGON ((0 0, 1 0, 1 1, 0 0))'

Ich habe in einer der Antworten und in den Dokumenten gesehen, dass _diese Operation nicht notwendig ist_, da die 3. Dimension _keine Auswirkung auf die geometrische Analyse hat_ . Aber als ich meine eigene Funktion implementierte, um die linke Seite einer geteilten Geometrie zu bestimmen (dies ist noch nicht implementiert: https://github.com/Toblerity/Shapely/issues/589), sah ich, dass diese Funktionalität nützlich sein könnte:

from shapely.geometry import (LinearRing, 
                              LineString, 
                              Polygon)


def is_left(polygon: Polygon,
            line: LineString) -> bool:
    """
    Determines if the polygon is on the left side of the line
    according to:
    https://stackoverflow.com/questions/50393718/determine-the-left-and-right-side-of-a-split-shapely-geometry
    """
    ring = LinearRing([*line.coords, *polygon.centroid.coords])
    return ring.is_ccw

Dieser Code schlägt bei 3D-Geometrien fehl:

p = Polygon([(0, 0, 0), (1, 0, 0), (1, 1, 0)])
l = LineString([(0, 0, 0), (1, 0, 0)])
is_left(p, l)

wird diesen Fehler geben:

AttributeError                            Traceback (most recent call last)
~/miniconda3/lib/python3.7/site-packages/shapely/speedups/_speedups.pyx in shapely.speedups._speedups.geos_linearring_from_py()

AttributeError: 'list' object has no attribute '__array_interface__'

During handling of the above exception, another exception occurred:

IndexError                                Traceback (most recent call last)
<ipython-input-55-555b9e2533fa> in <module>()
----> 1 is_left(p, l)

<ipython-input-52-7fad75b19ce3> in is_left(polygon, line)
      6     https://stackoverflow.com/questions/50393718/determine-the-left-and-right-side-of-a-split-shapely-geometry
      7     """
----> 8     ring = LinearRing([*line.coords, *polygon.centroid.coords])
      9     return ring.is_ccw

~/miniconda3/lib/python3.7/site-packages/shapely/geometry/polygon.py in __init__(self, coordinates)
     51         BaseGeometry.__init__(self)
     52         if coordinates is not None:
---> 53             self._set_coords(coordinates)
     54 
     55     <strong i="18">@property</strong>

~/miniconda3/lib/python3.7/site-packages/shapely/geometry/polygon.py in _set_coords(self, coordinates)
     66     def _set_coords(self, coordinates):
     67         self.empty()
---> 68         ret = geos_linearring_from_py(coordinates)
     69         if ret is not None:
     70             self._geom, self._ndim = ret

~/miniconda3/lib/python3.7/site-packages/shapely/speedups/_speedups.pyx in shapely.speedups._speedups.geos_linearring_from_py()

IndexError: tuple index out of range

Dies liegt daran, dass der Schwerpunkt von Polygon immer in 2D (https://github.com/Toblerity/Shapely/issues/554) zurückgegeben wird und ein LinearRing dies nicht kann aus Punkten konstruiert werden, die eine unterschiedliche Anzahl von Dimensionen haben.

Wenn es eine drop_z -Methode gäbe, würde ich einfach ring = LinearRing([*line.drop_z.coords, *polygon.centroid.coords]) schreiben, anstatt den Code mit Dingen wie line = LineString([xy[:2] for xy in list(line.coords)]) zu überladen oder eine Funktion dafür zu implementieren. Oder noch besser, ich würde die redundante dritte Dimension, die nur aus Nullen besteht, aus dem ursprünglichen übergeordneten Polygon löschen, das ich aus einer Datei auf der obersten Ebene gelesen habe, sodass alle untergeordneten Geometrien nur zwei Dimensionen hätten.


Formschöne Version: 1.6.4.post1, installiert von conda.

wontfix

Hilfreichster Kommentar

Für andere Leute, die von Google hierher kommen, habe ich eine sehr einfache Methode gefunden:

def _to_2d(x, y, z):
    return tuple(filter(None, [x, y]))

new_shape = shapely.ops.transform(_to_2d, shape)

(Dank an @feenster und @hunt3ri von https://github.com/hotosm/tasking-manager/blob/master/server/services/grid/grid_service.py :heart:)

Alle 3 Kommentare

@ LostFan123 Ich denke, eine Methode zum Löschen von Z-Werten wäre eine angemessene Ergänzung für 1.7. Danke für den Vorschlag.

Für andere Leute, die von Google hierher kommen, habe ich eine sehr einfache Methode gefunden:

def _to_2d(x, y, z):
    return tuple(filter(None, [x, y]))

new_shape = shapely.ops.transform(_to_2d, shape)

(Dank an @feenster und @hunt3ri von https://github.com/hotosm/tasking-manager/blob/master/server/services/grid/grid_service.py :heart:)

Ich werde dieses Problem zugunsten der obigen 2-Linien-Lösung schließen. Danke @Juanlu001 !

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen