• 通俗易懂的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,枚举值如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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),常规使用时,可以直接将地图的空间参考提供给要素集,创建代码如下:

    1
    2
    3
    4
    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中添加如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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的数据挂载进地图的操作。

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    #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

     

     

  • 相关阅读:
    路由重分布的概念与配置
    spring security为啥是个垃圾框架?
    JMeter分布式压测及4种参数化方式,转发收藏
    Apache安装教程
    excel卡住了还没保存怎么办?
    【Vue.js设计与实现】第3章 Vue.js 3 的设计思路
    mysql面试题20:有哪些合适的分布式主键方案
    方舟开服务器Vmware虚拟机安装不上?
    线性回归学习
    详解差分进化算法:从基础到小生境(Niche)技术与多目标优化在Python的实现
  • 原文地址:https://www.cnblogs.com/kiba/p/16139750.html