Новое в Python версии 2.5 это – ctypes, библиотека внешний функций. Она обеспечивает C-совместимые типы данных и позволяет вызывать функции с помощью динамически-подключаемых библиотек (DLL) или других общих библиотек. Используя модуль ctypes в Python, в инструменте-скрипте геообработки можно использовать код ArcObjects, написанный в C++ .
Применяя ctypes в Python, вы можете с легкостью изменять параметры и типы инструмента-скрипта без перекомпиляции кода C++. Модуль ctypes поддерживает любую C- функцию с основными типами данных, например char, int, float и double , а также structs and pointers.
Возможность вызова DLL из скрипта Python дает множество преимуществ. Вы можете использовать с выгодой для себя тонко настроенные классы ArcObjects в ваших заданиях по геообработке, ваша интеллектуальная собственность будут защищена, и это намного проще сделать, чем пользоваться интерфейсами IGPFunction2 и IGPFunctionFactory. Вы создаете ваш объект в Python и вызываете метод выполнения (execute), передавая необходимые параметры из скрипта при помощи структуры геокодирования.
принцип работы
Необходимо выполнить следующие действия:
Создание проекта C++ Win32 в Visual Studio 2008, поддерживающего экспорт простой функции с прототипом:
int GpExecutetool(char* parameter1, char* parameter2)
Не забудьте включить в проект директорию ArcGIS\com\directory и импортировать файлы ArcObjects.olb.
Создайте инструмент-скрипт в пользовательском наборе инструментов, где производится проверка этих двух параметров и их переотправка в скрипт.
Ваш скрипт Python сделает следующее:
- Импорт arcpy и ctypes.
- Получит параметры от инструмента-скрипта
- Импортирует DLL в память.
- Наведите курсор на функцию в DLL.
- Укажите необходимые типы аргументов функций, экспортированных из DLLs, установив атрибут argtypes и обратный тип.
- Передайте параметры в C++ code в DLL.
Подробности
Проект C++ project (именуемый для данного примера GPToolAsSimpleDLL) является простым проектом Win32, который добавляет в класс пространственных объектов поле AREA и вычисляет его значение.
Файл заголовка
#ifdef GPTOOLASSIMPLEDLL_EXPORTS
#define GPTOOLASSIMPLEDLL_API extern "C"__declspec(dllexport)
#else
#define GPTOOLASSIMPLEDLL_API extern "C"__declspec(dllimport)
#endif
GPTOOLASSIMPLEDLL_API int GPexecutetool(char*, char*);
Файл – источник GPToolAsSimpleDLL открывает указанный класс полигональных объектов и устанавливает указанное поле в область (area) каждого полигонального объекта. Каждая функция геообработки, которую вы пишете, может быть реализована простой точкой входа функции С (C function), все в одном и том же DLL, вместе с компаньонами инструмента-скрипта, чтобы каждая функция была видна в ArcToolbox.
GPTOOLASSIMPLEDLL_API int GPexecutetool(char* featureclassPath, char* fieldname)
{
// Convert char*s to bstring
_bstr_t catalogPath;
catalogPath = featureclasspath;
_bstr_t newfieldname;
newfieldname = fieldname;
// Coinitialize GP utilities class
IGPUtilitiesPtr ipUtil(CLSID_GPUtilities);
// Feature class holder
IFeatureClassPtr ipFeatureclass(0);
HRESULT hr;
// Try to fetch feature class from catalog path
if (FAILED(hr = ipUtil->OpenFeatureClassFromString(catalogPath, &ipFeatureclass)))
{
return -1;
}
// Index position of the specified field
long fieldIndex;
ipFeatureclass->FindField(newfieldname, &fieldIndex);
// Set up query filter and feature cursor
IQueryFilterPtr ipFilter(CLSID_QueryFilter);
IFeatureCursorPtr ipCursor;
IFeaturePtr ipRow;
IGeometryPtr ipShape;
// Open search cursor on feature class
ipFeatureclass->Search(ipFilter, VARIANT_FALSE, &ipCursor);
// Iterate
esriGeometryType gt;
for (ipCursor->NextFeature(&ipRow);
ipRow != NULL;
ipCursor->NextFeature(&ipRow))
{
// Get row's associated geometry
ipRow->get_Shape(&ipShape);
// Ensure we've got a polygon
ipShape->get_GeometryType(>);
if (gt != esriGeometryPolygon)
return -2;
// Get area
IAreaPtr ipArea(ipShape);
double area;
ipArea->get_Area(&area);
// Pop double into a variant
VARIANT value;
value.vt = VT_R8;
value.dblVal = area;
// Set double variant onto target field
ipRow->put_Value(fieldIndex, value);
// Save
ipRow->Store();
}
return S_OK;
}
Скрипт Python действует как брокер, принимая два параметра от инструмента-скрипта в текстовом виде и пересылая их в функцию DLL какchar*, разделенные нулем строки. До вызова функции в DLL данный скрипт использует также инструмент геообработки Добавить поле. Это может сделать ваш рабочий процесс более сложным, требующим реализации вашей персональной функциональности в C++ в сочетании с выполнением общих задач в Python.
import arcpy
import ctypes
# Get the parameters from the script tool dialog
#
shp = arcpy.GetParameterAsText(0)
fieldName = arcpy.GetParameterAsText(1)
# See if the field already exists in the feature class.
# If not, add it.
if len(arcpy.ListFields(shp, fieldName)) == 0:
arcpy.AddField_management(shp, fieldName, "DOUBLE")
# Import DLL into memory and get a pointer to the function
# Note: be sure the DLL is in your Python search path
#
dll = ctypes.cdll.GPToolAsSimpleDLL
perform_function = dll.GPExecutetool
# Tell ctypes the function accepts two char* arguments
#
perform_function.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
# Tell ctypes the function return type
#
perform_function.restype = ctypes.c_int
# Call the function in the DLL
#
retval = perform_function(shp, fieldName)
# Check the return value. If a 0 returned, success!
#
if retval == 0:
arcpy.AddMessage("Success")
elif retval == 1:
arcpy.AddError("Unable to open " + shp)
elif retval == 2:
arcpy.AddError("Not a polygon feature class")