BufferSnapAgent\BufferSnap.cs
// Copyright 2012 ESRI // // All rights reserved under the copyright laws of the United States // and applicable international laws, treaties, and conventions. // // You may freely redistribute and use this sample code, with or // without modification, provided you include the original copyright // notice and use restrictions. // // See the use restrictions. // 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 } }