Shapely: 3์ฐจ์› ๋“œ๋กญ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

์— ๋งŒ๋“  2019๋…„ 05์›” 05์ผ  ยท  3์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: Toblerity/Shapely

3D ์ง€์˜ค๋ฉ”ํŠธ๋ฆฌ๋ฅผ 2D๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ GIS Stack Exchange์— ๋Œ€ํ•œ ์˜ค๋ž˜๋œ ์งˆ๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค: Convert 3D WKT to 2D Shapely Geometry . ์ด ๊ธฐ๋Šฅ์€ Shapely์— ํฌํ•จ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

๋‚˜๋Š” ๋‹ต๋ณ€ ์ค‘ ํ•˜๋‚˜์™€ ๋ฌธ์„œ์—์„œ 3์ฐจ์› ์ด _๊ธฐํ•˜ํ•™์  ๋ถ„์„์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— _์ด ์ž‘์—…์ด ํ•„์š”ํ•˜์ง€ ์•Š์Œ _์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ถ„ํ•  ์ง€์˜ค๋ฉ”ํŠธ๋ฆฌ์˜ ์™ผ์ชฝ์„ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด ์ž์ฒด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ(์•„์ง ๊ตฌํ˜„๋˜์ง€ ์•Š์Œ: 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]) ๋งŒ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋˜๋Š” ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ตœ์ƒ์œ„ ์ˆ˜์ค€์˜ ํŒŒ์ผ์—์„œ ์ฝ์€ ์›๋ž˜ ์ƒ์œ„ ๋‹ค๊ฐํ˜•์˜ 0์œผ๋กœ๋งŒ ๊ตฌ์„ฑ๋œ ์ค‘๋ณต 3์ฐจ์›์„ ์‚ญ์ œํ•˜์—ฌ ๋ชจ๋“  ํ•˜์œ„ ๋„ํ˜•์ด 2์ฐจ์›๋งŒ ๊ฐ–๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.


Shapely ๋ฒ„์ „: 1.6.4.post1, conda์—์„œ ์„ค์น˜๋จ.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

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 :heart:์—์„œ @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 :heart:์—์„œ @feenster ๋ฐ @hunt3ri ์— ๋Œ€ํ•œ ํฌ๋ ˆ๋”ง)

์œ„์˜ 2์ค„ ์†”๋ฃจ์…˜์„ ์œ„ํ•ด ์ด ๋ฌธ์ œ๋ฅผ ๋งˆ๋ฌด๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. @Juanlu001 ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰