zoukankan      html  css  js  c++  java
  • 【转载】Python与ArcGIS Engine的集成

     

    1 在Python中调用AO类库

    1.1  准备工作

    本文所使用环境:ArcGIS 10.0Python 2.6

    AO类库在本质是COM组件,在Python中无法直接使用COM,应此需要把COM转换成Python能识别的类型。

    Comtypes是一个开源的基于ctypes python的、轻量级的纯COM客户端和服务器框架,利用comtypes可以把AO对象转换成python能识别的类型。Comtypes的下载地址:http://sourceforge.net/projects/comtypes/

    下载完直接安装后就可以在Python中使用了。Comtypes是利用comtypes.client.GetModule方法将需要的类库生成到comtypes/gen文件夹中,因此 首先需要定义一个GetAoModule函数:

    def GetAoModule(moduleName):

     import comtypes

     from comtypes.client import GetModule

     GetModule('C:/Program Files/ArcGIS/Engine10.0/com/' + moduleName)

    这样就可以引入AO对象库了,比如使用GetAoModule('esriControls.olb'),就可以引入esriControl了。

    我们在使用AO时还需要创建AO对象,这里要使用 comtypes.client.CreateObjec来进行创建,在程序中定义一个AoObj函数:

    #Python中创建一个ArcObjects对象

    def AoObj(MyClass, MyInterface):

     from comtypes.client import CreateObject

     try:

      obj = CreateObject(MyClass, interface=MyInterface)

      return obj

     except:

      return None

    此外还需要定义一个函数用于接口跳转:

    #接口跳转

    def AoCType(obj, interface):

     try:

      newobj = obj.QueryInterface(interface)

      return newobj

     except:

      return None

    使用AO还需要绑定ArcGIS EngineDesktop的许可。在ArcGIS 10.0之后,还需要指定ArcGIS的版本。

    #利用GP绑定许可 

    import arcgisscripting

    gp = arcgisscripting.create(10.0)

    gp.setProduct("ArcEngine")

    #初始化许可

    GetAoModule('esriSystem.olb')

    import comtypes.gen.esriSystem as esriSystem

    pInit = AoObj(esriSystem.AoInitialize,esriSystem.IAoInitialize)

    eProduct = esriSystem.esriLicenseProductCodeEngine 

    licenseStatus = pInit.IsProductCodeAvailable(eProduct)

    if licenseStatus == esriSystem.esriLicenseAvailable:

     pInit.Initialize(eProduct)

    这样在python中使用AO的准备工作就完成了

    1.2  编写脚本

    Python作为一种脚本语言,能够执行批处理程序、开发基于ArcGIS Desktop的小工具,特别是在执行批处理程序上有着很明显的优势。本节利用python编写了一个脚本,用于输出线要素每个结点的M值。

    具体代码如下:

    #打开Shapefile

    GetAoModule('esriGeoDatabase.olb')

    import comtypes.gen.esriGeoDatabase as esriGeoDatabase

    GetAoModule('esriDataSourcesFile.olb')

    import comtypes.gen.esriDataSourcesFile as esriDataSourcesFile

    GetAoModule('esriDataSourcesGDB.olb')

    import comtypes.gen.esriDataSourcesGDB as esriDataSourcesGDB

    GetAoModule('esriGeometry.olb')

    import comtypes.gen.esriGeometry as esriGeometry

    fileWorkspaceFactory=AoObj(esriDataSourcesFile.ShapefileWorkspaceFactory,esriGeoDatabase.IWorkspaceFactory)

    pfw=fileWorkspaceFactory.OpenFromFile('D:/LinearReferencing/',0)

    featureWorkspce = AoCType(pfw, esriGeoDatabase.IFeatureWorkspace)

    featureClass=AoObj(esriGeoDatabase.FeatureClass,esriGeoDatabase.IFeatureClass)

    featureClass=featureWorkspce.OpenFeatureClass("Export_Output.shp")

    #选择所有要素

    queryFilter2=AoObj(esriGeoDatabase.QueryFilter,esriGeoDatabase.IQueryFilter2)

    queryFilter2.WhereClause =''

    fs=featureClass.Search(queryFilter2,0)#0就是Fasle

    featureCursor=AoCType(fs, esriGeoDatabase.IFeatureCursor)

    #创建txt

    f=open('D:/M值表.txt','w')

    fc = featureCursor.NextFeature()

    #循环输出每个线要素的所有结点的M

    while fc:    

        pFeat = AoCType(fc, esriGeoDatabase.IFeature)    

        ps=pFeat.Shape 

        pPl=AoCType(ps, esriGeometry.IPolyline)    

        pPC=AoCType(pPl, esriGeometry.IPointCollection)    

        f.write('OBJECTID  ' + ','+repr(pFeat.OID)+'\n')

        f.write('节点' + "," + '  M'+'\n')

        for i in range(0,pPC.PointCount):

            ppct=pPC.Point[i]       

            pPoint =AoCType(ppct, esriGeometry.IPoint)

            ID=i+1

            f.write(repr(ID) + ",  " + repr(pPoint.M)+'\n')

        fc = featureCursor.NextFeature()

    #关闭文件输入

    f.close()

    脚本运行完毕后,会创建一个txt文件,里面包含了每条线要素所有结点的M值,如下图所示:


    1.3  创建GUI程序

    Python是一种脚本语言,但是python也有很多GUI程序包,比如tkinterwxpythonpyqt等,利用这些程序包可以创建GUI应用程序。本小节利用wxpython调用AE控件创建了一个简单的应用程序,如下图所示。


    首先必须引入esriControls.olb,这样才能使用MapControlTOCControlAE控件。

    #引入esriControls

    GetAoModule('esriControls.olb')

    import comtypes.gen.esriControls as esriControls

    接下来利用wxPython建立框架,并引入MapControlTOCControlToolbarControl。要注意的问题是必须把AE控件当成ActiveX进行转换,这样才能够在Python中应用。

    import wx

    import wx.aui

    #把控件当成ActiveX进行转换

    import wx.lib.activex as ActiveX

    class MyFrame(wx.Frame):

        def __init__(self, *args, **kwargs):

            

            wx.Frame.__init__(self, *args, **kwargs)

            self.mgr = wx.aui.AuiManager(self)

            #添加AE控件

            ax_MapControl = ActiveX.ActiveXCtrl(self,str(esriControls.MapControl ._reg_clsid_),

                                        -1, wx.DefaultPosition,wx.DefaultSize, 0, "MapControl")

            ax_TocControl = ActiveX.ActiveXCtrl(self,str(esriControls.TOCControl ._reg_clsid_),

                                        -1, wx.DefaultPosition,wx.Size(200,100), 0, "TocControl")

            ax_ToolbarControl = ActiveX.ActiveXCtrl(self, str(esriControls.ToolbarControl._reg_clsid_), -1,

                                           wx.DefaultPosition,wx.DefaultSize, 0, "ToolbarControl")

          

            #把控件添加至Frame中       aui.AuiPaneInfo().

            self.mgr.AddPane(ax_ToolbarControl, wx.aui.AuiPaneInfo().Name("地图工具条").Caption("地图工具条").Top())                 

            self.mgr.AddPane(ax_MapControl, wx.aui.AuiPaneInfo().Name("地图控件").Caption("地图控件").Center())        

            self.mgr.AddPane(ax_TocControl, wx.aui.AuiPaneInfo().Name("TOC目录").Caption("TOC目录").Left())

           

            #设置mapcontrol与 toolbarControltocControl的伙伴关系

            toolbarControl = ax_ToolbarControl.ctrl

            tocControl = ax_TocControl.ctrl

            MapControl= ax_MapControl.GetCtrl()

            

            self.Add_toolbar_Command(toolbarControl)

            toolbarControl.SetBuddyControl(MapControl)

            tocControl.SetBuddyControl(MapControl)

            

            self.mgr.Update()

            

        #向 ToolbarControl 中添加命令按钮

        def Add_toolbar_Command(self,toolbarControl):            

                toolbarControl.AddItem('esriControlCommands.ControlsOpenDocCommand',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsMapZoomInTool',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsMapZoomOutTool',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsMapZoomInFixedCommand',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsMapZoomOutFixedCommand',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsMapPanTool',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsMapFullExtentCommand',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsMapZoomToLastExtentBackCommand',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsMapZoomToLastExtentForwardCommand',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsSelectFeaturesTool',-1,-1,False,0,1)

                toolbarControl.AddItem('esriControlCommands.ControlsSelectTool',-1,-1,False,0,1)

    class MyApp(wx.App):

        def OnInit(self):

            frame = MyFrame(None, -1, 'Python中使用ArcGIS Engine',(100,100),(800,600))

            frame.Show()

            

            self.SetTopWindow(frame)

            return 1

    app = MyApp(0)

    app.MainLoop()

    2 ArcGIS Engine程序中调用python脚本

    基于AE的二次开发有很多种方式,包括JAVAC++.NET。本节介绍在.NET中调用python脚本。

    .NET程序中使用python脚本,必须使用IronPythonIronPython是一个开源的项目,能够使用户在.NET环境中使用python,我们可以在http://ironpython.codeplex.com/ 上下载对应用python版本的IronPython。最新的IronPython要求.NET版本必须在4.0以上。

    下载并安装IronPython后,需要在.NET程序中进行设置。首先在程序中添加IronPython.dllMicrosoft.Scripting.dll的引用,这两个dll位于IronPython的安装目录下。

     

    然后在程序中添加using IronPython.Hostingusing Microsoft.Scripting.Hosting


    我们还需要把python文件添加至工程中,需要注意的是,要把Python文件的属性“复制到输出目录”设置成“始终复制”。

     

    这样,就可以在程序中调用python脚本了。

    ScriptRuntime pyRuntime = Python.CreateRuntime();

    dynamic obj = pyRuntime.UseFile("Ratio_divided.py");

    obj.Ratio_divided();

    需要注意的是Python脚本中不能使用ArcPy包,否则就会出现如下的错误:没有arcpy的模型包。

     

    这样,就可以在程序中调用python脚本了。

    ScriptRuntime pyRuntime = Python.CreateRuntime();

    dynamic obj = pyRuntime.UseFile("Ratio_divided.py");

    obj.Ratio_divided();

    需要注意的是Python脚本中不能使用ArcPy包,否则就会出现如下的错误:没有arcpy的模型包。

     

    这主要是因为IronPython不支持ArcPy,因为ArcPy是基于cpython开发的,而IronPython不支持cpython,当然国外也有人用IronClad(一个IronPython)在IronPython中使用cpython的包,但是其对 ArcPy支持不是很好。

    详见http://forums.arcgis.com/threads/21405-Arcpy-in-SharpDevelop-4.0 

    3 PythonArcGIS Engine集成的几种方式对比

    前面介绍了PythonArcGIS Engine集成的三种方法,现在对这三种方法进行一个比较,见下表。

     

    开发难宜

    资源

    应用范围

    推荐

    利用Python调用AO,编写脚本

    ☆☆☆

    ☆☆☆

    ☆☆☆☆

    利用Python调用AO,创建GUI程序

    ☆☆☆

    AE程序中调用Python

    ☆☆

    ☆☆☆

    ☆☆☆

    python脚本特别适合一些批处理操作,如果用户要处理空间数据,而又没有ArcGIS Desktop,只有ArcGIS Engine,利用python调用AO写个小脚本,会非常方便,效率也会很不错。当然如果装了Desktop,可以导入ArcPy站点包,那就会更方便了。

    利用Python调用AO,创建GUI程序,也是一种可以的方法,但是个人很不推荐,因为comtypesAO类型库转换后,AO对象的事件很不好操作,当然如果你很爱折腾,又很闲的话,也可以试试这种方法。

    而在AE程序中调用Python的话,在某些情况的话也是很不错的选择,比如已经有一个写好的python文件,而里面有个功能正是我们想要的,我们当然要发挥“拿来主义”了。但是我们可以这样想一下,无论是采用.NET还是JAVA或是C++都能很方便的调用AO,那我们为什么还要舍近求远,在Python中使用AO,然后再调用Python呢?

    所以个人觉得在ArcGIS中利用python的最好方式就是编写python脚本,这样便能充分python的优势:简洁、高效。

  • 相关阅读:
    嵌入式框架Zorb Framework搭建三:列表的实现
    嵌入式框架Zorb Framework搭建二:环形缓冲区的实现
    C#比较两个时间大小
    大数据概述
    综合练习:英文词频统计
    熟悉常用的Linux操作
    Python基础画五星红旗
    字符串、组合数据类型练习
    简化版C语言文法
    词法分析实验报告
  • 原文地址:https://www.cnblogs.com/jhlong/p/5394530.html
Copyright © 2011-2022 走看看