ArcObjects'e Python'dan Erişim?


132

arcgisscriptingArcPy ya da maruz kalmadıkları bazı şeyleri kodlayabilmek istiyorum.

ArcObjects'e Python'dan nasıl erişirim ?


3
Bu yöntemleri üretim ortamlarında kullanmak isteyen var mı? Birkaç yıl önce UC'de, Python modüllerinin çoğunu yazan ESRI C ++ dev'lerden biriyle konuştum ve IronPython'u üretim ortamında kullanmaya şiddetle karşı çıktı - ama bu birkaç yıl önceydi.
Chad Cooper

Yanıtlar:


113

Comtype'leri indirin ve kurun *, SnippetsPYTHONPATH'deki Mark Cederholm'dan modülü yerleştirin ve hepiniz hazırsınız.

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

Arka plan için Mark Cederholm'un UberPyGeeks ile ilgili "Python'da ArcObjects Kullanımı" konulu sunumlarına bakın . VBA ve C ++ geliştirici perspektifleri için ayrı olanlar vardır. Visual Studio'yu kullanırlar (evet Express iyidir) ve Windows SDK'yı kullanırlar , ancak bunlar zorunlu değildir, sadece ArcGIS, Python ve comtypes yeterlidir.

Snippets modülünü alma

* 10.1+ için notautomation.py , comtypes modülünde küçük bir değişiklik yapmanız gerekir . Bkz. ArcObjects + comtypes, 10.1 .


Sonraki adımlar

... ya da: beyin yılan gibi mi gitti ? C # kodu örneklerine bakmak gözlerinizin yüzmesini sağlar ve bir vinç gibi düşünemeyeceğiniz gibi deneyin ? Buraya bak:


10
Bu konu dikkatimi çekti ve etrafta dolaşan bazı kavram yanılgıları var. ArcObjects'i Python'da kullanmak için Visual Studio ya da MIDL derleyicisine ihtiyacınız yoktur; İhtiyacınız olan tek şey comtypes paketi. Sunumum Python kullanarak bir COM bileşeni oluşturmada ileri bir alıştırma içermişti, ancak bu UberPyGeeks içindi. Snippets.py dosyası, ihtiyacınız olan tüm örnekleri içerir.

1
@Mark, düzeltme için çok teşekkürler. Açık olmak gerekirse: yukarıdaki tarifte, kipler zaten kurulu olduğu sürece, 1,3,4 basamakları çıkarılabilir mi?
matt wilkie

2
Evet. Laboratuarda test etti. Sadece prototipleri kurman gerekiyor.
RK

@RK, harika! Doğrulama ve cevabı güncellediğiniz için teşekkür ederiz.
matt wilkie

1
Yüklenebilir olarak yeniden biçimlendirilmiştir Snippet'ler modülü ao : Burada modülün github.com/maphew/arcplus/tree/master/arcplus/ao (10,3 için güncellenmiş, 10.2 için dosyanın önceki sürümlerini bakınız). Bazı hatalar giderildikten sonra ana cevabı güncelleyeceğim.
matt wilkie

32

Evet, Mark Cederholm'un Matt Wilkie'nin yukarıda bahsettiği sunumu başlamak için harika bir yer. Matt'in sunduğu tarif / kod, kesinlikle kaygan ve muhtemelen işlerle ilgili en iyi yoldur. Yine de ArcGIS 10.0'da kullandığım oldukça kaba kuvvet yönteminden bahsetmek istedim. Bu şekilde çalıştırdığım birkaç otomasyon betiğim var (bağımsız, uygulama sınırının dışında) ve bunlar gayet iyi çalışıyor. Eğer maksimum hız bir endişe ise, sadece Matt'in çözümüne gidip bununla bitebilirsiniz.

Tüm ArcObjects kütüphanelerinin (.olb) sarılmasını zorlamak için comtypes paketini kullanıyorum. Sonra Python tüm ArcObjects öğelerine erişebilir. Paket kodunu Frank Perks'ten bir ESRI forum ilanı aracılığıyla aldım . Temelde aynı şeyi yapan kendi kodum vardı, ancak çok daha güzel olmasına rağmen şişirildi ve yalnızca işlevseldi. Yani:

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)

Öyleyse, Mark Cederholm'un sunumundan hemen hemen:

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

Bu kadar. AppRef nesnesinde IApplication olan pApp nesnesiyle başlayan ArcObjects öğesine tam erişiminiz olmalıdır. Tecrübelerime göre, ArcObjects kütüphanelerinin ilk çalıştırmada sarılması sakıncalı derecede yavaş değildir ve sonraki çalıştırmalar için sargı gerçekleşmez. Kütüphaneler zaten sarılmış ve derlenmiştir, bu yüzden işler çok daha hızlıdır.

Eklendi: Bununla birlikte büyük bir dikkat var. Burada verilen NewObj işlevi, Python betiğinin işlem sırasında çalıştırıldığını varsayar. Aksi takdirde, bu işlev Python işleminde nesneler yaratacaktır (işlem dışı) ve nesne referansları yanlış olacaktır. Harici bir Python betiğinden işlem nesnesi oluşturmak için IObjectFactory kullanmanız gerekir. Daha fazla bilgi için Kirk Kuykendall'ın bu stackexchange yazısındaki yorumlarını ve ipuçlarını inceleyin .


1
Bu yaklaşımla ilgili güzel şey, onunla yapacağınız tek şey com nesnelerini kaydettiriyorsa, oldukça ağır olan Visual Studio'nun yüklenmesini gerektirmemesidir. Bu saf piton yöntemini bilseydim, muhtemelen Cederholm'un rotasını hiç denemezdim. ;-)
matt wilkie

1
Bu kavram üzerinde bu cevabı biraz geliştirdim, ithalat ve tip kütüphanelerini tek adımlı bir süreç haline
getirdim

20

Arcobjects'e python'dan nasıl erişirim?

Eğer aradığınız şey, C ++ Arcobjects kodunda var olan ve var olan belirli bir işlevsellik ise, en iyi bahsiniz, onları çağırmak için C ++ yöntemleri oluşturmak .... ve sonra bu C ++ yöntemlerine erişmek için bir piton sarıcı oluşturmak olacaktır.

Python'dan C ++ yöntemlerine erişmenin epeyce yolu vardır ve bunu yapan birçok kişi SW ++ gibi bir aracı kullanarak python sınıflarını C ++ yöntem imzalarından otomatik olarak oluşturur. Bu otomatikleştirilmiş API'lerin yerel olmayan C ++ türlerini (int, float) geçirirken oldukça kötüye gittiği ve hiçbir zaman çok " pitonik " olmadıklarıma dair deneyimim oldu .

Önerilen çözüm, ctypes API'sini kullanmak olacaktır. Harika bir öğretici burada: http://python.net/crew/theller/ctypes/tutorial.html

Temel adımlar:

  1. Python performansının bir sorun olabileceğine inandığınız bazı C ++ mantığınızı yazın.
  2. Bu çekirdek mantığı (bu durumda, ArcObject C ++ API yönteminin çağırdığı kullanarak) nesne dosyalarından, herhangi bir sistem derleyicisini (nmake, make, etc.) kullanarak paylaşılan (.so) veya dinamik bir kütüphaneye (.dll) dönüştürün.
  3. Python sınıfı ve C ++ yöntemi imzası arasında eşleme kipleri yazın [SWIG bunu otomatikleştirmeye çalışır, ancak çılgın nesne türleri kullanıyor olsa bile kolaydır]
  4. Derlenmiş kütüphaneyi python programınıza alın ve ilişkili sınıf / yöntem bağlantılarını diğer python sınıfları gibi kullanın!

Bu muhtemelen C / C ++ koduna python içinden başvurmak için daha genel bir yoldur, COM nesnelerle uğraşmak zorunda kalmazsanız, uzun vadede muhtemelen çok daha kolay olacaktır. Ayrıca, sisteme özgü tüm işlevselliğin, bağlantılı kütüphane nesnesinin derlemesinde bulunmasına izin verecektir (dolayısıyla python, sistem / python uygulamasına özel olmayacaktır).


3
ArcObjects ile etkileşime geçmek için en iyi yöntem budur. Komotiplerin kullanımı prototipleme için mükemmeldir ancak kendi C uzantınızı yazmak iyi bir Pythonic tasarım (çünkü bunu düşünmek zorundasınızdır) ve daha iyi performansa neden olur çünkü C ++ / Python nesne engelini bu kadar aşmazsınız. Pratik amaçlar olsa da, hızlı ve kirli camdan dışarı çıkması için tasarım / geliştirme / hata ayıklama daha zordur.
Jason Scheirer

18

Diğer bir seçenek ise Python for .NET kullanmaktır - kurulumu çok kolaydır ve ArcObject'ler de dahil olmak üzere herhangi bir .NET DLL dosyası ile çalışabilir.

Süreç içi engellerle ilgili herhangi bir sorun yaşamadım ve bir ArcMap örneği açmak ve benim için işe yarayan katmanlar eklemek ve işlemek benim için iyi oldu.

Tek gereksinim, .NET kütüphanesi için Python ve standart bir Python kurulumunu içeren bir klasördür.

Daha fazla detay ve burada örnek komut dosyası . Örnek komut dosyası doğrudan http://gist.github.com/923954 adresinde de görülebilir.

Ne yazık ki, bu yerel bir geliştirme makinesinde sorunsuz çalışıyor olsa da, başka bir yere yerleştirmek için ArcObjects SDK ve Visual Studio'nun (ücretsiz Express sürümü de dahil) kurulması gerekir. ArcObject .NET DLLlerini Dağıtma bölümüne bakınız.


Tarif açık, berrak ve iyi sundu. Geographika teşekkürler! Cevabınıza minimal bir kod pasajı eklemenizi tavsiye ederim, böylece sitenizde yenileme çalışmaları yapılacaksa, yanıtın kendi üzerinde durması gerekir.
matt wilkie

1
Bu eski blog yayınında yaptığım tam olarak buydu ( gissolved.blogspot.com/2009/06/python-toolbox-3-pythonnet.html ) ve beklendiği gibi çalışıyor ancak Python betiğinizin anladığı sonuçları döndürdüğünden emin olun (dizeler, sayılar) veya geçersiz).
Samuel,


5

Diğer cevaplarda bahsetmediğim bir yaklaşım, kutup kütüphanelerinin kendilerinin kullandığı yöntemleri kullanmaktır. Örneğin, C: \ Program Files \ ArcGIS \ Desktop10.0 \ arcpy \ arcpy \ cartography.py, Python'un bazı fixargs ve nesne dönüştürme işlevlerini kullanarak ArcObjects araçlarını çağırdığını görüyoruz.

Buraya burada yayınlamak ne kadar uygun değil, çünkü kod "TİCARET GİRİŞLERİ: ESRI PROPRIETARY VE GİZLİDİR"; ama onu web üzerinde başka bir yerde bulacaksın. Neyse, bu, SimplifyBuilding_cartography()prototip veya başka herhangi bir ekstra kütüphaneyi kurmadan yapılan fonksiyonları çağırmanın nispeten kolay bir yolu gibi görünüyor .

Düzenle:

Jason'ın aşağıdaki yorumlarına bakın. Yukarıdakileri yapmak gibi geliyor size çok fazla almaz.


Ben de farkettim, gerçi çok fazla vudu gibi görünüyor.
blah238

1
Tamamen açığa çıkmış bir arcobject dizisi değil.
Jason Scheirer,

@JasonScheirer, göründüğü gibi, ArcObjects'e (sanırım) düz arkalı API'dan daha fazla erişime izin veriyor gibi görünüyor ve başka bir kütüphanenin kurulmasını gerektirmeme avantajına sahip. İkincisi, diğer insanların kullanması için araçlar geliştiriyorsanız önemli olabilir. Bu yöntemle nelerin erişebildiğini tam olarak bilmek isterim - belirli amaçlar için yeterli olabilir. (Şu anda kontrol edemiyorum - şirket
LAN'ında

1
Sizi gerçek olmadığı için temin ederim. Ben çoğunu geliştirdim.
Jason Scheirer,

1
Yapamazsın. "ArcObject", bu örnekte bir yanlış isim biraz. Temel nesnelere ulaşmanın bir yolu yoktur ve tüm ArcObjects öğelerini arcgcripcripting / arcpy içinde herhangi bir yerde açığa vuran bir COM bağlayıcı yoktur.
Jason Scheirer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.