About the Buffer snap agent Sample
[C#]
BufferSnap.cs
using System;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.Controls;
namespace BufferSnapCS
{
[Guid("44BDCF61-5CD0-41f3-A934-8CAFCD931DEF")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("BufferSnapCS.BufferSnap")]
/// <summary>
/// Uses the Create Feature event to turn on the extension, which
/// implements a snapping agent. The Buffer Snap agent is based on a buffer
/// around the points of the first editable point feature class.
/// A buffer of 1000 map units is created and if the next point feature created
/// is within the tolerance it is snapped to the buffer ring.
/// </summary>
public sealed class BufferSnap : IEngineSnapAgent, IEngineSnapAgentCategory, IPersistVariant, IExtension
{
#region COM Registration Function(s)
[ComRegisterFunction()]
[ComVisible(false)]
static void RegisterFunction(Type registerType)
{
// Required for ArcGIS Component Category Registrar support
ArcGISCategoryRegistration(registerType);
}
[ComUnregisterFunction()]
[ComVisible(false)]
static void UnregisterFunction(Type registerType)
{
// Required for ArcGIS Component Category Registrar support
ArcGISCategoryUnregistration(registerType);
}
#region ArcGIS Component Category Registrar generated code
/// <summary>
/// Required method for ArcGIS Component Category registration -
/// Do not modify the contents of this method with the code editor.
/// </summary>
private static void ArcGISCategoryRegistration(Type registerType)
{
string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID);
EngineSnapAgents.Register(regKey);
}
/// <summary>
/// Required method for ArcGIS Component Category unregistration -
/// Do not modify the contents of this method with the code editor.
/// </summary>
private static void ArcGISCategoryUnregistration(Type registerType)
{
string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID);
EngineSnapAgents.Unregister(regKey);
}
#endregion
#endregion
//declare and initialize class variables.
private IFeatureCache m_featureCache;
private IFeatureClass m_featureClass;
private IEngineEditor m_engineeditor;
public BufferSnap()
{
}
#region "IPersistVariant Implementations"
public ESRI.ArcGIS.esriSystem.UID ID
{
get
{
UID uID = new UIDClass();
uID.Value = "BufferSnapCS.BufferSnap";
return uID;
}
}
public void Load(ESRI.ArcGIS.esriSystem.IVariantStream Stream)
{
}
public void Save(ESRI.ArcGIS.esriSystem.IVariantStream Stream)
{
}
#endregion
#region "IEngineSnapAgent Implementations"
public string Name
{
get
{
return "Buffer Snap CS";
}
}
public bool Snap(ESRI.ArcGIS.Geometry.IGeometry geom,
ESRI.ArcGIS.Geometry.IPoint point, double tolerance)
{
GetFeatureClass();
bool b_setNewFeatureCache = false;
if (m_featureClass == null || m_engineeditor == null)
return false;
if (m_featureClass.ShapeType != esriGeometryType.esriGeometryPoint)
return false;
//Check if a feature cache has been created.
if (!b_setNewFeatureCache)
{
m_featureCache = new FeatureCache();
b_setNewFeatureCache = true;
}
//Fill the cache with the geometries.
//It is up to the developer to choose an appropriate value
//given the map units and the scale at which editing will be undertaken.
FillCache(m_featureClass, point, 10000);
IProximityOperator proximityOp = point as IProximityOperator;
double minDist = tolerance;
IPoint cachePt = new PointClass();
IPoint snapPt = new PointClass();
IPolygon outPoly = new PolygonClass();
ITopologicalOperator topoOp;
IFeature feature;
int Index = 0;
for (int Count = 0; Count < m_featureCache.Count; Count++)
{
feature = m_featureCache.get_Feature(Count);
cachePt = feature.Shape as IPoint;
topoOp = cachePt as ITopologicalOperator;
//Set the buffer distance to an appropriate value
//given the map units and data being edited
outPoly = topoOp.Buffer(1000) as IPolygon;
double Dist = proximityOp.ReturnDistance(outPoly);
if (Dist < minDist)
{
Index = Count;
minDist = Dist;
}
}
//Make sure minDist is within the search tolerance.
if (minDist >= tolerance)
return false;
//Retrieve the feature and its part again.
feature = m_featureCache.get_Feature(Index);
cachePt = feature.Shape as IPoint;
topoOp = cachePt as ITopologicalOperator;
//Set the buffer distance to an appropriate value
//given the map scale and data being edited
outPoly = topoOp.Buffer(1000) as IPolygon;
proximityOp = outPoly as IProximityOperator;
snapPt = proximityOp.ReturnNearestPoint(point,esriSegmentExtension.esriNoExtension);
//Since point was passed in ByValue, we have to modify its values instead.
//of giving it a new address.
point.PutCoords(snapPt.X, snapPt.Y);
return true;
}
private void FillCache(ESRI.ArcGIS.Geodatabase.IFeatureClass FClass,
ESRI.ArcGIS.Geometry.IPoint pPoint, double Distance)
{
m_featureCache.Initialize(pPoint, Distance);
m_featureCache.AddFeatures(FClass);
}
#endregion
private void GetFeatureClass()
{
IMap map = m_engineeditor.Map as IMap;
IEngineEditLayers snapLayers = m_engineeditor as IEngineEditLayers;
IFeatureLayer featLayer = snapLayers.TargetLayer as IFeatureLayer;
//Search the editable layers and set the snap feature class to the point layer.
for (int CountLayers = 0; CountLayers < map.LayerCount; CountLayers++)
{
if (featLayer == null)
return;
if (featLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPoint)
{
return;
}
else
{
m_featureClass = featLayer.FeatureClass;
}
}
}
#region "IExtension Members"
public void Shutdown()
{
m_engineeditor = null;
m_featureCache = null;
}
public void Startup(ref object initializationData)
{
if (initializationData != null && initializationData is IEngineEditor)
{
m_engineeditor = (IEngineEditor)initializationData;
}
#endregion
}
#region "IEngineSnapAgentCategory Members"
string IEngineSnapAgentCategory.Category
{
get {return ("Buffer Snap Category CS");}
}
#endregion
}
}
[Visual Basic .NET]
BufferSnap.vb
Imports System
Imports System.Runtime.InteropServices
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.Geometry
Imports ESRI.ArcGIS.ADF.CATIDs
Imports ESRI.ArcGIS.Controls
Namespace BufferSnapVB
'/ <summary>
'/ Uses the Create Feature event to turn on the extension, which
'/ implements a snapping agent. The Buffer Snap agent is based on a buffer
'/ around the points of the first editable point feature class.
'/ A buffer of 1000 map units is created if the next point feature created
'/ is within the tolerance it is snapped to the buffer ring.
'/ </summary>
<Guid("A7BE542E-6C0D-423f-8824-FFC7B6ADF0B4"), ClassInterface(ClassInterfaceType.None), ProgId("BufferSnapVB.BufferSnap")> _
Public Class BufferSnap
Implements IEngineSnapAgent
Implements IEngineSnapAgentCategory
Implements IPersistVariant
Implements IExtension
#Region "COM Registration Function(s)"
<ComRegisterFunction(), ComVisible(False)> _
Public Shared Sub RegisterFunction(ByVal registerType As Type)
' Required for ArcGIS Component Category Registrar support
ArcGISCategoryRegistration(registerType)
End Sub
<ComUnregisterFunction(), ComVisible(False)> _
Public Shared Sub UnregisterFunction(ByVal registerType As Type)
' Required for ArcGIS Component Category Registrar support
ArcGISCategoryUnregistration(registerType)
End Sub
#Region "ArcGIS Component Category Registrar generated code"
'/ <summary>
'/ Required method for ArcGIS Component Category registration -
'/ Do not modify the contents of this method with the code editor.
'/ </summary>
Private Shared Sub ArcGISCategoryRegistration(ByVal registerType As Type)
Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
EngineSnapAgents.Register(regKey)
End Sub
'/ <summary>
'/ Required method for ArcGIS Component Category unregistration -
'/ Do not modify the contents of this method with the code editor.
'/ </summary>
Private Shared Sub ArcGISCategoryUnregistration(ByVal registerType As Type)
Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
EngineSnapAgents.Unregister(regKey)
End Sub
#End Region
#End Region
'declare and initialize class variables.
Private m_featureCache As IFeatureCache
Private m_featureClass As IFeatureClass
Private m_editor As IEngineEditor
Public Sub New()
End Sub
#Region "IPersist Variant Members."
''' <summary>
''' Get the ID of the object.
''' </summary>
Private ReadOnly Property ID() As ESRI.ArcGIS.esriSystem.UID Implements ESRI.ArcGIS.esriSystem.IPersistVariant.ID
Get
Dim pID As New UID
pID.Value = "BufferSnapVB.BufferSnap"
Return pID
End Get
End Property
Private Sub Load(ByVal stream As ESRI.ArcGIS.esriSystem.IVariantStream) Implements ESRI.ArcGIS.esriSystem.IPersistVariant.Load
End Sub
Private Sub Save(ByVal Stream As ESRI.ArcGIS.esriSystem.IVariantStream) Implements ESRI.ArcGIS.esriSystem.IPersistVariant.Save
End Sub
#End Region
#Region "IEngineSnapAgent Implementations"
Public ReadOnly Property Name() As String Implements IEngineSnapAgent.Name, IExtension.Name
Get
Return "Buffer Snap VB"
End Get
End Property
Public Function Snap(ByVal geom As IGeometry, ByVal point As IPoint, ByVal tolerance As Double) As Boolean Implements IEngineSnapAgent.Snap
GetFeatureClass()
Dim b_setNewFeatureCache As Boolean = False
If m_featureClass Is Nothing Or m_editor Is Nothing Then
Return False
End If
If m_featureClass.ShapeType <> esriGeometryType.esriGeometryPoint Then
Return False
End If
'Check if a feature cache has been created.
If Not b_setNewFeatureCache Then
m_featureCache = New FeatureCache()
b_setNewFeatureCache = True
End If
'Fill the New Cache with the geometries.
'It is up to the developer to choose an appropriate value
'given the map units and the scale at which editing will be undertaken.
FillCache(m_featureClass, point, 10000)
Dim proximityOp As IProximityOperator = DirectCast(point, IProximityOperator)
Dim minDist As Double = tolerance
Dim cachePt As IPoint = New PointClass()
Dim snapPt As IPoint = New PointClass()
Dim outPoly As IPolygon = New PolygonClass()
Dim topoOp As ITopologicalOperator
Dim feature As IFeature
Dim Index As Integer = 0
Dim Count As Integer
For Count = 0 To m_featureCache.Count - 1 Step Count + 1
feature = m_featureCache.Feature(Count)
cachePt = feature.Shape
topoOp = cachePt
'Set the buffer distance to an appropriate value
'given the map units and data being edited
outPoly = topoOp.Buffer(1000)
Dim Dist As Double = proximityOp.ReturnDistance(outPoly)
If Dist < minDist Then
Index = Count
minDist = Dist
End If
Next
'Make sure minDist is within the search tolerance.
If minDist >= tolerance Then
Return False
End If
'Retrieve the feature and its part again.
feature = m_featureCache.Feature(Index)
cachePt = feature.Shape
topoOp = cachePt
'Set the buffer distance to an appropriate value
'given the map units and data being edited
outPoly = topoOp.Buffer(1000)
proximityOp = outPoly
snapPt = proximityOp.ReturnNearestPoint(point, esriSegmentExtension.esriNoExtension)
'Since point was passed in ByValue, we have to modify its values instead.
'of giving it a new address.
point.PutCoords(snapPt.X, snapPt.Y)
Return True
End Function
Private Sub FillCache(ByVal FClass As IFeatureClass, ByVal pPoint As IPoint, ByVal Distance As Double)
m_featureCache.Initialize(pPoint, Distance)
m_featureCache.AddFeatures(FClass)
End Sub
#End Region
#Region "IEngineSnapAgentCategory Implementation"
Public ReadOnly Property Category() As String Implements IEngineSnapAgentCategory.Category
Get
Return "Buffer Snap Category VB"
End Get
End Property
#End Region
Private Sub GetFeatureClass()
Dim map As IMap = m_editor.Map
Dim snapLayers As IEngineEditLayers = m_editor
Dim featLayer As IFeatureLayer = snapLayers.TargetLayer
'Search the editable layers and set the snap feature class to the point layer.
Dim CountLayers As Integer
For CountLayers = 0 To map.LayerCount - 1 Step CountLayers + 1
If featLayer Is Nothing Then
Return
End If
If featLayer.FeatureClass.ShapeType <> esriGeometryType.esriGeometryPoint Then
Return
Else
m_featureClass = featLayer.FeatureClass
End If
Next
End Sub
#Region "IExtension Members"
Public Sub Shutdown() Implements IExtension.Shutdown
m_editor = Nothing
End Sub
Public Sub Startup(ByRef initializationData As Object) Implements IExtension.Startup
If initializationData IsNot Nothing AndAlso TypeOf initializationData Is IEngineEditor Then
m_editor = DirectCast(initializationData, IEngineEditor)
End If
End Sub
#End Region
End Class
End Namespace