4 votos

No se puede correctamente recorrer IFeatureCursor (llamadas de ArcObjects de Python)

He comenzado recientemente a través de algunos de los ArcObjects dentro de mi módulos de Python. Tener todos los útiles posts e ideas compartidas por @matt wilkie et al, yo era capaz de conseguir comenzó muy rápidamente (la instalación de la comtypes con el pip y la descarga de la 10.2 fragmento de Pierssen y cambiar "10.2" a "10.3" en todas partes).

Estoy tratando de recorrer IFeatureCursor y obtener todas las características dentro de una clase de entidad. Sin embargo, me estoy volviendo sólo la última función (con el mayor valor de ObjectID).

Hay 6 características de la clase de entidad de ahí xrange(6) de mantenerlo simple.

from comtypes.client import GetModule, CreateObject
from snippets102 import GetStandaloneModules, InitStandalone

# First time through, need to import the "StandaloneModules". Can comment out later.
#GetStandaloneModules()
InitStandalone()

def iterate_features():

    # Get the GDB module
    esriGeodatabase = GetModule(r"C:\Program Files (x86)\ArcGIS\Desktop10.3\com\esriGeoDatabase.olb")
    esriDataSourcesGDB = GetModule(r"C:\Program Files (x86)\ArcGIS\Desktop10.3\com\esriDataSourcesGDB.olb")

    # Create a file geodatabase pointer
    file_gdb_pointer = CreateObject(progid=esriDataSourcesGDB.FileGDBWorkspaceFactory,
                                    interface=esriGeodatabase.IWorkspaceFactory)

    file_gdb = file_gdb_pointer.OpenFromFile(r"C:\GIS\arcobjects\MyData.gdb",hWnd=0)

    #access contents inside gdb
    feature_workspace = file_gdb.QueryInterface(esriGeodatabase.IFeatureWorkspace)

    in_fc = feature_workspace.OpenFeatureClass("Warehouses")

    def enum_features(in_fc):
        """returns pointers to IFeature objects inside Feature Class"""
        cur = in_fc.Search(None,True)
        for i in xrange(6):
            feature_obj = yield cur.NextFeature()

    feats = [feat for feat in enum_features(in_fc)]
    print [f.OID for f in feats]

iterate_features()

La línea print [f.OID for f in feats] devuelve [6, 6, 6, 6, 6, 6].

¿Qué estoy haciendo mal? La misma lógica con generador/rendimiento (def enum_features()) funciona bien cuando se itera clases de entidad dentro del dataset de entidades.

el feats_OIDs = [feat.OID for feat in enum_features(in_fc)] va a dar resultados correctos, [1, 2, 3, 4, 5, 6], sin realizar ninguna modificación en el código. El problema parece estar en que cuando hago una lista de características [feat for feat in enum_features(in_fc)], todos ellos se refieren a la misma función (porque cuando voy a explorar cada uno de ellos más tarde, cada uno de ellos tienen el mismo OID).

3voto

steveax Puntos 316

Creo que un mejor enfoque puede ser para obtener el número de primer uso de la FeatureCount() método de la IFeatureClass Interfaz. Esto funcionó para mí:

import arcobjects # my copy of snippets
from comtypes.client import CreateObject
import os

pars = r'C:\TEMP\frontage_test.gdb\parcels'
fc = arcobjects.OpenFeatureClass(*os.path.split(pars))

def enum_features(fc):
    import comtypes.gen.esriGeoDatabase as esriGeoDatabase
    qf = CreateObject(progid=esriGeoDatabase.QueryFilter, interface=esriGeoDatabase.IQueryFilter) #can use NewObj here too if you have it in your snippets
    count = fc.FeatureCount(qf)
    cur = fc.Search(qf, True)
    for i in xrange(count):
        yield cur.NextFeature()


for ft in enum_features(fc):
    print ft.OID

Y desde mi arcobjects módulo, este es mi OpenFeatureClass() función:

def OpenFeatureClass(sFileGDB, sFCName):
    InitStandalone()
    import comtypes.gen.esriGeoDatabase as esriGeoDatabase
    import comtypes.gen.esriDataSourcesGDB as esriDataSourcesGDB
    pWSF = NewObj(esriDataSourcesGDB.FileGDBWorkspaceFactory, \
                  esriGeoDatabase.IWorkspaceFactory2)
    pWS = pWSF.OpenFromFile(sFileGDB, 0)
    pFWS = CType(pWS, esriGeoDatabase.IFeatureWorkspace)

    # determine if FC exists before attempting to open
    # http://edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/IWorkspace2_NameExists.htm
    #   5 = feature class datatype
    pWS2 = CType(pWS, esriGeoDatabase.IWorkspace2)
    if pWS2.NameExists(5, sFCName):
        pFC = pFWS.OpenFeatureClass(sFCName)
    else:
        pFC = None
        print '** %s not found' % sFCName

    return pFC

EDITAR

@Alex Tereshenkov planteó la cuestión de cómo conseguir esto en una lista de punteros a IFeature objetos, y esto se puede hacer con una lista de comprensión. Así que la respuesta es sí.

>>> features = [ft for ft in enum_features(fc)]
>>> features[:5] # lots of features, so lets just show the first few
[<POINTER(IFeature) ptr=0x2b2d930 at 2c13440>, <POINTER(IFeature) ptr=0x2b2d930 at 2c13490>, <POINTER(IFeature) ptr=0x2b2d930 at 32f5210>, <POINTER(IFeature) ptr=0x2b2d930 at 32f5260>, <POINTER(IFeature) ptr=0x2b2d930 at 32f52b0>]
>>> 

EDIT 2:

He encontrado el problema. Realmente no quieren reciclar las filas. Una vez que he cambiado que a false, podemos salir cada IFeature en una lista.

cur = fc.Search(None, False) #do not recycle this IFeature object!

Así que ahora al hacer esto usted debe obtener un objeto para cada fila:

features = [ft for ft in enum_features(fc)]
print [ft.OID for ft in features[:5]]

Este se presenta en la ayuda de google docs:

El reciclaje de los controles de parámetros de la fila objeto de asignación de comportamiento. El reciclaje de los cursores rehidratar una sola característica del objeto en cada captura y puede ser usado para optimizar el acceso sólo de lectura, por ejemplo, al dibujar. Es ilegal para mantener una referencia a un objeto de función devuelve un reciclaje cursor a través de varias llamadas a NextFeature en el cursor. Características devuelto por un reciclaje cursor no debe ser modificado. No reciclaje de los cursores de retorno de una función independiente del objeto en cada captura. Las características devuelto por un no-reciclaje de cursor puede ser modificado y almacena con el comportamiento polimórfico.

La Geodatabase garantiza "la única instancia de la semántica", en la no reciclaje característica de los objetos recuperados durante una sesión de edición. En otras palabras, si la característica recuperados por la búsqueda de cursor ya ha sido crea una instancia y se hace referencia a la aplicación de llamada, a continuación, una referencia a la característica existente objeto es devuelto.

No característica de reciclaje cursores devuelto por la Búsqueda método DEBE se utiliza cuando las funciones de copia, desde el cursor en una inserción del cursor de otra clase. Esto es debido a un reciclaje cursor vuelve a utilizar el mismo la geometría y, en algunas circunstancias todas las características que se inserta en la inserción del cursor puede tener la misma geometría. El uso de un no reciclaje cursor se asegura de que cada geometría es único.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X