zoukankan      html  css  js  c++  java
  • GP开发示例:数据库去重

    这个例子专业讲解基于ArcEngine使用GP开发的过程及遇到的问题。更多GP使用方法:GP使用心得

    功能需求:现在外业第一次数据(简称调绘.mdb)和第二次数据(简称检查.mdb)有重复。第二次是在第一次的基础上进行的,即如果调绘.mdb中LCA层有365个要素,检查时发现错误,就删除了11个错误,并新增了43个,共408个,检查.mdb相对于调绘.mdb实际上有354个重复,现在要将重复的删除,mdb中包括点、线、面三种类型的要素类。

    软件实现:在ArcGIS里利用工具可以实现,使用按空间位置查询,找出重复的,然后删除即可;由于每个mdb中的要素图层比较多,所以可以使用批处理,批处理时填写参数可以利用Excel快速进行。但是,mdb较多,路径各不相同,图层较多,操作起不比较费时。

    程序实现

    1.首先确定用什么工具来实现(先在ArcGIS里做一次):利用空间位置查询选择重复的要素,开启编辑器,删除!

    2.设计界面,我每写一个功能,都要把界面整理一下,因为我不想让它很丑就出去见人。这里使用DotNetBar,节省了相当多的时间。

    image

    3.因为是直接对数据库进行操作,所以首先就要遍历数据中的要素图层,一般做法是利用GP的ListFeatureClasses方法。

    GP.SetEnvironmentValue("workspace", moreDBPath.Trim());
    IGpEnumList pGpEnumList = GP.ListFeatureClasses("", "", "");
    string strFC = pGpEnumList.Next();
    while (strFC != "")
    {
        System.Windows.Forms.Application.DoEvents();
        Console.WriteLine(strFC);
        strFC = pGpEnumList.Next();
    }

    选择遍历数据库没有问题!

    4.利用按位置选择

    SelectLayerByLocation SLBL = new SelectLayerByLocation();
    SLBL.in_layer = moreDB + "\" + strFC;
    SLBL.select_features = referDB + "\" + strFC;
    SLBL.overlap_type = "ARE_IDENTICAL_TO";
    GPClass.Execute(SLBL); //这里使用了自定义的GPClass类,可以直接使用GPExecute

    报错ERROR 000368,去官网帮助一查,竟然没有368,这是为什么?但从相邻错误信息来看,应该是哪个参数无效!

    image

    再去官网看了按空间位置查询的帮助文档。它说:输入必须是要素图层;不可以是要素类。要素图层?要素类?以前一直把它们看成是一种意思,于是去查一下了帮助,长知识了。

    image

    结果Python的示例代码,使用了MakeFeatureLayer来创建要素图层。

    image

    //创建要素图层
    MakeFeatureLayer MFL = new MakeFeatureLayer();
    MFL.in_features = moreDB + "\" + strFC;
    MFL.out_layer = strFC + @"_Lyr";
    GPClass.Execute(MFL);
    
    //按位置选择
    SelectLayerByLocation SLBL = new SelectLayerByLocation();
    SLBL.in_layer = strFC + @"_Lyr";
    SLBL.select_features = referDB + "\" + strFC;
    SLBL.overlap_type = "ARE_IDENTICAL_TO";
    GPClass.Execute(SLBL);

    GP执行成功,虽然还看不到效果。因为MakeFeatureLayer是临时图层,程序结束就没有了,需要将它导出来:

    //复制要素导出
    CopyFeatures CF = new CopyFeatures();
    CF.in_features = strFC + @"_Lyr";
    CF.out_feature_class = resultDB + "\" + strFC;
    GPClass.Execute(CF);

    现在的问题是是选择类型是ARE_IDENTICAL_TO,如果输入图层中的要素与某一选择要素相同(就几何而言),则会选择这些要素。生成的mdb是重复那一部分,而需要的结果是不重复的那一部分。在ArcGIS里可以通过切换选择来操作。于是想,先把它全部选中,然后将重复的移除。代码:

    //创建要素图层
    MakeFeatureLayer MFL = new MakeFeatureLayer();
    MFL.in_features = moreDB + "\" + strFC;
    MFL.out_layer = strFC + @"_Lyr";
    GPClass.Execute(MFL);
    
    //选择所有
    SelectLayerByAttribute SLBA = new SelectLayerByAttribute();
    SLBA.in_layer_or_view = strFC + @"_Lyr";
    GPClass.Execute(SLBA);
    
    //按位置选择(移除)
    SelectLayerByLocation SLBL = new SelectLayerByLocation();
    SLBL.in_layer = strFC + @"_Lyr";
    SLBL.select_features = referDB + "\" + strFC;
    SLBL.overlap_type = "ARE_IDENTICAL_TO";
    SLBL.selection_type = "REMOVE_FROM_SELECTION";
    GPClass.Execute(SLBL);
    
    //复制要素
    CopyFeatures CF = new CopyFeatures();
    CF.in_features = strFC + @"_Lyr";
    CF.out_feature_class = resultDB + "\" + strFC;
    GPClass.Execute(CF);
    终于实现了。

    5.为了增加用户的体验,重写在了一个类,并把新建一个线程来处理:

    string referDB = "";
    string moreDB = "";
    string resultDB = "";
    ProgressBarX progress = null;
    public NoRepeatClass(string _referDB, string _moreDB, string _resultDB, ProgressBarX _progress)
    {
        referDB = _referDB;
        moreDB = _moreDB;
        resultDB = _resultDB;
        progress = _progress;
    
        Thread MyThreadOne = new Thread(new ThreadStart(MainFun));
        MyThreadOne.Name = "NoRepeat";
        MyThreadOne.IsBackground = true;
        MyThreadOne.Start();
    }
    
    private void MainFun()
    {
     //主程序代码
    }

    6.为了让用户知道处理的进度,于是添加了进度条,并更新内容为当前处理图层的名称。但这里,不能直接在一个线程里设置主线程的控件属性,于是找了一个函数:

    #region 设置控件参数
    /// <summary>
    /// 设置控件参数
    /// </summary>
    /// <param name="oControl">控件</param>
    /// <param name="propName">参数名称</param>
    /// <param name="propValue">参数值</param>
    delegate void SetControlValueCallback(Control oControl, string propName, object propValue);
    public static  void SetControlPropertyValue(Control oControl, string propName, object propValue)
    {
        if (oControl.InvokeRequired)
        {
            SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
            oControl.Invoke(d, new object[] { oControl, propName, propValue });
        }
        else
        {
            Type t = oControl.GetType();
            System.Reflection.PropertyInfo[] props = t.GetProperties();
            foreach (System.Reflection.PropertyInfo p in props)
            {
                if (p.Name.ToUpper() == propName.ToUpper())
                {
                    p.SetValue(oControl, propValue, null);
                }
            }
        }
    }
    #endregion

    目前的效果如下:

    image

    7.为了提高操作效率,增加了路径拖放功能,下面是拖放类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    
    namespace GPTools
    {
        class DragClass
        {
            private  Control control;
            private string fileType = "";
    
            public DragClass(Control _control,string _fileType)
            {
                //如果控件为空 
                if (_control == null)
                {
                    return;
                }
                control = _control;
                fileType = _fileType;
    
                //设置是否可以拖放
                control.AllowDrop = true;
    
                //定义拖放事件
                control.DragEnter += new DragEventHandler(control_DragEnter);
              ontrol.DragDrop += new DragEventHandler(control_DragDrop);
    
            }
    
            private void control_DragEnter(object sender, DragEventArgs e)
            {
                if (e.Data.GetDataPresent(DataFormats.FileDrop))
                {
                    e.Effect = DragDropEffects.Copy;
                }
            }
    
            private void control_DragDrop(object sender, DragEventArgs e)
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                foreach (string file in files)
                {
                    //判断文件类型
                    if (Path.GetExtension(file) == fileType)
                    {
                        Console.WriteLine(file);
                        control.Text = file;
                    }
                }
            }
        }
    }
    

    在初始化主程序后实例化拖放类,一旦拖放就会触发DragEnter事件和DragDrop事件:

    DragClass dg = new DragClass(this.txbReferDB, ".mdb");
    DragClass dg2 = new DragClass(this.txbMoreDB, ".mdb");

    8.因为我们只遍历了检查.mdb中的图层,万一调绘.mdb中没有对应图层怎么,所以,我们得检查,如果没有则跳过。

    //创建要素图层
    //……
    
    //检查数据
    object dt = "";
    if (GPClass.GP.Exists(referDB + "\" + strFC, ref dt))
    {
        //3.选择所有
        //4.按位置选择(移除)
    }
    //复制要素
    //……
    9.为了更准确的统计操作时间,添加了计时功能。效果图如下:

    image

    10.为了让用户快速进行执行任务,可以在执行按钮上添加Enter事件。

    private void btnExcute_Enter(object sender, EventArgs e)
    {
        Excute();
    }
    
    private void Excute()
    {
        referDBPath = txbReferDB.Text.Trim();
        moreDBPath = txbMoreDB.Text.Trim();
        resultDBPath = txbResultDB.Text.Trim();
    
        if (referDBPath.Trim() != "" && moreDBPath.Trim() != "" && resultDBPath.Trim() != "")
        {
            NoRepeatClass nr = new NoRepeatClass(referDBPath, moreDBPath, resultDBPath, progressBar);
        }
        else
        {
            MessageBoxEx.EnableGlass = false;
            MessageBoxEx.Show("警告:数据库路径选择有误!
        请检查数据路径是否正确。", "提示");
        }
    }

    参考:http://bbs.esrichina-bj.cn/esri/viewthread.php?tid=50540

  • 相关阅读:
    再起航,我的学习笔记之JavaScript设计模式13(装饰者模式)
    在 ASP.NET Core 中执行租户服务
    再起航,我的学习笔记之JavaScript设计模式12(适配器模式)
    再起航,我的学习笔记之JavaScript设计模式11(外观模式)
    再起航,我的学习笔记之JavaScript设计模式10(单例模式)
    Entity Framework Core 2.0 全局查询过滤器
    再起航,我的学习笔记之JavaScript设计模式09(原型模式)
    APScheduler
    Gvim打造python编辑器,附自己的配置文件
    Python通过logging记录日志并应用coloredlogs在控制台输出有色字体
  • 原文地址:https://www.cnblogs.com/liweis/p/4213673.html
Copyright © 2011-2022 走看看