Shapely: рддреАрд╕рд░рд╛ рдЖрдпрд╛рдо рдЫреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝реЗрдВ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 5 рдордИ 2019  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: Toblerity/Shapely

3D рдЬреНрдпрд╛рдорд┐рддрд┐ рдХреЛ 2D рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ GIS рд╕реНрдЯреИрдХ рдПрдХреНрд╕рдЪреЗрдВрдЬ рдкрд░ рдПрдХ рдкреБрд░рд╛рдирд╛ рдкреНрд░рд╢реНрди рд╣реИ: 3D WKT рдХреЛ 2D рд╢реЗрдкрд▓реА рдЬреНрдпреЛрдореЗрдЯреНрд░реА рдореЗрдВ рдХрдирд╡рд░реНрдЯ рдХрд░реЗрдВ ред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рд╢реЗрдкрд▓реА рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рддрд╛рдХрд┐ рд╣рдо рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХреЗрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬреИрд╕реЗ:

>>> 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))'

рдореИрдВрдиреЗ рдПрдХ рдЙрддреНрддрд░ рдореЗрдВ рдФрд░ рдбреЙрдХреНрд╕ рдореЗрдВ рджреЗрдЦрд╛ рд╣реИ рдХрд┐ _рдпрд╣ рдСрдкрд░реЗрд╢рди рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ_ рдХреНрдпреЛрдВрдХрд┐ рддреАрд╕рд░рд╛ рдЖрдпрд╛рдо _рдЬреНрдпрд╛рдорд┐рддреАрдп рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдкрд░ рдХреЛрдИ рдкреНрд░рднрд╛рд╡ рдирд╣реАрдВ рдбрд╛рд▓рддрд╛ рд╣реИ ред рд▓реЗрдХрд┐рди рдПрдХ рд╡рд┐рднрд╛рдЬрд┐рдд рдЬреНрдпрд╛рдорд┐рддрд┐ рдХреЗ рдмрд╛рдИрдВ рдУрд░ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдХрд╛рд░реНрдп рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╕рдордп (рдпрд╣ рдЕрднреА рддрдХ рд▓рд╛рдЧреВ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ: https://github.com/Toblerity/Shapely/issues/589), рдореИрдВрдиреЗ рджреЗрдЦрд╛ рдХрд┐ рдпрд╣ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛рдо рдЖ рд╕рдХрддреА рд╣реИ:

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

рдпрд╣ рдХреЛрдб 3D рдЬреНрдпрд╛рдорд┐рддрд┐ рдХреЗ рд▓рд┐рдП рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рдПрдЧрд╛:

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

рдпрд╣ рддреНрд░реБрдЯрд┐ рджреЗрдЧрд╛:

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

рдпрд╣ рдЗрд╕ рддрдереНрдп рдХреЗ рдХрд╛рд░рдг рд╣реИ рдХрд┐ Polygon рдХрд╛ рдХреЗрдВрджреНрд░рдХ рд╣рдореЗрд╢рд╛ 2D (https://github.com/Toblerity/Shapely/issues/554) рдореЗрдВ рд▓реМрдЯрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ LinearRing рдРрд╕рд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╡рд┐рднрд┐рдиреНрди рдЖрдпрд╛рдореЛрдВ рд╡рд╛рд▓реЗ рдмрд┐рдВрджреБрдУрдВ рд╕реЗ рдирд┐рд░реНрдорд╛рдг рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдпрджрд┐ рдХреЛрдИ drop_z рд╡рд┐рдзрд┐ рд╣реЛрддреА, рддреЛ рдореИрдВ рдХреЛрдб рдХреЛ line = LineString([xy[:2] for xy in list(line.coords)]) рдЬреИрд╕реА рдЪреАрдЬрд╝реЛрдВ рдХреЗ рд╕рд╛рде рдЕрд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ рдпрд╛ рдЙрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдХреЗрд╡рд▓ ring = LinearRing([*line.drop_z.coords, *polygon.centroid.coords]) рд▓рд┐рдЦрддрд╛ред рдпрд╛ рдЗрд╕рд╕реЗ рднреА рдмреЗрд╣рддрд░, рдореИрдВ рдореВрд▓ рдорд╛рддрд╛-рдкрд┐рддрд╛ рдмрд╣реБрднреБрдЬ рд╕реЗ рдХреЗрд╡рд▓ рд╢реВрдиреНрдп рд╕реЗ рдорд┐рд▓рдХрд░ рддреАрд╕рд░реЗ рдЖрдпрд╛рдо рдХреЛ рдЫреЛрдбрд╝ рджреВрдВрдЧрд╛, рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рд╢реАрд░реНрд╖ рд╕реНрддрд░ рдкрд░ рдПрдХ рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдкрдврд╝рд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╕рднреА рдмрд╛рд▓ рдЬреНрдпрд╛рдорд┐рддрд┐ рдореЗрдВ рдХреЗрд╡рд▓ 2 рдЖрдпрд╛рдо рд╣реЛрдВрдЧреЗред


рд╕реБрдбреМрд▓ рд╕рдВрд╕реНрдХрд░рдг: 1.6.4.post1, рдХреЛрдВрдбрд╛ рд╕реЗ рд╕реНрдерд╛рдкрд┐рддред

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

Google рд╕реЗ рдпрд╣рд╛рдВ рдЖрдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреНрдп рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП, рдореБрдЭреЗ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рд╡рд┐рдзрд┐ рдорд┐рд▓реА:

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

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

(https://github.com/hotosm/tasking-manager/blob/master/server/services/grid/grid_service.py рд╕реЗ @feenster рдФрд░ @hunt3ri рдХреЛ рд╢реНрд░реЗрдп: рджрд┐рд▓ :)

рд╕рднреА 3 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

@ LostFan123 рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ Z рдорд╛рдиреЛрдВ рдХреЛ рдЫреЛрдбрд╝рдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ 1.7 рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рдЬреЛрдбрд╝ рд╣реЛрдЧрд╛ред рдЗрд╕рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред

Google рд╕реЗ рдпрд╣рд╛рдВ рдЖрдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреНрдп рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП, рдореБрдЭреЗ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рд╡рд┐рдзрд┐ рдорд┐рд▓реА:

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

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

(https://github.com/hotosm/tasking-manager/blob/master/server/services/grid/grid_service.py рд╕реЗ @feenster рдФрд░ @hunt3ri рдХреЛ рд╢реНрд░реЗрдп: рджрд┐рд▓ :)

рдореИрдВ рдЙрдкрд░реЛрдХреНрдд 2-рд▓рд╛рдЗрди рд╕рдорд╛рдзрд╛рди рдХреЗ рдкрдХреНрд╖ рдореЗрдВ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдмрдВрдж рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдВред рдзрдиреНрдпрд╡рд╛рдж @ рдЬреБрдЖрдирд▓реБ001 !

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕