Uzyskujesz dostęp do ArcObjects z Python?


132

Chciałbym mieć możliwość pisania skryptów niektórych rzeczy, które nie są ujawniane za pośrednictwem arcgisscriptingani ArcPy.

Jak uzyskać dostęp do ArcObjects z Python?


3
Czy ktoś zastanawia się nad zastosowaniem tych metod w środowisku produkcyjnym? Kilka lat temu na UC rozmawiałem z jednym z deweloperów ESRI C ++, który pisze większość swoich modułów Python i był zdecydowanie przeciwny używaniu IronPython w środowisku produkcyjnym - ale to było kilka lat temu.
Chad Cooper

Odpowiedzi:


113

Pobierz i zainstaluj typy *, umieść Snippetsmoduł od Mark Cederholm w PYTHONPATH i gotowe.

from snippets102 import GetLibPath, InitStandalone
from comtypes.client import GetModule, CreateObject
m = GetModule(GetLibPath() + "esriGeometry.olb")
InitStandalone()
p = CreateObject(m.Point, interface=m.IPoint)
p.PutCoords(2,3)
print p.X, p.Y

W tle zobacz prezentacje Marka Cederholma dla UberPyGeeks na temat „Korzystanie z ArcObjects w Pythonie” . Istnieją osobne perspektywy programistów VBA i C ++. Używają Visual Studio (tak, Express jest w porządku) i Windows SDK , ale nie są one wymagane, wystarczy ArcGIS, Python i typy plików.

Pobieranie modułu Snippets

* Uwaga dla wersji 10.1+ należy wprowadzić niewielką zmianę automation.pyw module comtypes. Zobacz ArcObjects + comtypes w 10.1 .


Następne kroki

... lub: mózg zwariował ? Patrząc na przykłady kodu C # sprawia, że oczy pływać i spróbuj jak to może po prostu nie można myśleć jak dźwigu ? Popatrz tutaj:


10
Zwrócono mi uwagę na ten wątek i wydaje się, że krążą wokół niego pewne nieporozumienia. NIE potrzebujesz Visual Studio ani kompilatora MIDL, aby używać ArcObjects w Pythonie; wszystko czego potrzebujesz to pakiet comtypes. Moja prezentacja obejmowała zaawansowane ćwiczenie tworzenia komponentu COM przy użyciu Pythona, ale było to przeznaczone dla UberPyGeeks. Plik snippets.py zawiera wszystkie potrzebne przykłady.

1
@ Mark, wielkie dzięki za korektę. Żeby było jasne: w powyższym przepisie można było usunąć kroki 1,3,4, o ile ctypy są już zainstalowane?
matt wilkie

2
Tak. Przetestowałem to w laboratorium. Musisz tylko zainstalować typy.
RK

@RK, świetnie! Dziękujemy za weryfikację i aktualizację odpowiedzi.
matt wilkie

1
Moduł fragmentów przekształcenie jako zainstalowania ao modułu tutaj: github.com/maphew/arcplus/tree/master/arcplus/ao (aktualizacja do 10.3, patrz poprzednie wersje pliku do 10.2). Zaktualizuje główną odpowiedź, gdy tylko zostaną usunięte niektóre błędy.
matt wilkie

32

Tak, prezentacja Marka Cederholma, o której wspomina Matt Wilkie, jest świetnym miejscem do rozpoczęcia. Przepis / kod, który przedstawia Matt, jest z pewnością sprytnym i prawdopodobnie najlepszym sposobem na załatwienie sprawy. Chciałem jednak wspomnieć o dość brutalnej metodzie, której używam w ArcGIS 10.0. Mam kilka skryptów automatyzacji (autonomicznych, poza granicami aplikacji), które uruchamiam w ten sposób i działają one dobrze. Jeśli jednak chodzi o maksymalną prędkość, możesz po prostu skorzystać z rozwiązania Matta i skończyć z nim.

Korzystam z pakietu comtypes, aby wymusić zawijanie wszystkich bibliotek ArcObjects (.olb). Następnie Python ma dostęp do wszystkich ArcObjects. Otrzymałem kod owijania od Franka Perksa poprzez post na forum ESRI . Miałem własny kod, który zasadniczo robił to samo, ale był nadęty i funkcjonalny, a jego jest ładniejszy. Więc:

import sys, os
if '[path to your Python script/module directory]' not in sys.path:
    sys.path.append('[path to your Python script/module directory]')

import comtypes
#force wrapping of all ArcObjects libraries (OLBs)
import comtypes.client
# change com_dir to whatever it is for you
com_dir = r'C:\Program Files (x86)\ArcGIS\Desktop10.0\com'
coms = [os.path.join(com_dir, x) for x in os.listdir(com_dir) if os.path.splitext(x)[1].upper() == '.OLB']
map(comtypes.client.GetModule, coms)

Następnie, prawie prosto z prezentacji Marka Cederholma:

import comtypes.gen.esriFramework

pApp = GetApp()

def GetApp():
    """Get a hook into the current session of ArcMap"""
    pAppROT = NewObj(esriFramework.AppROT, esriFramework.IAppROT)
    iCount = pAppROT.Count

    if iCount == 0:
        print 'No ArcGIS application currently running.  Terminating ...'
        return None
    for i in range(iCount):
        pApp = pAppROT.Item(i)  #returns IApplication on AppRef
        if pApp.Name == 'ArcMap':
            return pApp
    print 'No ArcMap session is running at this time.'
    return None

def NewObj(MyClass, MyInterface):
    """Creates a new comtypes POINTER object where\n\
    MyClass is the class to be instantiated,\n\
    MyInterface is the interface to be assigned"""
    from comtypes.client import CreateObject
    try:
        ptr = CreateObject(MyClass, interface=MyInterface)
        return ptr
    except:
        return None

Otóż ​​to. Powinieneś mieć pełny dostęp do ArcObjects, zaczynając od obiektu pApp, którym jest IApplication na obiekcie AppRef. Z mojego doświadczenia wynika, że ​​owijanie bibliotek ArcObjects przy pierwszym uruchomieniu nie jest obiektywnie powolne, a dla kolejnych uruchomień owijanie nie następuje. Biblioteki są już opakowane i skompilowane, więc wszystko jest znacznie szybsze.

Dodano: Jest z tym duża uwaga. Podana tutaj funkcja NewObj zakłada, że ​​skrypt Pythona jest uruchamiany w trakcie procesu. Jeśli nie, ta funkcja utworzy obiekty w procesie Pythona (tj. Poza procesem), a odwołania do obiektów będą niepoprawne. Aby tworzyć obiekty w procesie z zewnętrznego skryptu Python, należy użyć IObjectFactory. Zobacz komentarze i wskazówki Kirka Kuykendalla w tym poście do wymiany stosów, aby uzyskać więcej informacji.


1
Zaletą tego podejścia jest to, że nie wymaga instalowania programu Visual Studio, co jest dość ciężkie, jeśli jedyną rzeczą, jaką z nim zrobisz, jest zarejestrowanie obiektów com. Gdybym wiedział o tej czystej metodzie pytona, prawdopodobnie nigdy nie spróbowałbym trasy Cederholma. ;-)
matt wilkie 10.01.11

1
Rozszerzyłem nieco tę koncepcję w tej odpowiedzi, czyniąc importowanie i pakowanie bibliotek typów procesem jednoetapowym: gis.stackexchange.com/questions/5017/…
blah238

20

Jak uzyskać dostęp do obiektów Arcob z Pythona?

Jeśli szukasz konkretnej funkcjonalności, która istnieje i znajduje się w kodzie Arcobjects C ++, najlepiej założyć metody C ++, aby je wywołać .... a następnie utworzyć opakowanie Pythona, aby uzyskać dostęp do tych metod C ++.

Istnieje wiele sposobów uzyskiwania dostępu do metod C ++ z poziomu Pythona, a wiele osób korzysta z takiego narzędzia, jak SWIG, do automatycznego generowania klas Python z sygnatur metody C ++. Z mojego doświadczenia wynika, że ​​te automatycznie generowane interfejsy API stają się dość nieprzyjemne podczas przekazywania nienatywnych typów C ++ (int, float) i nigdy nie są bardzo „ pythoniczne ”.

Moim zalecanym rozwiązaniem byłoby użycie API ctypes. Świetny samouczek jest tutaj: http://python.net/crew/theller/ctypes/tutorial.html

Podstawowe kroki to:

  1. napisz trochę swojej podstawowej logiki w C ++, te, w których Twoim zdaniem wydajność Pythona może być problemem
  2. Skompiluj tę podstawową logikę (w tym przypadku przy użyciu wywołań metod ArcObject C ++ API) z plików obiektowych do współdzielonej (.so) lub biblioteki dynamicznej (.dll) przy użyciu dowolnego kompilatora systemowego (nmake, make itp.)
  3. Napisz odwzorowanie typów między klasą python a sygnaturą metody C ++ [SWIG próbuje to zautomatyzować, ale jest to łatwe, nawet przy użyciu szalonych typów obiektów]
  4. Zaimportuj skompilowaną bibliotekę do swojego programu python i użyj powiązanych powiązań klasy / metody jak każda inna klasa python!

Jest to prawdopodobnie bardziej ogólny sposób odwoływania się do kodu C / C ++ z poziomu Pythona, prawdopodobnie na dłuższą metę będzie prawdopodobnie znacznie prostszy, jeśli nie będziesz musiał zajmować się obiektami COM. Pozwoli to również, aby cała funkcjonalność specyficzna dla systemu znajdowała się w kompilacji połączonego obiektu biblioteki (więc python nie będzie specyficzny dla systemu / implementacji Pythona).


3
Jest to zdecydowanie najlepsza metoda interakcji z ArcObjects. Użycie typów jest świetne do tworzenia prototypów, ale napisanie własnego rozszerzenia C spowoduje dobry, Pythoniczny projekt (ponieważ musisz o tym pomyśleć) i lepszą wydajność, ponieważ nie przekraczasz bariery obiektowej C ++ / Python. Chociaż ze względów praktycznych jest to trudniejsze do zaprojektowania / opracowania / debugowania, więc szybkie i brudne pliki znikają z okna.
Jason Scheirer

18

Inną opcją jest użycie Pythona dla platformy .NET - jest to bardzo łatwe do skonfigurowania i może współpracować z dowolnymi bibliotekami DLL .NET, w tym ArcObjects.

Nie spotkałem się z żadnymi problemami z obiektami w trakcie procesu, a otwarcie instancji ArcMap oraz dodawanie i manipulowanie warstwami działało dla mnie dobrze.

Jedyne wymagania to folder zawierający bibliotekę Python dla .NET i standardowa instalacja Pythona.

Więcej informacji i przykładowy skrypt tutaj . Przykładowy skrypt można również zobaczyć bezpośrednio na stronie http://gist.github.com/923954

Niestety, chociaż działa to bez problemów na lokalnym komputerze programistycznym, wdrożenie go w innym miejscu wymaga zainstalowania ArcObjects SDK i Visual Studio (w tym darmowej wersji Express). Zobacz Wdrażanie bibliotek DLL ArcObject .NET


Przepis jest jasny, przejrzysty i dobrze zaprezentowany. Dzięki Geographika! Zachęcam do dołączenia do odpowiedzi minimalnego fragmentu skryptu, aby w przypadku remontu witryny odpowiedź była samodzielna.
matt wilkie

1
Właśnie to zrobiłem w tym starym wpisie na blogu ( gissolved.blogspot.com/2009/06/python-toolbox-3-pythonnet.html ) i działa zgodnie z oczekiwaniami, ale pamiętaj, aby zwrócić wyniki zrozumiałe dla skryptu Python (ciągi, liczby lub nieważne).
Samuel,


5

Jedno podejście, którego nie widzę wspomniane w innych odpowiedziach, polega na użyciu tych samych metod, których używają same biblioteki Arcpy. Np. W C: \ Program Files \ ArcGIS \ Desktop10.0 \ arcpy \ arcpy \ cartography.py widzimy Python wywołujący narzędzia ArcObjects przy użyciu niektórych poprawek i funkcji konwersji obiektów.

Nie wiem, jak dobrze jest pisać o tym tutaj, ponieważ kod mówi „TAJEMNICE HANDLOWE: ESRI WŁAŚCIWE I POUFNE”; ale znajdziesz go również w Internecie. W każdym razie wygląda to na stosunkowo łatwy sposób wywoływania funkcji, takich jak SimplifyBuilding_cartography()bez instalowania typów plików lub innych dodatkowych bibliotek.

Edytować:

Zobacz komentarze Jasona poniżej. Wygląda na to, że wykonanie powyższej czynności nie za wiele kupi.


Zauważyłem to też, wydaje się jednak, że to za dużo voodoo.
blah238,

1
Nie nazywa to w pełni odsłoniętym zestawem obiektów arkadowych.
Jason Scheirer,

@JasonScheirer, chociaż w rzeczywistości może on zapewniać większy stopień dostępu do ArcObjects (jak sądzę) niż prosty Arcpy API i ma tę zaletę, że nie wymaga instalacji innej biblioteki. To ostatnie może być ważne, jeśli opracowujesz narzędzia dla innych osób. Chciałbym poznać pełny zakres tego, do czego można uzyskać dostęp za pomocą tej metody - może być wystarczający do niektórych celów. (Nie mogę teraz sprawdzić - nie jestem w firmowej sieci LAN.)
LarsH

1
Zapewniam cię, że tak nie jest. Dużo tego opracowałem.
Jason Scheirer,

1
Nie możesz. „ArcObject” jest w tym przypadku trochę mylącą nazwą. Nie ma sposobu, aby dostać się do obiektów leżących poniżej, i nie ma powiązania COM ujawniającego wszystkie ArcObjects w dowolnym miejscu w arcgisscripting / arcpy.
Jason Scheirer
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.