CurveConversionDockWin.vb
' Copyright 2010 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. ' Imports System.Windows.Forms Imports ESRI.ArcGIS.esriSystem Imports ESRI.ArcGIS.Geodatabase Imports ESRI.ArcGIS.EditorExt Imports ESRI.ArcGIS.Geometry Imports ESRI.ArcGIS.ArcMapUI Imports ESRI.ArcGIS.Editor Imports ESRI.ArcGIS.Framework ''' <summary> ''' Designer class of the dockable window add-in. It contains user interfaces that ''' make up the dockable window. ''' </summary> Public Class CurveConversionDockWin Private _CurveDockwin As ESRI.ArcGIS.Framework.IDockableWindow Public Shared _MFields As IFields Dim _UpdateValue As System.Object Shared _Cancel As Boolean = False Dim _UpdateFieldIsString As Boolean = False Private _CheckTol As Boolean = False Dim _Editor As IEditor Dim _InvalidEnv As IEnvelope Shared _Tolerance As [Double] = 0.1 Shared _sFieldName As [String] = "" Shared _CurveUserControl As CurveConversionDockWin Public Sub New(ByVal hook As Object) ' This call is required by the Windows Form Designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. Me.Hook = hook _CurveUserControl = Me End Sub Private m_hook As Object ''' <summary> ''' Host object of the dockable window ''' </summary> Public Property Hook() As Object Get Return m_hook End Get Set(ByVal value As Object) m_hook = value End Set End Property Private Sub buttonOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonOK.Click 'You may also want to check that a shapefile is not being used. 'Get a refence to the editor. Dim uidEditor As New UID uidEditor.Value = "esriEditor.Editor" _Editor = TryCast(My.ArcMap.Application.FindExtensionByCLSID(uidEditor), ESRI.ArcGIS.Editor.IEditor) If CheckValues() = False Then Return End If _Tolerance = Convert.ToDouble(textBoxTolerance.Text) System.Windows.Forms.Cursor.Current = Cursors.WaitCursor 'Run the curve update CurveUpdate(_CheckTol) _Cancel = False System.Windows.Forms.Cursor.Current = Cursors.Default 'Cast the control to a dockable window to hide it from the user _CurveDockwin = CurveConversionCmd.GetCurveConversionWindow() If _CurveDockwin Is Nothing Then Return End If _CurveDockwin.Show(False) End Sub Private Sub buttonCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonCancel.Click 'hide the dockable window from the user. _CurveDockwin = CurveConversionCmd.GetCurveConversionWindow If _CurveDockwin Is Nothing Then Return End If _CurveDockwin.Show(False) End Sub Private Function CheckValues() As Boolean CheckValues = False 'Check for numeric tolerance value if option is checked If checkBoxTolerance.Checked = True And Not IsNumeric(textBoxTolerance.Text) Then MessageBox.Show("Tolerance value must be numeric!!") Exit Function End If 'Check for numeric value if field to update is not a string field If comboBoxField.SelectedIndex > 0 Then If Not IsNumeric(textBoxvalue.Text) And Not _UpdateFieldIsString Then MessageBox.Show("Update value must be numeric when the field is numeric!!!") Exit Function End If End If CheckValues = True End Function ''' <summary> ''' Populates the Fields combo box with the fields other than Shape_length and area. ''' </summary> ''' <remarks></remarks> Shared Sub UpdateFieldList() Dim lLoop As Long _CurveUserControl.comboBoxField.Items.Clear() _CurveUserControl.comboBoxField.Items.Add("<none>") If Not _MFields Is Nothing Then For lLoop = 0 To _MFields.FieldCount - 1 If _MFields.Field(lLoop).Type = esriFieldType.esriFieldTypeDouble Or _ _MFields.Field(lLoop).Type = esriFieldType.esriFieldTypeSingle Or _ _MFields.Field(lLoop).Type = esriFieldType.esriFieldTypeInteger Or _ _MFields.Field(lLoop).Type = esriFieldType.esriFieldTypeSmallInteger Or _ _MFields.Field(lLoop).Type = esriFieldType.esriFieldTypeString Then If UCase(_MFields.Field(lLoop).Name) <> "SHAPE_LENGTH" And _ UCase(_MFields.Field(lLoop).Name) <> "SHAPE_AREA" Then _CurveUserControl.comboBoxField.Items.Add(_MFields.Field(lLoop).Name) End If End If Next lLoop End If _Cancel = True _CurveUserControl.checkBoxTolerance.Checked = False _CurveUserControl.textBoxTolerance.Text = CStr(_Tolerance) _CurveUserControl.textBoxTolerance.Enabled = False _CurveUserControl.textBoxvalue.Text = "" _sFieldName = "" _CurveUserControl.comboBoxField.SelectedIndex = 0 End Sub ''' <summary> ''' Implementation class of the dockable window add-in. It is responsible for ''' creating and disposing the user interface class for the dockable window. ''' </summary> Public Class AddinImpl Inherits ESRI.ArcGIS.Desktop.AddIns.DockableWindow Private m_windowUI As CurveConversionDockWin Protected Overrides Function OnCreateChild() As System.IntPtr m_windowUI = New CurveConversionDockWin(Me.Hook) Return m_windowUI.Handle End Function Protected Overrides Sub Dispose(ByVal Param As Boolean) If m_windowUI IsNot Nothing Then m_windowUI.Dispose(Param) End If MyBase.Dispose(Param) End Sub End Class Private Sub CurveUpdate(ByVal _CheckTol As Boolean) Try 'Set up the progress bar. Dim _Status As IStatusBar = My.ArcMap.Application.StatusBar Dim _StepProg As IStepProgressor = _Status.ProgressBar With _StepProg .Position = 1 .MaxRange = _Editor.SelectionCount .Message = "Update progress:" .StepValue = 1 .Show() End With Dim lCount As Integer = 0 _InvalidEnv = Nothing 'You will get an error if your feature is stored in a shapefile. 'Check to make sure there is no existing edit operation, then start one. Dim _WorkspaceEdit As IWorkspaceEdit2 = DirectCast(_Editor.EditWorkspace, IWorkspaceEdit2) If Not _WorkspaceEdit.IsInEditOperation Then _Editor.StartOperation() End If Dim _Curve As ICurve Dim _Curve2 As ICurve Dim _OrigSegs As ISegmentCollection Dim _Polyline As ISegmentCollection Dim _MidPoint As IPoint Dim _NewLine As IConstructCircularArc Dim _bSegCheck As [Boolean] Dim _OutPoint As IPoint = New PointClass() Dim _Seg As ISegment Dim _Dist As [Double] = 0, _Dist1 As [Double] = 0, _Dist2 As [Double] = 0 Dim _Side As [Boolean] = False, _Updated As [Boolean] = False Dim _EdgeEnum As IEnumTopologyEdge Dim _Path As ISegmentCollection = New PathClass() Dim _TopoEdge As ITopologyEdge Dim _SomeLine As IPolyline Dim _EnumFeat As IEnumFeature = _Editor.EditSelection Dim feat As IFeature = _EnumFeat.[Next]() 'Check for a topology Dim _TopoGraph As ITopologyGraph = TopologyCheck(feat.[Class]) Do If feat.Shape.GeometryType = ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline And (Not IsStraight(feat)) Then 'Create the new segment based on a 3pt curve through the start point, mid point and end point of the feat geometry. _Curve = TryCast(feat.Shape, ICurve) _OrigSegs = TryCast(_Curve, ISegmentCollection) _MidPoint = New PointClass() _Curve.QueryPoint(ESRI.ArcGIS.Geometry.esriSegmentExtension.esriNoExtension, 0.5, True, _MidPoint) _NewLine = New CircularArcClass() _NewLine.ConstructThreePoints(_Curve.FromPoint, _MidPoint, _Curve.ToPoint, False) _Curve2 = TryCast(_NewLine, ICurve) 'Check that the segments are within the tolerance. _bSegCheck = False If _CheckTol Then For lLoop As Integer = 1 To _OrigSegs.SegmentCount - 1 _Seg = _OrigSegs.Segment(lLoop) _Curve2.QueryPointAndDistance(ESRI.ArcGIS.Geometry.esriSegmentExtension.esriNoExtension, _Seg.FromPoint, False, _MidPoint, _Dist, _Dist1, _ _Side) _Curve2.QueryPointAndDistance(ESRI.ArcGIS.Geometry.esriSegmentExtension.esriNoExtension, _Seg.ToPoint, False, _MidPoint, _Dist, _Dist2, _ _Side) If _Dist1 > _Tolerance Or _Dist2 > _Tolerance Then _bSegCheck = True Exit For End If Next End If If Not _bSegCheck Then If _TopoGraph IsNot Nothing Then _EdgeEnum = GetParents(feat, _TopoGraph) If _EdgeEnum Is Nothing Then 'not sure what i need to add, but to get here something went wrong. Else Dim Missing As Object = Type.Missing _Path.AddSegment(TryCast(_NewLine, ISegment), Missing, Missing) Select Case _EdgeEnum.Count Case 1 _EdgeEnum.Reset() _TopoEdge = _EdgeEnum.[Next]() _Updated = UpdateEdge(_TopoGraph, _TopoEdge, _Path) If _Updated Then UpdateField(feat, True) lCount += 1 End If Exit Select Case 2 _EdgeEnum.Reset() _TopoEdge = _EdgeEnum.[Next]() Do _SomeLine = TryCast(_TopoEdge.Geometry, IPolyline) Dim X1 As Double = _Path.Segment(0).FromPoint.X Dim Y1 As Double = _Path.Segment(0).FromPoint.Y Dim X2 As Double = _Path.Segment(0).ToPoint.X Dim Y2 As Double = _Path.Segment(0).ToPoint.Y If X1 = _SomeLine.FromPoint.X And Y1 = _SomeLine.FromPoint.Y And X2 = _SomeLine.ToPoint.X And Y2 = _SomeLine.FromPoint.Y Then _Updated = UpdateEdge(_TopoGraph, _TopoEdge, _Path) If _Updated Then UpdateField(feat, True) lCount += 1 End If Exit Do End If _TopoEdge = _EdgeEnum.[Next]() Loop While _TopoEdge IsNot Nothing Exit Select Case Else Exit Select End Select _EdgeEnum = Nothing End If Else 'the current feature is not part of a topo, so just update it. _Polyline = New PolylineClass() Dim Missing As Object = Type.Missing _Polyline.AddSegment(TryCast(_NewLine, ISegment), Missing, Missing) 'This code sets the polyline ZAware so it will handle Z aware features. 'However you need to check that the feature is Z aware first, so you can add this code here. 'Dim zAware as IZAware = _Polyline as IZAware 'zAware.ZAware = true feat.Shape = TryCast(_Polyline, IGeometry) UpdateField(feat, False) feat.Store() lCount += 1 If _InvalidEnv Is Nothing Then _InvalidEnv = feat.Shape.Envelope Else _InvalidEnv.Union(feat.Shape.Envelope) End If End If End If End If feat = _EnumFeat.[Next]() My.ArcMap.Application.StatusBar.ProgressBar.[Step]() Loop While feat IsNot Nothing If lCount = 0 Then MessageBox.Show("No features were updated.") _Editor.AbortOperation() Else MessageBox.Show(lCount & " feature(s) updated") _Editor.StopOperation("Update Curves") End If If _InvalidEnv IsNot Nothing Then Dim _Doc As IMxDocument = TryCast(My.ArcMap.Application.Document, IMxDocument) _Doc.ActiveView.PartialRefresh(ESRI.ArcGIS.Carto.esriViewDrawPhase.esriViewAll, Nothing, _InvalidEnv) End If My.ArcMap.Application.StatusBar.ProgressBar.Hide() Catch ex As Exception MessageBox.Show("Error in updating the Curve, make sure you are not using a shapefile." + ex.Message) My.ArcMap.Application.StatusBar.ProgressBar.Hide() Return End Try End Sub Private Sub UpdateField(ByVal feat As IFeature, ByVal shouldStore As Boolean) Try Dim lFieldIndex As Integer = 0 If Not _sFieldName Is "<none>" Then lFieldIndex = feat.Fields.FindField(_sFieldName) If lFieldIndex > -1 Then _UpdateValue = textBoxvalue.Text feat.Value(lFieldIndex) = _UpdateValue Select Case feat.Fields.Field(lFieldIndex).Type Case esriFieldType.esriFieldTypeString feat.Value(lFieldIndex) = _UpdateValue.ToString() Case esriFieldType.esriFieldTypeInteger Or esriFieldType.esriFieldTypeString feat.Value(lFieldIndex) = Convert.ToInt32(_UpdateValue) Case esriFieldType.esriFieldTypeDouble Or esriFieldType.esriFieldTypeSingle feat.Value(lFieldIndex) = Convert.ToDouble(_UpdateValue) Case Else Return End Select If shouldStore Then feat.Store() End If End If End If Catch ex As Exception Return End Try End Sub Private Function UpdateEdge(ByVal topoGraph As ITopologyGraph, ByVal _TopoEdge As ITopologyEdge, ByVal _Path As ISegmentCollection) As Boolean Try Dim _NewSegs As ISegmentCollection = TryCast(_TopoEdge.Geometry, ISegmentCollection) Dim _Invalid As IEnvelope = New EnvelopeClass() Dim inCount As Integer = _NewSegs.SegmentCount topoGraph.SetEdgeGeometry(_TopoEdge, TryCast(_Path, IPath)) topoGraph.Post(_Invalid) If _InvalidEnv Is Nothing Then _InvalidEnv = _Invalid Else _InvalidEnv.Union(_Invalid) End If _NewSegs = TryCast(_TopoEdge.Geometry, ISegmentCollection) If _NewSegs.SegmentCount = 1 And inCount > 1 Then Return True Else Return False End If Catch e As Exception MessageBox.Show("Error in updating the topo edge " & e.Message) Return False End Try End Function Private Function GetParents(ByVal feat As IFeature, ByVal _TopoGraph As ITopologyGraph) As IEnumTopologyEdge Dim fFC As IFeatureClass = TryCast(feat.[Class], IFeatureClass) Dim _EnumTopoEdge As IEnumTopologyEdge = _TopoGraph.GetParentEdges(fFC, feat.OID) If _EnumTopoEdge Is Nothing Then _TopoGraph.SetEmpty() _TopoGraph.Build(feat.Shape.Envelope, False) _EnumTopoEdge = _TopoGraph.GetParentEdges(fFC, feat.OID) Else If _EnumTopoEdge.Count > 1 Then _TopoGraph.DeletePseudoNodesFromSelection() End If End If Return _EnumTopoEdge End Function ''' <summary> ''' Check to see if the line is straight. So we do NOT convert straight lines to polycurves. ''' </summary> ''' <param name="feat"></param> ''' <returns></returns> ''' <remarks></remarks> Private Function IsStraight(ByVal feat As IFeature) As Boolean Try If feat.Shape.GeometryType <> ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline Then Return True End If Dim _SR As ISpatialReference = feat.Shape.SpatialReference Dim _PolyCurve As IPolycurve = TryCast(feat.ShapeCopy, IPolycurve) Dim _SegColl As ISegmentCollection = TryCast(_PolyCurve, ISegmentCollection) Dim _x As Double Dim _y As Double Dim _units As Double _SR.GetFalseOriginAndUnits(_x, _y, _units) _PolyCurve.Generalize(2 / _units) If _SegColl.SegmentCount = 1 Then Return True Else Return False End If Catch e As Exception MessageBox.Show("Error in checking straight " & e.Message) Return False End Try End Function ''' <summary> ''' Checks to see if the feature class is part of a gdb or map topology. ''' If it is it will build the topo cache and return the topology graph. ''' </summary> ''' <param name="oBJClass"></param> ''' <returns></returns> ''' <remarks></remarks> Private Function TopologyCheck(ByVal oBJClass As IObjectClass) As ITopologyGraph Try Dim topoClass As ITopologyClass = TryCast(oBJClass, ITopologyClass) Dim topoGraph As ITopologyGraph If topoClass.IsInTopology Then If topoClass.Topology.Cache IsNot Nothing Then topoGraph = TryCast(topoClass.Topology.Cache, ITopologyGraph) Else topoGraph = Nothing End If Else 'Check to see if the class of the selected feature is part of a map topology. Dim mUID As UID = New UIDClass() mUID.Value = "esriEditor.TopologyExtension" Dim topoExt As ITopologyExtension = TryCast(My.ArcMap.Application.FindExtensionByCLSID(mUID), ITopologyExtension) Dim mapTopo As IMapTopology = topoExt.MapTopology Dim featClass As IFeatureClass = TryCast(oBJClass, IFeatureClass) Dim lID As Integer = mapTopo.FindClass(featClass) If lID > -1 Then topoGraph = mapTopo.Cache Else topoGraph = Nothing End If End If Return topoGraph Catch e As Exception MessageBox.Show("Error checking topology: " & e.Message) Return Nothing End Try End Function Private Sub checkBoxTolerance_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles checkBoxTolerance.CheckedChanged If checkBoxTolerance.Checked = False Then _CheckTol = False textBoxTolerance.Enabled = False Else _CheckTol = True textBoxTolerance.Enabled = True End If End Sub Private Sub comboBoxField_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles comboBoxField.SelectedIndexChanged Try If comboBoxField.SelectedIndex > 0 Then Dim lIndex As Integer = _MFields.FindField(comboBoxField.Text) If lIndex > -1 Then If _MFields.Field(lIndex).Type = esriFieldType.esriFieldTypeString Then _UpdateFieldIsString = True _sFieldName = _MFields.Field(lIndex).Name Else _UpdateFieldIsString = False _sFieldName = _MFields.Field(lIndex).Name End If Else 'resets the field to none. comboBoxField.SelectedIndex = 0 End If Else _UpdateFieldIsString = False End If Catch ex As Exception Return End Try End Sub End Class