天天看點

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

目錄

1. 面要素合并

1.1 代碼

1.2 效果示範

2 根據屬性合并線要素

2.1 遇到的問題

2.3 代碼

2.5 總結

3 根據幾何合并

3.1 程式思路和實作過程

3.2 程式執行個體和結果

3.3 代碼

說明:

使用ContructionUnion進行要素合并得到的要素實際上是複合要素,即一個集合要素由多個幾何圖形構成,而我們常見的要素一般是一個幾何要素隻包含一個幾何圖形

如果合并之後,還需要拆分操作請參考部落格文章:基于C#的ArcEngine二次開發23:複合要素的識别與導出

本文為網絡搜集代碼整理,希望友善大家借鑒參考,如有侵權,請聯系删除!

以下代碼及示範來源于以下部落格:

第一部分:ArcEngine合并要素

第二部分: ArcEngine中合并斷開的線要素(根據幾何判斷)

第三部分:ArcEngine環境下合并斷開的線要素(根據屬性)

感謝原作者

本文的第一部分,亦在公衆号【運籌優化與圖像處理算法程式設計】公衆号同步刊發,歡迎關注!

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

0 基礎知識

0.1 ArcGIS常用工具:union、merge、append、dissolve差別

原文來自https://blog.csdn.net/sisiiiiiii/article/details/39178913

  • union(聯合)

      要求輸入的要素必須是多邊形,即求得兩個及以上多邊形的并集,對輸入要素的屬性字段沒有要求,輸出要素是所有輸入的屬性的集合。如下圖輸入三個要素面,輸出要素面為7個。

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并
  • merge(合并)

      将資料類型相同的多個輸入資料集合并為新的單個輸出資料集,屬性字段也合并成兩個要素屬性全集

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并
  • append(追加)

      将多個輸入資料集追加到現有目标資料集,與合并差別是合并生成新的要素集,追加是在現有要素基礎上。

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并
  • dissolve(融合)

      對于融合需要選擇一個或者多個指定的屬性字段,融合的要素必須具有相同的幾何類型,可以簡單了解為具有相同屬性要素集合成一個要素集。融合後的屬性字段僅輸出融合前指定的。

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

面狀資料調整,需要把多個面融合為一個面,屬性保留一種,那就需要用到融合工具(dissolve)

0.2 融合示例ArcGIS示範

文獻來源:https://blog.csdn.net/aganliang/article/details/81560293

 下面詳細講解使用方法,如圖所示。

1.先把屬性改成一樣

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

2.打開融合工具

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

3.自動生成的字段不要勾選

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

4.結果如圖所示。

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

要素融合+要素轉點的代碼實作:

//在D:\data目錄下建立temp.gdb檔案夾,存儲計算的中間結果
public check(string inPath, string checkLayerName)
{
    //初始化GP工具
    ESRI.ArcGIS.Geoprocessor.Geoprocessor pGeoprocessor = new ESRI.ArcGIS.Geoprocessor.Geoprocessor {OverwriteOutput = true, AddOutputsToMap = false};
    //建立GDB檔案
    CreateFileGDB processor1 = new CreateGDB {out_folder_path = @"D:\data", out_name = "temp.gdb"}; 
    pGeoprocessor.Execute(processor1, null);
    
    string lcaPath = inPath + "\\" + checkLayerName;
    string gdbPath = processor1.out_folder_path + "\\" + processor1.out_name);

    //面融合
    string dissolveLayerName = gdbPath + "\\dissolve";
    pGeoprocessor.Execute(areaDissolve(lcaPath, dissolveLayerName), null);
    
    //要素轉點
    string featureToPointLayerName= gdbPath + "\\dissolve";
    pGeoprocessor.Execute(featureToPoint(lcaPath, featureToPointLayerName), null);


}

//面融合函數
public void areaDissolve(string lcaPath, string dissolveLayerName)
{
    Dissolve disolve = new Disolve {};
    dissolve.in_features = lcaPath;
    dissolve.out_features = dissolveLayerName;
    dissolve.dissolve_fields = "FEAID";
    return disolve;
}
//要素轉點
public void featureToPoint(string lcaPath, string featureToPointLayerName)
{
    FeatureToPoint pFeaToPt = new FeatureToPoint {};
    pFeaToPt.in_features = lcaPath;
    pFeaToPt.out_features_class = featureToPointLayerName;
    pFeaToPt.point_location = "INSIDE";
    return pFeaToPt;
}
           

1. 面要素合并

1.1 代碼

開發環境:VS2013 + ArcEngine 10.4

在資料量較大時,請用ITopologicalOperator的ConstructUnion方法,而不是一個一個Union

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.DataSourcesFile;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Output;
using ESRI.ArcGIS.SystemUI;

namespace WindowsFormsApplication2
{
    public class MergeTool
    {
        /// <summary>
        /// 輸入要素
        /// </summary>
        private IFeatureClass in_FeatureClass;

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="in_FeatureClass"></param>
        public MergeTool(IFeatureClass in_FeatureClass)
        {
            this.in_FeatureClass = in_FeatureClass;
        }

        /// <summary>
        /// 擷取空間參考
        /// </summary>
        /// <returns></returns>
        private ISpatialReference GetSpatialReference()
        {
            IGeoDataset pGeoDataset = in_FeatureClass as IGeoDataset;
            ISpatialReference pSpatialReference = pGeoDataset.SpatialReference;
            return pSpatialReference;
        }

        /// <summary>
        /// 合并幾何體
        /// </summary>
        /// <returns></returns>
        private IGeometry GetMergeGeometry()
        {
            IGeometryBag pGeometryBag = new GeometryBag() as IGeometryBag;
            pGeometryBag.SpatialReference = GetSpatialReference();
            IGeometryCollection pGeometryCollection = pGeometryBag as IGeometryCollection;

            // 屬性過濾
            IQueryFilter pQueryFilter = new QueryFilter();
            pQueryFilter.AddField("Shape");

            // 要素遊标
            IFeatureCursor pFeatureCursor = in_FeatureClass.Search(pQueryFilter, true);
            IFeature pFeature = pFeatureCursor.NextFeature();
            if (pFeature == null)
            {
                return null;
            }

            // 周遊遊标
            object missing = Type.Missing;
            while (pFeature != null)
            {
                pGeometryCollection.AddGeometry(pFeature.ShapeCopy, ref missing, ref missing);
                pFeature = pFeatureCursor.NextFeature();
            }
            Marshal.ReleaseComObject(pFeatureCursor);

            // 合并要素
            ITopologicalOperator pTopologicalOperator = null;
            if (in_FeatureClass.ShapeType == esriGeometryType.esriGeometryPoint)
            {
                pTopologicalOperator = new Multipoint() as ITopologicalOperator;
                pTopologicalOperator.ConstructUnion(pGeometryCollection as IEnumGeometry);
            }
            else if (in_FeatureClass.ShapeType == esriGeometryType.esriGeometryPolyline)
            {
                pTopologicalOperator = new Polyline() as ITopologicalOperator;
                pTopologicalOperator.ConstructUnion(pGeometryCollection as IEnumGeometry);
            }
            else
            {
                pTopologicalOperator = new Polygon() as ITopologicalOperator;
                pTopologicalOperator.ConstructUnion(pGeometryCollection as IEnumGeometry);
            }
            return pTopologicalOperator as IGeometry;
        }

        /// <summary>
        /// 執行工具
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public IFeatureClass ExecuteTool(string filePath)
        {
            IGeometryDef pGeometryDef = new GeometryDef();
            IGeometryDefEdit pGeometryDefEdit = pGeometryDef as IGeometryDefEdit;
            if (in_FeatureClass.ShapeType == esriGeometryType.esriGeometryPoint)
            {
                pGeometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryMultipoint;
                pGeometryDefEdit.HasM_2 = false;
                pGeometryDefEdit.HasZ_2 = false;
                pGeometryDefEdit.SpatialReference_2 = GetSpatialReference();
            }
            else if (in_FeatureClass.ShapeType == esriGeometryType.esriGeometryPolyline)
            {
                pGeometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolyline;
                pGeometryDefEdit.HasM_2 = false;
                pGeometryDefEdit.HasZ_2 = false;
                pGeometryDefEdit.SpatialReference_2 = GetSpatialReference();
            }
            else
            {
                pGeometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolygon;
                pGeometryDefEdit.HasM_2 = false;
                pGeometryDefEdit.HasZ_2 = false;
                pGeometryDefEdit.SpatialReference_2 = GetSpatialReference();
            }

            // 字段集合
            IFields pFields = new Fields();
            IFieldsEdit pFieldsEdit = pFields as IFieldsEdit;

            // Shape
            IField pField = new Field();
            IFieldEdit pFieldEdit = pField as IFieldEdit;
            pFieldEdit.Type_2 = esriFieldType.esriFieldTypeGeometry;
            pFieldEdit.GeometryDef_2 = pGeometryDef;
            pFieldEdit.AliasName_2 = "Shape";
            pFieldEdit.Name_2 = "Shape";
            pFieldEdit.IsNullable_2 = false;
            pFieldEdit.Required_2 = true;
            pFieldsEdit.AddField(pField);

            // 建立要素類
            IWorkspaceFactory pWorkspaceFactory = new ShapefileWorkspaceFactory();
            IWorkspace pWorkspace = pWorkspaceFactory.OpenFromFile(System.IO.Path.GetDirectoryName(filePath), 0);
            IFeatureWorkspace pFeatureWorkspace = pWorkspace as IFeatureWorkspace;
            IFeatureClass pFeatureClass = pFeatureWorkspace.CreateFeatureClass(System.IO.Path.GetFileName(filePath), pFields, null, null, esriFeatureType.esriFTSimple, "Shape", "");

            // 插入要素
            IFeatureBuffer pFeatureBuffer = pFeatureClass.CreateFeatureBuffer();
            IFeatureCursor pFeatureCursor = pFeatureClass.Insert(true);
            pFeatureBuffer.Shape = GetMergeGeometry();
            pFeatureCursor.InsertFeature(pFeatureBuffer);
            pFeatureCursor.Flush();
            return pFeatureClass;
        }
    }
}
           

1.2 效果示範

合并之前

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

合并之後

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

2 根據屬性合并線要素

2.1 遇到的問題

 最近遇到線上要素(矢量資料)中,一條完整的道路、河流等往往是斷開的,如下圖1所示:

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并
基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并
基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

     2.2 思路與結果

      在ArcGIS Desktop中沒有相關的工具可以将這些斷開的線要素進行自動合并,今天自己寫了一個Arcmap上的一個插件,實作當點選插件按鈕後,對地圖視窗中斷開的線要素進行合并。合并的依據是具有相同NAME屬性(如長沙-張家界高速)的Polyline要素進行合并,然後存儲在另一個線要素圖層中。

      程式運作的結果如下,這樣本來屬于同一段道路的多個Polyline就合并成一條Polyline:

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

2.3 代碼

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using ESRI.ArcGIS.ArcMapUI;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;

namespace MergeDisconnectPolylineAddin
{
    public class MergePolyline : ESRI.ArcGIS.Desktop.AddIns.Button
    {
        
        IMap map = null;
        IActiveView pActiveView = null;
        //private List<IPolyline> DisconnPolylineList = new List<IPolyline>();

        public MergePolyline()
        {
            IMxDocument mxDoc = ArcMap.Application.Document as IMxDocument;
            map = mxDoc.FocusMap;
            pActiveView = mxDoc.ActivatedView;
        }

        protected override void OnClick()
        {
            //
            //  TODO: Sample code showing how to access button host
            //
            ArcMap.Application.CurrentTool = null;

            //計算程式耗時
            DateTime beforDT = System.DateTime.Now;
            
            List<string> distinctString = getDistinctNAMEValue();
            MergePloyline(distinctString);

            DateTime afterDT = System.DateTime.Now;
            TimeSpan ts = afterDT.Subtract(beforDT);
            MessageBox.Show("線要素合并結束,運作程式共耗時約:"+ ts.Minutes+"分鐘");
        }
        
        public List<string> getDistinctNAMEValue()
        {
            IFeatureLayer featureLayer = map.get_Layer(0) as IFeatureLayer;
            IFeatureClass featureClass = featureLayer.FeatureClass;
            IQueryFilter queryFilter = new QueryFilterClass();
            queryFilter.WhereClause = "";
            IFeatureCursor pFeatCursor = featureClass.Search(queryFilter, false);
            IFeature pFeature = pFeatCursor.NextFeature();
            ArrayList fieldArray = new ArrayList();
            List<string> distinctString = new List<string>();
            while (pFeature != null)
            {
                if (featureClass.ShapeType == esriGeometryType.esriGeometryPolyline)
                {
                    IFields fields = pFeatCursor.Fields;
                    int fieldIndex = fields.FindField("NAME");
                    string field_NAME = (string)pFeature.get_Value(fieldIndex);
                    fieldArray.Add(field_NAME);
                }
                pFeature = pFeatCursor.NextFeature();
            }
            distinctString = removeSameString(fieldArray);
            return distinctString;
        }

        public void MergePloyline(List<string> DistinctNameValue)
        {
            IFeatureLayer featureLayer = map.get_Layer(0) as IFeatureLayer;
            IFeatureClass featureClass = featureLayer.FeatureClass;

            //IDataset dataset = featureClass as IDataset;
            //IWorkspaceEdit workspaceEdit = dataset.Workspace as IWorkspaceEdit;
            //Type.Missing指的是空類型,因為有些方法你傳null給它會出錯的,必須要用Type.Missing.
            object Missing = Type.Missing;
            //workspaceEdit.StartEditing(true);
            //workspaceEdit.StartEditOperation();
            //string field_NAME = "";

            for (int i = 0; i < DistinctNameValue.Count; i++)
            {
                IQueryFilter queryFilter = new QueryFilterClass();
                queryFilter.WhereClause = "";
                IFeatureCursor pFeatCursor = featureClass.Search(queryFilter, false);
                IFeature pFeature = pFeatCursor.NextFeature();

                IFeature pFeatureFirst = pFeature;
                //List<IPolyline> toMergePolylineList = new List<IPolyline>();

                IGeometryCollection Geometrybag = new GeometryBagClass();
                ITopologicalOperator2 pTopOperatorFirst = null;
                IGeometry geometrySecond = null;
                IGeometry pGeometryFirst = null;
                bool bSwitch = true;
                while (pFeature != null)
                {
                    map.SelectFeature(featureLayer, pFeature);
                    if (featureClass.ShapeType == esriGeometryType.esriGeometryPolyline)
                    {                       
                        //IPolyline polyline = geometry as IPolyline;
                        IFields fields = pFeatCursor.Fields;
                        int fieldIndex = fields.FindField("NAME");
                        string field_NAME = (string)pFeature.get_Value(fieldIndex);
                        
                        if (field_NAME == DistinctNameValue[i])
                        {
                            if (bSwitch)
                            {
                                //将目前name字段相同的feature中的第一個feature傳給pFeatureFirst
                                pFeatureFirst = pFeature;
                                pGeometryFirst = pFeature.Shape;
                                pTopOperatorFirst = (ITopologicalOperator2) pGeometryFirst;
                                pTopOperatorFirst.IsKnownSimple_2 = false;
                                pTopOperatorFirst.Simplify();
                                pGeometryFirst.SnapToSpatialReference();
                                bSwitch = false;
                                //break;
                            }
                            else
                            {
                                //geometrySecond = pFeature.ShapeCopy;
                                geometrySecond = pFeature.Shape;
                                Geometrybag.AddGeometry(geometrySecond, ref Missing, ref Missing);
                                //toMergePolylineList.Add(polyline);
                            }                           
                        }
                        //DisconnPolylineList.Add(polyline);
                    }
                    pFeature = pFeatCursor.NextFeature();
                }
                IEnumGeometry tEnumGeometry = (IEnumGeometry)Geometrybag;
                //IGeometry mergeGeomery = null;
                pTopOperatorFirst.ConstructUnion(tEnumGeometry);

                pTopOperatorFirst.IsKnownSimple_2 = false;
                pTopOperatorFirst.Simplify();
                pFeatureFirst.Shape = pGeometryFirst;
                //pFeatureFirst.Store();
                IFeatureLayer featureLayer2 = map.get_Layer(1) as IFeatureLayer;
                IFeatureClass featureClass2 = featureLayer2.FeatureClass;
                AddPolyline(featureClass2, pGeometryFirst);
            }
            //workspaceEdit.StopEditOperation();
            //workspaceEdit.StopEditing(true);           
        }
        private void AddPolyline(IFeatureClass pFeatureClass, IGeometry polyline)
        {
            IFeatureBuffer featureBuffer = pFeatureClass.CreateFeatureBuffer();
            IFeatureCursor featureCursor;
            featureCursor = pFeatureClass.Insert(true);
            featureBuffer.Shape = polyline;
            featureCursor.InsertFeature(featureBuffer);
            featureCursor.Flush();
            System.Runtime.InteropServices.Marshal.ReleaseComObject(featureCursor);
        }
        public List<string> removeSameString(ArrayList stringArray)
        {
            //List用于存儲從數組裡取出來的不相同的元素
            List<string> distinctString = new List<string>();
            foreach (string eachString in stringArray)
            {
                if (!distinctString.Contains(eachString))
                    distinctString.Add(eachString);
            }
            return distinctString;
        }

        protected override void OnUpdate()
        {
            Enabled = ArcMap.Application != null;
        }
    }

}
           

2.5 總結

      這個插件還有一些不足的地方,如不是從線要素首尾點相鄰的角度尋找相鄰點(這種方法存在判斷三條線要素交叉而形成的節點的判斷和是否進行合并的問題和難點),在下一篇随筆裡面會介紹從純幾何學的角度實作線要素的連接配接的實作。

3 根據幾何合并

通過幾何條件判斷的方式連接配接斷開的線要素的ArcGIS 插件完成,在這裡把思路和代碼和大家分享下:

3.1 程式思路和實作過程

1.首先讀取shp線檔案,将各條線要素周遊,存儲在List<IFeature>,這裡之是以不存在List<IPolyline>和List<IGeometry>中的原因是後兩者會丢失要素的屬性資訊;

2.為了簡化合并算法的邏輯和複雜性,采用分治思想。将線要素分為需要進行合并和不需要進行合并(獨立的線,ToPoint或FromPoint是“節點”的線和ToPoint,FromPoint均是“節點”線)的兩大類,分别存儲在兩個集合中;

3.現在隻需對需要進行合并的的線要素集合進行合并操作。首先從集合中選取一條Polyline,然後在集合剩下的元素中尋找與其ToPoint或FromPoint相同的線要素,然後使用ITopologicalOperator2.Union()方法進行合并,然後尋找和合并後新的Polyline的ToPoint或FromPoint相同的線要素繼續合并,沒合并一次,就将合并入的Polyline從集合中移除,直到剩下的Polyline不可和目前合并的Polyline合并為止,這樣就得到了第一條合并好的Polyline。接着從集合剩下的線要素再找一條Polyline開始新一輪合并操作,直到List<IFeature>為空,整個合并操作結束;

4.得到合并好的List<IFeature> mergeResultLineList後,需要為其添加屬性(NAME等字段),通過IFeatureBuffer接口寫入shape和Fields,然後Flush到檔案中,結束。

3.2 程式執行個體和結果

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

運作結果圖

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

合并前屬性表

基于C#的ArcEngine二次開發34:使用ConstructUnion方法進行多要素合并0 基礎知識0.2 融合示例ArcGIS示範1. 面要素合并2 根據屬性合并線要素3 根據幾何合并

合并後屬性表

3.3 代碼

public class MergeDisconnectLine : ESRI.ArcGIS.Desktop.AddIns.Button
    {

        public int CountPercent { get; set; }
        IMap map = null;
        private List<IFeature> DisconnPolylineList = new List<IFeature>();
        private List<IFeature> firstRowFeatureList = new List<IFeature>();

        public MergeDisconnectLine()
        {
            IMxDocument mxDoc = ArcMap.Application.Document as IMxDocument;
            map = mxDoc.FocusMap;
        }
        protected override void OnClick()
        {
            //
            //  TODO: Sample code showing how to access button host
            //
            ArcMap.Application.CurrentTool = null;

            //計算程式耗時
            DateTime beforDT = System.DateTime.Now;
            //Application.EnableVisualStyles();
            //Application.SetCompatibleTextRenderingDefault(false);
            ProgressBar pBar = new ProgressBar();
            //Application.Run(new ProgressBar());           
            List<IFeature> allPolylineList = getAllPolyline();
            List<IFeature> noNeedUnionLineList = getWithoutNeedUnionLineList(allPolylineList);
            List<IFeature> toUnionLineList = GetToUnionLineList(allPolylineList, noNeedUnionLineList);
            List<IFeature> unionLineList = MergeLineListOperate(toUnionLineList);
            AddField();
            WriteNoNeedUnionLineToFile(noNeedUnionLineList);
            WriteUnionLineToFile(unionLineList, firstRowFeatureList);
            DateTime afterDT = System.DateTime.Now;
            TimeSpan ts = afterDT.Subtract(beforDT);
            int minutes = ts.Minutes;
            int seconds = ts.Seconds%60;
            //pBar.Hide();
            MessageBox.Show("線要素合并結束,運作程式共耗時約:" + minutes + "分"+ seconds + "秒");
        }
        //擷取shp檔案中所有的Polyline(IFeature)對象
        public List<IFeature> getAllPolyline()
        {
            IFeatureLayer featureLayer = map.get_Layer(1) as IFeatureLayer;
            IFeatureClass featureClass = featureLayer.FeatureClass;
            IQueryFilter queryFilter = new QueryFilter();
            queryFilter.WhereClause = "";
            IFeatureCursor pFeatCursor = featureClass.Search(queryFilter, false);
            IFeature pFeature = pFeatCursor.NextFeature();

            while (pFeature != null)
            {
                if (featureClass.ShapeType == esriGeometryType.esriGeometryPolyline)
                {
                    DisconnPolylineList.Add(pFeature);
                }
                pFeature = pFeatCursor.NextFeature();                 
            }
            return DisconnPolylineList;
        }

        //擷取需要進行合并的線(是noNeedUnionLineList的補集)
        public List<IFeature> GetToUnionLineList(List<IFeature> allPolylineList, List<IFeature> noNeedUnionLineList)
        {
            List<IFeature> toUnionLineList = allPolylineList;
            foreach (IFeature featureLine in noNeedUnionLineList)
            {
                toUnionLineList.Remove(featureLine);
            }
            return toUnionLineList;
        }

        //擷取不需要進行合并的線(獨立線,一端是節點的線,和兩端都是節點的線)       
        public List<IFeature> getWithoutNeedUnionLineList(List<IFeature> allPolylineList)
        {
            List<IFeature> noNeedUnionLineList = new List<IFeature>();
            foreach (IFeature featureLine in allPolylineList)
            {
                int count = featureLine.Fields.FieldCount;
                List<IFeature> allPolylineListCopy = allPolylineList;
                IGeometry geoLine = featureLine.Shape;
                IPolyline lineFirst = geoLine as IPolyline;
                IPoint startPt1 = lineFirst.FromPoint;
                IPoint endPt1 = lineFirst.ToPoint;
                int fromFlag = 0;
                int toFlag = 0;
                for (int i = 0; i < allPolylineListCopy.Count; i++)
                {
                    IFeature line2 = allPolylineListCopy[i];
                    IGeometry geoLine2 = line2.Shape;
                    IPolyline lineSecond = geoLine2 as IPolyline;
                    IPoint startPt2 = lineSecond.FromPoint;
                    IPoint endPt2 = lineSecond.ToPoint;
                    //FromPoint相同的點
                    if ((startPt1.X == startPt2.X && startPt1.Y == startPt2.Y) ||
                        (startPt1.X == endPt2.X && startPt1.Y == endPt2.Y))
                    {
                        fromFlag++;
                    }
                    //ToPoint相同的點
                    if ((endPt1.X == endPt2.X && endPt1.Y == endPt2.Y) ||
                    (endPt1.X == startPt2.X && endPt1.Y == startPt2.Y))
                    {
                        toFlag++;
                    }
                }
                if (fromFlag > 2 || toFlag > 2 || (fromFlag == 1 && toFlag == 1))
                {
                    noNeedUnionLineList.Add(featureLine);
                    //noNeedUnionLineFileds.Add(featureLine.Fields);
                }
            }
            return noNeedUnionLineList;
        }

        //将需要進行合并的線要素(沒有節點)集合進行合并,結果為多條線       
        public List<IFeature> MergeLineListOperate(List<IFeature> toUnionLineList)
        {
            List<IFeature> mergeResultLineList = new List<IFeature>();
            int CountPercent = 0;
            while (toUnionLineList.Count > 0)
            {
                CountPercent++;
                //初始化目前合并的線要素
                IFeature unionCurrentLine = toUnionLineList[0];
                //将第一個要素的屬性字段值作為最終合并線要素的值
                firstRowFeatureList.Add(unionCurrentLine);
                List<IFeature> currentMergeLineList = new List<IFeature>();
                int count2 = 0;
                do
                {
                    count2++;
                    IFeature featureFirst = unionCurrentLine;
                    IGeometry geoLineFirst = featureFirst.Shape;
                    IPolyline lineFirst = geoLineFirst as IPolyline;
                    IPoint startPt1 = lineFirst.FromPoint;
                    IPoint endPt1 = lineFirst.ToPoint;
                    toUnionLineList.Remove(featureFirst);
                    currentMergeLineList.Clear();
                    currentMergeLineList.Add(featureFirst); 

                    List<IFeature> allPolylineListTemp1 = new List<IFeature>();
                    List<IFeature> allPolylineListTemp2 = new List<IFeature>();
                    int bStart1 = 0;
                    int bStart2 = 0;
                    for (int j = 0; j < toUnionLineList.Count; j++)
                    {
                        IFeature featureSecond = toUnionLineList[j];
                        IGeometry geoLineSecond = featureSecond.Shape;
                        IPolyline lineSecond = geoLineSecond as IPolyline;
                        IPoint startPt2 = lineSecond.FromPoint;
                        IPoint endPt2 = lineSecond.ToPoint;

                        if ((startPt1.X == startPt2.X && startPt1.Y == startPt2.Y) ||
                            (startPt1.X == endPt2.X && startPt1.Y == endPt2.Y))
                        {
                            bStart1++;
                            if (bStart1 > 0)
                            {
                                allPolylineListTemp1.Add(featureSecond);
                                currentMergeLineList.AddRange(allPolylineListTemp1);
                                toUnionLineList.Remove(featureSecond);
                            }
                        }
                        if ((endPt1.X == endPt2.X && endPt1.Y == endPt2.Y) ||
                            (endPt1.X == startPt2.X && endPt1.Y == startPt2.Y))
                        {
                            bStart2++;
                            if (bStart2 > 0)
                            {
                                allPolylineListTemp2.Add(featureSecond);
                                currentMergeLineList.AddRange(allPolylineListTemp2);
                                toUnionLineList.Remove(featureSecond);
                            }

                        }
                       
                    }
                    if (currentMergeLineList.Count > 1)
                    {
                        unionCurrentLine = UnionCurrentLineList(currentMergeLineList);
                    }
                    else
                    {
                        int ii = 0;
                    }
                } while (currentMergeLineList.Count > 1);

                mergeResultLineList.Add(unionCurrentLine);
            }
            return mergeResultLineList;
        }

        //為待寫入圖層添加Name和GB字段
        public void AddField()
        {
            IFeatureLayer featureLayer2 = map.get_Layer(0) as IFeatureLayer;
            IFeatureClass featureClass2 = featureLayer2.FeatureClass;
            IClass pClass = featureClass2 as IClass;
            IField fld1 = new Field();
            IField fld2 = new Field();
            IFieldEdit2 fld_NAME = fld1 as IFieldEdit2;
            IFieldEdit2 fld_GB = fld2 as IFieldEdit2;
            fld_NAME.Type_2 = esriFieldType.esriFieldTypeString;
            fld_NAME.Name_2 = "NAME";
            fld_GB.Type_2 = esriFieldType.esriFieldTypeString;
            fld_GB.Name_2 = "GB";
            pClass.AddField(fld_GB);
            pClass.AddField(fld_NAME);
            
        }

        public void WriteNoNeedUnionLineToFile(List<IFeature> pLineList)
        {           
            foreach (IFeature featureLine in pLineList)
            {
                IFeatureLayer featureLayer2 = map.get_Layer(0) as IFeatureLayer;
                IFeatureClass featureClass2 = featureLayer2.FeatureClass;          
                IFeatureBuffer featureBuffer = featureClass2.CreateFeatureBuffer();
                IFeatureCursor featureCursor;
                featureCursor = featureClass2.Insert(true);               
                IGeometry pGeometry = featureLine.Shape;
                featureBuffer.Shape = pGeometry;
                int NAME_Index = featureLine.Fields.FindField("NAME");
                int GB_Index = featureLine.Fields.FindField("GB");
                string name = featureLine.get_Value(NAME_Index).ToString();
                string gb = featureLine.get_Value(GB_Index).ToString();
                int fieldindex1 = featureBuffer.Fields.FindField("NAME");
                int fieldindex2 = featureBuffer.Fields.FindField("GB");
                if (fieldindex1 >= 0)
                {
                    featureBuffer.set_Value(fieldindex1, name);
                }
                if (fieldindex2 >= 0)
                {
                    featureBuffer.set_Value(fieldindex2, gb);
                }
                featureCursor.InsertFeature(featureBuffer);
                featureCursor.Flush();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(featureCursor);               
            }           
        }
        public void WriteUnionLineToFile(List<IFeature> mergeResultLineList, List<IFeature> firstFeatureList)
        {
            int index = 0;
            foreach (IFeature featureLine in mergeResultLineList)
            {
                IFeatureLayer featureLayer2 = map.get_Layer(0) as IFeatureLayer;
                IFeatureClass featureClass2 = featureLayer2.FeatureClass;
                IFeatureBuffer featureBuffer = featureClass2.CreateFeatureBuffer();
                IFeatureCursor featureCursor;
                featureCursor = featureClass2.Insert(true);
                IGeometry pGeometry = featureLine.Shape;
                featureBuffer.Shape = pGeometry;
                int NAME_Index = firstFeatureList[index].Fields.FindField("NAME");
                int GB_Index = firstFeatureList[index].Fields.FindField("GB");
                string name = firstFeatureList[index].get_Value(NAME_Index).ToString();
                string gb = firstFeatureList[index].get_Value(GB_Index).ToString();
                int fieldindex1 = featureBuffer.Fields.FindField("NAME");
                int fieldindex2 = featureBuffer.Fields.FindField("GB");
                if (fieldindex1 >= 0)
                {
                    featureBuffer.set_Value(fieldindex1, name);
                }
                if (fieldindex2 >= 0)
                {
                    featureBuffer.set_Value(fieldindex2, gb);
                }
   
                featureCursor.InsertFeature(featureBuffer);
                featureCursor.Flush();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(featureCursor);
                index++;
            }
        }

        //将傳入的List<IPolylne>中的多條線要素進行合并為一條線要素
        public IFeature UnionCurrentLineList(List<IFeature> currentMergeLineList)
        {
            IFeatureLayer featureLayer = map.get_Layer(1) as IFeatureLayer;
            IFeatureClass featureClass = featureLayer.FeatureClass;
           
            ITopologicalOperator2 pTopologicalOperator;
            IFeature pFeatureTemp = currentMergeLineList[0];
            IGeometry pGeometry = pFeatureTemp.Shape;
            int i = 1;
            while (i < currentMergeLineList.Count)
            {
                pTopologicalOperator = pGeometry as ITopologicalOperator2;
                //ITopologicalOperator的操作是bug很多的,先強制的檢查下面三個步驟,再進行操作
                //modifiy in 2016/03/20 12:47
                pTopologicalOperator.IsKnownSimple_2 = false;
                pTopologicalOperator.Simplify();
                pGeometry.SnapToSpatialReference();

                pGeometry = currentMergeLineList[i].Shape;
                pGeometry = pTopologicalOperator.Union(pGeometry);
                i++;
            }
            IFeature unionLine = featureClass.CreateFeature();
            unionLine.Shape = pGeometry;
            IDataset pDataset = featureClass as IDataset;
            pDataset.Workspace.ExecuteSQL("delete from " + featureClass.AliasName + " where SHAPE_Length = 0" );
            return unionLine;
        }
              
        protected override void OnUpdate()
        {
            Enabled = ArcMap.Application != null;
        }
    }
           

繼續閱讀