Доступ до ArcObjects з Python?


132

Я хотів би мати можливість сценарію деяких речей, які не відкриваються через arcgisscriptingабо ArcPy.

Як отримати доступ до ArcObjects з Python?


3
У когось є думки щодо використання цих методів у виробничих умовах? Кілька років тому в UC я спілкувався з одним із розробників ESRI C ++, який пише більшість своїх модулів Python, і він був рішуче проти використання IronPython у виробничих умовах - але це було кілька років тому.
Чад Купер

Відповіді:


113

Завантажте та встановіть комтити *, поставте Snippetsмодуль від Марка Седерхольма в PYTHONPATH, і все готово.

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

Для ознайомлення див. Презентації Марка Седерхольма для UberPyGeeks на тему "Використання ArcObjects в Python" . Існують окремі для перспектив розробників VBA та C ++. Вони використовують Visual Studio (так, з Express це нормально) та Windows SDK , але вони не потрібні, достатньо лише ArcGIS, Python та комтитів.

Отримання модуля Snippets

* Примітка для версії 10.1+ вам потрібно внести невеликі зміни automation.pyв модуль comtypes. Дивіться ArcObjects + comtypes в 10.1 .


Наступні кроки

... або: мозок пішов зміїним ? Дивлячись на приклади коду c #, ваші очі плавають, і спробуйте, як ви могли, просто не можете думати, як журавель ? Послухайте:


10
Ця нитка була донесена до мене, і, здається, навколо неї пливуть деякі хибні уявлення. Вам НЕ потрібна Visual Studio або компілятор MIDL для того, щоб використовувати ArcObjects в Python; все, що вам потрібно, - це пакунок comtypes. Моя презентація включала вдосконалену вправу по створенню COM-компонента за допомогою Python, але це було призначено для UberPyGeeks. Файл snippets.py містить усі необхідні приклади.

1
@ Марк, велике спасибі за виправлення. Щоб було зрозуміло: з наведеного вище рецепту можна було б видалити кроки 1,3,4, поки вже встановлені ctypes ?
matt wilkie

2
Так. Випробували його в лабораторії. Вам просто потрібно встановити комтити.
РК

@RK, чудово! Дякуємо за перевірку та оновлення відповіді.
matt wilkie

1
Уривки модуль переробки в встановлюється ат модуля тут: github.com/maphew/arcplus/tree/master/arcplus/ao (оновлено 10,3 см попередніх версій файлу для 10.2). Оновить основну відповідь, як тільки я випрацюю деякі помилки.
matt wilkie

32

Так, презентація Марка Седерхольма, яку Метт Вілкі згадує вище, - чудове місце для початку. Рецепт / код, який Метт представляє, - це, безумовно, гладкий і, мабуть, найкращий шлях для речей. Хотілося б згадати, проте, досить жорстокий метод, який я використовую в ArcGIS 10.0. У мене є кілька сценаріїв автоматизації (автономний, поза межами програми), які я запускаю таким чином, і вони працюють чудово. Якщо максимальна швидкість викликає занепокоєння, ви можете просто піти з рішенням Метта і зробити це з ним.

Я використовую пакет comtypes для примусового обгортання всіх бібліотек ArcObjects (.olb). Тоді Python має доступ до всіх ArcObjects. Я отримав пакувальний код від Франка Перкса через розміщення на форумі ESRI . У мене був власний код, який по суті робив те саме, але він був роздутим і просто функціональним, тоді як його набагато красивіше. Тому:

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)

Потім, майже прямо з презентації Марка Седерхольма:

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

Це воно. Ви повинні мати повний доступ до ArcObjects, починаючи з об'єкта pApp, який є IApplication на об’єкт AppRef. На мій досвід, обгортання бібліотек ArcObjects під час першого запуску не є заперечно повільним, і для наступних запусків обгортання не відбувається. Бібліотеки вже завернуті і складені, тому справи набагато швидше.

Додано: Існує велика обережність, яка пов'язана з цим. Функція NewObj, наведена тут, передбачає, що сценарій Python виконується в процесі роботи. Якщо ні, ця функція створить об'єкти в процесі Python (тобто поза процесом), і посилання на об'єкти будуть неправильними. Для створення об'єктів процесу із зовнішнього скрипта Python слід використовувати IObjectFactory. Дивіться коментарі та поради Кірка Куйкендала в цій публікації про зміну ставок для отримання додаткової інформації.


1
Приємно в цьому підході є те, що він не вимагає встановлення Visual Studio, який є досить важким, якщо єдине, що ви коли-небудь будете робити з ним, - це зареєструвати ком-об’єкти. Якби я знав про цей чистий метод пітона, я, мабуть, ніколи не спробував би маршрут Седерхольма. ;-)
matt wilkie

1
Я трохи розширив цю концепцію у цій відповіді, зробивши імпорт та обгортання бібліотек типів одноетапним процесом: gis.stackexchange.com/questions/5017/…
blah238

20

Як отримати доступ до аркобектів з python?

Якщо ви шукаєте специфічну функціональність, яка існує і міститься в коді Arcobjects C ++, то найкращим варіантом буде створити методи C ++, щоб викликати їх ...., а потім створити обгортку пітона для доступу до цих методів C ++.

Існує досить багато способів отримати доступ до методів C ++ з python, і багато людей, які роблять це, використовують такий інструмент, як SWIG, щоб автоматично генерувати класи python з підписів методу C ++. З мого досвіду, ці автогенеровані API стають досить неприємними при передачі не-рідних типів C ++ (int, floats ) і ніколи не є дуже " пітонічними ".

Моїм рекомендованим рішенням було б використання API ctypes. Чудовий посібник тут: http://python.net/crew/theller/ctypes/tutorial.html

Основні етапи:

  1. написати деякі ваші основні логіки в C ++, ті, де ви вважаєте, що продуктивність пітона може бути проблемою
  2. Скомпілюйте цю основну логіку (у цьому випадку за допомогою виклику методу ArcObject C ++ API) з об’єктних файлів у спільну (.so) або динамічну бібліотеку (.dll), використовуючи будь-який системний компілятор (nmake, make тощо).
  3. Запишіть зіставлення типів між класом python та підписом методу C ++ [SWIG намагається це автоматизувати, але це легко, навіть якщо використовують шалені типи об'єктів]
  4. Імпортуйте скомпільовану бібліотеку у вашу програму python та використовуйте прив’язаний клас / метод прив'язки, як і будь-який інший клас python!

Це, мабуть, більш загальний спосіб посилання на код C / C ++ зсередини python, мабуть, у перспективі буде набагато простіше, якщо вам не доведеться мати справу з об’єктами COM. Це також дозволить усім функціональним функціям системи перебувати в компіляції пов'язаного об'єкта бібліотеки (тому python не буде специфічним для системи / python реалізації).


3
Це далеко не найкращий метод взаємодії з ArcObjects. Використання комтипів відмінно підходить для складання прототипів, але написання власного розширення C призведе до гарного, пітонічного дизайну (тому що ви повинні думати над цим) та кращої продуктивності, оскільки ви не перестанете стільки об'єктного бар'єру C ++ / Python. Хоча для практичних цілей, це важче спроектувати / розробити / налагодити, щоб швидко і брудно виходити у вікно.
Jason Scheirer

18

Іншим варіантом є використання Python для .NET - це дуже просто налаштувати, і він може працювати з будь-якими .NET DLL, включаючи ArcObjects.

У мене не виникало жодних проблем із предметами, які перебувають у процесі, і відкриття екземпляра ArcMap та додавання та маніпулювання шарами спрацювало мені добре.

Єдині вимоги - це папка, що містить бібліотеку Python для .NET, і стандартна установка Python.

Детальніше та зразок сценарію тут . Зразок сценарію також можна побачити безпосередньо на веб- сайті http://gist.github.com/923954

На жаль, хоча це працює без проблем на локальній машині розробки, для його розміщення в іншому місці потрібно встановити пакет програм ArcObjects SDK та Visual Studio (включаючи безкоштовне видання Express). Див. Розгортання DLL-файлів ArcObject .NET


Рецепт чіткий, чіткий і добре представлений. Дякую Географіку! Я закликаю вас включити у свою відповідь мінімальний фрагмент сценарію, щоб у випадку, коли ваш сайт пройшов оновлення, відповідь може стояти самостійно.
matt wilkie

1
Саме це я і зробив у цьому старому блозі ( gisssol.blogspot.com/2009/06/python-toolbox-3-pythonnet.html ), і він працює як слід, але обов'язково повертайте результати, зрозумілі вашим сценарієм Python (рядки, числа або недійсні).
Самуїл

Посилання geographika.co.uk/using-arcobjects-and-net-in-python порушено.
SIslam

5

Один із підходів, який я не бачу згадувати в інших відповідях, - це використовувати ті самі методи, якими користуються самі бібліотеки архпій. Наприклад, у C: \ Program Files \ ArcGIS \ Desktop10.0 \ arcpy \ arcpy \ cartography.py, ми бачимо, що Python викликає інструменти ArcObjects з використанням деяких поправок та функцій перетворення об’єктів.

Я не дуже сильно розміщувати про це тут, оскільки в коді написано: "ТРАНСПОРТНІ ТАЙНИ: ESRI ВЛАСНИЙ ТА КОНФІДЕНЦІЙНИЙ"; але ви також знайдете його в Інтернеті. У будь-якому випадку це виглядає як відносно простий спосіб викликати такі функції, як SimplifyBuilding_cartography()без встановлення комтитів чи будь-яких інших зайвих бібліотек.

Редагувати:

Дивіться коментарі Джейсона нижче. Здається, що виконання вищезазначеного не дуже придбає вас.


Я помітив, що теж здається, що занадто багато вуду, хоча.
blah238

1
Це не виклик повністю відкритого набору аркобектів.
Jason Scheirer

@JasonScheirer, як би там не було, він, мабуть, дозволяє дещо більший ступінь доступу до ArcObjects (я думаю), ніж API прямого arcpy, і він має перевагу в тому, що не вимагає встановлення іншої бібліотеки. Останнє може бути важливим, якщо ви розробляєте інструменти для використання іншими людьми. Я хотів би дізнатися всю міру того, до чого можна отримати доступ за допомогою цього методу - це може бути достатньо для певних цілей. (Я зараз не можу перевірити - я не в мережі LAN.)
LarsH

1
Я можу запевнити вас у тому, що це не так. Я багато чого розвинув.
Jason Scheirer

1
Ти не можеш. "ArcObject" - трохи помилка в цьому випадку. Немає способу дістатись до основних об'єктів, і немає COM-прив'язки, яка б відкривала всі ArcObjects ніде в arcgiskcripting / arcpy.
Jason Scheirer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.