2010-06-08 26 views

回答

2

下面的代碼展示了通過使用擴展方法來實現這一點的方法。 ArcObjects API經常被批評爲具有太多可能的接口,導致可讀性較差的代碼。我相信擴展方法可以解決許多這些問題。缺點是閱讀代碼的人無法區分作爲API一部分的擴展方法和方法。

我不確定問題的背景,但是如果您爲街道交叉點創建點,則可以考慮使用不同的點哈希函數。這將允許道路交叉點在多個點交叉的地方由單點表示。這將與地圖拓撲中使用的集羣容差類似。

我還沒有真正掌握一個很好的繼承方法來爲自定義異常調用基礎構造函數。任何建議,將不勝感激。

using System; 
using System.Runtime.InteropServices; 
using ESRI.ArcGIS.ADF.BaseClasses; 
using ESRI.ArcGIS.Framework; 
using System.Windows.Forms; 
using ESRI.ArcGIS.Geometry; 
using ESRI.ArcGIS.ArcMapUI; 
using ESRI.ArcGIS.Geodatabase; 
using ESRI.ArcGIS.Carto; 
using System.Collections.Generic; 
using ESRI.ArcGIS.Editor; 

namespace IGG.SurveyTools 
{ 
    /// <summary> 
    /// Summary description for TestCommand. 
    /// </summary> 
    [ProgId("IGG.SurveyTools.TestCommand")] 
    public sealed class TestCommand : BaseCommand 
    { 
     private IEditor m_Editor; 
     public TestCommand() 
     { 
      // 
      // TODO: Define values for the public properties 
      // 
      base.m_category = ""; //localizable text 
      base.m_caption = "Add End points"; //localizable text 
      base.m_message = ""; //localizable text 
      base.m_toolTip = ""; //localizable text 
      base.m_name = ""; //unique id, non-localizable (e.g. "MyCategory_MyCommand") 
     } 

     #region Overriden Class Methods 

     /// <summary> 
     /// Occurs when this command is created 
     /// </summary> 
     /// <param name="hook">Instance of the application</param> 
     public override void OnCreate(object hook) 
     { 
      IApplication app = hook as IApplication; 
      if (app == null) 
       return; 
      m_Editor = app.FindExtensionByName("ESRI Object Editor") as IEditor; 
     } 
     public override bool Enabled 
     { 
      get 
      { 
       return (m_Editor != null && m_Editor.EditState == esriEditState.esriStateEditing); 
      } 
     } 
     public override void OnClick() 
     { 
      try 
      { 
       string fmt = "{0},{1}"; 

       IMxDocument mxDoc = (IMxDocument)m_Editor.Parent.Document; 

       IFeatureLayer polylineLayer = mxDoc.FocusMap.FindFLayer("My Polylines"); 
       IFeatureLayer pointLayer = mxDoc.FocusMap.FindFLayer("My Points"); 
       if(((IDataset)pointLayer.FeatureClass).Workspace != m_Editor.EditWorkspace) 
       { 
        MessageBox.Show(new Win32Win(m_Editor), "Points layer is not being edited"); 
        return; 
       } 
       Dictionary<string, IPoint> endPoints = polylineLayer.GetEndPoints(fmt); 
       if (endPoints.Count == 0) 
       { 
        MessageBox.Show("no end points found"); 
        return; 
       } 
       Dictionary<string,IPoint> existingPoints = pointLayer.GetPoints(fmt); 
       Dictionary<string,IPoint> newPoints = endPoints.Subtract(existingPoints); 
       if(newPoints.Count == 0) 
       { 
        MessageBox.Show(new Win32Win(m_Editor.Parent),"all endpoints are present in pointslayer"); 
        return; 
       } 

       m_Editor.StartOperation(); 
       try 
       { 
        pointLayer.FeatureClass.PutPoints(newPoints.Values); 
        m_Editor.StopOperation(String.Format("Added {0} new endpoints", newPoints.Count)); 
        ((IActiveView)m_Editor.Map).Refresh(); 
       } 
       catch(Exception ex) 
       { 
        m_Editor.AbortOperation(); 
       } 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(new Win32Win(m_Editor), ex.Message + Environment.NewLine + ex.StackTrace); 
      } 
     }   
     #endregion 

    } 

    public class Win32Win : IWin32Window 
    { 
     private IntPtr m_handle; 
     public Win32Win(IApplication app) { m_handle = new IntPtr(app.hWnd); } 
     public IntPtr Handle { get { return m_handle; } } 
     public Win32Win(int hwnd) { m_handle = new IntPtr(hwnd); } 
     public Win32Win(IEditor editor) { m_handle = new IntPtr(editor.Parent.hWnd); } 
    } 

    public class LayerNotFoundException : Exception 
    { 
     public LayerNotFoundException(string lyrName) 
      : base("Layer not found: " + lyrName) 
     { 
     } 
    } 

    public class FeatureLayerNotFoundException : LayerNotFoundException 
    { 
     public FeatureLayerNotFoundException(string lyrName) 
      : base(lyrName) 
     { 
     } 
    } 

    public static class MyExtensions 
    { 
     public static void PutPoints(this IFeatureClass fc, IEnumerable<IPoint> pnts) 
     { 
      IFeatureCursor fCur = fc.Insert(false); 
      IFeatureBuffer buff = fc.CreateFeatureBuffer(); 
      foreach (IPoint pnt in pnts) 
      { 
       buff.Shape = pnt; 
       fCur.InsertFeature(buff); 
      } 
      fCur.Flush(); 
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur); 
     } 

     /// <summary> 
     /// returns first layer in map with case-insensitive name 
     /// </summary> 
     /// <param name="map"></param> 
     /// <param name="name"></param> 
     /// <returns></returns> 
     public static ILayer FindLayer(this IMap map, string name) 
     { 
      if (map.LayerCount == 0) 
       throw new LayerNotFoundException(name); 
      IEnumLayer enumLayer = map.get_Layers(null, true); 
      ILayer layer; 
      while ((layer = enumLayer.Next()) != null) 
      { 
       if (layer.Name.Trim().ToUpper() == name.Trim().ToUpper()) 
        return layer; 
      } 
      throw new LayerNotFoundException(name); 
     } 

     public static IFeatureLayer FindFLayer(this IMap map, string name) 
     { 
      IFeatureLayer fLayer = map.FindLayer(name) as IFeatureLayer; 
      if (fLayer == null) 
       throw new FeatureLayerNotFoundException(name); 
      return fLayer; 
     } 

     public static Dictionary<string, IPoint> GetPoints(this IFeatureLayer fLayer, string fmt) 
     { 
      if (fLayer.FeatureClass == null 
       || fLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPoint) 
       throw new Exception("bad point layer: " + fLayer.Name); 

      Dictionary<string, IPoint> outDict = new Dictionary<string, IPoint>(); 
      IFeatureCursor fCur = fLayer.FeatureClass.Search(null, false); 
      IFeature feat; 
      while ((feat = fCur.NextFeature()) != null) 
      { 
       outDict.AddPoint((IPoint)feat.ShapeCopy,fmt); 
      } 
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur); 
      return outDict; 
     } 

     public static Dictionary<string, IPoint> GetEndPoints(this IFeatureLayer fLayer, string fmt) 
     { 
      if (fLayer.FeatureClass == null 
       || fLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPolyline) 
       throw new Exception("bad polyline layer: " + fLayer.Name); 

      Dictionary<string, IPoint> outDict = new Dictionary<string, IPoint>(); 
      IFeatureCursor fCur = fLayer.FeatureClass.Search(null, false); 
      IFeature feat; 
      while ((feat = fCur.NextFeature()) != null) 
      { 
       IPolyline polyline = (IPolyline)feat.ShapeCopy; 
       if (polyline == null || polyline.IsEmpty) 
        continue; 
       outDict.AddPoint(polyline.FromPoint,fmt); 
       outDict.AddPoint(polyline.ToPoint,fmt); 
      } 
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur); 
      return outDict; 
     } 
     public static string Hash(this IPoint pnt, string fmt) 
     { 
      // use different formatting options to do quick and dirty clustering 
      return String.Format(fmt, pnt.X, pnt.Y); 
     } 

     public static void AddPoint(this Dictionary<string,IPoint> dict ,IPoint pnt, string fmt) 
     { 
      string hash = pnt.Hash(fmt); 
      if (!dict.ContainsKey(hash)) 
       dict.Add(hash, pnt); 
     } 
     public static Dictionary<string, IPoint> Subtract(this Dictionary<string, IPoint> inDict, Dictionary<string, IPoint> otherDict) 
     { 
      Dictionary<string, IPoint> outDict = new Dictionary<string, IPoint>(); 
      foreach (KeyValuePair<string, IPoint> kvp in inDict) 
      { 
       if (!otherDict.ContainsKey(kvp.Key)) 
        outDict.Add(kvp.Key, kvp.Value); 
      } 
      return outDict; 
     } 
    } 
} 
+0

太棒了!我一早上班就會給這個代碼一個旋轉。 這是我的第一個Arc項目,所以我仍然在尋找我的專長,但我已經開始將大量的東西抽象爲擴展方法,這使得我的代碼變得更容易理解。 我不知道我明白你的意思與自定義異常的基礎構造函數的東西。你做的事情對我來說看起來很完美。我唯一可能改變的是從ApplicationException繼承,以迂迴地表明它是從我的應用程序堆棧向上而不是從下面的例外。但它是微不足道的。 – 2010-06-08 20:02:03

+0

對於您的GetPoints方法,您是否可以不使用循環遊標,因爲您正在複製點的副本? – 2010-06-10 11:56:10

+0

是的,這可能是回收,並會使其運行速度更快。爲了加快查詢速度,您可以將IQueryFilter傳遞給Search方法,並確保將IQueryFilter.SubFields設置爲僅包含ObjectID字段。默認情況下,光標獲取所有字段。 – 2010-06-10 14:20:59

相關問題