Shapefile是GIS建库的常用格式之一,Shapefile从ArcView时代开始以结构清晰、简单高效的特点凭借ESRI公司的强势推动,广泛应用于GIS的各种场合。本文讨论的数据加工也是基于Shapefile格式。ArcObjects是ESRI随新一代ArcGIS推出的组件式GIS开发平台,同时还推出了新的数据模型Geodatabase。ArcObjects功能非常强大,涵盖几何编辑、数据库操作、符号化、空间分析、栅格分析、网络分析等各个方面。ArcObjects在生产中能够发挥明显作用,提高生产效率。本文也将详述ArcObjects在Shapefile数据更新加工项目中的应用过程。

1数据采集

采集方式:屏幕数字化。加工平台:ArcGIS/ArcObjects。

2数据转换

源数据格式:Geoway数据平台;目标格式:ESRI的Shapefile格式;

这里的数据转换已超出了数据格式转换的范围,实际上是包括数据格式转换、编码系统对应更新、数据拼合、相关层次整理、符号重绘等一系列问题。

2.1 GeowayàShapefile

ESRI没有提供专门访问Geoway的接口,只能由Geoway生成ESRI的Shapefile或E00文件。从技术角度看,Geoway数据转换Shapefile有一些特点:

1) Geoway工作区中包含GIS数据与制图数据两类数据,转换前需要区分。否则同一地物转换会有重复。

2) 符号化信息丢失。用户无法解决的原因:一是Geoway与Shapefile数据结构不统一且Geoway没有公开的交换格式;二是Geoway没有提供二次开发接口;三是Geoway没有提供将符号信息批量转入属性表的功能,需要人工录入。

3) 生成Shapefile过程中可能出错,生成的Shapefile不能被正确打开。

4) Geoway中点、线、面、注记可共层并且可共用编码。一个Geoway层转换为若干个Shapefile。

因此GeowayàShapefile不能解决所有问题,必要时还要经过AutoCAD进行补充。Geoway转换为DXF的符号化做得较好。

2.2也谈DXF/DWG与Shapefile的转换

同样是数据格式转换,DXF/DWG与Shapefile的方式要灵活得多。首先DXF是一个明码的开放数据格式,其次ArcGIS可以直接读取DWG,第三DWG编辑和开发环境是AutoCAD,具有开放的二次开发接口。DXF/DWG与Shapefile转换有以下几种可选方式:

1) 利用二次开发工具生成对方的文件格式或交换文件。如利用AutoCAD的二次开发工具生成SHP/E00,要求开发者熟悉Shapefile及DBF二进制格式或者E00的文本格式,否则生成的Shapefile容易不能被打开。反之,用ESRI二次开发工具生成DXF需要对DXF格式足够熟悉。

2) 利用第三方工具,如MapInfo 通用转换器、Geoway的数据转换器、FME等。其中MapInfo和Geoway的数据转换工具可定制性较差。FME转换虽可定制,但需要掌握FME的映射语法(当然FME的界面操作可使此步骤减化)。使用第三方工具的代价是需要专门购买工具甚至整个软件平台。

3) 利用ESRI的工具 ArcCatalog/ArcToolbox导入或导出DXF/DWG。优点是操作简单,缺点是可定制性较差。并且由于Geodatabase数据精度问题,当小数位数要求较高时,由ArcCatalog/ArcToolbox生成的DXF,可能产生一些变形。

4) 利用ESRI的组件MapObjects、ArcObjects等与AutoCAD开发接口交互,创建新格式对象。例如用ArcMap的VBA通过Automation机制读写AutoCAD的DWG。该方式的缺点是需要访问注册表来获取COM类的GUID,程序运行速度较慢。这种方法不同于常规数据转换方法,实际是数据再生成。下列代码利用ArcObjects和Automation机制实现了将一个几何类型为Polygon的特征类转换为AutoCAD的Polyline实体并设置图层、Thickness等属性的功能。

Sub TransPolyline(AcadApp As Object, pFeatClass As IFeatureClass)
 ……     '省略若干变量定义
 Set pCursor = pFeatClass.Search(Nothing, False)
 Set pFeature = pCursor.NextFeature
 While Not pFeature Is Nothing  '循环遍厉所有的特征
   Set pPolyline = pFeature.Shape
   Set pGeometryColl = pPolyline
   fld = pFeatClass.FindField("CODE")
   Tck = pFeature.Value(fld)
   lyr = pFeatClass.AliasName
   For j = 0 To pGeometryColl.GeometryCount - 1
     Set pPath = pGeometryColl.Geometry(j)
     Set pPointColl = pPath
     ReDim points(0 To pPointColl.PointCount * 3 - 1) As Double
     PointCollToCADPoints pPointColl, points
     '创建AutoCAD的Polyline实体
     Set myPline = AcadApp.ActiveDocument.ModelSpace.AddPolyline(points)     
     If Not findLayerInAcadDoc(AcadApp.ActiveDocument, lyr) Then
       CreateLayerInAcadDoc AcadApp.ActiveDocument, lyr  '创建AutoCAD图层
     End If
     myPline.Layer = lyr
     myPline.Thickness = Tck
   Next
   Set pFeature = pCursor.NextFeature
 Wend
End Sub

2.3 Shapefile合并问题

2.3.1合并前提

合并两个或更多Shapefile有两个前提,一是对象几何类型相同,如面文件与面文件合并;一是属性表结构要相同。对象类型相同与否较容易判断,表结构是否相同在此即比较DBF文件的关系模式是否相同。可以利用Visual Basic、Delphi等通过ODBC、Borland Database Engine等开放数据标准或数据引擎来编写程序,实现DBF文件表结构比较。

DBF文件表结构不同有两种情况:当总Shapefile的表结构比待合并Shapefile表结构全,不影响合并;当出现某待合并的Shapefile比总Shapefile的表结构多出某字段时不能直接合并,有两种处理方式:一是待合并Shapefile多出字段删除(应保证字段值为空),另一种是为总Shapefile添加字段。

2.3.2合并解决方式

1) 编写程序以二进制方式直接重新生成新的Shapefile。该方式同样要求开发者熟悉Shapefile及DBF的二进制格式。

2) 用ArcGIS的Load Data菜单命令。该方式的缺点是要在Geodatabase下建立数据集,而数据集是具有空间参考信息特性的,空间参考包含了一个重要的要素是由X、Y的域范围确定的精度,因此在测区坐标范围较大且小数位数要求较高的条件下精度可能会有损失;优点是由ArcCatalog完成,操作简单,不许要额外的工具。

3) 利用ArcObjects的IObjectLoader。能够自由灵活地适应各种合并需要,但需要编写相应代码。笔者利用该方式实现了多目录下同名Shapefile合并、同目录下多个Shapefile合并等合并功能。

2.4编码体系更新问题

编码体系更新有两个步骤:先建立新旧代码转换表,然后编写程序进行代码属性对应更新。代码属性对应更新可以有两种可选的方式,一是利用ArcObjects的ICalculator,一是直接访问DBF并利用SQL执行Update语句更新。

2.5线、面互转问题

在Geodatabase模型中,多义线由路径组成,多边形由环组成。其中多义线和多边形对应于一个特征对象的几何数据(即Shape字段的内容),可以存储于内存和硬盘中,而路径和环仅仅是构成特征的几何数据的元素,只能临时存储于内存中。多义线、多边形在ArcObjects分别定义接口为IPolyline和IPolygon,而路径和环被定义接口为IPath与IRing。

因此Geodatabase多义线与多边形互转问题被进一步转化为IRing与IPath的转换,从ArcObjects的UML类图上可以看出IRing继承自IPath,所以在代码中IRing直接由类型转换成为IPath,在ArcMap中Polygon对象在跨层编辑时可以直接粘贴到线特征类中成为多义线(Polyline)。而IPath接口转换成IRing接口则需要进一步降低组成单位,即直接去获取点坐标集合。IRing和IPath对象都实现了点坐标集合接口IPointCollection,通过IPointCollection::AddPointCollection方法可实现IPath到IRing的转换。

2.6符号重绘

Shapefile本身不存储符号化信息。一些不依比例的地物可以换一种方式来表示存储以达到一定程度上的符号重现。例如不依比例尺房屋在源格式中存储为有向点,转换为Shapefile后可以依据点坐标和角度属性按图式符号大小绘制面特征,通过属性数据中代码字段来标识该种地物类别。房屋、桥梁、道路在重新绘制时都需要遇到推平行线的问题。可以按照几何公式自行计算,也可以ArcObjects提供的IConstructPoint::ConstructParallel方法实现此功能。

3 ArcObjects数据模型

3.1 ArcObjects下GIS数据模型的关系数据库视角

GIS本质上是管理空间数据的信息系统,因此可以按照关系数据库的模型来建立对ArcObjects的认识。笔者试图用数据库开发者角度讨论ArcObjects对空间对象数据库模型。表-1列出了SQL操作与 ArcObjects接口对应关系。

SQL操作与 ArcObjects接口对照                      表-1         



数据操作

SQL谓词

ArcObjects接口、属性或方法

选择

SELECT

IFeatureClass::Select()、IFeatureClass::Search()、IFeatureClass.SubFields

更新

UPDATE

ICalculator

插入

INSERT

IFeatureClass::CreateBuffer()、IFeatureCursor::InsertFeature()

删除

DELETE

IFeature::Delete()

分组

GROUP BY

IDataStatistics.UniqueValues

排序

ORDER BY

ITablesort.Sort

条件设置

WHERE

IQueryFilter::WhereClause




此外游标常用于特征集、查询结果集的访问遍历。ArcObjects中游标的使用同样与关系数据库中结果集遍历类似,如对应Transact-SQL中的FETCH NEXT语句,ArcObjects中利用IFeatureCursor::NextFeature()实现游标功能。

3.2表结构维护问题

1) DBF直接添加,即利用FoxBase、Visual FoxPro、MapInfo、Borland Database Desktop等DBF编辑工具或用Visual Basic等语言直接访问DBF添加字段。

2) 利用ArcObjects的IFieldEdits不但可以定义非二进制的属性字段,还可以定义二进制的几何字段。虽然Shapefile的属性表中并未存储几何字段,但Geodatabase数据存取对象(Geodatabase Data Access Objects,以下简称GDAO)却屏蔽了实际代码操作过程的细节,把Shapefile的几何数据和Geodatabase几何字段的定义以相同的接口提供给开发者使用。

3.3 Geodatabase与Shapefile的比较

3.3.1 Shapefile模型分析

Shapefile属于混合结构数据管理模型,即文件与关系数据库混合管理模式。这种模式下几何图形数据用文件形式以特定内部结构进行存取和管理;属性数据通过关系数据库管理系统实现管理访问。几何图形数据和属性数据通过对象的ID关联。Shapefile的几何图形数据存储于扩展名为*.shp的文件中,而属性数据存储于dBASE格式(*.DBF)数据表中。早期的Shapefile开发工具主要是组件集MapObjects或者ArcView及其脚本语言。

3.3.2 Geodatabase模型分析

Geodatabase是随ArcGIS一同推出的新一代GIS数据模型,鉴于Geodatabase模型的庞大复杂,在此仅简述的该模型的最明显的特性。Geodatabase是一种面向对象(OO)数据模型,几何图形、属性数据统一存储于关系数据库中。面向对象GIS数据模型中不会出现几何数据丢失属性数据保留或者属性数据丢失几何数据保留的状况。空间对象除了具有属性特征,还可以具有一组操作,并且支持继承特性。用户可以利用CASE工具设计定义数据类型,以UML格式提交给ArcGIS。

3.4 ArcObjects操作Shapefile的优点

利用ArcObjects可以在Geodatabase的数据模型下对Shapefile操作,也就是说Shapefile的每条记录在ArcObjects框架下具有了对象特性,Shapefile的记录集被对应于Geodatabase中的FeatureClass。由于IFeatureClass接口的定义,利用GDAO能使Geodatabase、Shapefile对数据内部操作的细节被封装隐藏。开发者通过IFeatureClass操作特征时,可以不用关心被操作的文件具体是Shapefile还是Geodatabase。

ArcMap中用内置ArcObjects的VBA比ArcView中用脚本操作Shapefile更加灵活和方便,而且ArcObjects对Shapefile的操作比MapObjects要强大许多。

4空间查询与拓扑运算的应用

空间查询是GIS数据模型与一般关系模型的典型区别;拓扑运算是不同于关系模型集合操作、侧重于几何数据的操作,是GIS特有的空间运算。

利用ArcObjects的空间过滤器ISpatialFilter按空间关系(如邻接、包含等)执行查询,然后配合拓扑算子IToplogicalOperateor的进行拓扑运算(如缓冲区、并交差、裁切等),可以解决面合并、切割、删除重复线、删除重复点问题等实际问题。

4.1切割问题

切割在此指用面特征去擦除与其它特征重叠的部分,是屏幕数字化作业过程中对Shapefile进行数据编辑经常遇到的问题。切割的实现方法比较如下:

1) ArcMap的Clip菜单命令。由ArcMap包含的功能,缺点是不能切割线、点。

2) 用ArcToolBox,即Analysis Tools/Overlay/Erase工具。该方法要求切割者与被切割者都是要素集,对于要素集内实现对象间切割不够方便。

3) 利用ArcObjects中的IToplogicalOperateor编写代码实现。该方法可以切割线、点、面,灵活性大,可以附加实际需要的其他操作。切割的代码实现如下:

Sub MutiClipObj()
……  '省略若干变量定义 
 pID = "esriCore.editor"
 Set pApp = Application
 Set pEditor = pApp.FindExtensionByCLSID(pID)
 Set pEnumFeat = pEditor.EditSelection
 Set pSetFeature = pEnumFeat.Next
  If pFeatCliper Is Nothing Then Exit Sub
 Set pGeometry = pFeatCliper.Shape
 While Not pSetFeature Is Nothing
   Set pSetGeometry = pSetFeature.Shape
   Set pPointColl = pSetFeature.Shape     
   If (Not pSetGeometry Is Nothing) And (pPointColl.PointCount > 0) Then
     Set pTop = pSetGeometry
     Set pTopResult = pTop.Difference(pGeometry)
     Set pPointColl = pTopResult
     If pPointColl.PointCount = 0 Then
       pSetFeature.Delete
     Else
       Set pSetFeature.Shape = pTopResult
       pSetFeature.Store
     End If
   Else
     pSetFeature.Delete
   End If
   Set pSetFeature = pEnumFeat.Next
 Wend
End Sub

4.2接边问题

数据接边在此是指合并共边的Polygon或共点的Polyline。合并共边的Polygon代码实现如下:

Sub JieBian()
……  '省略若干变量定义 
 Set pMap = ThisDocument.FocusMap
 Set pFeatLyr = pMap.layer(0)
 pID = "esriCore.editor"
 Set pApp = Application
 Set pEditor = pApp.FindExtensionByCLSID(pID)
 Set pEnumFeat = pEditor.EditSelection
 Set pFeature = pEnumFeat.Next
 While Not pFeature Is Nothing
    Set pGeometry = pFeature.Shape
    Set pFeatureClass = pFeature.Class
    Set pSpatialFilter = New SpatialFilter
    Set pSpatialFilter.Geometry = pGeometry                   '以本对象为空间选择条件
    pSpatialFilter.SpatialRel = esriSpatialRelTouches            '邻接关系
    pSpatialFilter.GeometryField = pFeatureClass.ShapeFieldName
    Set pQueryFilter = pSpatialFilter
    Set pCursor = pFeatLyr.Search(pQueryFilter, False)          '以空间过滤为条件
    Set pSetFeature = pCursor.NextFeature
    While Not pSetFeature Is Nothing                         '有邻接面
      Set pSetGeometry = pSetFeature.Shape
      Set pTop = pGeometry
      Set pFeature.Shape = pTop.Union(pSetGeometry)           '合并后赋给当前对象
      pFeature.Store        
      pSetFeature.Delete                                    '被合并的对象删除
      Set pSetFeature = pCursor.NextFeature
    Wend
    Set pFeature = pEnumFeat.Next
 Wend
End Sub

5定制编辑环境

ArcObjects不仅可以用作对数据本身的进行操作,还可以对ArcMap编辑环境进行定制,进而提高效率、方便操作以及对数据编辑添加自定义特性。

5.1标注问题

当多个层有同名属性需要同时标注时,可以利用以下代码实现。

Sub LabelAllLayerField()
……  '省略若干变量定义
 Set pColor = New RgbColor
 pColor.RGB = RGB(0, 0, 0)    
 Set pMap = ThisDocument.FocusMap
 LabelField = InputBox("输入标注字段", "输入", "name")
 For i = 0 To pMap.LayerCount - 1
   Set pFeatLyr = pMap.Layer(i) 
   If pFeatLyr.FeatureClass.FindField(LabelField) <> -1 Then
     pFeatLyr.DisplayAnnotation = True
     Set pAnnoLayerPropsColl = pFeatLyr.AnnotationProperties
     pAnnoLayerPropsColl.QueryItem 0, pAnnoLayerProps, Nothing, Nothing
     Set aLELayerProps = pAnnoLayerProps
     aLELayerProps.Symbol.size = 11
     aLELayerProps.Symbol.Color = pColor
     aLELayerProps.Expression = "[" + LabelField + "]"
   End If
 Next
 pMxDoc.ActivatedView.Refresh
End Sub

5.2捕捉事件

许多GIS数据采集软件或者构建在图形系统上的数字制图软件都提供了地物属性添加、命令操作与编码的绑定。例如点击标有房屋图标的工具栏后,用户绘制的新地物是房屋,并为新地物设置了房屋代码。ArcGIS是GIS平台而非GIS应用软件,没有提供类似的功能。开发者可以利用ArcObjects在ArcMap中根据实际需要扩展应用,达到解决类似问题的目的。下列VBA代码将使用户在ArcMap中新建一个地物特征时必须录入其分类属性。

Private WithEvents EditorEvents As Editor
Private WithEvents EditorEvents2 As EditEvents2
Public m_pEditor As IEditor
Public m_pEditLayers As IEditLayers
Public Sub InitEvents()
 Dim pUID As New UID
 pUID = "esriEditor.Editor"
 Set m_pEditor = Application.FindExtensionByCLSID(pUID)
 If m_pEditor Is Nothing Then Exit Sub
 Set m_pEditLayers = m_pEditor
 Set EditorEvents = m_pEditor
 Set EditorEvents2 = m_pEditor
End Sub
Private Sub EditorEvents_OnCreateFeature(ByVal obj As esriGeodatabase.IObject)
……  '省略若干变量定义
 Set pFeatureClass = obj.Class  
 Set pfeat = obj
 fld = pFeatureClass.FindField("layer")
 strLyrName = InputBox("请输入层名", "", strLyrName)
 While CheckLayerIsValid(strLyrName) = False
   strLyrName = InputBox("层名非法,请重新输入层名", "", strLyrName)
 Wend    
 pfeat.Value(fld) = strLyrName
 pfeat.Store
End Sub

6小结

提高工作效率是生产单位一直值得探讨的问题,扩展软件功能可以增加软件灵活性并加快操作速度,程序取代人工重复操作可以降低工作强度并保证正确性。利用开发工具来提高生产效率不失为一个好的方法,应当是GIS数据生产单位可以推广和提倡的方式。

ArcObjects类库规模庞大、结构复杂,编程被停滞往往并非开发者程序编写水平问题,而是开发者常常限于茫茫组件中找不到要完成操作所对应的类和接口,本文对ArcObjects应用的讨论仅是冰山一角。另外ArcGIS开发者需要较深入地理解Geodatabase 模型,ArcObjects类库的结构是与Geodatabase相匹配的。使用ArcObjects需要开发者对数据库有必要理解,具备GIS理论基础,并且要求开发者对COM编程有足够熟悉。COM是组件式编程的基础,比如习惯了AutoCAD的VBA中类似ThisDrawing.Application.ActiveDocument.ModelSpace.AddPolyline的编程方式的开发者,对于ArcObjects中接口应用(如QueryInterface机制)可能会不适应。ArcObjects的开放性更大,对开发者区别了类和接口,二次开发的成果仍然可以是符合COM的产品(除非语言本身限制)。利用ArcObjects开发基于Shapefile的扩展应用并非新瓶旧酒,是Geodatabase 模型对旧格式的保留和升级,是ArcObjects功能强大、兼容良好、设计精巧的体现。


 

【参考文献】

1. Michael Zeiler,Exploring ArcObjects[M],ESRI Press,2001

2.蒋波涛,ArcObjects开发基础与技巧[M],武汉大学出版社,2006

3.龚健雅,地理信息系统基础[M],科学出版社,2001

4.张敬祥等译,为我们的世界建模——ESRI地理数据库设计指南[M],人民邮电出版社,2004

5.张新长等,地理信息系统数据库[M],科学出版社,2005

6.萨师煊、王珊,数据库系统概论(第三版)[M],高等教育出版社,2000