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, true);
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, True)
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