Suite

Impossible d'itérer correctement IFeatureCursor (appel d'ArcObjects à partir de Python)

Impossible d'itérer correctement IFeatureCursor (appel d'ArcObjects à partir de Python)


J'ai récemment commencé à utiliser certains des ArcObjects dans mes modules Python. Ayant tous les articles et informations utiles partagés par @matt wilkie et al, j'ai pu démarrer assez rapidement (installer les comtypes avec pip et télécharger l'extrait 10.2 de Pierssen et changer "10.2" en "10.3" partout).

j'essaye d'itérerIFeatureCurseuret obtenez toutes les fonctionnalités à l'intérieur d'une classe d'entités. Cependant, je ne récupère que la dernière fonctionnalité (avec la valeur ObjectID la plus élevée).

Il y a 6 entités dans la classe d'entités doncxrange(6)pour rester simple.

de comtypes.client importer GetModule, CreateObject à partir de snippets102 importer GetStandaloneModules, InitStandalone # La première fois, vous devez importer les « StandaloneModules ». Peut commenter plus tard. #GetStandaloneModules() InitStandalone() def iterate_features(): # Obtenir le module GDB esriGeodatabase = GetModule(r"C:Program Files (x86)ArcGISDesktop10.3comesriGeoDatabase.olb") esriDataSourcesGDB = GetModule(r "C:Program Files (x86)ArcGISDesktop10.3comesriDataSourcesGDB.olb") # Créer un pointeur de géodatabase fichier file_gdb_pointer = CreateObject(progid=esriDataSourcesGDB.FileGDBWorkspaceFactory, interface=esriGeodatabase.IWorkspaceOpenbromFile =) file_gdFbromFile (r"C:GISarcobjectsMyData.gdb",hWnd=0) #accéder au contenu dans gdb feature_workspace = file_gdb.QueryInterface(esriGeodatabase.IFeatureWorkspace) in_fc = feature_workspace.OpenFeatureClass("Warehouses") def enum_features(in_fc): """ renvoie des pointeurs vers des objets IFeature à l'intérieur de la classe d'entités""" 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 pour f dans feats] iterate_features()

La ligneprint [f.OID pour f dans exploits]Retour[6, 6, 6, 6, 6, 6].

Qu'est-ce que je fais mal? La même logique avec générateur/rendement (def enum_features()) fonctionne correctement lors de l'itération des classes d'entités à l'intérieur du jeu de classes d'entités.

lesfeats_OIDs = [feat.OID pour exploit dans enum_features(in_fc)]donnera des résultats corrects,[1, 2, 3, 4, 5, 6], sans que je modifie le code. Le problème semble être que lorsque je crée une liste de fonctionnalités[exploit pour exploit dans enum_features(in_fc)], ils font tous référence à la même fonctionnalité (car lorsque j'explore chacun d'eux plus tard, chacun d'eux a le même OID).


Je pense qu'une meilleure approche pourrait être d'obtenir le décompte d'abord en utilisant leNombre d'entités()méthode de laIFeatureClassInterface. Cela a fonctionné pour moi:

import arcobjects # ma copie des extraits de comtypes.client import CreateObject import os pars = r'C:TEMPfrontage_test.gdbparcels' 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 ici aussi si vous l'avez dans vos extraits 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

Et de monarcobjetsmodule, voici ma fonction OpenFeatureClass() :

def OpenFeatureClass(sFileGDB, sFCName): InitStandalone() importe comtypes.gen.esriGeoDatabase comme esriGeoDatabase importe comtypes.gen.esriDataSourcesGDB comme esriDataSourcesGDB pWSF = NewObj(esriDataSourcesGDB.FileGDBeoDatabase.FileGDBWorkspaceFactory),  SFW pFWS = CType(pWS, esriGeoDatabase.IFeatureWorkspace) # déterminez si FC existe avant d'essayer d'ouvrir # http://edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/IWorkspace2_NameExists.htm # 5 = type de données de classe d'entités pWS2 = CType (pWS, esriGeoDatabase.IWorkspace2) si pWS2.NameExists(5, sFCName) : pFC = pFWS.OpenFeatureClass(sFCName) sinon : pFC = None print '** %s not found' % sFCName return pFC

ÉDITER

@Alex Tereshenkov a soulevé la question de savoir comment intégrer cela dans une liste de pointeurs versIFonctionobjets, et cela peut être fait avec une compréhension de liste. Donc, la réponse est oui.

>>> features = [ft for ft in enum_features(fc)] >>> features[:5] # beaucoup de fonctionnalités, alors montrons juste les premières [, , , , ] >>>

EDIT 2:

J'ai trouvé le problème. Nous ne voulons pas réellement recycler les lignes. Une fois que j'ai changé cela en faux, nous pouvons sortir chacunIFonctiondans une liste.

cur = fc.Search(None, False) #ne pas recycler cet objet IFeature !

Alors maintenant, lorsque vous faites cela, vous devriez obtenir un objet pour chaque ligne :

features = [ft pour ft dans enum_features(fc)] print [ft.OID pour ft dans features[:5]]

Ceci est indiqué dans la documentation d'aide :

Le paramètre de recyclage contrôle le comportement d'allocation des objets de ligne. Les curseurs de recyclage réhydratent un seul objet caractéristique à chaque extraction et peuvent être utilisés pour optimiser l'accès en lecture seule, par exemple, lors du dessin. Il est illégal de conserver une référence sur un objet de fonctionnalité renvoyé par un curseur de recyclage sur plusieurs appels à NextFeature sur le curseur. Les fonctionnalités renvoyées par un curseur de recyclage ne doivent pas être modifiées. Les curseurs non recyclables renvoient un objet caractéristique distinct à chaque extraction. Les caractéristiques renvoyées par un curseur de non-recyclage peuvent être modifiées et stockées avec un comportement polymorphe.

La géodatabase garantit une "sémantique d'instance unique" sur les objets d'entités non recyclables récupérés lors d'une session de mise à jour. En d'autres termes, si la caractéristique récupérée par un curseur de recherche a déjà été instanciée et est référencée par l'application appelante, alors une référence à l'objet caractéristique existant est renvoyée.

Curseurs de fonction non recyclés renvoyés par la méthode de recherche DOIT être utilisé lors de la copie d'entités du curseur dans un curseur d'insertion d'une autre classe. En effet, un curseur de recyclage réutilise la même géométrie et, dans certaines circonstances, toutes les entités insérées dans le curseur d'insertion peuvent avoir la même géométrie. L'utilisation d'un curseur de non-recyclage garantit que chaque géométrie est unique.