通俗易懂的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。

要素表的图形(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中各种元素展示如下:

注3:Arcgis专用的mdb会有一些表存储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程序集下的工具,引入即可。

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

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

功能开发
在导入Arcgis的类库后,我们会在工具栏总看到如下控件:
AxMapControl 就是 Map 地图控件
AxPageLayouControl 是布局地图控件
AxTOCControl 是目录控件
AxToolbarControl 是 GIS 工具栏控件
AxSceneControl 是 Scene 三维场景控件
AxGlobeControl 是 Globe 控件
AxLicenseControl 是许可控件
AxSymbologyControl 是符号选择器控件
AxArcReaderControl 是 ArcReader 控件
AxArcReaderGlobeControl 是 ArcReaderGlobe 控件
如下图:

本文主要使用AxMapControl (Map 地图控件),AxPageLayouControl (是布局地图控件),AxTOCControl (目录控件)。
首先向窗体里添加这三个控件,然后设置控件AxPageLayouControl 和AxTOCControl 的buddy属性为AxMapControl ,目的是AxPageLayouControl 和AxTOCControl成为AxMapControl 的伙伴控件,实现数据的同步和共享。
设置buddy属性,需要右键控件,在下拉菜单中选择属性,如下图:


然后我们创建一个按钮,导入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
结果如下下图所示:

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开发快速入门的更多相关文章
- Transform组件C#游戏开发快速入门
Transform组件C#游戏开发快速入门大学霸 组件(Component)可以看作是一类属性的总称.而属性是指游戏对象上一切可设置.调节的选项,如图2-8所示.本文选自C#游戏开发快速入门大学霸 ...
- HealthKit开发快速入门教程之HealthKit数据的操作
HealthKit开发快速入门教程之HealthKit数据的操作 数据的表示 在HealthKit中,数据是最核心的元素.通过分析数据,人们可以看到相关的健康信息.例如,通过统计步数数据,人们可以知道 ...
- HealthKit开发快速入门教程之HealthKit框架体系创建健康AppID
HealthKit开发快速入门教程之HealthKit框架体系创建健康AppID HealthKit开发准备工作 在开发一款HealthKit应用程序时,首先需要讲解HealthKit中有哪些类,在i ...
- HealthKit开发快速入门教程之HealthKit开发概述简介
HealthKit开发快速入门教程之HealthKit开发概述简介 2014年6月2日召开的年度开发者大会上,苹果发布了一款新的移动应用平台,可以收集和分析用户的健康数据.该移动应用平台被命名为“He ...
- Apple Watch开发快速入门教程
Apple Watch开发快速入门教程 试读下载地址:http://pan.baidu.com/s/1eQ8JdR0 介绍:苹果为Watch提供全新的开发框架WatchKit.本教程是国内第一本A ...
- 游戏控制杆OUYA游戏开发快速入门教程
游戏控制杆OUYA游戏开发快速入门教程 1.2.2 游戏控制杆 游戏控制杆各个角度的视图,如图1-4所示,它的硬件规格是本文选自OUYA游戏开发快速入门教程大学霸: 图1-4 游戏控制杆各个角度的 ...
- SpringBoot开发快速入门
SpringBoot开发快速入门 目录 一.Spring Boot 入门 1.Spring Boot 简介 2.微服务 3.环境准备 1.maven设置: 2.IDEA设置 4.Spring Boot ...
- WPF开发快速入门【7】WPF的拖放功能(Drag and Drop)
概述 本文描述WPF的拖放功能(Drag and Drop). 拖放功能涉及到两个功能,一个就是拖,一个是放.拖放可以发生在两个控件之间,也可以在一个控件自己内部拖放.假设界面上有两个控件,一个Tre ...
- abp vnext 开发快速入门 1 认识框架
最近在做一个项目,用的框架是Abp vnext ,不是Abp, 我自己也是刚开始用这个框架来做项目,难免要查资料,这个框架官方有中文文档,可以到官网www.abp.io 去查看,国内也有一些写了相关的 ...
随机推荐
- MVCC多版本并发控制
MVCC多版本并发控制 爱情小傻蛋关注 82019.09.28 23:23:37字数 4,740阅读 91,421 前提概要 什么是MVCC 什么是当前读和快照读? 当前读,快照读和MVCC的关系 M ...
- 解释AOP?
面向切面的编程,或AOP, 是一种编程技术,允许程序模块化横向切割关注点,或横切典型的责任划分,如日志和事务管理.
- Spring框架中有哪些不同类型的事件?
Spring 提供了以下5种标准的事件: (1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refre ...
- 算法 | 串匹配算法之KMP算法及其优化
主串 s:A B D A B C A B C 子串 t: A B C A B 问题:在主串 s 中是否存在一段 t 的子串呢? 形如上述问题,就是串匹配类问题.[串匹配--百度百科] 串匹配问题是一 ...
- 还能这样?把 Python 自动翻译成 C++
作者:byronhe,腾讯 WXG 开发工程师 一.问题背景 随着深度学习的广泛应用,在搜索引擎/推荐系统/机器视觉等业务系统中,越来越多的深度学习模型部署到线上服务. 机器学习模型在离线训练时,一般 ...
- css 垂直居中方法汇总
查看原文可以有更好的排版效果哦 前言 居中是平时工作中的最常见的一种需求,各种图片居中或者各种弹窗,水平居中还好,特别是垂直居中,很多初学者表示太难写了,现在列举一些常用的方法. 实战 这里只讲述cs ...
- 在微信小程序中绘制图表(part2)
本期大纲 1.确定纵坐标的范围并绘制 2.根据真实数据绘制折线 相关阅读:在微信小程序中绘制图表(part1)在微信小程序中绘制图表(part3) 关注我的 github 项目 查看完整代码. 确定纵 ...
- Nuxt.js服务端渲染实践,从开发到部署
感悟 经过几个周六周日的尝试,终于解决了服务端渲染中的常见问题,当SEO不在是问题的时候,或许才是我们搞前端的真正的春天,其中也遇到了一些小坑,Nuxt.js官方还是很给力的,提issue后很积极的给 ...
- vue重构--H5--canvas实现粒子时钟
上一篇文章讲解了如何用js+canvas实现粒子时钟,本篇文章 ,主要是使用vue重构,让它在vue也能使用. 我们使用简单的方式重构,不使用vue工程,先加入vue cdn的地址,如下: <s ...
- 数组 indexOf()
众所周知,indexOf()这个方法经常出现在字符串的使用中,也许是用来寻找字符串中某一字符在字符串中的位置,或者也可以用来寻找字符串中重复出现的字符有哪些.对于刚接触 JS 的我们来说,在对数组的操 ...