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("警告:數據庫路徑選擇有誤!\n    請檢查數據路徑是否正確。", "提示");
    }
}

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM