Mengakses ArcObjects dari Python?

132

Saya ingin dapat skrip beberapa hal yang tidak diekspos melalui arcgisscriptingatau ArcPy.

Bagaimana cara mengakses ArcObjects dari Python?

matt wilkie
sumber
3
Adakah yang memiliki pemikiran untuk menggunakan metode ini di lingkungan produksi? Beberapa tahun yang lalu di UC saya berbicara dengan salah satu ESRI C ++ devs yang menulis sebagian besar modul Python mereka dan dia sangat menentang penggunaan IronPython dalam lingkungan produksi - tetapi itu beberapa tahun yang lalu.
Chad Cooper

Jawaban:

113

Unduh dan pasang comtypes *, masukkan Snippetsmodul dari Mark Cederholm di PYTHONPATH, dan Anda siap.

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

Untuk latar belakang lihat presentasi Mark Cederholm untuk UberPyGeeks tentang "Menggunakan ArcObjects dengan Python" . Ada yang terpisah untuk perspektif pengembang VBA dan C ++. Mereka menggunakan Visual Studio (yes Express ok) dan Windows SDK , tetapi ini tidak diperlukan, hanya ArcGIS, Python dan comtypes sudah cukup.

Mendapatkan modul Snippets

* Catatan untuk 10.1+ Anda perlu membuat perubahan kecil automation.pypada modul comtypes. Lihat ArcObjects + comtypes di 10.1 .


Langkah selanjutnya

... atau: otaknya menjadi berliku ? Melihat contoh kode c # membuat mata Anda berenang, dan berusaha sekuat tenaga Anda tidak bisa berpikir seperti burung bangau ? Lihat di sini:

matt wilkie
sumber
10
Utas ini telah menarik perhatian saya, dan tampaknya ada beberapa kesalahpahaman yang beredar. Anda TIDAK perlu Visual Studio atau kompiler MIDL untuk menggunakan ArcObjects dengan Python; yang Anda butuhkan hanyalah paket comtypes. Presentasi saya termasuk latihan lanjutan dalam membuat komponen COM menggunakan Python, tapi itu dimaksudkan untuk UberPyGeeks. File snippets.py berisi semua contoh yang Anda butuhkan.
1
@ Mark, terima kasih banyak atas koreksi. Untuk menjadi jelas: dalam resep di atas orang bisa menghapus langkah 1,3,4 selama ctypes sudah diinstal?
matt wilkie
2
Ya. Mengujinya di lab. Anda hanya perlu menginstal comtypes.
RK
@RK, bagus! Terima kasih atas verifikasi dan memperbarui jawabannya.
matt wilkie
1
Cuplikan modul menyusun kembali sebagai diinstal ao modul di sini: github.com/maphew/arcplus/tree/master/arcplus/ao (diperbarui untuk 10,3, lihat versi sebelumnya dari file untuk 10,2). Akan memperbarui jawaban utama setelah saya menyelesaikan beberapa bug.
matt wilkie
32

Ya, presentasi Mark Cederholm yang disebutkan Matt Wilkie di atas adalah tempat yang bagus untuk memulai. Resep / kode yang disajikan Matt tentu saja licin dan mungkin cara terbaik untuk menyelesaikan masalah. Saya ingin menyebutkan, metode yang agak kasar yang saya gunakan di ArcGIS 10.0. Saya memiliki beberapa skrip otomatisasi (mandiri, di luar batas aplikasi) yang saya jalankan dengan cara ini, dan mereka berfungsi dengan baik. Namun, jika kecepatan maksimum menjadi perhatian, Anda mungkin hanya pergi dengan solusi Matt dan selesai dengan itu.

Saya menggunakan paket comtypes untuk memaksa pembungkus semua perpustakaan ArcObjects (.olb). Kemudian Python memiliki akses ke semua ArcObjects. Saya mendapat kode pembungkus dari Frank Perks melalui posting forum ESRI . Saya memiliki kode sendiri yang pada dasarnya melakukan hal yang sama, tetapi itu membengkak dan hanya berfungsi, sementara itu jauh lebih cantik. Begitu:

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)

Kemudian, langsung dari presentasi Mark Cederholm:

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

Itu dia. Anda harus memiliki akses penuh ke ArcObjects yang dimulai dengan objek pApp yaitu IApplication pada objek AppRef. Dalam pengalaman saya, pembungkus pustaka ArcObjects pada proses pertama tidak terlalu lambat, dan untuk proses selanjutnya pembungkus tidak terjadi. Perpustakaan sudah dibungkus dan dikompilasi, jadi semuanya jauh lebih cepat.

Ditambahkan: Ada kehati-hatian besar yang datang dengan ini. Fungsi NewObj yang diberikan di sini mengasumsikan skrip Python sedang dijalankan dalam proses. Jika tidak, fungsi ini akan membuat objek dalam proses Python (mis. Proses out-of), dan referensi objek akan salah. Untuk membuat objek dalam proses dari skrip Python eksternal Anda harus menggunakan IObjectFactory. Lihat komentar dan tips Kirk Kuykendall dalam posting pertukaran stack ini untuk info lebih lanjut.

celticflute
sumber
1
Yang menyenangkan tentang pendekatan ini adalah tidak perlu menginstal Visual Studio, yang cukup berat jika satu-satunya hal yang pernah Anda lakukan dengannya adalah mendaftarkan objek com. Jika saya tahu tentang metode python murni ini saya kemungkinan tidak akan pernah mencoba rute Cederholm. ;-)
matt wilkie
1
Saya sedikit memperluas konsep ini dalam jawaban ini, membuat impor dan membungkus pustaka jenis satu langkah proses: gis.stackexchange.com/questions/5017/…
blah238
20

Bagaimana cara mengakses arcobjects dari python?

Jika yang Anda cari adalah fungsionalitas khusus yang ada dan ada dalam kode Arcobject C ++, maka taruhan terbaik Anda adalah membuat metode C ++ untuk memanggil mereka .... dan kemudian membuat pembungkus python untuk mengakses metode C ++ tersebut.

Ada beberapa cara untuk mengakses metode C ++ dari python, dan banyak orang yang melakukannya menggunakan alat seperti SWIG untuk secara otomatis menghasilkan kelas-kelas python dari tanda tangan metode C ++. Sudah pengalaman saya bahwa API autogenerasi ini menjadi sangat jahat ketika melewati tipe C ++ non-asli (int, float) dan tidak pernah sangat ' pythonic '.

Solusi saya yang disarankan adalah menggunakan API ctypes. Tutorial yang hebat ada di sini: http://python.net/crew/theller/ctypes/tutorial.html

Langkah-langkah dasarnya adalah:

  1. tulis beberapa logika inti Anda di C ++, yang menurut Anda kinerja python mungkin menjadi masalah
  2. Kompilasi logika inti tersebut (dalam hal ini menggunakan panggilan metode ArcObject C ++ API) dari file objek ke shared (.so) atau dynamic library (.dll) menggunakan kompiler sistem apa saja (buat, buat, dll.)
  3. Tulis pemetaan ctypes antara kelas python dan tanda tangan metode C ++ [SWIG mencoba mengotomatisasi ini, tetapi mudah, bahkan jika menggunakan tipe objek gila]
  4. Impor pustaka yang dikompilasi ke dalam program python Anda dan gunakan binding kelas / metode binding seperti kelas python lainnya!

Ini mungkin cara yang lebih umum untuk referensi kode C / C ++ dari dalam python, mungkin akan jauh lebih sederhana dalam jangka panjang jika Anda tidak harus berurusan dengan objek COM. Ini juga akan memungkinkan semua fungsionalitas sistem khusus berada dalam kompilasi objek pustaka yang ditautkan (sehingga python tidak akan menjadi sistem / implementasi python spesifik).

tmarthal
sumber
3
Ini adalah metode terbaik untuk berinteraksi dengan ArcObjects. Penggunaan comtypes sangat bagus untuk membuat prototipe tetapi menulis ekstensi C Anda sendiri akan menghasilkan desain Pythonic yang baik (karena Anda harus memikirkannya) dan kinerja yang lebih baik karena Anda tidak melewati banyak penghalang objek C ++ / Python. Meskipun untuk tujuan praktis, ini lebih sulit untuk merancang / mengembangkan / debug sehingga yang cepat dan kotor keluar jendela.
Jason Scheirer
18

Pilihan lain adalah dengan menggunakan Python untuk .NET - ini sangat mudah diatur, dan dapat bekerja dengan .NET DLL termasuk ArcObjects.

Saya tidak mengalami masalah dengan obrolan dalam proses, dan membuka instance ArcMap dan menambahkan dan memanipulasi lapisan bekerja dengan baik untuk saya.

Satu-satunya persyaratan adalah folder yang berisi Python untuk .NET library, dan instalasi Python standar.

Lebih detail dan contoh skrip di sini . Contoh skrip juga dapat dilihat langsung di http://gist.github.com/923954

Sayangnya, sementara ini bekerja tanpa masalah pada mesin pengembangan lokal, menyebarkannya di tempat lain membutuhkan ArcObjects SDK, dan Visual Studio (termasuk edisi Express gratis) untuk diinstal. Lihat Menyebarkan ArcObject. NET DLL

geografi
sumber
Resepnya jelas, jernih, dan disajikan dengan baik. Terima kasih Geographika! Saya mendorong Anda untuk memasukkan potongan skrip minimal dalam jawaban Anda, sehingga jika situs Anda mengalami renovasi, jawabannya dapat berdiri sendiri.
matt wilkie
1
Itulah yang saya lakukan di blogpost lama ini ( gissolved.blogspot.com/2009/06/python-toolbox-3-pythonnet.html ) dan berfungsi seperti yang diharapkan tetapi pastikan untuk mengembalikan hasil yang dipahami oleh skrip Python Anda (string, angka atau batal).
Samuel
5

Satu pendekatan yang saya tidak lihat disebutkan dalam jawaban lain adalah dengan menggunakan metode yang sama dengan perpustakaan arcpy sendiri. Misalnya dalam C: \ Program Files \ ArcGIS \ Desktop10.0 \ arcpy \ arcpy \ cartography.py, kita melihat Python memanggil alat ArcObjects menggunakan beberapa fixargs dan fungsi konversi objek.

Saya tidak tahu seberapa banyak yang boleh saya posting di sini, karena kode itu mengatakan "RAHASIA DAGANG: PROPRIETER ESRI DAN RAHASIA"; tetapi Anda juga akan menemukannya di tempat lain di web. Bagaimanapun, ini terlihat seperti cara yang relatif mudah untuk memanggil fungsi-fungsi seperti SimplifyBuilding_cartography()tanpa menginstal comtypes atau perpustakaan tambahan lainnya.

Sunting:

Lihat komentar Jason di bawah ini. Kedengarannya seperti melakukan di atas tidak akan membeli banyak.

Lars
sumber
Saya perhatikan itu juga, sepertinya terlalu banyak voodoo.
blah238
1
Itu tidak memanggil satu set arcobjects sepenuhnya terbuka.
Jason Scheirer
@JasonScheirer, seperti itu, tampaknya memang memungkinkan beberapa tingkat akses yang lebih besar ke ArcObjects (saya pikir) daripada API lurus busur, dan memiliki keuntungan karena tidak memerlukan instalasi perpustakaan lain. Yang terakhir dapat menjadi penting jika Anda mengembangkan alat untuk digunakan orang lain. Saya ingin mengetahui sepenuhnya apa yang dapat Anda akses melalui metode ini - mungkin cukup untuk tujuan tertentu. (Namun saya tidak dapat memeriksa sekarang - Saya tidak di LAN perusahaan.)
LarsH
1
Saya dapat meyakinkan Anda untuk fakta tidak. Saya mengembangkan banyak hal.
Jason Scheirer
1
Kamu tidak bisa. "ArcObject" sedikit keliru dalam hal ini. Tidak ada cara untuk sampai ke objek yang mendasarinya, dan tidak ada ikatan COM yang mengekspos semua ArcObject di mana saja di arcgisscripting / arcpy.
Jason Scheirer