هناك سؤال قديم على GIS Stack Exchange حول تحويل الأشكال الهندسية ثلاثية الأبعاد إلى 2D: تحويل WKT ثلاثي الأبعاد إلى هندسي أنيق ثنائي الأبعاد . أعتقد أنه يجب تضمين هذه الوظيفة في 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))'
لقد رأيت في إحدى الإجابات وفي المستندات أن _ هذه العملية ليست ضرورية _ لأن البعد الثالث _ ليس له تأثير على التحليل الهندسي_ . ولكن عند تنفيذ وظيفتي الخاصة لتحديد الجانب الأيسر من هندسة الانقسام (لم يتم تنفيذ ذلك بعد: 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
سيفشل هذا الرمز في الأشكال الهندسية ثلاثية الأبعاد:
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
، فسأكتب ring = LinearRing([*line.drop_z.coords, *polygon.centroid.coords])
فقط بدلاً من تكديس الكود بأشياء مثل line = LineString([xy[:2] for xy in list(line.coords)])
أو تنفيذ وظيفة لذلك. أو أفضل من ذلك ، سأقوم بإسقاط البعد الثالث الزائد الذي يتكون فقط من الأصفار من المضلع الأصلي الأصلي الذي قرأته من ملف في المستوى الأعلى ، لذلك فإن كل الأشكال الهندسية الفرعية سيكون لها بعدين فقط.
إصدار جميل: 1.6.4.post1 ، مثبت من conda.
@ 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)
(الائتمان إلى feenster و @ hunt3ri من https://github.com/hotosm/tasking-manager/blob/master/server/services/grid/grid_service.py: القلب :)
سأغلق هذه المشكلة لصالح الحل المكون من سطرين أعلاه. شكرا @ Juanlu001 !
التعليق الأكثر فائدة
بالنسبة للأشخاص الآخرين الذين يصلون إلى هنا من Google ، وجدت طريقة بسيطة جدًا:
(الائتمان إلى feenster و @ hunt3ri من https://github.com/hotosm/tasking-manager/blob/master/server/services/grid/grid_service.py: القلب :)