在上一篇ArcEngine环境下合并断开的线要素(根据属性)随笔中介绍了如何通过shp文件属性表中相同的属性字段进行线要素的合并。今天刚把通过几何条件判断的方式连接断开的线要素的ArcGIS 插件完成,在这里把思路和代码和大家分享下:
一,程序思路和实现过程
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到文件中,结束。
二,程序实例和结果
图1 程序执行结果
图2 合并前的属性表
图3 合并后的属性表
三,程序详细代码
1 public class MergeDisconnectLine : ESRI.ArcGIS.Desktop.AddIns.Button 2 { 3 4 public int CountPercent { get; set; } 5 IMap map = null; 6 private List<IFeature> DisconnPolylineList = new List<IFeature>(); 10 private List<IFeature> firstRowFeatureList = new List<IFeature>(); 11 12 public MergeDisconnectLine() 13 { 14 IMxDocument mxDoc = ArcMap.Application.Document as IMxDocument; 15 map = mxDoc.FocusMap; 16 } 17 protected override void OnClick() 18 { 19 // 20 // TODO: Sample code showing how to access button host 21 // 22 ArcMap.Application.CurrentTool = null; 23 24 //计算程序耗时 25 DateTime beforDT = System.DateTime.Now; 27 //Application.EnableVisualStyles(); 28 //Application.SetCompatibleTextRenderingDefault(false); 29 ////ProgressBar pBar = new ProgressBar(); 30 //Application.Run(new ProgressBar()); 32 List<IFeature> allPolylineList = getAllPolyline(); 33 List<IFeature> noNeedUnionLineList = getWithoutNeedUnionLineList(allPolylineList); 34 List<IFeature> toUnionLineList = GetToUnionLineList(allPolylineList, noNeedUnionLineList); 35 List<IFeature> unionLineList = MergeLineListOperate(toUnionLineList); 36 AddField(); 37 WriteNoNeedUnionLineToFile(noNeedUnionLineList); 38 WriteUnionLineToFile(unionLineList, firstRowFeatureList); 39 DateTime afterDT = System.DateTime.Now; 40 TimeSpan ts = afterDT.Subtract(beforDT); 41 int minutes = ts.Minutes; 42 int seconds = ts.Seconds%60; 43 //pBar.Hide(); 44 MessageBox.Show("线要素合并结束,运行程序共耗时约:" + minutes + "分"+ seconds + "秒"); 45 } 48 //获取shp文件中所有的Polyline(IFeature)对象 49 public List<IFeature> getAllPolyline() 50 { 51 IFeatureLayer featureLayer = map.get_Layer(1) as IFeatureLayer; 52 IFeatureClass featureClass = featureLayer.FeatureClass; 53 IQueryFilter queryFilter = new QueryFilter(); 54 queryFilter.WhereClause = ""; 55 IFeatureCursor pFeatCursor = featureClass.Search(queryFilter, false); 56 IFeature pFeature = pFeatCursor.NextFeature(); 57 58 while (pFeature != null) 59 { 60 if (featureClass.ShapeType == esriGeometryType.esriGeometryPolyline) 61 { 62 DisconnPolylineList.Add(pFeature); 63 } 64 pFeature = pFeatCursor.NextFeature(); 66 } 67 return DisconnPolylineList; 68 } 170 171 //获取需要进行合并的线(是noNeedUnionLineList的补集) 172 public List<IFeature> GetToUnionLineList(List<IFeature> allPolylineList, List<IFeature> noNeedUnionLineList) 173 { 174 List<IFeature> toUnionLineList = allPolylineList; 175 foreach (IFeature featureLine in noNeedUnionLineList) 176 { 177 toUnionLineList.Remove(featureLine); 178 } 179 return toUnionLineList; 180 } 181 182 //获取不需要进行合并的线(独立线,一端是节点的线,和两端都是节点的线) 183 public List<IFeature> getWithoutNeedUnionLineList(List<IFeature> allPolylineList) 184 { 185 List<IFeature> noNeedUnionLineList = new List<IFeature>(); 186 foreach (IFeature featureLine in allPolylineList) 187 { 188 int count = featureLine.Fields.FieldCount; 189 List<IFeature> allPolylineListCopy = allPolylineList; 190 IGeometry geoLine = featureLine.Shape; 191 IPolyline lineFirst = geoLine as IPolyline; 192 IPoint startPt1 = lineFirst.FromPoint; 193 IPoint endPt1 = lineFirst.ToPoint; 194 int fromFlag = 0; 195 int toFlag = 0; 196 for (int i = 0; i < allPolylineListCopy.Count; i++) 197 { 198 IFeature line2 = allPolylineListCopy[i]; 199 IGeometry geoLine2 = line2.Shape; 200 IPolyline lineSecond = geoLine2 as IPolyline; 201 IPoint startPt2 = lineSecond.FromPoint; 202 IPoint endPt2 = lineSecond.ToPoint; 203 //FromPoint相同的点 204 if ((startPt1.X == startPt2.X && startPt1.Y == startPt2.Y) || 205 (startPt1.X == endPt2.X && startPt1.Y == endPt2.Y)) 206 { 207 fromFlag++; 208 } 209 //ToPoint相同的点 210 if ((endPt1.X == endPt2.X && endPt1.Y == endPt2.Y) || 211 (endPt1.X == startPt2.X && endPt1.Y == startPt2.Y)) 212 { 213 toFlag++; 214 } 215 } 216 if (fromFlag > 2 || toFlag > 2 || (fromFlag == 1 && toFlag == 1)) 217 { 218 noNeedUnionLineList.Add(featureLine); 219 //noNeedUnionLineFileds.Add(featureLine.Fields); 220 } 221 } 222 return noNeedUnionLineList; 223 } 224 225 //将需要进行合并的线要素(没有节点)集合进行合并,结果为多条线 227 public List<IFeature> MergeLineListOperate(List<IFeature> toUnionLineList) 228 { 229 List<IFeature> mergeResultLineList = new List<IFeature>(); 230 int CountPercent = 0; 231 while (toUnionLineList.Count > 0) 232 { 233 CountPercent++; 234 //初始化当前合并的线要素 235 IFeature unionCurrentLine = toUnionLineList[0]; 236 //将第一个要素的属性字段值作为最终合并线要素的值 237 firstRowFeatureList.Add(unionCurrentLine); 238 List<IFeature> currentMergeLineList = new List<IFeature>(); 239 int count2 = 0; 240 do 241 { 242 count2++; 243 IFeature featureFirst = unionCurrentLine; 244 IGeometry geoLineFirst = featureFirst.Shape; 245 IPolyline lineFirst = geoLineFirst as IPolyline; 246 IPoint startPt1 = lineFirst.FromPoint; 247 IPoint endPt1 = lineFirst.ToPoint; 248 toUnionLineList.Remove(featureFirst); 251 currentMergeLineList.Clear(); 252 currentMergeLineList.Add(featureFirst); 253 254 List<IFeature> allPolylineListTemp1 = new List<IFeature>(); 255 List<IFeature> allPolylineListTemp2 = new List<IFeature>(); 256 int bStart1 = 0; 257 int bStart2 = 0; 260 for (int j = 0; j < toUnionLineList.Count; j++) 261 { 264 IFeature featureSecond = toUnionLineList[j]; 265 IGeometry geoLineSecond = featureSecond.Shape; 266 IPolyline lineSecond = geoLineSecond as IPolyline; 267 IPoint startPt2 = lineSecond.FromPoint; 268 IPoint endPt2 = lineSecond.ToPoint; 269 270 if ((startPt1.X == startPt2.X && startPt1.Y == startPt2.Y) || 271 (startPt1.X == endPt2.X && startPt1.Y == endPt2.Y)) 272 { 273 bStart1++; 274 if (bStart1 > 0) 275 { 276 allPolylineListTemp1.Add(featureSecond); 277 currentMergeLineList.AddRange(allPolylineListTemp1); 279 toUnionLineList.Remove(featureSecond); 280 } 281 } 282 if ((endPt1.X == endPt2.X && endPt1.Y == endPt2.Y) || 283 (endPt1.X == startPt2.X && endPt1.Y == startPt2.Y)) 284 { 285 bStart2++; 286 if (bStart2 > 0) 287 { 288 allPolylineListTemp2.Add(featureSecond); 289 currentMergeLineList.AddRange(allPolylineListTemp2); 290 toUnionLineList.Remove(featureSecond); 291 } 292 293 } 296 297 } 298 if (currentMergeLineList.Count > 1) 299 { 301 unionCurrentLine = UnionCurrentLineList(currentMergeLineList); 302 } 303 else 304 { 306 int ii = 0; 307 } 308 } while (currentMergeLineList.Count > 1); 309 310 mergeResultLineList.Add(unionCurrentLine); 312 } 313 return mergeResultLineList; 314 } 315 316 //为待写入图层添加Name和GB字段 317 public void AddField() 318 { 319 IFeatureLayer featureLayer2 = map.get_Layer(0) as IFeatureLayer; 320 IFeatureClass featureClass2 = featureLayer2.FeatureClass; 322 IClass pClass = featureClass2 as IClass; 324 IField fld1 = new Field(); 325 IField fld2 = new Field(); 326 IFieldEdit2 fld_NAME = fld1 as IFieldEdit2; 327 IFieldEdit2 fld_GB = fld2 as IFieldEdit2; 328 fld_NAME.Type_2 = esriFieldType.esriFieldTypeString; 329 fld_NAME.Name_2 = "NAME"; 330 fld_GB.Type_2 = esriFieldType.esriFieldTypeString; 331 fld_GB.Name_2 = "GB"; 332 pClass.AddField(fld_GB); 333 pClass.AddField(fld_NAME); 334 335 } 336 337 public void WriteNoNeedUnionLineToFile(List<IFeature> pLineList) 338 { 340 foreach (IFeature featureLine in pLineList) 341 { 342 IFeatureLayer featureLayer2 = map.get_Layer(0) as IFeatureLayer; 343 IFeatureClass featureClass2 = featureLayer2.FeatureClass; 345 IFeatureBuffer featureBuffer = featureClass2.CreateFeatureBuffer(); 346 IFeatureCursor featureCursor; 347 featureCursor = featureClass2.Insert(true); 348 IGeometry pGeometry = featureLine.Shape; 349 featureBuffer.Shape = pGeometry; 350 int NAME_Index = featureLine.Fields.FindField("NAME"); 351 int GB_Index = featureLine.Fields.FindField("GB"); 352 string name = featureLine.get_Value(NAME_Index).ToString(); 353 string gb = featureLine.get_Value(GB_Index).ToString(); 355 int fieldindex1 = featureBuffer.Fields.FindField("NAME"); 356 int fieldindex2 = featureBuffer.Fields.FindField("GB"); 357 if (fieldindex1 >= 0) 358 { 359 featureBuffer.set_Value(fieldindex1, name); 360 } 361 if (fieldindex2 >= 0) 362 { 363 featureBuffer.set_Value(fieldindex2, gb); 364 } 368 featureCursor.InsertFeature(featureBuffer); 369 featureCursor.Flush(); 370 System.Runtime.InteropServices.Marshal.ReleaseComObject(featureCursor); 371 } 372 } 373 public void WriteUnionLineToFile(List<IFeature> mergeResultLineList, List<IFeature> firstFeatureList) 374 { 375 int index = 0; 376 foreach (IFeature featureLine in mergeResultLineList) 377 { 378 IFeatureLayer featureLayer2 = map.get_Layer(0) as IFeatureLayer; 379 IFeatureClass featureClass2 = featureLayer2.FeatureClass; 380 IFeatureBuffer featureBuffer = featureClass2.CreateFeatureBuffer(); 381 IFeatureCursor featureCursor; 382 featureCursor = featureClass2.Insert(true); 383 IGeometry pGeometry = featureLine.Shape; 384 featureBuffer.Shape = pGeometry; 385 int NAME_Index = firstFeatureList[index].Fields.FindField("NAME"); 386 int GB_Index = firstFeatureList[index].Fields.FindField("GB"); 387 string name = firstFeatureList[index].get_Value(NAME_Index).ToString(); 388 string gb = firstFeatureList[index].get_Value(GB_Index).ToString(); 390 int fieldindex1 = featureBuffer.Fields.FindField("NAME"); 391 int fieldindex2 = featureBuffer.Fields.FindField("GB"); 392 if (fieldindex1 >= 0) 393 { 394 featureBuffer.set_Value(fieldindex1, name); 395 } 396 if (fieldindex2 >= 0) 397 { 398 featureBuffer.set_Value(fieldindex2, gb); 399 } 400 401 featureCursor.InsertFeature(featureBuffer); 402 featureCursor.Flush(); 403 System.Runtime.InteropServices.Marshal.ReleaseComObject(featureCursor); 404 index++; 405 } 406 } 407 408 //将传入的List<IPolylne>中的多条线要素进行合并为一条线要素 409 public IFeature UnionCurrentLineList(List<IFeature> currentMergeLineList) 410 { 411 IFeatureLayer featureLayer = map.get_Layer(1) as IFeatureLayer; 412 IFeatureClass featureClass = featureLayer.FeatureClass; 413 414 ITopologicalOperator2 pTopologicalOperator; 415 IFeature pFeatureTemp = currentMergeLineList[0]; 416 IGeometry pGeometry = pFeatureTemp.Shape; 419 int i = 1; 420 while (i < currentMergeLineList.Count) 421 { 422 pTopologicalOperator = pGeometry as ITopologicalOperator2; 423 //ITopologicalOperator的操作是bug很多的,先强制的检查下面三个步骤,再进行操作 424 //modifiy in 2016/03/20 12:47 425 pTopologicalOperator.IsKnownSimple_2 = false; 426 pTopologicalOperator.Simplify(); 427 pGeometry.SnapToSpatialReference(); 428 429 pGeometry = currentMergeLineList[i].Shape; 430 pGeometry = pTopologicalOperator.Union(pGeometry); 431 i++; 432 } 433 IFeature unionLine = featureClass.CreateFeature(); 434 unionLine.Shape = pGeometry; 436 IDataset pDataset = featureClass as IDataset; 438 pDataset.Workspace.ExecuteSQL("delete from " + featureClass.AliasName + " where SHAPE_Length = 0" ); 439 return unionLine; 440 } 441 442 protected override void OnUpdate() 443 { 444 Enabled = ArcMap.Application != null; 445 } 446 }
-------------------------------------------------------------------------------------------------------------------------
本文系作者GISQZC原创文章,欢迎转载,但必须注明出处,否则将追究相关法律责任!