3 根据几何合并
通过几何条件判断的方式连接断开的线要素的ArcGIS 插件完成,在这里把思路和代码和大家分享下:
3.1 程序思路和实现过程
1.首先读取shp线文件,将各条线要素遍历,存储在List,这里之所以不存在List和List中的原因是后两者会丢失要素的属性信息;
2.为了简化合并算法的逻辑和复杂性,采用分治思想。将线要素分为需要进行合并和不需要进行合并(独立的线,ToPoint或FromPoint是“节点”的线和ToPoint,FromPoint均是“节点”线)的两大类,分别存储在两个集合中;
3.现在只需对需要进行合并的的线要素集合进行合并操作。首先从集合中选取一条Polyline,然后在集合剩下的元素中寻找与其ToPoint或FromPoint相同的线要素,然后使用ITopologicalOperator2.Union()方法进行合并,然后寻找和合并后新的Polyline的ToPoint或FromPoint相同的线要素继续合并,没合并一次,就将合并入的Polyline从集合中移除,直到剩下的Polyline不可和当前合并的Polyline合并为止,这样就得到了第一条合并好的Polyline。接着从集合剩下的线要素再找一条Polyline开始新一轮合并操作,直到List为空,整个合并操作结束;
4.得到合并好的List mergeResultLineList后,需要为其添加属性(NAME等字段),通过IFeatureBuffer接口写入shape和Fields,然后Flush到文件中,结束。
3.2 程序实例和结果
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; } }