Доступ к ArcObjects из Python?

132

Я хотел бы иметь возможность написать некоторые вещи, которые не доступны через arcgisscriptingArcPy или ArcPy.

Как мне получить доступ к ArcObjects из Python?

Мэтт Уилки
источник
3
У кого-нибудь есть мысли об использовании этих методов в производственных средах? Несколько лет назад в Калифорнийском университете я разговаривал с одним из разработчиков 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 и compepes.

Получение модуля Snippets

* Обратите внимание, что для версии 10.1+ необходимо внести небольшое изменение automation.pyв модуль comtypes. Смотрите ArcObjects + comtypes в 10.1 .


Следующие шаги

... или: мозг сошел с ума ? Глядя на примеры кода на c #, вы поплываете в глаза и стараетесь, как можете, просто не думать как журавль ? Смотри сюда:

matt wilkie
источник
10
Эта тема была доведена до моего внимания, и, похоже, вокруг нее всплывают некоторые заблуждения. Вам НЕ нужен Visual Studio или компилятор MIDL для использования ArcObjects в Python; все, что вам нужно, это пакет comtypes. Моя презентация включала в себя расширенное упражнение по созданию COM-компонента с использованием Python, но это было предназначено для UberPyGeeks. Файл snippets.py содержит все необходимые примеры.
1
@ Марк, большое спасибо за исправление. Для ясности: в приведенном выше рецепте можно удалить шаги 1,3,4, если ctypes уже установлен?
Мэтт Уилки
2
Да уж. Проверял это в лаборатории. Вам просто нужно установить комтипы.
RK
@RK, отлично! Спасибо за проверку и обновление ответа.
Мэтт Вилки
1
Отрывки модуль переделки в устанавливаемом ао модуля здесь: github.com/maphew/arcplus/tree/master/arcplus/ao (обновлено 10,3 см предыдущих версий файла для 10.2). Обновлю основной ответ, как только я устраню некоторые ошибки.
Мэтт Уилки
32

Да, презентация Марка Седерхольма, о которой упоминал Мэтт Уилки, - отличное место для начала. Рецепт / код, который представляет Мэтт, безусловно, является хитрым и, вероятно, лучшим способом решения проблем. Я хотел упомянуть, однако, довольно грубый метод, который я использую в ArcGIS 10.0. У меня есть несколько сценариев автоматизации (автономных, вне границ приложения), которые я запускаю таким образом, и они работают просто отлично. Если максимальная скорость вызывает беспокойство, вы можете просто воспользоваться решением Мэтта и покончить с ним.

Я использую пакет comtypes для принудительного переноса всех библиотек ArcObjects (.olb). Затем Python имеет доступ ко всем объектам ArcObject. Я получил упаковочный код от Фрэнка Перкса через публикацию на форуме 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

Вот и все. У вас должен быть полный доступ к объектам ArcObject, начиная с объекта pApp, который является IApplication для объекта AppRef. По моему опыту, оборачивание библиотек ArcObjects при первом запуске не является неожиданно медленным, и для последующих запусков обертывание не происходит. Библиотеки уже упакованы и скомпилированы, так что все намного быстрее.

Добавлено: с этим связана большая осторожность. Функция NewObj, приведенная здесь, предполагает, что скрипт Python выполняется в процессе. Если нет, эта функция будет создавать объекты в процессе Python (т.е. вне процесса), и ссылки на объекты будут неправильными. Для создания в процессе объектов из внешнего скрипта Python вы должны использовать IObjectFactory. См. Комментарии и советы Кирка Куйкендалла в этом стековом сообщении для получения дополнительной информации.

celticflute
источник
1
Хорошая вещь в этом подходе состоит в том, что он не требует установки Visual Studio, что довольно тяжело, если единственное, что вы когда-либо будете с ним делать, это зарегистрируйте com-объекты. Если бы я знал об этом методе чистого питона, я бы, вероятно, никогда бы не попробовал маршрут Седерхольма. ;-)
Мэтт Уилки
1
В этом ответе я немного расширил эту концепцию, сделав импорт и упаковку библиотек типов одним процессом: gis.stackexchange.com/questions/5017/…
blah238
20

Как я могу получить доступ к arcobjects из python?

Если вам нужна конкретная функциональность, которая существует и присутствует в коде C ++ Arcobjects, то лучше всего было бы создать методы C ++ для их вызова ..., а затем создать оболочку Python для доступа к этим методам C ++.

Существует довольно много способов получить доступ к методам C ++ из python, и многие люди, которые делают это, используют такой инструмент, как SWIG, для автоматической генерации классов python из сигнатур методов C ++. По моему опыту, эти автоматически сгенерированные API-интерфейсы становятся довольно неприятными при передаче не родных типов C ++ (int, float) и никогда не бывают « питонными ».

Мое рекомендуемое решение было бы использовать API ctypes. Отличное учебное пособие здесь: http://python.net/crew/theller/ctypes/tutorial.html

Основные шаги:

  1. написать некоторую основную логику на C ++, в которой вы считаете, что производительность Python может быть проблемой
  2. Скомпилируйте эту базовую логику (в данном случае, используя вызовы методов ArcObject C ++ API) из объектных файлов в общую (.so) или динамическую библиотеку (.dll), используя любой системный компилятор (nmake, make и т. Д.)
  3. Напишите отображение ctypes между классом python и сигнатурой метода C ++ [SWIG пытается автоматизировать это, но это легко, даже если используются сумасшедшие типы объектов]
  4. Импортируйте скомпилированную библиотеку в вашу программу на Python и используйте привязки связанного класса / метода, как и любой другой класс Python!

Вероятно, это более общий способ ссылаться на код C / C ++ изнутри python, в долгосрочной перспективе, вероятно, будет намного проще, если вам не придется иметь дело с COM-объектами. Это также позволит использовать все специфические для системы функции при компиляции связанного библиотечного объекта (поэтому python не будет зависеть от реализации системы / python).

tmarthal
источник
3
Это, безусловно, лучший способ взаимодействия с ArcObjects. Использование comtypes отлично подходит для создания прототипов, но написание собственного C-расширения приведет к хорошему Pythonic-дизайну (потому что вы должны подумать об этом) и лучшей производительности, потому что вы не столько пересекаете объектный барьер C ++ / Python. Хотя для практических целей это сложнее спроектировать / разработать / отладить, поэтому быстрое и грязное уходит в окно.
Джейсон Шейрер
18

Другой вариант - использовать Python для .NET - его очень легко настроить, и он может работать с любыми .NET DLL, включая ArcObjects.

У меня не было никаких проблем с внутрипроцессными объектами, и открытие экземпляра ArcMap, добавление и управление слоями работало для меня нормально.

Единственными требованиями являются папка, содержащая библиотеку Python for .NET, и стандартная установка Python.

Более подробная информация и образец сценария здесь . Пример сценария также можно увидеть по адресу http://gist.github.com/923954.

К сожалению, хотя это работает без проблем на локальном компьютере разработки, для его развертывания в другом месте требуется установить ArcObjects SDK и Visual Studio (включая бесплатную редакцию Express). См. Развертывание DLL-библиотек ArcObject .NET.

geographika
источник
Рецепт ясен, ясен и хорошо представлен. Спасибо География! Я рекомендую вам включить в свой ответ минимальный фрагмент сценария, чтобы в случае обновления вашего сайта ответ мог стоять самостоятельно.
Мэтт Вилки
1
Это именно то, что я сделал в этом старом посте блога ( gissolved.blogspot.com/2009/06/python-toolbox-3-pythonnet.html ), и он работает как положено, но убедитесь, что вы возвращаете результаты, которые понимает ваш скрипт Python (строки, числа или недействительным).
Самуил
Ссылка geographika.co.uk/using-arcobjects-and-net-in-python не работает.
SIslam
5

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

Я не знаю, насколько это нормально, чтобы публиковать об этом здесь, так как в коде написано "СЕКРЕТЫ ТОРГОВЛИ: СОБСТВЕННОСТЬ И КОНФИДЕНЦИАЛЬНОСТЬ ESRI"; но вы найдете это и в других местах в Интернете. В любом случае, это выглядит как относительно простой способ вызова функций, например, SimplifyBuilding_cartography()без установки comtypes или каких-либо других дополнительных библиотек.

Редактировать:

Смотрите комментарии Джейсона ниже. Похоже, что выполнение вышеупомянутого не купит вам много.

LarsH
источник
Я тоже это заметил, похоже, слишком много вуду.
blah238
1
Это не вызывает полностью выставленный набор arcobjects.
Джейсон Шейрер
@JasonScheirer, как бы то ни было, он, по-видимому, допускает более высокую степень доступа к ArcObjects (я думаю), чем прямой arcpy API, и имеет то преимущество, что не требует установки другой библиотеки. Последнее может быть важно, если вы разрабатываете инструменты для использования другими людьми. Я хотел бы знать в полной мере, что вы можете получить доступ с помощью этого метода - это может быть достаточно для определенных целей. (Я не могу проверить прямо сейчас - я не нахожусь в локальной сети компании.)
LarsH
1
Я могу заверить вас в том, что это не так. Я разработал большую часть этого.
Джейсон Шейрер,
1
Тебе нельзя. «ArcObject» в данном случае немного ошибочен. Нет никакого способа добраться до базовых объектов, и нет привязки COM, которая выставляет все объекты ArcObject в любом месте arcgisscripting / arcpy.
Джейсон Шейрер