在ArcGIS 10以后,VBA将退出ArcGIS产品中,由此可想而知,将来Python在ArcGIS产品中的地位将会十分重要。虽然在ArcGIS中Python已经存在了很长一段时间,但是,一般常用的可能还是将模型导出为Python脚本,然后用以和他人交换或者使用操作系统定时任务等方式供其它程序调用。而本文需要描述的是,如何通过编写Python脚本,并在脚本中使用ArcObjects对象,来充分发挥Python胶水语言的特点,在其它程序和ArcGIS之间构造一个交互的桥梁。
我们都知道ArcGIS中的ArcObjects都是COM对象,在Python中调用COM对象需要一个开源的类库:comtypes,我们可以从sourceforge上下载并安装它:
在Windows下的安装界面是这个样子的:
在这步完成以后,所有对ArcGIS的调用就都是在Python环境下处理的问题了。让我们首先来看如何在Python中加载ArcObjects的组件库。
我这里写了一个方法,用以可以方便地加载ArcGIS的OLB文件:
def GetAoModule(moduleName): import comtypes from comtypes.client import GetModule GetModule('C:/Program Files (x86)/ArcGIS/Desktop10.0/com/' + moduleName)
这样,在我想使用AO中的几何对象时,只需要通过如下的代码把esriGeometry这个对象库加载上即可:
GetAoModule('esriGeometry.olb')
在这里我们可以看到我们刚才安装的comtypes的身影,我们依靠它才可以加载ArcGIS的对象库。同样,在这里我们还需要依靠comtypes帮我们创建ArcObjects对象(COM对象),为了方便我这里还定义了一个方法:
def AoObj(MyClass, MyInterface): from comtypes.client import CreateObject try: obj = CreateObject(MyClass, interface=MyInterface) return obj except: return None这样,如果我想要在Python中创建一个ArcObjects对象,比如Point,我们就可以使用如下的方法:
GetAoModule('esriGeometry.olb') import comtypes.gen.esriSystem as esriSystem pt = AoObj(esriSystem.Point, esriSystem.IPoint)
现在,我们已经可以创建ArcObjects对象了,但是,这里还有一个重要的问题需要解决,那就是如何进行对象接口类型转化。比如我得到了一个对象的IWorkspace接口,但是我需要调用的是这个对象的IFeatureWorkspace接口的方法,这个时候需要一个转化,在Python中我准备了另外一个方法去做这件事情:
def AoCType(obj, interface): try: newobj = obj.QueryInterface(interface) return newobj except: return None这样,如果我想将一个IWorkspace接口的对象转到IFeatureWorkspace接口时,就可以这样操刀:
GetAoModule('esriGeoDatabase.olb') import comtypes.gen.esriGeoDatabase as esriGeoDatabase fw = AoCType(w, esriGeoDatabase.IFeatureWorkspace)
通过上面的GetAoModule、AoObj和AoCType这3个方法,我们就可以方便地使用ArcObjects对象了。下面,让我们通过一个从ArcSDE数据库查询要素的例子来再次熟悉一下Python中ArcObjects对象的使用:
GetAoModule('esriSystem.olb')
GetAoModule('esriDataSourcesGDB.olb')
GetAoModule('esriGeoDatabase.olb')
import comtypes.gen.esriSystem as esriSystem
aoInit = AoObj(esriSystem.AoInitialize, esriSystem.IAoInitialize)
pCode = esriSystem.esriLicenseProductCodeArcInfo
status = aoInit.IsProductCodeAvailable(pCode)
if status == esriSystem.esriLicenseAvailable:
aoInit.Initialize(pCode)
props = AoObj(esriSystem.PropertySet, esriSystem.IPropertySet)
props.SetProperty("server", "localhost")
props.SetProperty("instance", "5151")
props.SetProperty("user", "sde")
props.SetProperty("password", "sde")
props.SetProperty("version", "SDE.DEFAULT")
import comtypes.gen.esriDataSourcesGDB as esriDataSourcesGDB
import comtypes.gen.esriGeoDatabase as esriGeoDatabase
wf = AoObj(esriDataSourcesGDB.SdeWorkspaceFactory, esriGeoDatabase.IWorkspaceFactory)
w = wf.Open(props, False)
fw = AoCType(w, esriGeoDatabase.IFeatureWorkspace)
fc = fw.OpenFeatureClass("sde.sde.cities")
c = fc.Search(None, False)
f = c.NextFeature()
while (f != None):
print(str(f.ObjectID))
f = c.NextFeature()