¿Dividir shapefile por función en Python usando GDAL?

15

¿Es posible dividir un archivo de forma por función en Python? (Lo mejor sería una solución donde pueda guardar temporalmente los objetos vectoriales resultantes en la memoria en lugar de en el disco).

La razón: quiero usar la función gdal rasterizeLayer con varios subconjuntos diferentes de shapefile. La función requiere un objeto osgeo.ogr.Layer.


mkay, intenté un poco y podría funcionar de la siguiente manera. Puede obtener la geometría de los objetos de capa de gdal por entidad de la siguiente manera.

#  Load shape into gdal
shapefile=str(vectorPath)
layer_source = ogr.Open(shapefile)
lyr = layer_source.GetLayer(0)
for i in range(0,lyr.GetFeatureCount()):
     feat = lyr.GetFeature(i)
     ge = feat.geometry()

Ahora solo necesito saber cómo crear un objeto osgeo.ogr.layer basado en esta geometría.


Para aclaraciones Necesito una función en código simple ogr / gdal! Esto parece ser de cierto interés para otras personas también y todavía quiero una solución sin ningún módulo secundario (aunque cualquier solución que provenga de aquí se usará en un complemento qgis disponible de forma gratuita).

Zarapito
fuente

Respuestas:

7

OK, así que un segundo intento de responder a su pregunta con una solución GDAL pura.

En primer lugar, GDAL (Biblioteca de abstracción de datos geoespaciales) era originalmente solo una biblioteca para trabajar con datos geoespaciales ráster, mientras que la biblioteca separada de OGR estaba destinada a trabajar con datos vectoriales. Sin embargo, las dos bibliotecas ahora están parcialmente fusionadas, y generalmente se descargan e instalan juntas bajo el nombre combinado de GDAL. Entonces la solución realmente cae bajo OGR. Tienes esto en tu código inicial, así que supongo que lo sabías, pero es una distinción importante para recordar al buscar consejos y sugerencias.

Para leer datos de una capa vectorial, su código inicial está bien:

from osgeo import ogr
shapefile = ogr.Open(shapefile)
layer = shapefile.GetLayer(0)

for i in range(layer.GetFeatureCount()):
    feature = layer.GetFeature(i)
    name = feature.GetField("NAME")
    geometry = feature.GetGeometryRef()
    print i, name, geometry.GetGeometryName()

Necesitamos crear una nueva característica antes de poder escribirla en un archivo de forma (o cualquier otro conjunto de datos vectoriales). Para crear una nueva entidad, primero necesitamos: - Una geometría - Una definición de entidad, que probablemente incluirá definiciones de campo. Use el constructor Geometry ogr.Geometry () para crear un objeto Geometry vacío. Defina cuál es la geometría de una manera diferente para cada tipo (punto, línea, polígono, etc.). Así por ejemplo:

point = ogr.Geometry(ogr.wkbPoint)
point.AddPoint(10,20)

o

line = ogr.Geometry(ogr.wkbLineString)
line.AddPoint(10,10)
line.AddPoint(20,20)
line.SetPoint(0,30,30) #(10,10) -> (30,30)

Para una definición de campo

fieldDefn = ogr.FieldDefn('id', ogr.OFTInteger)

Ahora puedes crear tu capa vectorial. En este caso, un polígono cuadrado:

#create simple square polygon shapefile:
from osgeo import ogr
driver = ogr.GetDriverByName('ESRI Shapefile')

datasource = driver.CreateDataSource('YOUR_PATH')
layer = datasource.CreateLayer('layerName',geom_type=ogr.wkbPolygon)

#create polygon object:
myRing = ogr.Geometry(type=ogr.wkbLinearRing)
myRing.AddPoint(0.0, 0.0)     #LowerLeft
myRing.AddPoint(0.0, 10.0)    #UpperLeft
myRing.AddPoint(10.0, 10.0)   #UpperRight
myRing.AddPoint(10.0, 0.0)    #Lower Right
myRing.AddPoint(0.0, 0.0)     #close ring
myPoly = ogr.Geometry(type=ogr.wkbPolygon)
myPoly.AddGeometry(myRing)
print ('Polygon area =',myPoly.GetArea())  #returns correct area of 100.0

#create feature object with point geometry type from layer object:
feature = ogr.Feature( layer.GetLayerDefn())
feature.SetGeometry(myPoly)
layer.CreateFeature(feature)

#flush memory - very important
feature.Destroy()
datasource.Destroy()
Dan
fuente
gracias Dan! Tomé un enfoque diferente y mi complemento QGIS ya es funcional (con respecto a las consultas espaciales de datos ráster). En lugar de dividir, creé un subconjunto del ráster subyacente. Puede encontrar un caso de uso en mi blog ( tinyurl.com/cy6hs9q ). Su respuesta resuelve la pregunta original, si quiero dividir y guardar temporalmente las características vectoriales.
Curlew
5

He tenido suerte leyendo y escribiendo en capas. Específicamente, tengo un código que leerá una capa de archivo de forma que contiene polilíneas y generará la geometría de cada entidad en archivos de texto (utilizados como entrada para un modelo antiguo).

name     = layer.name()
provider = layer.dataProvider()
feat     = QgsFeature()

# Now we can loop through all the defined features
while provider.nextFeature(feat):

    # Get layer attributes               
    attrs = feat.attributeMap()
    for (k,attr) in attrs.iteritems():
        if k == 0:
            attrOne = attr.toString()
        elif k == 1:
            attrTwo = attr.toString()
        ...

    # Gets the geometry of the feature
    geom = feat.geometry()

    # Get the coordinates of the whole line [or use asPoint()]                    
    line = geom.asPolyline()
        # all points in the line
        for point in line:
            lat = point[0]
            lon = point[1]
            # Add these to a QgsGeometry
            your_Own_QgsGeometry.add...

Parece que podría ser útil obtener cada una de las características de sus capas.

Escribir en otra capa no debería ser demasiado complejo desde aquí. Algo como esto debería funcionar en teoría:

# New layer name
filename = "myNewLayer.shp"

# define fields for feature attributes
fields   = { 0 : QgsField("attrOne", QVariant.String),
             1 : QgsField("attrTwo", QVariant.String),
             2 : QgsField("...", QVariant.Int) }

# Create coordinate reference system as WGS84
crs    = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.PostgisCrsId)

# Create the vector layer
writer = QgsVectorFileWriter(filename, "CP1250", fields, QGis.WKBLineString, crs)

# Create some features
feat = QgsFeature()
feat.addAttribute(0, QVariant(runway))
feat.addAttribute(1, QVariant(arriveDepart))
feat.addAttribute(2, QVariant(subTrack))

# Add your geometry
feat.setGeometry(your_Own_QgsGeometry)

# Add the features
writer.addFeature(feat)

# Add it to QGIS project
self.iface.addVectorLayer(filename, "MyLayerName", "ogr")

Desde aquí, debería poder obtener datos de cada entidad y escribir nuevas entidades en una nueva capa.

Dan

Dan
fuente
Hey gracias. Algunas partes de su código serán útiles, si quiero escribir atributos en mis formas. Sin embargo, como mencioné anteriormente, solo estoy usando gdal (específicamente la función gdal.RasterizeFunction) y, a menos que alguien sepa cómo convertir un objeto QgsVectorLayer en un objeto gdal y viceversa, esta pregunta aún no se ha resuelto.
Curlew
No mencionó que necesita hacer esto con QGIS. su ejemplo inicial parece ser simple vainilla ogr.
DavidF
Quiero hacer esto en QGIS (lo necesito como una función para un complemento QGIS), pero sin depender de los módulos QGIS.core. Por lo tanto, necesito la solución en formato simple. Dan respondió porque mencioné en otra publicación que este código es para un complemento QGIS.
Curlew