通俗易懂的ArcGis开发快速入门

前言

本文主要介绍ArcGis的ArcEngine开发,学习时,我们需要放下心里障碍,那就是Gis开发只是普通的软件开发,并不需要专业的GIS知识,就是非常普通的,调用相关的C++开发的COM组件。

开发环境:VS2017。

ArcEngine版本:10.1。

基础学习

正式使用ArcGis之前,需要先学习ArcGis一些基础概念。

工作空间(IWorkspace):

存储ArcGis数据的对象,他可以从多种数据库中读取ArcGis数据,如oracle,mdb等等。

普通表(ITable):

跟我们常用的表一样,又称对象类。由于ArcGis是C++写的,所以读取表数据的时候,要使用游标一行一行的读取;普通表(ITable)默认第一个字段是主键,名称为OBJECTID。

要素表(IFeatureClass):

要素表有两部分组成,一部分是图像,一部分是普通表,他在代码中是一个对象,但在数据中是以两个表存在的,如下图(test2和test2_SHAPE_Index)。

但我们要注意的是,要素表(FeatureClass)存储图像的字段是表test2的SHAPE,而不是在test2_SHAPE_Index表中;要素表(FeatureClass)默认第一个字段是主键,名称为OBJECTID,第二个字段是图像字段,默认名称为SHAPE。

通俗易懂的ArcGis开发快速入门

要素表的图形(SHAPE字段):

要素表的图形就是第二个字段,默认名称为SHAPE的图像字段;图像字段有很多种类型,其对应枚举为esriGeometryType,枚举值如下:

 esriGeometryType.esriGeometryAny://"任何类型(Any valid geometry)"                 esriGeometryType.esriGeometryBag://"任意几何类型的集合(GeometryBag)"                 esriGeometryType.esriGeometryBezier3Curve:// "贝兹曲线(BezierCurve)"                 esriGeometryType.esriGeometryCircularArc:// "圆弧(CircularArc)"                 esriGeometryType.esriGeometryEllipticArc://"椭圆弧(EllipticArc)"                 esriGeometryType.esriGeometryEnvelope://"外包(Envelope)"                 esriGeometryType.esriGeometryLine:// "线段(Line)"                 esriGeometryType.esriGeometryMultiPatch:// "表面几何(MultiPatch)"                 esriGeometryType.esriGeometryMultipoint://"多点(Multipoint)"                 esriGeometryType.esriGeometryNull:// "未知类型(Unknown)"                 esriGeometryType.esriGeometryPath://"路径(Path)"                 esriGeometryType.esriGeometryPoint://"点(Point)"                 esriGeometryType.esriGeometryPolygon://"多边形(Polygon)"                 esriGeometryType.esriGeometryPolyline:// "多段线(Polyline)"                 esriGeometryType.esriGeometryRay://"射线(Ray)"                 esriGeometryType.esriGeometryRing://"环(Ring)"                 esriGeometryType.esriGeometrySphere://"球体(Sphere)"                 esriGeometryType.esriGeometryTriangleFan:// "三角扇形(TriangleFan)"                 esriGeometryType.esriGeometryTriangleStrip://"三角带(TriangleStrip)"                 esriGeometryType.esriGeometryTriangles:// "三角形(Triangles)"

我们最常用的就是点(esriGeometryPoint),线(esriGeometryPolyline),面(esriGeometryPolygon)。

要素集(IFeatureDataset):

要素集,顾名思义就是要素表的集合,创建要素集的时候要提供空间参考(SpatialReference),常规使用时,可以直接将地图的空间参考提供给要素集,创建代码如下:

IFeatureWorkspace featureWorkspace = workspace as IFeatureWorkspace;             ISpatialReference spatialReference = axMapControl1.ActiveView.FocusMap.SpatialReference; //创建要素集 featureWorkspace.CreateFeatureDataset("Data2", spatialReference);

空间参考(SpatialReference)可以简单理解为横纵坐标系,因为世界上有很多种坐标系(如:北京54,西安80),所以在创建地图的时候,要指明使用哪种坐标系。

栅格数据(IRasterDataset):

栅格数据虽然是以Dataset存在,但他并不是类似要素集的存在,而是一个是独立存在的图像的文件。比如,我们可以通过IRasterDataset.OpenFromFile(filePath)来打开一个物理文件。

注意事项

注1:非空间数据:非空间数据就是可以在地图上展示或使用的业务数据;要素集中的非图形字段都是,普通表(ITable)存储的全是非空间数据。

注2:空间数据:空间数据即图形元素,又地图对象;几何数据类,要素类,关系类都是空间数据;空间数据可以被图层加载,形成图层对象,如:IFeatureLayer有个IFeatureClass属性,只要为该属性赋值要素类的对象,就成功加载了空间数据,此时,该图层也可称为要素图层。(要素表(IFeatureClass)包含空间数据和非空间数据两部分)。

ArcMap中各种元素展示如下:

通俗易懂的ArcGis开发快速入门

注3:Arcgis专用的mdb会有一些表存储Arcgis的专有数据,在数据库中的展示,如下图所示:

通俗易懂的ArcGis开发快速入门

准备开发

首先安装ArcGisEngine和ArcObjects Sdk,然后创建一个普通的Winform项目。

然后在Program.cs中添加如下代码:

static void Main() {     ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.Engine);     IAoInitialize aoInit = new AoInitializeClass();     aoInit.Initialize(esriLicenseProductCode.esriLicenseProductCodeEngine);     Application.EnableVisualStyles();     Application.SetCompatibleTextRenderingDefault(false);     Application.Run(new Form1());  }

注:Bind和Initialize函数要使用统一的Code,这里我都使用的是ProductCode.Engine的Code。

因为是使用VS2017,所以在工具箱中我们看不到ArcGis的工具;需要我们手动引入ArcGis工具,工具箱—选择项—.NET Framework组件,找到ESRI程序集下的工具,引入即可。

通俗易懂的ArcGis开发快速入门

然后把引入的类库的嵌入互操作类型熟悉修改为false,不然编译的时候会提示错误——无法嵌入互操作类型。

通俗易懂的ArcGis开发快速入门

如果我们在开发中发现有些ArcGis的类抛异常,那可以通过引用的方式,将ArcGis的Com组件引入进来,如,我们要打开SDE数据库,要使用ESRI.ArcGIS.DataSourcesGDB命名空间,就要添加Esri DataSourcesGDB OBJECT Library 10.1这个Com组件。

通俗易懂的ArcGis开发快速入门

功能开发

在导入Arcgis的类库后,我们会在工具栏总看到如下控件:

AxMapControl 就是 Map 地图控件

AxPageLayouControl 是布局地图控件

AxTOCControl 是目录控件

AxToolbarControl 是 GIS 工具栏控件

AxSceneControl 是 Scene 三维场景控件

AxGlobeControl 是 Globe 控件

AxLicenseControl 是许可控件

AxSymbologyControl 是符号选择器控件

AxArcReaderControl 是 ArcReader 控件

AxArcReaderGlobeControl 是 ArcReaderGlobe 控件

如下图:

通俗易懂的ArcGis开发快速入门

本文主要使用AxMapControl (Map 地图控件),AxPageLayouControl (是布局地图控件),AxTOCControl (目录控件)。

首先向窗体里添加这三个控件,然后设置控件AxPageLayouControl 和AxTOCControl 的buddy属性为AxMapControl ,目的是AxPageLayouControl 和AxTOCControl成为AxMapControl 的伙伴控件,实现数据的同步和共享。

设置buddy属性,需要右键控件,在下拉菜单中选择属性,如下图:

通俗易懂的ArcGis开发快速入门

通俗易懂的ArcGis开发快速入门

然后我们创建一个按钮,导入mdb数据库,并实现读取Mdb的要素集,要素类,表格数据,栅格数据等数据,并把名称显示在Listbox中。

代码编写思路介绍:

首先通过AccessWorkspaceFactoryClass实例化一个IWorkspaceFactory接口,然后用他打开一个mdb文件,并返回一个IWorkspace对象;然后通过IWorkspace的get_Datasets方法获取全部数据,(传递参数esriDatasetType.esriDTAny为获取全部数据),get_Datasets方法返回IEnumDataset,是一个枚举Dataset,这个对象不能for循环,只能使用Next函数获取下一个,这个也是C++的特点;然后我们通过while循环,取出所有数据,并显示在Listbox上;同时也做判断如果数据是要素类IFeatureClass ,则定义一个FeatureLayerClass对象,并将他的FeatureClass属性赋值,FeatureLayerClass添加进地图,这样就实现了将mdb的数据挂载进地图的操作。

代码如下:

#region 读取Mdb的要素集,要素类,表格数据,栅格数据等数据,并把名称显示在Listbox中 private void btnImportMDB_Click(object sender, EventArgs e) {     string WsName = SelectMdb();     List<string> listBoxSource = new List<string>();     if (WsName != "")     {         IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryClass();         workspace = workspaceFactory.OpenFromFile(WsName, 0); ​         IEnumDataset enumDataset_workspace = workspace.get_Datasets(esriDatasetType.esriDTAny);         IDataset dataset_Parent = enumDataset_workspace.Next();         datalistBox.DataSource = null;                 while (dataset_Parent != null)         {                        if (dataset_Parent.Type == esriDatasetType.esriDTFeatureClass)//要素类             {                 listBoxSource.Add(dataset_Parent.Name + "-要素类-parent");                 IFeatureClass featureClass = dataset_Parent as IFeatureClass;//将IDataset强转为IFeatureClass(要素对象)                  AddLayer(featureClass);//将要素对象挂载在要素图层上,并显示在地图上             }             else if (dataset_Parent.Type == esriDatasetType.esriDTFeatureDataset)//要素集             {                 string parentName = dataset_Parent.Name;                 listBoxSource.Add(parentName + "-要素集-parent");                 IFeatureDataset featureDataset_workspace = dataset_Parent as IFeatureDataset; ​                 IEnumDataset enumDataset_Child = dataset_Parent.Subsets;//取出要素对象的集合                 IDataset dataset_item = enumDataset_Child.Next();                 int index = 0;                 while (dataset_item != null)                 {                     listBoxSource.Add(dataset_item.Name + "-要素对象-父:" + parentName+"-" + dataset_item.Type);                     Console.WriteLine("dataset_item.Type:" + dataset_item.Type);                     IGeoDataset geoDataset = dataset_item as IGeoDataset; //也可以这样强转                     IFeatureClass featureClass = dataset_item as IFeatureClass;//将IDataset强转为IFeatureClass(要素对象)                                     AddLayer(featureClass);//将要素对象挂载在要素图层上,并显示在地图上                     index++;                     dataset_item = enumDataset_Child.Next();                 }             }             else if (dataset_Parent.Type == esriDatasetType.esriDTTable)//数据表             {                 string parentName = dataset_Parent.Name;                 listBoxSource.Add(parentName + "-数据表-parent");                 ITable table11_workspace = dataset_Parent as ITable;                 var count = table11_workspace.RowCount(new QueryFilterClass());                 Console.WriteLine("数据行数:" + count); ​             }             else if (dataset_Parent.Type == esriDatasetType.esriDTRasterDataset)//栅格数据             {                 ​                 string parentName = dataset_Parent.Name;                 listBoxSource.Add(parentName + "-栅格数据-parent");             }             else             {                 string parentName = dataset_Parent.Name;                 listBoxSource.Add(parentName + "-parent-" + dataset_Parent.Type.ToString()); ​             } ​             dataset_Parent = enumDataset_workspace.Next();         }     }      datalistBox.DataSource = listBoxSource;     datalistBox.Refresh(); ​     #region 刷新地图              axMapControl1.ActiveView.Refresh();//全图刷新              //axMapControl1.Map.MapScale = axMapControl1.Map.MapScale;             //axMapControl1.Map.MapScale = 25000;             Application.DoEvents();             ​             #endregion ​ ​ ​ } //添加图层 public void AddLayer(IFeatureClass featureClass) {      IFeatureLayer featureLayer = new FeatureLayerClass();     featureLayer.Name = featureClass.AliasName;     featureLayer.FeatureClass = featureClass; ​     ILayerEffects layerEffects = featureLayer as ILayerEffects;     layerEffects.Transparency = 1;//透明度设置 ​     IGeoFeatureLayer geoFeatureLayer = featureLayer as IGeoFeatureLayer;     IFeatureRenderer featRender = geoFeatureLayer.Renderer;     #region 样式设置              if (featRender is ISimpleRenderer)             {                 ISimpleRenderer simple = featRender as ISimpleRenderer;                 //Symbol一般不会为空,因为有默认值,这里的图层layer是新建的,这里将IFeatureLayer转换为IGeoFeatureLayer,然后取他的Renderer,而Renderer里的Symbol就已经有值了。                  IFillSymbol symbolFill = simple.Symbol as IFillSymbol; ​                 #region 获取和设置图层的符号的颜色                 if (symbolFill != null)//可以强转为IFillSymbol,即为填充符号,即面符号                 {                     RgbColor rgbColor = new RgbColor();                     rgbColor.RGB = symbolFill.Color.RGB;                     Color pSymbolColor = Color.FromArgb(rgbColor.Red, rgbColor.Green, rgbColor.Blue);                     symbolFill.Color = ConvertToArcGisColor(Color.Green);  // 设置图层的符号的颜色                     //设置图层的符号的边框的颜色,这里直接symbolFill.Outline.Color不好使,必须重新new一个线对象                     symbolFill.Outline = new SimpleLineSymbolClass() {  Color= ConvertToArcGisColor(Color.Purple), Width = 1 };                                                              }                 else                 {                     IMarkerSymbol symbolMarker = simple.Symbol as IMarkerSymbol;                     if (symbolMarker != null)//可以强转为IMarkerSymbol,即为标记符号,即点符号                     {                         RgbColor rgbColor = new RgbColor();                         rgbColor.RGB = symbolMarker.Color.RGB;                         Color pSymbolColor = Color.FromArgb(rgbColor.Red, rgbColor.Green, rgbColor.Blue);                         symbolMarker.Color = ConvertToArcGisColor(Color.Red);  // 设置图层的符号的颜色                     }                     else                     {                         ILineSymbol symbolLine = simple.Symbol as ILineSymbol;                         if (symbolLine != null)//可以强转为ILineSymbol,即为线符号                         {                             RgbColor rgbColor = new RgbColor();                             rgbColor.RGB = symbolLine.Color.RGB;                             Color pSymbolColor = Color.FromArgb(rgbColor.Red, rgbColor.Green, rgbColor.Blue);                             symbolLine.Color = ConvertToArcGisColor(Color.Blue);  // 设置图层的符号的颜色                         } ​                     }                 }                 #endregion ​             }             #endregion        axMapControl1.Map.AddLayer(featureLayer); ​ ​ } //选择文件数据库 public string SelectMdb() {     string WsFileName = "";     OpenFileDialog OpenFile = new OpenFileDialog();     OpenFile.Filter = "文件数据库(MDB)|*.mdb";     DialogResult DialogR = OpenFile.ShowDialog();     if (DialogR == DialogResult.Cancel)     { ​     }     else     {         WsFileName = OpenFile.FileName;     }     return WsFileName; ​ } #endregion ​

结果如下下图所示:

通俗易懂的ArcGis开发快速入门


BUG:您必须有许可证才能使用此 ActiveX 控件

首先打卡License Server Administrator,看看许可证是否正常启动。

如果解决不了,则重新安装license manager。

----------------------------------------------------------------------------------------------------

到此,最基础的Arcgis开发,我们就学会了。

代码已经传到Github上了,欢迎大家下载。

Github地址: https://github.com/kiba518/ArcgisEngine_Winform

----------------------------------------------------------------------------------------------------

注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
若您觉得这篇文章还不错,请点击下方的推荐】,非常感谢!

https://www.cnblogs.com/kiba/p/16139750.html

 通俗易懂的ArcGis开发快速入门

 

发表评论

相关文章