The code below illustrates ways of doing this through the use of extension methods. The ArcObjects API is often criticized for having too may interfaces, resulting in less readable code. I believe extension methods can address many of these concerns. The down side is that people reading the code cannot readily distinguish between extension methods and methods that are part of the API.
I'm not sure of the context of your problem, but if you're creating points for street intersections you might consider using a different Point hashing function. This would allow road intersections where roads cross at more than one point to be represented by a single point. This would be analogous to the cluster tolerance used in map topologies.
I haven't really gotten my head around a nice inheritance method for calling base constructors for custom Exceptions. Any suggestions there would be appreciated.
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;
}
}
}