Pedoman untuk menggunakan ArcObjects dari Python

10

Sejauh ini, Mengakses ArcObjects dari Python? adalah T&J saya yang paling banyak dibaca dan direferensikan di GIS Stack Exchange. Terlepas dari keberhasilan itu, itu mungkin salah satu area terlemah saya dalam hal penggunaan aktual. Sebagian besar dari pertunjukan yang buruk itu berasal dari kemampuan saya yang buruk untuk membaca dan memahami dokumen ArcObjects .

Jadi, untuk tugas apa pun, apa saja panduan untuk menerjemahkan .net / c ++ / java / ... dokumen dan contoh ke dalam persamaan python mereka? (bahasa manakah yang paling cocok untuk bekerja?) dan dari mana indeks atau halaman arahan terbaik untuk memulai? hal-hal apa yang harus difokuskan, dan kemungkinan setidaknya sama pentingnya, apa yang dapat diabaikan dengan bebas?

Asumsikan audiens Anda setidaknya sedikit melek python, dan buta huruf dalam bahasa pengembangan lainnya. Arahkan kami melalui latihan pengkodean kecil, dari ide awal dan penelitian hingga hasil python yang bekerja.

matt wilkie
sumber
1
Mungkin tidak menambahkan apa-apa ke percakapan di sini, tetapi saya ingin menyatakan untuk catatan saya akan sangat tertarik melihat set walkthrough ini berkembang. Terima kasih, Matt. Saya menemukan satu artikel oleh Darren Wiens membuat MXD dari awal dan mengisi tata letak dengan panduan. Tampaknya juga modul potongan Mark Cederholm sangat membantu / sering digunakan dalam upaya ini.
Jim
Contoh yang mungkin untuk digunakan: gis.stackexchange.com/questions/86007/… (pengungkapan: itu adalah masalah yang saya kerjakan, yang mendorong Q. Kalahkan saya ke jawaban (yang dibuat dengan baik), dapatkan semua kredit ! ;-)
matt wilkie
Arcobjects bisa sulit untuk masuk, dokumen bantuan OK tapi contohnya lebih baik: Salah satu masalah terbesar adalah mengerjakan warisan satu objek ke objek lain, seperti saya punya objek X, sekarang bagaimana saya mendapatkan objek Y ? Jika Anda bisa mendapatkan Visual Studio 2008 atau 2010 express (unduh gratis jika Anda dapat menemukannya) kemudian instal SDK Anda akan mendapatkan dokumen bantuan dan banyak contoh secara lokal.
Michael Stimson
1
@mattwilkie semoga ini tidak terlalu membebani air ... tetapi untuk porting yang ada .NET kode ke python dan mencari tahu tipe casting sintaks, python untuk. NET terlihat sedikit lebih lurus ke depan daripada pendekatan comtypes. Yang mengatakan, saya baru saja menemukan python untuk .NET dan belum mengujinya.
user2856
1
@mattwilkie baru saja menemukan python.Net membutuhkan ArcGIS SDK diinstal (kecuali dll bungkus pembungkus didistribusikan dengan skrip ...) selain ArcGIS Desktop, sehingga tidak cukup portabel seperti pendekatan comtypes.
user2856

Jawaban:

9

Saya juga tidak terlalu kuat di bidang ini, tetapi saya telah memodifikasi modul Snippets dan membuat beberapa pembungkus untuk tugas yang sangat sederhana. Saya punya contoh hanya menambahkan elemen garis. Contoh di bawah blok utama membentuk segitiga ke tampilan tata letak tepat di luar dokumen.

Saya menggunakan skrip ini bersama dengan kursor pencarian lain dan tidak jelas untuk membuat tabel grafik dalam tata letak dari setiap baris dan elemen teks, tetapi itu dengan cepat menjauh dari contoh "sederhana". Kode di bawah ini cukup sederhana dan menggunakan snippet versi yang dimodifikasi:

from snippets import *
def add_line(pApp=None, name='Line', x=None, y=None, end_x=None, end_y=None,
             x_len=0, y_len=0, anchor=0, view='layout'):
    '''adds a line to an ArcMap Document

    Required:
    pApp -- reference to either open ArcMap document or path on disk
    name -- name of line element

    Optional:
    x -- start x coordinate, if none, middle of the extent will be used (data view)
    y -- start y coordinate, if none, middle of the extent will be used (data view)
    end_x -- end x coordinate, if making straight lines use x_len
    end_y -- end y coordinate, if making straight lines use y_len
    x_len -- length of line in east/west direction
    y_len -- length of line in north/south direction
    anchor -- anchor point for line element
    view -- choose view for text element (layout|data)

        Anchor Points:
        esriTopLeftCorner   0   Anchor to the top left corner.
        esriTopMidPoint     1   Anchor to the top mid point.
        esriTopRightCorner  2   Anchor to the top right corner.
        esriLeftMidPoint    3   Anchor to the left mid point.
        esriCenterPoint     4   Anchor to the center point.
        esriRightMidPoint   5   Anchor to the right mid point.
        esriBottomLeftCorner    6   Anchor to the bottom left corner.
        esriBottomMidPoint  7   Anchor to the bottom mid point.
        esriBottomRightCorner   8   Anchor to the botton right corner.
    '''
    GetDesktopModules()
    import comtypes.gen.esriFramework as esriFramework
    import comtypes.gen.esriArcMapUI as esriArcMapUI
    import comtypes.gen.esriSystem as esriSystem
    import comtypes.gen.esriGeometry as esriGeometry
    import comtypes.gen.esriCarto as esriCarto
    import comtypes.gen.esriDisplay as esriDisplay
    import comtypes.gen.stdole as stdole

    # set mxd
    if not pApp:
        pApp = GetApp()
    pDoc = pApp.Document
    pMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)
    pMap = pMxDoc.FocusMap
    pMapL = pMap
    if view.lower() == 'layout':
        pMapL = pMxDoc.PageLayout
    pAV = CType(pMapL, esriCarto.IActiveView)
    pSD = pAV.ScreenDisplay

    # set coords for elment
    pFact = CType(pApp, esriFramework.IObjectFactory)
    if view.lower() == 'data':
        pEnv = pAV.Extent
        if x == None:
            x = (pEnv.XMin + pEnv.XMax) / 2
        if y == None:
            y = (pEnv.YMin + pEnv.YMax) / 2
    else:
        # default layout position, move off page
        if x == None: x = -4
        if y == None: y = 4

    # from point
    pUnk_pt = pFact.Create(CLSID(esriGeometry.Point))
    pPt = CType(pUnk_pt, esriGeometry.IPoint)
    pPt.PutCoords(x, y)

    # to point
    pUnk_pt2 = pFact.Create(CLSID(esriGeometry.Point))
    pPt2 = CType(pUnk_pt2, esriGeometry.IPoint)
    if x_len or y_len:
        pPt2.PutCoords(x + x_len, y + y_len)
    elif end_x or end_y:
        pPt2.PutCoords(end_x, end_y)

    # line (from point - to point)
    pUnk_line = pFact.Create(CLSID(esriGeometry.Polyline))
    pLg = CType(pUnk_line, esriGeometry.IPolyline)
    pLg.FromPoint = pPt
    pLg.ToPoint = pPt2

    # preset color according to RGB values
    pUnk_color = pFact.Create(CLSID(esriDisplay.RgbColor))
    pColor = CType(pUnk_color, esriDisplay.IRgbColor)
    pColor.Red, pColor.Green, pColor.Blue = (0,0,0) #black line

    # set line properties
    pUnk_line = pFact.Create(CLSID(esriDisplay.SimpleLineSymbol))
    pLineSymbol = CType(pUnk_line, esriDisplay.ISimpleLineSymbol)
    pLineSymbol.Color = pColor

    # create the actual element
    pUnk_elm = pFact.Create(CLSID(esriCarto.LineElement))
    pLineElement = CType(pUnk_elm, esriCarto.ILineElement)
    pLineElement.Symbol = pLineSymbol
    pElement = CType(pLineElement, esriCarto.IElement)

    # elm properties
    pElmProp = CType(pElement, esriCarto.IElementProperties3)
    pElmProp.Name = name
    pElmProp.AnchorPoint = esriCarto.esriAnchorPointEnum(anchor)
    pElement.Geometry = pLg

    # add to map
    pGC = CType(pMapL, esriCarto.IGraphicsContainer)
    pGC.AddElement(pElement, 0)
    pGCSel = CType(pMapL, esriCarto.IGraphicsContainerSelect)
    pGCSel.SelectElement(pElement)
    iOpt = esriCarto.esriViewGraphics + \
    esriCarto.esriViewGraphicSelection
    pAV.PartialRefresh(iOpt, None, None)
    return pElement

if __name__ == '__main__':

    # testing (make a triangle)
    add_line(name='hypot', end_x=-2, end_y=2, anchor=3)
    add_line(name='vertLine', y_len=-2, anchor=1)
    add_line(name='bottom', y=2, end_x=-2, end_y=2)

masukkan deskripsi gambar di sini

Edit:

@ mat wilkie

Adapun untuk mencari tahu impor, di situlah Anda harus melihat Diagram Model ArcObjects atau melihat namespace mana Kelas atau Antarmuka tertentu dipanggil dari dalam. NET SDK help docs. Dalam beberapa kasus, lebih dari satu namespace dapat digunakan karena warisan.

Saya bukan ahli dalam ArcObjects, jadi biasanya saya perlu waktu untuk mencari tahu kapan harus membuang sesuatu dengan CType (). Sebagian besar dari ini, saya telah mengambil dari sampel online. Juga, sintaks dari contoh VB.NET tampaknya lebih dekat dengan apa yang Anda lakukan dengan Python, tetapi contoh C # lebih masuk akal bagi saya dalam hal keterbacaan (jika itu masuk akal). Tapi, sebagai patokan saya biasanya mengikuti dua langkah ini:

  1. Buat variabel untuk objek COM baru (biasanya kelas) untuk membuat instance objek
  2. Gunakan CType untuk melemparkan objek COM ke antarmuka untuk memungkinkan akses ke metode dan properti. CType juga akan mengembalikan comtypes Interface Pointer melalui QueryInterface (). Setelah pointer dikembalikan, Anda dapat berinteraksi dengan properti dan metodenya.

Tidak yakin apakah saya menggunakan terminologi yang tepat atau tidak ... Saya terutama pengembang Python yang "mencoba-coba" di beberapa ArcObjects ... Saya hanya menyentuh ujung gunung es.

Juga, fungsi pembantu ini akan memuat semua Perpustakaan Objek ArcObjects (.olb):

def load_all():
    '''loads all object libraries'''
    from comtypes.client import GetModule
    mods = glob.glob(os.path.join(GetLibPath(), '*.olb'))
    for mod in mods:
        GetModule(mod)
    return


def GetLibPath():
    '''Reference to com directory which houses ArcObjects
    Ojbect Libraries (*.OLB)'''
    return glob.glob(os.path.join(arcpy.GetInstallInfo()['InstallDir'], 'com'))[0]
Crmackey
sumber
terima kasih atas contoh yang bermanfaat! Dorongan Q adalah (dimaksudkan untuk menjadi) kurang pada resep tugas tertentu dan lebih pada bagaimana seseorang mendapatkan dan menulis info untuk membangun resep di tempat pertama. Misalnya, bagaimana Anda tahu import comtypes.gen.esriArcMapUI as esriArcMapUIdan kemudian menggunakan pMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)(dan mengungkap sintaks dalam pernyataan itu)?
matt wilkie
Saya mengedit jawaban asli saya untuk mencoba menjawab pertanyaan Anda. Saya punya beberapa contoh lain juga, tetapi cuplikan di atas mungkin yang paling mudah dibaca.
crmackey
Juga, saya membeli buku ini tahun lalu: amazon.com/Mulai-ArcGIS-Desktop-Development-using/dp/…
crmackey
7

Dalam posting lain, terkait tapi sedikit berbeda, saya memberikan jawaban yang mungkin menarik bagi pengguna python mencoba untuk membungkus kepala mereka di sekitar Esri ArcObjects membantu dokumen ..

Saya datang dari sisi lain: Saya sudah tahu ArcObjects lama (lama sekali) bahkan sebelum saya mendengar tentang python dan terima kasih untuk posting seperti ini saya dapat memasukkan beberapa ArcObjects kritis dalam skrip mudah python (lihat posting ini sebagai contoh ). Saya ingat frustrasi mencoba memahami warisan, metode, dan properti; dilema seperti saya punya X yang semacam terkait dengan Y ... jadi bagaimana saya dapatkan dari X ke Y.Method ()?

Jawabannya adalah untuk melihat CoClasses yang mengimplementasikan antarmuka (lihat teks lengkap di sini ) .. untuk contoh dasar, jika saya ingin melihat apakah sebuah layer memiliki kueri definisi, dan jika demikian apa itu:

Dalam C #:

ILayer pLayer = pMap.get_Layer(LayerIndex);
IFeatureLayer pFtLayer = pLayer as IFeatureLayer; // also written pFtLayer = (IFeatureLayer) pLayer
IFeatureLayerDefinition pFtLayDef = (IFeatureLayerDefinition)pFtLayer; // also works as pFtLayDef = pFtLayer as IFeatureLayerDefinition;
if (pFtLayDef.DefinitionExpression.Length == 0)
    Console.WriteLine("No definition query");
else
    Console.WriteLine("Query is " + pFtLayDef.DefinitionExpression);

Alih-alih ctype(yang menonjol dalam VB) C # menggunakan ()atau asuntuk casting, misalnya IObject x = (IObject)y;(secara fundamental) sama dengan IObject x = y as IObject;yang akan dim x as IObject = ctype(y,IObject)di VB.

Saya dapat mengatakan bahwa saya memerlukan IFeatureLayer untuk sampai ke IFeatureLayerDefinition karena: masukkan deskripsi gambar di sini

Dan ketika Anda membaca dokumen bantuan untuk IFeatureLayer, Anda melihat: masukkan deskripsi gambar di sini

Yang menunjukkan bahwa itu aman untuk pergi ILayer-> IFeatureLayer-> IFeatureLayerDef, asalkan ILayer adalah tipe FeatureLayer (atau CoClasses lainnya).

Jadi ada apa dengan aku dan tidak? Antarmuka I berarti, itu bit yang berfungsi, tanpa I adalah CoClass ( tipe ), jadi apa pun yang ingin Anda gunakan benar-benar harus dimulai dengan I dan jika Anda membuat yang baru atau memeriksa jenisnya lalu lewati I. Antarmuka dapat memiliki banyak CoClasses dan CoClass dapat mendukung banyak antarmuka, tetapi antarmuka itulah yang sebenarnya berfungsi.

Dengan python:

# I'm assuming arcpy is already imported and comtypes installed
from comtypes.client import GetModule, CreateObject
mC = GetModule(r'C:\Your path\Desktop10.1\com\esriCarto.olb')
mU = GetModule(r'C:\Your path\Desktop10.1\com\esriArcMapUI.olb')
mF = GetModule(r"C:\Your path\Desktop10.1\com\esriFramework.olb")

import comtypes.gen.esriCarto as esriCarto
import comtypes.gen.esriFramework as esriFramework
import comtypes.gen.esriArcMapUI as esriArcMapUI

app = CreateObject(mF.AppROT, interface=mF.IAppROT) # a reference to the ArcMap application
pDoc = ctype(app.Item(0).Document,mU.IMxDocument)   # a reference to the current document
pMap = pDoc.FocusMap # the currently active map
pLayer = pMap.get_layer(LayerIndex)
pFtLayer = ctype(pLayer,esriCarto.IFeatureLayer)
pFtLayDef = ctype(pFtLayer,esriCarto.IFeatureLayerDefinition)
if len(pFtLayDef.DefinitionExpression) == 0:
    print("No definition expression")
else:
    print("Query is " + pFtLayDef.DefinitionExpression)

Sampel ini melakukan sedikit lebih banyak daripada C karena menemukan jalannya ke aplikasi saat ini, yang hanya akan tersedia di jendela python atau addin, jika Anda mencoba menjalankan ini dari baris perintah, aplikasi tersebut Null dan skrip kemudian akan macet dengan pengecualian referensi nol.

Michael Stimson
sumber
Wow, terima kasih banyak telah memposting ini! Saya telah mengalami beberapa kesulitan memahami Diagram ArcObject. Sangat menyenangkan memiliki beberapa masukan dari seseorang seperti Anda yang berasal dari sisi lain pagar (banyak pengalaman .NET ArcObjects). Satu hal yang saya punya kesulitan dengan mengakses kelas fitur yang berada di dataset fitur melalui comtypes dan python. Saya pikir di masa lalu saya telah mencoba membuka set data fitur pertama dan kemudian kelas fitur tetapi tidak berhasil (mendapatkan beberapa null pointer). Apakah Anda memiliki sampel python untuk itu?
crmackey
1
Tidak terlalu banyak, saya benar-benar hanya mulai dengan comtypes di python, tetapi untuk membuka kelas fitur dari workspace (IFeatueWorkspace) objek hanya menggunakan nama, jangan sertakan dataset fitur sama sekali - tidak masalah jika itu dalam dataset fitur, semua nama adalah unik ... lihat help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/ ... Bisakah Anda membuka pertanyaan baru dengan beberapa kode dan saya akan memeriksanya. Dataset fitur dapat digunakan dengan iterasi kumpulan data (IFeatureDataset.Subsets) tetapi lebih bersih jika hanya terbuka dengan namanya.
Michael Stimson
1
Terima kasih @Michael Miles-Stimson. Saya akan mencobanya lagi. Jika saya tidak bisa mengetahuinya, saya akan memposting pertanyaan baru dengan kode saya saat ini.
crmackey
@MichaelStimson Saya mengerti bahwa saya dapat menggunakan arcobjects di python menggunakan comtypes. Saya tidak pernah menggunakan arcobjects. Mengingat tidak ada sampel di mana pun untuk melakukan tugas misalnya membangun dataset jaringan menggunakan comtypes dan arcpy, apakah saya harus terlebih dahulu memahami arcobjects sebelum saya dapat menggunakan comtypes? Atau bisakah saya mempelajari comtypes sendiri untuk menggunakan arcpy dan comtypes?
ketar
1
@ketar, itu ide yang baik untuk mengetahui sedikit tentang ArcObjects sebelum Anda mencoba menggunakannya dalam python. Meskipun tidak ada banyak sampel ArcObjects dalam python (belum) ada sampel dalam ArcObjects membantu seperti resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/… untuk dataset jaringan (build adalah item terakhir pada halaman). Kode ArcObjects secara signifikan lebih verbose daripada python (arcpy); secara pribadi saya akan kode dalam VB atau C # dan kemudian ketika senang dengan hasil copy / paste ke python.
Michael Stimson