Вказівки щодо використання ArcObjects від Python


10

Безумовно, Доступ ArcObjects з Python? є моїм найбільш читаним та посиланням на питання QIS на біржі стеків. Незважаючи на цей успіх, це, мабуть, одна з моїх найслабших областей, коли справа стосується фактичного використання. Значна частина цього поганого відображення походить від моєї слабкої здатності читати та розуміти документи ArcObjects .

Отже, для будь-якої задачі є якісь вказівки щодо перекладу .net / c ++ / java / ... документів та прикладів у їх еквіваленти python? (з якої мови найкраще працювати з цього питання?) і з чого найкращий індекс або цільова сторінка для початку? на яких речах слід зосередити увагу і, мабуть, принаймні настільки важливо, що можна вільно ігнорувати?

Припустимо, що ваша аудиторія хоча б дещо грамотна і неграмотна іншими мовами розвитку. Проведіть нас через невелику вправу кодування, від початкової ідеї та досліджень до робочих результатів пітона.


1
Це може не додати нічого до розмови тут, але я хочу заявити, що для запису я був би дуже зацікавлений у тому, щоб цей набір покрокових інструкцій розвивався. Дякую Метт. Я знайшов одну статтю Даррена Wiens, що створює MXD з нуля і заповнює макет направляючими. Схоже, що модуль фрагментів Марка Седерхольма справді корисний / часто використовується у цих зусиллях.
Джим

Можливий приклад для використання: gis.stackexchange.com/questions/86007/… (розкриття: над якою я працював, це спонукало Q. Побий мене до (добре складеної) відповіді, отримай весь кредит ! ;-)
matt wilkie

Arcobjects може бути складно потрапити, довідкові документи в порядку, але приклади кращі: Однією з найбільших проблем є відпрацювання спадкування одного об'єкта на інший, як у мене є об'єкт X, тепер, як мені отримати об'єкт Y ? Якщо ви можете взяти свої руки на Visual Studio 2008 або 2010 Express (безкоштовно скачати, якщо зможете знайти), то встановіть SDK, ви отримаєте документи довідки та купу прикладів на місцевому рівні.
Майкл Стімсон

1
@mattwilkie сподіваємось, що це не замулює води занадто багато ... але для перенесення існуючого .NET-коду на python та з'ясування синтаксису кастингу типу, python для .NET виглядає дещо прямо, ніж підхід комтипів. Це означає, що я тільки що відкрив python для .NET і ще не перевірив його.
користувач2856

1
@mattwilkie щойно відкрили python.Net вимагає встановлення пакета SDK ArcGIS (крім випадків, коли комплекти обгорткових пакетів розподіляються зі сценарієм ...) на додаток до ArcGIS Desktop, тому не настільки портативний, як підхід комтитів.
користувач2856

Відповіді:


9

Я не дуже сильний у цій галузі, але я змінив модуль Snippets і створив пару обгортки для дуже простих завдань. У мене є приклад просто додавання елементів рядка. Приклад під основним блоком утворює трикутник до подання макета безпосередньо за межами документа.

Я використовую цей скрипт спільно з іншим курсором пошуку аркпії для створення графічних таблиць у макеті з окремих рядків та елементів тексту, але це швидко відходить від "простого" прикладу. Код нижче досить простий і використовує модифіковану версію фрагментів:

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)

введіть тут опис зображення

Редагувати:

@matt wilkie

Що стосується з'ясування імпорту, саме там вам доведеться переглянути діаграми моделі ArcObjects або побачити, з якого простору імен викликається конкретний клас чи інтерфейс у довідкових документах .NET SDK. У деяких випадках може бути використаний більше одного простору імен через успадкування.

Я не є експертом у ArcObjects, тому, як правило, потрібен час, щоб розібратися, коли викидати речі за допомогою CType () Більшу частину цього я зібрав із зразків в Інтернеті. Також синтаксис із прикладів VB.NET здається ближчим до того, що ви робите в Python, але приклади C # мають для мене більше сенсу з точки зору читабельності (якщо це має сенс). Але я, як правило, виконую наступні кроки:

  1. Створіть змінну для нового COM-об'єкта (як правило, класу) для інстанціювання об'єкта
  2. Використовуйте CType, щоб передати об’єкт COM на інтерфейс (и), щоб дозволити доступ до методів і proerties. CType також поверне вказівник інтерфейсу комтипів через QueryInterface (). Після повернення покажчика ви зможете взаємодіяти з його властивостями та методами.

Не впевнений, що я використовую належну термінологію чи ні ... Я, перш за все, розробник Python, який "спрацьовує" в деяких ArcObjects ... Хоча я торкнувся лише кінця айсберга.

Також ця допоміжна функція завантажить усі бібліотеки об'єктів 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]

дякую за корисний приклад! Сила Q (призначена таким чином) менше для конкретних рецептів завдань і більше про те, як можна отримати та написати інформацію в першу чергу для складання рецепту. Наприклад, як ви це знали, import comtypes.gen.esriArcMapUI as esriArcMapUIа потім і пізніше використовувати в pMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)(і розкрити синтаксис у цьому висловлюванні)?
matt wilkie

Я відредагував свою оригінальну відповідь, щоб спробувати відповісти на ваші запитання. У мене є також кілька інших прикладів, але вищенаведений фрагмент, мабуть, є найбільш читабельним.
crmackey

Також я придбав цю книгу минулого року: amazon.com/Beginning-ArcGIS-Desktop-Development-using/dp/…
crmackey

7

В іншому, пов’язаному, але дещо іншому пості, я надав відповідь, яка може бути цікавою для користувачів python, які намагаються обернути голову навколо довідкових документів Esri ArcObjects.

Я прийшов з іншого боку: я вже знав ArcObjects довго (довго), перш ніж я навіть чув про python, і завдяки таких публікацій я в змозі включити деякі критичні ArcObjects в легкий сценарій python (див. Цей пост для прикладу ). Я пам’ятаю розчарування, намагаючись зрозуміти спадщину, методи та властивості; дилеми, як у мене X, який схожий на Y ... так як я можу перейти з X до Y.Method ()?

Відповідь полягає в тому, щоб подивитися на CoClasses, які реалізують інтерфейс (див. Повний текст тут ). Для основного прикладу, якщо я хочу дізнатися, чи є у шару запит на визначення, і якщо так, що це:

В 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);

Замість ctype(що є помітним у VB), наприклад, використання C # ()або asдля кастингу, наприклад, IObject x = (IObject)y;є (принципово) тим же, IObject x = y as IObject;що було б dim x as IObject = ctype(y,IObject)у VB.

Я можу сказати, що мені потрібен IFeatureLayer, щоб дістатися до IFeatureLayerDefinition, оскільки: введіть тут опис зображення

І коли ви читаєте довідковий документ для IFeatureLayer, ви бачите: введіть тут опис зображення

Що вказує на те, що безпечно переходити на ILayer-> IFeatureLayer-> IFeatureLayerDef, за умови, що ILayer має тип FeatureLayer (або будь-який з інших CoClasses).

Отже, що з І, а я - ні? Я маю на увазі інтерфейс, це біт, який виконує роботу, без I - це CoClass ( тип ), тому все, що ви хочете насправді використовувати, слід починати з I, і якщо ви створюєте новий або перевіряєте тип потім пропустіть I. В інтерфейсі може бути багато CoClasses, а CoClass може підтримувати безліч інтерфейсів, але саме цей інтерфейс справді працює.

У пітоні:

# 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)

Цей зразок робить трохи більше, ніж C тим, що він знаходить свій шлях до поточної програми, яка була б доступна лише у вікні python або addin, якщо ви спробуєте запустити це з командного рядка, програма додає Null, і сценарій тоді збій із нульовим посиланням на виняток.


Ого, дякую тобі за публікацію! У мене були проблеми з розумінням діаграм ArcObject. Приємно мати якийсь внесок від когось, як ти, хто з іншого боку паркану (багато досвіду .NET ArcObjects). Одне, з чим у мене виникли певні труднощі, - це отримати доступ до класу характеристик, який знаходиться в наборі даних функцій за допомогою комтитів та python. Я думаю, що в минулому я намагався спершу відкрити набір даних про функції, а потім клас об’єктів, але не пощастило (отримати кілька нульових покажчиків). Чи є у вас для цього зразки пітона?
crmackey

1
Не так багато, я дійсно тільки починаю з комтитів у python, але що стосується відкриття класу функцій з робочого простору (IFeatueWorkspace), просто використовуйте ім'я, не включайте набір даних про особливості - не має значення, якщо він знаходиться в наборі даних функцій, усі назви унікальні ... див. help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/… Чи можете ви відкрити нове запитання з деяким кодом, і я перегляну. Набір даних можливостей може використовуватися для ітерації наборів даних (IFeatureDataset.Subsets), але чистіше просто відкрити ім'я.
Майкл Стімсон

1
Дякуємо @Michael Miles-Stimson Я дам йому ще один кадр. Якщо я не можу це зрозуміти, я опублікую нове запитання зі своїм поточним кодом.
crmackey

@MichaelStimson Я розумію, що я можу використовувати аркобекти в python, використовуючи comtypes. Я ніколи не використовував аркобекти. Зважаючи на те, що ніде немає зразків для виконання завдань, наприклад, побудови набору даних мережі за допомогою комтитів та arcpy, чи потрібно мені спочатку зрозуміти аркобекти, перш ніж я можу використовувати комтити? Або я можу просто навчитися комтитам самостійно, щоб використовувати arcpy та comtypes?
кетар

1
@ketar, непогано знати трохи про ArcObjects, перш ніж спробувати використовувати їх у python. Хоча існує не так багато зразків ArcObjects в Python (поки) є зразки допомоги ArcObjects як resources.arcgis.com/en/help/arcobjects-net/conceptualhelp / ... для мережевих наборів даних (збірка останнього елемента , який сторінки). Код ArcObjects значно більш багатослівний, ніж python (arcpy); особисто я кодую в VB або C # і тоді, коли задоволений результатами, скопіюйте / вставте в python.
Майкл Стімсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.