ArcGIS Engine空間查詢功能的實現(QueryFilterClass+SpatialFilterClass)
地圖中包含大量的資訊,為了快速地瞭解所需資訊,必須藉助為空間資料專門編寫的空間查詢功能。
空間查詢主要有兩種型別:
基於屬性的查詢,也稱為屬性查詢。
基於空間位置的查詢,也稱為空間查詢。
查詢類的基本思路(適用於屬性查詢以及空間查詢)
1、屬性查詢
基於屬性的查詢,即屬性查詢,是通過對要素的屬性資訊設定查詢條件來查詢、定位空間位置。
QueryFilterClass是專門用於屬性查詢的屬性查詢過濾器。
被稱為過濾器是因為擁有WhereClause屬性——能夠設定查詢條件的Sql語句。
注意:
使用WhereClause應該注意以下幾點:
(1)大小寫——欄位值不區分大小寫。
(2)萬用字元的使用——“?”代表單個字元,“*”代表一組字元。
(3)不支援Orderby關鍵字,可以通過ITablesort介面完成。
2、空間查詢
基於空間位置查詢,即空間查詢,是根據要素之間的空間位置關係進行的查詢,查詢結果包括了被查詢物件的空間資訊以及屬性資訊。
SpatialFilterClass物件類被稱為空間查詢過濾器。它是屬性過濾器的子類,它擁有的ISpatialFilter也繼承了IQueryFilter介面。
因此,空間查詢過濾器既能進行空間查詢也能進行屬性查詢。
一般地,要素之間的空間關係,即查詢範圍與被查詢物件的空間關係主要有以下幾種:
相交(Intersect)、疊加(Overlap)、穿越(Cross)、在內部(Within)和包含(Con-tain)。
空間關係(SpatialRel)屬性成員不需要使用者自定義,系統以列舉常量的方式(即ESRISpatialRelEnum)向用戶提供了多種空間關係。
(1)ESRISpatialRellntersects:空間相交
(2)ESRISpatialRelTouches:空間相接
(3)ESRISpatialRelOverlaps:覆蓋
(4)ESRISpatialRelCrosses:穿越
(5)ESRISpatialRelWithin:在內部
(6)ESRISpatialRelContains:包含
I.資料型別轉換(底層模組)
/// <summary> /// 轉換資料型別 /// </summary> /// <param name="type"></param> /// <returns></returns> private static string ParseFieldType(esriFieldType FieldType) { switch (FieldType) { case esriFieldType.esriFieldTypeInteger: return "System.Int32"; case esriFieldType.esriFieldTypeOID: return "System.Int32"; case esriFieldType.esriFieldTypeDouble: return "System.Double"; case esriFieldType.esriFieldTypeDate: return "System.DateTime"; default: return "System.String"; } }
II.屬性查詢實現模組
/// <summary> /// 核心屬性查詢函式 /// </summary> /// <param name="pFtClass"></param> /// <param name="pWhereClause"></param> /// <returns></returns> public static DataTable Search(IFeatureClass pFtClass, string pWhereClause) { //定義過濾器物件 IQueryFilter pQueryFilter = new QueryFilter(); //設定sql查詢語句 pQueryFilter.WhereClause = pWhereClause; //設定遊標 //呼叫.Search方法;false表示遊標到達最後一條要素以後不回收 //IFeatureCursor Search(IQueryFilter filter, bool Recycling); IFeatureCursor pFtCursor = pFtClass.Search(pQueryFilter, false); //宣告一個pFt要素並將查詢結果中的第一條Feature賦值給它 IFeature pFt = pFtCursor.NextFeature(); //例項化一個DataTable記憶體表物件, 用以儲存從要素中讀取出來的各屬性欄位值 DataTable DT = new DataTable(); for (int i = 0; i < pFtCursor.Fields.FieldCount; i++) { //構建表結構:欄位名和資料型別 DataColumn dc = new DataColumn(pFtCursor.Fields.get_Field(i).Name, System.Type.GetType(ParseFieldType(pFtCursor.Fields.get_Field(i).Type))); //欄位生成完成後新增到DT的列中 DT.Columns.Add(dc); } //當pFt不為空, 遍歷查詢屬性值放到DataTable中顯示 while (pFt != null) { //遍歷查詢結果逐個寫入到DT中 DataRow dr = DT.NewRow(); //以DT的表結構新建行物件 for (int i = 0; i < pFt.Fields.FieldCount; i++) { dr[i] = pFt.get_Value(i); } //完成某一行的欄位值錄入後向DT中新增此行物件 DT.Rows.Add(dr); //指向下一個要素 pFt = pFtCursor.NextFeature(); } return DT;//返回DataTable物件 }
III.空間查詢實現模組
/// <summary> /// 核心空間查詢函式 /// </summary> /// <param name="pFtClass">查詢要素類</param> /// <param name="pWhereClause">SQL語句</param> /// <param name="pGeometry">空間查詢範圍</param> /// <param name="pSpRel">空間關係</param> /// <returns></returns> private DataTable SpatialSearch(IFeatureClass pFtClass, string pWhereClause, IGeometry pGeometry, esriSpatialRelEnum pSpRel) { //定義空間查詢過濾器物件 ISpatialFilter pSpatialFilter = new SpatialFilterClass(); //設定sql查詢語句 pSpatialFilter.WhereClause = pWhereClause; //設定查詢範圍 pSpatialFilter.Geometry = pGeometry; //給定範圍與查詢物件的空間關係 pSpatialFilter.SpatialRel = pSpRel; //查詢結果以遊標的形式返回(下面與屬性查詢一樣) IFeatureCursor pFtCursor = pFtClass.Search(pSpatialFilter, false); IFeature pFt = pFtCursor.NextFeature(); DataTable DT = new DataTable(); for (int i = 0; i < pFtCursor.Fields.FieldCount; i++) { DataColumn dc = new DataColumn(pFtCursor.Fields.get_Field(i).Name, System.Type.GetType(ParseFieldType((pFtCursor.Fields.get_Field(i).Type)))); DT.Columns.Add(dc); } while (pFt != null) { DataRow dr = DT.NewRow(); for (int i = 0; i < pFt.Fields.FieldCount; i++) { dr[i] = pFt.get_Value(i); } DT.Rows.Add(dr); pFt = pFtCursor.NextFeature(); } return DT; }
IV.呼叫方法、顯示
1、屬性查詢
向ListBox中新增圖層欄位:
/// <summary> /// 獲取ComboBox被選定的索引號 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void cboSelectLayer_SelectedIndexChanged(object sender, EventArgs e) { AddFields(); } /// <summary> /// 向ListBox中新增圖層欄位 /// </summary> private void AddFields() { //清空ListBox lbShow.Items.Clear(); //將pWorkspace強轉成要素工作空間 IFeatureWorkspace pFtWorkspace = pWorkspace as IFeatureWorkspace; //通過要素工作空間開啟cboSelectLayer選擇的圖層, 並放在要素類中 IFeatureClass pFtClass = pFtWorkspace.OpenFeatureClass(cboSelectLayer.Text); //開啟遊標, null為查詢全部, false表示遊標到達最後一條要素以後不回收 IFeatureCursor pFtCursor = pFtClass.Search(null, false); //使用for迴圈逐一新增圖層欄位 for (int i = 0; i < pFtCursor.Fields.FieldCount; i++) { IField pField = pFtCursor.Fields.get_Field(i); //獲取欄位的下標 lbShow.Items.Add(pField.Name.ToString());//將欄位名加到ListBox中 } }
獲取唯一值:
/// <summary> /// 獲取唯一值 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnGetValue_Click(object sender, EventArgs e) { lbValue.Items.Clear(); //將pWorkspace強轉成要素工作空間 IFeatureWorkspace pFtWorkspace = pWorkspace as IFeatureWorkspace; //通過要素工作空間開啟cboSelectLayer選擇的圖層, 並放在要素類中 IFeatureClass pFtClass = pFtWorkspace.OpenFeatureClass(cboSelectLayer.Text); //開啟遊標, null為查詢全部, false表示遊標到達最後一條要素以後不回收 IFeatureCursor pFtCursor = pFtClass.Search(null, false); //宣告一個pFt要素並將查詢結果中的第一條Feature賦值給它 IFeature pFt = pFtCursor.NextFeature(); //宣告index作為下標使用 int index = 0; //將index賦值為找到選中欄位下標 index = pFtCursor.FindField(lbShow.Text); //當要素不為空時 while(pFt!=null) { //如果lbValue中包含要素下標則遊標到下一個要素, 跳過本次迴圈 if(lbValue.Items.Contains(pFt.get_Value(index))) { pFt = pFtCursor.NextFeature(); continue; } //將遊標的的要素加到lbValue中 lbValue.Items.Add(pFt.get_Value(index)); //轉到下一個要素 pFt = pFtCursor.NextFeature(); } }
查詢按鈕:
private void btnSelect_Click(object sender, EventArgs e) { //將工作空間強轉成要素工作空間 IFeatureWorkspace pFtWorkspace = pWorkspace as IFeatureWorkspace; //通過要素工作空間開啟cboSelectLayer選擇的圖層, 並放在要素類中 IFeatureClass pFtClass = pFtWorkspace.OpenFeatureClass(cboSelectLayer.Text); try { //呼叫核心查詢方法, 返回型別為DataTable Global.myDGV1.DataSource = Search(pFtClass, txtSql.Text.Trim()); } catch (Exception ex) { MessageBox.Show(ex.Message); } }
2、空間查詢
主檢視的OnMouseDown事件:
/// <summary> /// 主檢視的OnMouseDown事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void axMapControl1_OnMouseDown(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnMouseDownEvent e) { //當空間查詢的狀態為真時 if (IsSpatialSearch) { //獲取精確圖層 ILayer pLayer = axMapControl1.get_Layer(Get_Layer("北部灣")); //將圖層強轉成要素圖層 IFeatureLayer pFtLayer = pLayer as IFeatureLayer; //將要素圖層的圖層類強轉成要素類 IFeatureClass pFtClass = pFtLayer.FeatureClass as IFeatureClass; //隨著滑鼠拖動得到一個矩形框 IEnvelope pEnvelope = axMapControl1.TrackRectangle(); //呼叫核心空間查詢函式(採用空間相交的方法esriSpatialRelIntersects) dataGridView1.DataSource = SpatialSearch(pFtClass,"", pEnvelope,esriSpatialRelEnum.esriSpatialRelIntersects); axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null); } }
獲得精確圖層名下的index
/// <summary> /// 獲得精確圖層名下的index /// </summary> /// <param name="LayerName">圖層名字</param> /// <returns></returns> private int Get_Layer(string LayerName) { //遍歷主檢視的圖層 for (int i = 0; i < axMapControl1.LayerCount; i++) { //如果圖層索引對應的名字和使用者輸入的名字相同則返回索引 if (axMapControl1.get_Layer(i).Name.Equals(LayerName)) { return i; } } return -1;//返回-1 }
用於判斷空間查詢的狀態:
//用於判斷空間查詢的狀態 bool IsSpatialSearch = false;
謝謝觀看!本人初學GIS二次開發,如果有不對的地方,請多多包涵!
&n