About the ViperPin tool Sample
[C#]
ViperPinForm.cs
using ESRI.ArcGIS.ArcMapUI; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Editor; using ESRI.ArcGIS.Framework; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.esriSystem; using System; using System.Windows.Forms; using Microsoft.Win32; namespace ViperPin { public partial class ViperPinForm : Form { private IEditor m_editor; private IPolyline m_curve; private IEditLayers m_editLayers; private IEditSketch3 m_edSketch; private int m_lotNum; public ViperPinForm(IEditor3 editor) { InitializeComponent(); m_editor = editor; m_edSketch = m_editor as IEditSketch3; m_editLayers = m_editor as IEditLayers; lblEditLayer.Text = m_editLayers.CurrentLayer.Name; //Load field combo box with field names IFields pFields = m_editLayers.CurrentLayer.FeatureClass.Fields; for (int i=0; i < pFields.FieldCount; i++) { cmbPINField.Items.Add(pFields.get_Field(i).Name); } //get pinfield from registry string pinField = null; RegistryKey pRegKey = Registry.CurrentUser.OpenSubKey("Software\\ESRI\\ViperPin"); if (pRegKey != null) { pinField = pRegKey.GetValue("Pinfield").ToString(); } //set the combo box to the pinfield for (int i = 0; i < pFields.FieldCount; i++) { if (pinField == pFields.get_Field(i).Name) { cmbPINField.Text = pinField; break; } else { cmbPINField.Text = "None"; } } //cmbPINField.SelectedIndex = 0; cmbPINField.Refresh(); m_lotNum = 1; txtlot.Text = "1"; //Set center right of form to center right of screen this.StartPosition = FormStartPosition.Manual; this.Left = 0; this.Top = (Screen.PrimaryScreen.Bounds.Height / 2) - (this.Height / 2); } private void cmdOK_Click(object sender, EventArgs e) { m_lotNum = int.Parse(txtlot.Text); //Set pin value SetPINValue(); //save pinfield RegistryKey regKey = Registry.CurrentUser.OpenSubKey("Software",true); RegistryKey newKey = regKey.CreateSubKey("ESRI\\ViperPin"); newKey.SetValue("Pinfield", cmbPINField.Text); this.Hide(); //redraw labels //m_editor.Display.Invalidate(null, true, (short)esriViewDrawPhase.esriViewGraphics); IMxDocument mxDoc; mxDoc = m_editor.Parent.Document as IMxDocument; mxDoc.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null); } private void cmdCancel_Click(object sender, EventArgs e) { this.Close(); } private void SetPINValue() { //The Theory. //Select polygons that intersect the sketch. //Construct one polyline from the boundaries and intersect with sketch. //Sort resulting intersection locations (multipoint) by distance of the intersect // from the start of the sketch and create new ordered multipoint. //Loop through new ordered multipoint, select underlying parcel and calc pin. IFeatureLayer featLayer = m_editLayers.CurrentLayer; m_curve = m_edSketch.Geometry as IPolyline; //Search parcel polys by graphic to get feature cursor ISpatialFilter spatialFilter = new SpatialFilterClass(); spatialFilter.Geometry = m_curve; spatialFilter.GeometryField = m_editLayers.CurrentLayer.FeatureClass.ShapeFieldName; spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelCrosses; IFeatureCursor featCursor = featLayer.Search(spatialFilter,true); IFeature feature = featCursor.NextFeature(); //If we have no intersects then exit if (feature == null) return; //Make a GeomBag of the polygons boundaries (polylines) IGeometryCollection geomBag = new GeometryBagClass(); object missing = Type.Missing; while (feature != null) { ITopologicalOperator poly = feature.Shape as ITopologicalOperator; geomBag.AddGeometry(poly.Boundary,ref missing,ref missing); feature = featCursor.NextFeature(); } //Make one polyline from the boundaries IPolyline polyLineU = new PolylineClass(); ITopologicalOperator topoOp = polyLineU as ITopologicalOperator; topoOp.ConstructUnion(geomBag as IEnumGeometry); //Get the intersections of the boundaries and the curve IPointCollection pointCol = topoOp.Intersect(m_curve, esriGeometryDimension.esriGeometry0Dimension) as IPointCollection; //The point collection is not ordered by distance along the curve so //need to create a new collection with this info int[] pointOrder = new int[pointCol.PointCount]; double dac = 0, dfc = 0; bool bRS = false; for (int i = 0; i < pointCol.PointCount; i++) { IPoint queryPoint = new PointClass(); pointCol.QueryPoint(i, queryPoint); m_curve.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, queryPoint, false, null,ref dac,ref dfc,ref bRS); pointOrder[i] = (int)dac; } //use built in bubble sort System.Array.Sort(pointOrder); //Loop through the sorted array and calc midpoint between parcel boundaries IPointCollection midPoints = new MultipointClass(); for (int i = 0; i < pointOrder.Length -1; i++) { //Get the midpoint distance double midPointDist = (pointOrder[i] + pointOrder[i + 1]) / 2; //create a point at the distance and store in point collection IPoint queryPoint = new PointClass(); m_curve.QueryPoint(esriSegmentExtension.esriNoExtension, midPointDist, false, queryPoint); midPoints.AddPoint(queryPoint,ref missing,ref missing); } //If ends of sketch are included then add them as points if (chkEnds.Checked) { object before = 0 as object; midPoints.AddPoint(m_curve.FromPoint, ref before, ref missing); midPoints.AddPoint(m_curve.ToPoint, ref missing, ref missing); } m_editor.StartOperation(); //Loop through calculated midpoints, select polygon and calc pin for (int i = 0; i < midPoints.PointCount; i++) { IPoint midPoint = midPoints.get_Point(i); spatialFilter = new SpatialFilterClass(); spatialFilter.Geometry = midPoint; spatialFilter.GeometryField = m_editLayers.CurrentLayer.FeatureClass.ShapeFieldName; spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelWithin; featCursor = featLayer.Search(spatialFilter, false); while ((feature = featCursor.NextFeature()) != null) { feature.set_Value(feature.Fields.FindField(cmbPINField.Text), m_lotNum); feature.Store(); m_lotNum += int.Parse(txtlotinc.Text); } } m_editor.StopOperation("ViperPIN"); txtlot.Text = m_lotNum.ToString(); } } }
[Visual Basic .NET]
ViperPinForm.vb
Imports Microsoft.VisualBasic Imports ESRI.ArcGIS.ArcMapUI Imports ESRI.ArcGIS.Carto Imports ESRI.ArcGIS.Editor Imports ESRI.ArcGIS.Framework Imports ESRI.ArcGIS.Geometry Imports ESRI.ArcGIS.Geodatabase Imports ESRI.ArcGIS.esriSystem Imports System Imports System.Windows.Forms Imports Microsoft.Win32 Namespace ViperPin Partial Public Class ViperPinForm Inherits Form Private m_editor As IEditor3 Private m_curve As IPolyline Private m_editLayers As IEditLayers Private m_edSketch As IEditSketch3 Private m_lotNum As Integer Public Sub New(ByVal editor As IEditor3) InitializeComponent() m_editor = editor m_edSketch = TryCast(m_editor, IEditSketch3) m_editLayers = TryCast(m_editor, IEditLayers) lblEditLayer.Text = m_editLayers.CurrentLayer.Name 'Load field combo box with field names Dim fields As IFields = m_editLayers.CurrentLayer.FeatureClass.Fields For i As Integer = 0 To fields.FieldCount - 1 cmbPINField.Items.Add(fields.Field(i).Name) Next i 'get pinfield from registry Dim pinField As String = Nothing Dim pRegKey As RegistryKey = Registry.CurrentUser.OpenSubKey("Software\ESRI\ViperPin") If pRegKey IsNot Nothing Then pinField = pRegKey.GetValue("Pinfield").ToString() End If 'set the combo box to the pinfield For i As Integer = 0 To fields.FieldCount - 1 If pinField = fields.Field(i).Name Then cmbPINField.Text = pinField Exit For Else cmbPINField.Text = "None" End If Next i 'cmbPINField.SelectedIndex = 0; cmbPINField.Refresh() m_lotNum = 1 txtlot.Text = "1" 'Set center right of form to center right of screen Me.StartPosition = FormStartPosition.Manual Me.Left = 0 Me.Top = CInt((Screen.PrimaryScreen.Bounds.Height / 2) - (Me.Height \ 2)) End Sub Private Sub cmdOK_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cmdOK.Click m_lotNum = Integer.Parse(txtlot.Text) 'Set pin value SetPINValue() 'save pinfield Dim regKey As RegistryKey = Registry.CurrentUser.OpenSubKey("Software", True) Dim newKey As RegistryKey = regKey.CreateSubKey("ESRI\ViperPin") newKey.SetValue("Pinfield", cmbPINField.Text) Me.Hide() 'redraw labels 'm_Editor.Display.Invalidate(Nothing, True, CShort(esriViewDrawPhase.esriViewGraphics)) Dim mxDoc As IMxDocument mxDoc = TryCast(m_editor.Parent.Document, IMxDocument) mxDoc.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing) End Sub Private Sub cmdCancel_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cmdCancel.Click Me.Close() End Sub Private Sub SetPINValue() 'The Theory. 'Select polygons that intersect the sketch. 'Construct one polyline from the boundaries and intersect with sketch. 'Sort resulting intersection locations (multipoint) by distance of the intersect ' from the start of the sketch and create new ordered multipoint. 'Loop through new ordered multipoint, select underlying parcel and calc pin. Dim featLayer As IFeatureLayer = m_editLayers.CurrentLayer m_curve = TryCast(m_edSketch.Geometry, IPolyline) 'Search parcel polys by graphic to get feature cursor Dim spatialFilter As ISpatialFilter = New SpatialFilterClass() spatialFilter.Geometry = m_curve spatialFilter.GeometryField = m_editLayers.CurrentLayer.FeatureClass.ShapeFieldName spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelCrosses Dim featCursor As IFeatureCursor = featLayer.Search(spatialFilter, True) Dim feature As IFeature = featCursor.NextFeature() 'If we have no intersects then exit If feature Is Nothing Then Return End If 'Make a GeomBag of the polygons boundaries (polylines) Dim geomBag As IGeometryCollection = New GeometryBagClass() Dim missing As Object = Type.Missing Do While feature IsNot Nothing Dim pPoly As ITopologicalOperator = TryCast(feature.Shape, ITopologicalOperator) geomBag.AddGeometry(pPoly.Boundary, missing, missing) feature = featCursor.NextFeature() Loop 'Make one polyline from the boundaries Dim polyLineU As IPolyline = New PolylineClass() Dim topoOp As ITopologicalOperator = TryCast(polyLineU, ITopologicalOperator) topoOp.ConstructUnion(TryCast(geomBag, IEnumGeometry)) 'Get the intersections of the boundaries and the curve Dim pointCol As IPointCollection = TryCast(topoOp.Intersect(m_curve, esriGeometryDimension.esriGeometry0Dimension), IPointCollection) 'The point collection is not ordered by distance along the curve so 'need to create a new collection with this info Dim pointOrder(pointCol.PointCount - 1) As Integer Dim dac As Double = 0, dfc As Double = 0 Dim bRS As Boolean = False For i As Integer = 0 To pointCol.PointCount - 1 Dim queryPoint As IPoint = New PointClass() pointCol.QueryPoint(i, queryPoint) m_curve.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, queryPoint, False, Nothing, dac, dfc, bRS) pointOrder(i) = CInt(Fix(dac)) Next i 'use built in bubble sort System.Array.Sort(pointOrder) 'Loop through the sorted array and calc midpoint between parcel boundaries Dim midPoints As IPointCollection = New MultipointClass() For i As Integer = 0 To pointOrder.Length - 2 'Get the midpoint distance Dim midPointDist As Double = (pointOrder(i) + pointOrder(i + 1)) / 2 'create a point at the distance and store in point collection Dim queryPoint As IPoint = New PointClass() m_curve.QueryPoint(esriSegmentExtension.esriNoExtension, midPointDist, False, queryPoint) midPoints.AddPoint(queryPoint, missing, missing) Next i 'If ends of sketch are included then add them as points If chkEnds.Checked Then Dim before As Object = TryCast(0, Object) midPoints.AddPoint(m_curve.FromPoint, before, missing) midPoints.AddPoint(m_curve.ToPoint, missing, missing) End If m_editor.StartOperation() 'Loop through calculated midpoints, select polygon and calc pin For i As Integer = 0 To midPoints.PointCount - 1 Dim midPoint As IPoint = midPoints.Point(i) spatialFilter = New SpatialFilterClass() spatialFilter.Geometry = midPoint spatialFilter.GeometryField = m_editLayers.CurrentLayer.FeatureClass.ShapeFieldName spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelWithin featCursor = featLayer.Search(spatialFilter, False) feature = featCursor.NextFeature() Do While feature IsNot Nothing feature.Value(feature.Fields.FindField(cmbPINField.Text)) = m_lotNum feature.Store() m_lotNum += Integer.Parse(txtlotinc.Text) feature = featCursor.NextFeature() Loop Next i m_editor.StopOperation("ViperPIN") txtlot.Text = m_lotNum.ToString() End Sub End Class End Namespace