ใครสามารถสาธิตวิธีง่าย ๆ ในการเขียนโครงสร้างข้อมูลเรขาคณิตจากหุ่นดีไปเป็นไฟล์รูปร่างได้ ฉันสนใจรูปหลายเหลี่ยมโดยเฉพาะอย่างยิ่งกับรูและ linestrings มันจะมีประโยชน์ถ้าอยู่ห่างจาก arcpy (เช่น osgeo, pyshp เป็นต้นจะดีกว่า)
ใครสามารถสาธิตวิธีง่าย ๆ ในการเขียนโครงสร้างข้อมูลเรขาคณิตจากหุ่นดีไปเป็นไฟล์รูปร่างได้ ฉันสนใจรูปหลายเหลี่ยมโดยเฉพาะอย่างยิ่งกับรูและ linestrings มันจะมีประโยชน์ถ้าอยู่ห่างจาก arcpy (เช่น osgeo, pyshp เป็นต้นจะดีกว่า)
คำตอบ:
ไบนารีที่รู้จักกันดีคือรูปแบบการแลกเปลี่ยนไบนารีที่ดีที่สามารถแลกเปลี่ยนกับซอฟต์แวร์ GIS มากมายรวมถึง Shapely และ GDAL / OGR
นี่เป็นตัวอย่างเล็ก ๆของเวิร์กโฟลว์ด้วยosgeo.ogr
:
from osgeo import ogr
from shapely.geometry import Polygon
# Here's an example Shapely geometry
poly = Polygon([(0, 0), (0, 1), (1, 1), (0, 0)])
# Now convert it to a shapefile with OGR
driver = ogr.GetDriverByName('Esri Shapefile')
ds = driver.CreateDataSource('my.shp')
layer = ds.CreateLayer('', None, ogr.wkbPolygon)
# Add one attribute
layer.CreateField(ogr.FieldDefn('id', ogr.OFTInteger))
defn = layer.GetLayerDefn()
## If there are multiple geometries, put the "for" loop here
# Create a new feature (attribute and geometry)
feat = ogr.Feature(defn)
feat.SetField('id', 123)
# Make a geometry, from Shapely object
geom = ogr.CreateGeometryFromWkb(poly.wkb)
feat.SetGeometry(geom)
layer.CreateFeature(feat)
feat = geom = None # destroy these
# Save and close everything
ds = layer = feat = geom = None
อัปเดต : แม้ว่าผู้โพสต์จะตอบรับ GDAL / OGR แต่นี่เป็นสิ่งที่เทียบเท่ากับFiona :
from shapely.geometry import mapping, Polygon
import fiona
# Here's an example Shapely geometry
poly = Polygon([(0, 0), (0, 1), (1, 1), (0, 0)])
# Define a polygon feature geometry with one attribute
schema = {
'geometry': 'Polygon',
'properties': {'id': 'int'},
}
# Write a new Shapefile
with fiona.open('my_shp2.shp', 'w', 'ESRI Shapefile', schema) as c:
## If there are multiple geometries, put the "for" loop here
c.write({
'geometry': mapping(poly),
'properties': {'id': 123},
})
(หมายเหตุผู้ใช้ Windows: คุณไม่มีข้อแก้ตัว )
ฉันออกแบบฟิโอน่าให้ทำงานได้ดีกับหุ่นดี นี่เป็นตัวอย่างง่ายๆของการใช้ร่วมกันเพื่อคุณสมบัติ "ล้าง" รูปร่างไฟล์:
import logging
import sys
from shapely.geometry import mapping, shape
import fiona
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
with fiona.open('docs/data/test_uk.shp', 'r') as source:
# **source.meta is a shortcut to get the crs, driver, and schema
# keyword arguments from the source Collection.
with fiona.open(
'with-shapely.shp', 'w',
**source.meta) as sink:
for f in source:
try:
geom = shape(f['geometry'])
if not geom.is_valid:
clean = geom.buffer(0.0)
assert clean.is_valid
assert clean.geom_type == 'Polygon'
geom = clean
f['geometry'] = mapping(geom)
sink.write(f)
except Exception, e:
# Writing uncleanable features to a different shapefile
# is another option.
logging.exception("Error cleaning feature %s:", f['id'])
จากhttps://github.com/Toblerity/Fiona/blob/master/examples/with-shapely.py
นอกจากนี้คุณยังสามารถเขียนรูปทรงหุ่นดีโดยใช้ PyShp (เนื่องจากโปสเตอร์ต้นฉบับถามเกี่ยวกับ PyShp ด้วย)
วิธีหนึ่งก็คือการแปลงรูปทรงเรขาคณิตของคุณให้เป็นรูปแบบ geojson (ด้วยวิธี shapely.geometry.mapping) จากนั้นใช้ส้อม PyShpที่แก้ไขของฉันซึ่งมีวิธีนักเขียนที่ยอมรับพจนานุกรมรูปทรงเรขาคณิตของ geojson เมื่อเขียนเป็นรูปร่างไฟล์
หากคุณต้องการพึ่งพารุ่น PyShp หลักฉันยังได้จัดให้มีฟังก์ชั่นการแปลงด้านล่าง:
# THIS FUNCTION CONVERTS A GEOJSON GEOMETRY DICTIONARY TO A PYSHP SHAPE OBJECT
def shapely_to_pyshp(shapelygeom):
# first convert shapely to geojson
try:
shapelytogeojson = shapely.geometry.mapping
except:
import shapely.geometry
shapelytogeojson = shapely.geometry.mapping
geoj = shapelytogeojson(shapelygeom)
# create empty pyshp shape
record = shapefile._Shape()
# set shapetype
if geoj["type"] == "Null":
pyshptype = 0
elif geoj["type"] == "Point":
pyshptype = 1
elif geoj["type"] == "LineString":
pyshptype = 3
elif geoj["type"] == "Polygon":
pyshptype = 5
elif geoj["type"] == "MultiPoint":
pyshptype = 8
elif geoj["type"] == "MultiLineString":
pyshptype = 3
elif geoj["type"] == "MultiPolygon":
pyshptype = 5
record.shapeType = pyshptype
# set points and parts
if geoj["type"] == "Point":
record.points = geoj["coordinates"]
record.parts = [0]
elif geoj["type"] in ("MultiPoint","Linestring"):
record.points = geoj["coordinates"]
record.parts = [0]
elif geoj["type"] in ("Polygon"):
record.points = geoj["coordinates"][0]
record.parts = [0]
elif geoj["type"] in ("MultiPolygon","MultiLineString"):
index = 0
points = []
parts = []
for eachmulti in geoj["coordinates"]:
points.extend(eachmulti[0])
parts.append(index)
index += len(eachmulti[0])
record.points = points
record.parts = parts
return record
เพียงแค่คัดลอกและวางฟังก์ชั่นไปยังสคริปต์ของคุณและเรียกใช้เพื่อแปลงรูปทรงเรขาคณิตของคุณให้เป็นรูปแบบที่รองรับ pyshp หากต้องการบันทึกคุณเพียงเพิ่มรูปร่าง pyshp ที่ได้แต่ละรายการลงในรายการ. file รูปร่างของผู้ใช้ของอินสแตนซ์ (ตัวอย่างเช่นดูสคริปต์ทดสอบที่ด้านล่างของโพสต์นี้)
อย่างไรก็ตามโปรดทราบ: ฟังก์ชั่นจะไม่จัดการกับหลุมรูปหลายเหลี่ยมภายในใด ๆ หากมีมันจะไม่สนใจมัน แน่นอนว่ามันเป็นไปได้ที่จะเพิ่มฟังก์ชั่นนั้นในฟังก์ชั่น แต่ฉันก็ยังไม่ได้ใส่ใจ ข้อเสนอแนะหรือแก้ไขเพื่อปรับปรุงฟังก์ชั่นยินดีต้อนรับ :)
นี่คือสคริปต์ทดสอบแบบสแตนด์อโลนเต็มรูปแบบ:
### HOW TO SAVE SHAPEFILE FROM SHAPELY GEOMETRY USING PYSHP
# IMPORT STUFF
import shapefile
import shapely, shapely.geometry
# CREATE YOUR SHAPELY TEST INPUT
TEST_SHAPELYSHAPE = shapely.geometry.Polygon([(133,822),(422,644),(223,445),(921,154)])
#########################################################
################## END OF USER INPUT ####################
#########################################################
# DEFINE/COPY-PASTE THE SHAPELY-PYSHP CONVERSION FUNCTION
def shapely_to_pyshp(shapelygeom):
# first convert shapely to geojson
try:
shapelytogeojson = shapely.geometry.mapping
except:
import shapely.geometry
shapelytogeojson = shapely.geometry.mapping
geoj = shapelytogeojson(shapelygeom)
# create empty pyshp shape
record = shapefile._Shape()
# set shapetype
if geoj["type"] == "Null":
pyshptype = 0
elif geoj["type"] == "Point":
pyshptype = 1
elif geoj["type"] == "LineString":
pyshptype = 3
elif geoj["type"] == "Polygon":
pyshptype = 5
elif geoj["type"] == "MultiPoint":
pyshptype = 8
elif geoj["type"] == "MultiLineString":
pyshptype = 3
elif geoj["type"] == "MultiPolygon":
pyshptype = 5
record.shapeType = pyshptype
# set points and parts
if geoj["type"] == "Point":
record.points = geoj["coordinates"]
record.parts = [0]
elif geoj["type"] in ("MultiPoint","Linestring"):
record.points = geoj["coordinates"]
record.parts = [0]
elif geoj["type"] in ("Polygon"):
record.points = geoj["coordinates"][0]
record.parts = [0]
elif geoj["type"] in ("MultiPolygon","MultiLineString"):
index = 0
points = []
parts = []
for eachmulti in geoj["coordinates"]:
points.extend(eachmulti[0])
parts.append(index)
index += len(eachmulti[0])
record.points = points
record.parts = parts
return record
# WRITE TO SHAPEFILE USING PYSHP
shapewriter = shapefile.Writer()
shapewriter.field("field1")
# step1: convert shapely to pyshp using the function above
converted_shape = shapely_to_pyshp(TEST_SHAPELYSHAPE)
# step2: tell the writer to add the converted shape
shapewriter._shapes.append(converted_shape)
# add a list of attributes to go along with the shape
shapewriter.record(["empty record"])
# save it
shapewriter.save("test_shapelytopyshp.shp")
คำตอบของ Karim นั้นค่อนข้างเก่า แต่ฉันใช้รหัสของเขาและอยากจะขอบคุณเขา สิ่งหนึ่งที่ฉันคิดโดยใช้รหัสของเขา: ถ้าประเภทรูปร่างเป็นรูปหลายเหลี่ยมหรือหลายรูปแบบมันอาจยังมีหลายส่วน (รูด้านใน) ดังนั้นควรเปลี่ยนรหัสบางส่วนเป็น
elif geoj["type"] == "Polygon":
index = 0
points = []
parts = []
for eachmulti in geoj["coordinates"]:
points.extend(eachmulti)
parts.append(index)
index += len(eachmulti)
record.points = points
record.parts = parts
elif geoj["type"] in ("MultiPolygon", "MultiLineString"):
index = 0
points = []
parts = []
for polygon in geoj["coordinates"]:
for part in polygon:
points.extend(part)
parts.append(index)
index += len(part)
record.points = points
record.parts = parts