1、资料内容仅供您学习参考,如有不当或者侵权,请联系改正或者删除。 扩展MapObjects数据源的研究I——将Shapefiles保存到ADO.NET数据集 蔡德利郭庆丰汪春 ( 黑龙江八一农垦大学植物科技学院大庆, 163319) 摘要: 本文经过编程实现了Shapefiles中的几何对象与二进制数据流的双向转换, 将Shapefiles引入到ADO.NET数据表中, 使空间数据和属性数据的管理达到统一, GIS数据组织变得简单、 高效, 且突破了ESRI空间数据只能单独存放的限制。 关键词: Shapefiles; 几何对象; 数据流; ADO.NET; 空间数据 Studyf
2、orMapObjectsDataSourceExtensionI–ImportShapefilestoADO.NETDataset CaiDeliGuoQingfengWangChun (CollegeofPlantSciencesandTechnology,HeilongjiangAugustFirstLandReclamationUniversity,Daqing163319) Abstract: ConversionbetweengeometryobjectsofShapefilesandbinarydatastreamwascarriedoutbyprogramming.Then
3、theShapefileswereimportedtoADO.NETDataTable.Themanipulationmodeofspatialdataandattributedatacouldbeunified.ItmadeGISdatamanagementsimpleandefficient.Furthermore,itbrokethroughthelimitationofESRIspatialdatainsavingalone. Keyword: Shapefiles; geometryobjects; datastream; ADO.NET; spatialdata 0引言 Ma
4、pObjects是由全球最大的GIS厂商——美国环境系统研究所( ESRI) 推出的基于COM的GIS组件, 其优点是能够无缝地嵌入到其它的软件中, 由于强大的功能, MapObjects在GIS应用领域得到了广泛的应用。 由于ESRI为MapObject2.2提供了运行环境可调用包装( RCW) , 因此当Microsoft的开发工具升级到.NET环境时依然能够使用MapObjects的Map控件及相关对象。但由于MapObjects矢量图层使用旧的DAO数据访问方式, 编程时经常发生错误; 如果属性数据使用ADO.NET管理, 与空间数据的协调就成了让人头疼的事。在编写精准农业GIS的时
5、候, 我们尝试用ADO.NET统一管理空间数据和属性数据, 二者不但无缝地融为一体, 在功能上还突破了ESRI的许多限制, 收到了意想不到的效果。 1MapObjects数据源 MapObjects认为一个综合性的地图由多个图层构成, 图层数据来源广泛, 既能够是GIS矢量图层, 也能够是CAD图层, 甚至影像数据。矢量图层内部统一用记录集( Recordset) 来表示, 最常见的矢量数据文件是形文件( Shapefiles) , MapObjects也是能够经过ESRI的专用数据库引擎连接的专用数据库。 Recordset正象关系数据库中的二维表, Shape字段以面向对象的技术封装
6、了要素的图形部分。GIS图形分为三种类型, 即点、 线、 面, 除此之外, 还引入了一个部件( Part) , 这些几何对象之间的关系能够由下图表示: 线(Line) 多边形(Polygon) 部件(Part) 点集(Points) 点(Point) 2ADO.NET ADO.NET是一种新的数据访问策略, 而不但仅是ADO的改进版本, 我们能够称其为”与数据源断开的活动连接”。 在许多情况下, 应用程序需要处理下一条记录时都返回到数据库是不切实际的, 因此解决方案就是临时存储从数据库检索的记录, 然后使用该临时集, 这便是数据集( Dataset) 的概念。 数据集包
7、含一个或多个表( DataTable, 相当于实际数据库中的表) , 数据集中还能够包含表之间的关系以及对表数据约束的信息。数据集内的数据一般是数据库中内容的非常精简的版本, 能够用与操作实际数据十分类似的方式操作( 添加、 修改、 删除) 数据集记录( DataRow) , 需要的时候, 能够将这些更新写回到数据库中。 尽管数据集是作为从数据库获取的数据的缓存, 但数据集与数据库之间没有任何实际关系, 数据集仅仅是数据容器, 我们也能够编程在内存中生成数据集。以下程序建立数据集和一个数据表: DimmyDatasetAsNewDataSet DimdtAsDataTable=myDa
8、taset.Tables.Add("Croplands") dt.Columns.Add("CroplandId",Type.GetType("System.Int32")) dt.Columns.Add("Shape",Type.GetType("System.Byte[]")) 3引入Shapefiles 以引入Polygon类型的Shapefiles为例, 首先要询问用户Shapefiles所在的位置, 然后经过MapObjects打开, 图层对象( MapLayer) 记录集( Recordset) 中的每条记录是一个图斑, 即多边形对象( Polygon) 。将Polygon
9、对象转换为字符数组Byte(), 即可保存到ADO.NET的数据集中。 下面是详细的引入过程。 3.1获取Shapefiles所在的文件夹和文件名 以传递引用的方式调用过程, 经过OpenFileDialog对象获取Shapefiles所在的文件夹和文件名。 PrivateSubGetShapefile(ByRefstrFolderAsString,ByRefstrShapefileAsString) DimoDialogAsNewOpenFileDialog,intResultAsInteger WithoDialog'打开对话框 .DefaultExt="shp" .Fil
10、ter="形文件(*.shp)|*.shp" .Multiselect=False .Title="打开形文件" intResult=.ShowDialog EndWith strShapefile=""'不能获取形文件名, 返回空 IfintResult=DialogResult.OKThen'用户按”确定”按钮 intResult=oDialog.FileName.LastIndexOf("\") strFolder=oDialog.FileName.Substring(0,intResult) strShapefile=oDialog.FileName.Substrin
11、g(intResult+1) EndIf oDialog.Dispose() EndSub 3.2打开Shapefiles 编写一个过程, 尝试正确打开Shapefiles, 并确认其中保存的是多边形对象。 PrivateFunctionOpenShapefiles(ByValstrFolderAsString,ByValstrShapeFileAsString)_ DimmyLayerAsESRI.MapObjects2.Core.MapLayer DimmyConnectionAsNewESRI.MapObjects2.Core.DataConnection Dimfla
12、gAsBoolean=False myConnection.Database=strFolder IfmyConnection.Connect()Then DimmyGeoDataAsESRI.MapObjects2.Core.GeoDataset'地理数据源 myGeoData=myConnection.FindGeoDataset(strShapeFile) IfNotmyGeoDataIsNothingThen'打开数据源 myLayer=NewESRI.MapObjects2.Core.MapLayer myLayer.GeoDataset=myGeoData flag
13、myLayer.shapeType=_ ESRI.MapObjects2.Core.ShapeTypeConstants.moShapeTypePolygon) EndIf myConnection.Disconnect() EndIf ReturnIIf(flag,myLayer,Nothing) EndFunction 3.3将几何对象读到DataTable中 过程ShapefilesToDataTable从图层中读取多边形对象, 转换为二进制数据流后保存到Croplands数据表的Shape字段中, Croplands数据表事先建有ID和Shape两个字段。 Pri
14、vateSubShapefilesToDataTable(ByRefmyLayerAsESRI.MapObjects2.Core.MapLayer) DimdtAsDataTable=myDataset.Tables.Item("Croplands") DimoRecsAsESRI.MapObjects2.Core.Recordset=myLayer.Records oRecs.MoveFirst() DoUntiloRecs.EOF DimdrAsDataRow=dt.NewRow() dr.Item("CroplandId")=oRecs.Fields.Item("ID").V
15、alue dr.Item("Shape")=SerializePolygonToByte(oRecs.Fields.Item("Shape").Value) dt.Rows.Add(dr) oRecs.MoveNext() Loop EndSub .NET提供了串行化技术, 是将对象状态转变为可保持或传输的格式的过程, 与其相反的操作是反串行化。串行化的好处是能够在应用程序之间传递对象, 或将对象作为”原子”值保存到任意的数据库中。 一般一个类包含非托管的内存或文件句柄时, 是不支持串行化的。COM组件、 AxtiveX接口和Win32API函数都是非托管代码, 因此, MapO
16、bjects的几何对象均不支持串行化操作, 无法直接转变为序列数据, 从而进行远程传输。 在MapObjects中, Polygon对象由一个Parts对象构成, Parts中的每个Part都是Points对象, Points由Point构成, 当不包含Z值时, Point对象的X、 Y属性是Polygon对象的一个角点。基于此原理, SerializePolygonToByte过程将一个Polygon对象转变为二进制数据。 PublicFunctionSerializePolygonToByte(ByValoPolygonAsESRI.MapObjects2.Core.Polygon)A
17、sByte() DimbytCount(2),bytData(8),bytPolygon()AsByte DimintByteCountAsInteger=0 DimdblXYAsDouble,iAsShort DimshtPartCountAsShort=oPolygon.Parts.Count bytCount=BitConverter.GetBytes(shtPartCount) ReDimPreservebytPolygon(intByteCount+2) Array.Copy(bytCount,0,bytPolygon,intByteCount,2) intByteC
18、ount+=2 Fori=0ToshtPartCount-1 DimoPartAsESRI.MapObjects2.Core.Points oPart=oPolygon.Parts.Item(i) DimshtPointCountAsShort=oPart.Count bytCount=BitConverter.GetBytes(shtPointCount) ReDimPreservebytPolygon(intByteCount+2) Array.Copy(bytCount,0,bytPolygon,intByteCount,2) intByteCount+=2 DimjA
19、sShort Forj=0ToshtPointCount-1 DimoPointAsESRI.MapObjects2.Core.Point=oPart.Item(j) dblXY=oPoint.X bytData=BitConverter.GetBytes(dblXY) ReDimPreservebytPolygon(intByteCount+8) Array.Copy(bytData,0,bytPolygon,intByteCount,8) intByteCount+=8 dblXY=oPoint.Y bytData=BitConverter.GetBytes(dblXY)
20、 ReDimPreservebytPolygon(intByteCount+8) Array.Copy(bytData,0,bytPolygon,intByteCount,8) intByteCount+=8 Next Next ReturnbytPolygon EndFunction 3.4显示DataTable中的几何对象 首先建立一个临时Shapefiles, 包含图斑编号字段。 PrivateFunctionCreateShapefiles(ByRefmyConnectionAsESRI.MapObjects2.Core.DataConnection)_ AsES
21、RI.MapObjects2.Core.MapLayer DimflagAsBoolean=False DimmyLayerAsNewESRI.MapObjects2.Core.MapLayer DimstrShapeFileAsString="TempMap" DimoTableDecAsNewTableDesc WithoTableDec .FieldCount=1 .FieldName(0)="ID" .FieldType(0)=FieldTypeConstants.moLong EndWith DimmyGeoDataAsESRI.MapObjects2.Core.
22、GeoDataset myGeoData=myConnection.AddGeoDataset(strShapeFile,_ ShapeTypeConstants.moShapeTypePolygon,oTableDec) IfNotmyGeoDataIsNothingThen myLayer=NewESRI.MapObjects2.Core.MapLayer myLayer.GeoDataset=myGeoData flag=True EndIf ReturnIIf(flag,myLayer,Nothing) EndFunction 第二步, 将保存在Croplands数
23、据集中的序列数据反串行化后写入到临时Shapefiles, 再将形成的图层添加到地图控件中就会看到矢量图形。限于篇幅, 只列出反串行化过程。 PublicFunctionDeserializeByteToPolygon(ByValbytPolygon()AsByte)_ AsESRI.MapObjects2.Core.Polygon DimoPolygonAsNewESRI.MapObjects2.Core.Polygon DimintByteCountAsInteger=0 DimshtPartCount,i,jAsShort shtPartCount=BitConverter.
24、ToInt16(bytPolygon,intByteCount) intByteCount+=2 Fori=0ToshtPartCount-1 DimoPartAsNewESRI.MapObjects2.Core.Points DimshtPointCountAsShort shtPointCount=BitConverter.ToInt16(bytPolygon,intByteCount) intByteCount+=2 Forj=0ToshtPointCount-1 DimoPointAsNewESRI.MapObjects2.Core.Point oPoint.X=Bi
25、tConverter.ToDouble(bytPolygon,intByteCount) intByteCount+=8 oPoint.Y=BitConverter.ToDouble(bytPolygon,intByteCount) intByteCount+=8 oPart.Add(oPoint) Next oPolygon.Parts.Add(oPart) Next ReturnoPolygon EndFunction 4结语 本文讨论了Shapefiles的空间数据与二进制数据流的正反向转换, 将空间数据和属性数据同时引入到ADO.NET数据集中, 使ADO.NET
26、这一新的数据访问方法能够无缝地处理GIS数据, 对GIS数据组织是一种新的尝试。 ADO.NET数据集中的数据能够随时保存到SQLSever等大型数据库中, 此时的空间数据与普通数据一样, 既能够实现”断开的连接”, 又能够保证完整性。本研究下文将讨论将空间数据保存到SQLServer中。 参考文献 [1]李新召.基于COM组件的Shape文件生成算法[J].矿山测量. ,(4):29-31 [2]翟长江, 张秋文.基于控件MapObjects开发GIS应用系统[J].微计算机信息. ,19(5):82-83 [3]刘光编着.地理信息系统二次开发实例教程——组件篇[M].北京: 清华大学出版社, .1 [4]王嘉彬.MapObjects2.2在VisualStudio.NET环境里的开发.ESRI中国通讯. 4月, 总第14期. [5]苏乐平.MapObjects开发技术.ESRI中国通讯. 9月, 总第11期. [6]TonyBain,DeniseGosnell等着, 康博译.VB.NET和SQLServer 高级编程——创立高效数据层[M].北京: 清华大学出版社, .11






