资源描述
资料内容仅供您学习参考,如有不当或者侵权,请联系改正或者删除。
扩展MapObjects数据源的研究I——将Shapefiles保存到ADO.NET数据集
蔡德利郭庆丰汪春
( 黑龙江八一农垦大学植物科技学院大庆, 163319)
摘要: 本文经过编程实现了Shapefiles中的几何对象与二进制数据流的双向转换, 将Shapefiles引入到ADO.NET数据表中, 使空间数据和属性数据的管理达到统一, GIS数据组织变得简单、 高效, 且突破了ESRI空间数据只能单独存放的限制。
关键词: Shapefiles; 几何对象; 数据流; ADO.NET; 空间数据
StudyforMapObjectsDataSourceExtensionI–ImportShapefilestoADO.NETDataset
CaiDeliGuoQingfengWangChun
(CollegeofPlantSciencesandTechnology,HeilongjiangAugustFirstLandReclamationUniversity,Daqing163319)
Abstract: ConversionbetweengeometryobjectsofShapefilesandbinarydatastreamwascarriedoutbyprogramming.ThentheShapefileswereimportedtoADO.NETDataTable.Themanipulationmodeofspatialdataandattributedatacouldbeunified.ItmadeGISdatamanagementsimpleandefficient.Furthermore,itbrokethroughthelimitationofESRIspatialdatainsavingalone.
Keyword: Shapefiles; geometryobjects; datastream; ADO.NET; spatialdata
0引言
MapObjects是由全球最大的GIS厂商——美国环境系统研究所( ESRI) 推出的基于COM的GIS组件, 其优点是能够无缝地嵌入到其它的软件中, 由于强大的功能, MapObjects在GIS应用领域得到了广泛的应用。
由于ESRI为MapObject2.2提供了运行环境可调用包装( RCW) , 因此当Microsoft的开发工具升级到.NET环境时依然能够使用MapObjects的Map控件及相关对象。但由于MapObjects矢量图层使用旧的DAO数据访问方式, 编程时经常发生错误; 如果属性数据使用ADO.NET管理, 与空间数据的协调就成了让人头疼的事。在编写精准农业GIS的时候, 我们尝试用ADO.NET统一管理空间数据和属性数据, 二者不但无缝地融为一体, 在功能上还突破了ESRI的许多限制, 收到了意想不到的效果。
1MapObjects数据源
MapObjects认为一个综合性的地图由多个图层构成, 图层数据来源广泛, 既能够是GIS矢量图层, 也能够是CAD图层, 甚至影像数据。矢量图层内部统一用记录集( Recordset) 来表示, 最常见的矢量数据文件是形文件( Shapefiles) , MapObjects也是能够经过ESRI的专用数据库引擎连接的专用数据库。
Recordset正象关系数据库中的二维表, Shape字段以面向对象的技术封装了要素的图形部分。GIS图形分为三种类型, 即点、 线、 面, 除此之外, 还引入了一个部件( Part) , 这些几何对象之间的关系能够由下图表示:
线(Line)
多边形(Polygon)
部件(Part)
点集(Points)
点(Point)
2ADO.NET
ADO.NET是一种新的数据访问策略, 而不但仅是ADO的改进版本, 我们能够称其为”与数据源断开的活动连接”。
在许多情况下, 应用程序需要处理下一条记录时都返回到数据库是不切实际的, 因此解决方案就是临时存储从数据库检索的记录, 然后使用该临时集, 这便是数据集( Dataset) 的概念。
数据集包含一个或多个表( DataTable, 相当于实际数据库中的表) , 数据集中还能够包含表之间的关系以及对表数据约束的信息。数据集内的数据一般是数据库中内容的非常精简的版本, 能够用与操作实际数据十分类似的方式操作( 添加、 修改、 删除) 数据集记录( DataRow) , 需要的时候, 能够将这些更新写回到数据库中。
尽管数据集是作为从数据库获取的数据的缓存, 但数据集与数据库之间没有任何实际关系, 数据集仅仅是数据容器, 我们也能够编程在内存中生成数据集。以下程序建立数据集和一个数据表:
DimmyDatasetAsNewDataSet
DimdtAsDataTable=myDataset.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对象转换为字符数组Byte(), 即可保存到ADO.NET的数据集中。
下面是详细的引入过程。
3.1获取Shapefiles所在的文件夹和文件名
以传递引用的方式调用过程, 经过OpenFileDialog对象获取Shapefiles所在的文件夹和文件名。
PrivateSubGetShapefile(ByRefstrFolderAsString,ByRefstrShapefileAsString)
DimoDialogAsNewOpenFileDialog,intResultAsInteger
WithoDialog'打开对话框
.DefaultExt="shp"
.Filter="形文件(*.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.Substring(intResult+1)
EndIf
oDialog.Dispose()
EndSub
3.2打开Shapefiles
编写一个过程, 尝试正确打开Shapefiles, 并确认其中保存的是多边形对象。
PrivateFunctionOpenShapefiles(ByValstrFolderAsString,ByValstrShapeFileAsString)_
DimmyLayerAsESRI.MapObjects2.Core.MapLayer
DimmyConnectionAsNewESRI.MapObjects2.Core.DataConnection
DimflagAsBoolean=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=(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两个字段。
PrivateSubShapefilesToDataTable(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").Value
dr.Item("Shape")=SerializePolygonToByte(oRecs.Fields.Item("Shape").Value)
dt.Rows.Add(dr)
oRecs.MoveNext()
Loop
EndSub
.NET提供了串行化技术, 是将对象状态转变为可保持或传输的格式的过程, 与其相反的操作是反串行化。串行化的好处是能够在应用程序之间传递对象, 或将对象作为”原子”值保存到任意的数据库中。
一般一个类包含非托管的内存或文件句柄时, 是不支持串行化的。COM组件、 AxtiveX接口和Win32API函数都是非托管代码, 因此, MapObjects的几何对象均不支持串行化操作, 无法直接转变为序列数据, 从而进行远程传输。
在MapObjects中, Polygon对象由一个Parts对象构成, Parts中的每个Part都是Points对象, Points由Point构成, 当不包含Z值时, Point对象的X、 Y属性是Polygon对象的一个角点。基于此原理, SerializePolygonToByte过程将一个Polygon对象转变为二进制数据。
PublicFunctionSerializePolygonToByte(ByValoPolygonAsESRI.MapObjects2.Core.Polygon)AsByte()
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)
intByteCount+=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
DimjAsShort
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)
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)_
AsESRI.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.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数据集中的序列数据反串行化后写入到临时Shapefiles, 再将形成的图层添加到地图控件中就会看到矢量图形。限于篇幅, 只列出反串行化过程。
PublicFunctionDeserializeByteToPolygon(ByValbytPolygon()AsByte)_
AsESRI.MapObjects2.Core.Polygon
DimoPolygonAsNewESRI.MapObjects2.Core.Polygon
DimintByteCountAsInteger=0
DimshtPartCount,i,jAsShort
shtPartCount=BitConverter.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=BitConverter.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这一新的数据访问方法能够无缝地处理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
展开阅读全文