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 效果演示
合并之前
合并之后
2 根据属性合并线要素
2.1 遇到的问题
最近遇到在线要素(矢量数据)中,一条完整的道路、河流等往往是断开的,如下图1所示:
2.2 思路与结果
在ArcGIS Desktop中没有相关的工具可以将这些断开的线要素进行自动合并,今天自己写了一个Arcmap上的一个插件,实现当点击插件按钮后,对地图窗口中断开的线要素进行合并。合并的依据是具有相同NAME属性(如长沙-张家界高速)的Polyline要素进行合并,然后存储在另一个线要素图层中。
程序运行的结果如下,这样本来属于同一段道路的多个Polyline就合并成一条Polyline:
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 总结
这个插件还有一些不足的地方,如不是从线要素首尾点相邻的角度寻找相邻点(这种方法存在判断三条线要素交叉而形成的节点的判断和是否进行合并的问题和难点),在下一篇随笔里面会介绍从纯几何学的角度实现线要素的连接的实现。