CurveConversionDockWin.cs
// 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. // using System; using System.Windows.Forms; using ESRI.ArcGIS.Editor; using ESRI.ArcGIS.EditorExt; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.ArcMapUI; using ESRI.ArcGIS.Framework; namespace CurveConversion { /// <summary> /// Designer class of the dockable window add-in. It contains user interfaces that /// make up the dockable window. /// </summary> public partial class CurveConversionDockWin : UserControl { private IDockableWindow _CurveDockWin; public static Double _Tolerance = 0.1; public static String _sFieldName = ""; public static IFields _MFields; public static System.Object _UpdateValue = 0; private static bool _Cancel = false; public bool _UpdateFieldIsString = false; private bool _CheckTol = false; public IEditor _Editor; public IEnvelope _InvalidEnv; internal static CurveConversionDockWin _CurveUserControl; public CurveConversionDockWin(object hook) { InitializeComponent(); this.Hook = hook; _CurveUserControl = this; } /// <summary> /// Host object of the dockable window /// </summary> private object Hook { get; set; } /// <summary> /// Implementation class of the dockable window add-in. It is responsible for /// creating and disposing the user interface class of the dockable window. /// </summary> public class AddinImpl : ESRI.ArcGIS.Desktop.AddIns.DockableWindow { private CurveConversionDockWin m_windowUI; public AddinImpl() { } protected override IntPtr OnCreateChild() { m_windowUI = new CurveConversionDockWin(this.Hook); return m_windowUI.Handle; } protected override void Dispose(bool disposing) { if (m_windowUI != null) m_windowUI.Dispose(disposing); base.Dispose(disposing); } } /// <summary> /// Populates the Fields combo box with the fields other than Shape_length and area. /// </summary> public static void UpdateFieldList() { _CurveUserControl.comboBoxField.Items.Clear(); _CurveUserControl.comboBoxField.Items.Add("<none>"); if (_MFields != null) { for (int i = 0; i < _MFields.FieldCount; i++) { if (_MFields.get_Field(i).Type == esriFieldType.esriFieldTypeDouble | _MFields.get_Field(i).Type == esriFieldType.esriFieldTypeInteger | _MFields.get_Field(i).Type == esriFieldType.esriFieldTypeSingle | _MFields.get_Field(i).Type == esriFieldType.esriFieldTypeString) { string FieldName = _MFields.get_Field(i).Name.ToUpper(); if (FieldName != "SHAPE_LENGTH" & FieldName != "SHAPE_AREA") { _CurveUserControl.comboBoxField.Items.Add(_MFields.get_Field(i).Name); } } } } //Reset the form. _Cancel = true; _CurveUserControl.checkBoxTolerance.Checked = false; _CurveUserControl.textBoxTolerance.Text = _Tolerance.ToString(); _CurveUserControl.textBoxTolerance.Enabled = false; _CurveUserControl.textBoxvalue.Text = ""; _sFieldName = ""; _CurveUserControl.comboBoxField.SelectedIndex = 0; } private void buttonOK_Click(object sender, EventArgs e) { //You may also want to check that a shapefile is not being used. //Get the editor for the dockable window. UID eUID = new UIDClass(); eUID.Value = "esriEditor.Editor"; _Editor = ArcMap.Application.FindExtensionByCLSID(eUID) as IEditor; if (CheckValues() == false) return; _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 == null) return; _CurveDockWin.Show(false); } private void buttonCancel_Click(object sender, EventArgs e) { //hide the dockable window from the user. _CurveDockWin = CurveConversionCmd.GetCurveConversionWindow; if (_CurveDockWin == null) return; _CurveDockWin.Show(false); } private void checkBoxTolerance_CheckedChanged(object sender, EventArgs e) { if (checkBoxTolerance.Checked == false) { _CheckTol = false; textBoxTolerance.Enabled = false; } else { _CheckTol = true; textBoxTolerance.Enabled = true; } } private void comboBoxField_SelectedIndexChanged(object sender, EventArgs e) { if (comboBoxField.SelectedIndex > 0) { int lIndex = _MFields.FindField(comboBoxField.Text); if (lIndex > -1) { if (_MFields.get_Field(lIndex).Type == esriFieldType.esriFieldTypeString) { _UpdateFieldIsString = true; _sFieldName = _MFields.get_Field(lIndex).Name; } else { _UpdateFieldIsString = false; _sFieldName = _MFields.get_Field(lIndex).Name; } } else { //resets the field to none. comboBoxField.SelectedIndex = 0; } } else { _UpdateFieldIsString = false; } } private bool CheckValues() { //Check for numeric tolerance value if option is checked int i; bool isnumeric = Int32.TryParse(textBoxTolerance.Text, out i); double a; isnumeric = double.TryParse(textBoxTolerance.Text, out a); if ((checkBoxTolerance.Checked == true) & (isnumeric == false)) { MessageBox.Show("Tolerance value must be numeric!!"); return false; } //Check for numeric value if field to update is not a string field if (comboBoxField.SelectedIndex > 0) { isnumeric = int.TryParse(textBoxvalue.Text, out i); if ((isnumeric = false) & (_UpdateFieldIsString = false)) { MessageBox.Show("Update value must be numeric when the field is numeric!!!"); return false; } } return true; } private void CurveUpdate(bool checkTol) { try { //***Not sure that the progress bar is needed***// //Set up the progress bar. IStatusBar _Status = ArcMap.Application.StatusBar; IStepProgressor _StepProg = _Status.ProgressBar; _StepProg.Position = 1; _StepProg.MaxRange = _Editor.SelectionCount; _StepProg.Message = "Update progress:"; _StepProg.StepValue = 1; _StepProg.Show(); int lCount = 0; _InvalidEnv = null; //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. IWorkspaceEdit2 _WorkspaceEdit = (IWorkspaceEdit2)_Editor.EditWorkspace; if (!_WorkspaceEdit.IsInEditOperation) { _Editor.StartOperation(); } ICurve _Curve; ICurve _Curve2; ISegmentCollection _OrigSegs; ISegmentCollection _Polyline; IConstructCircularArc _NewLine; Boolean _bSegCheck; IPoint _MidPoint; ISegment _Seg; Double _Dist = 0, _Dist1 = 0, _Dist2 = 0; Boolean _Side = false, _Updated = false; IEnumTopologyEdge _EdgeEnum; ISegmentCollection _Path = new PathClass(); ITopologyEdge _TopoEdge; IPolyline _SomeLine; IEnumFeature _EnumFeat = _Editor.EditSelection; IFeature feat = _EnumFeat.Next(); //Check for a topology ITopologyGraph _TopoGraph = TopologyCheck(feat.Class); do { if (feat.Shape.GeometryType == esriGeometryType.esriGeometryPolyline & (!IsStraight(feat))) { //Create the new segment based on a 3pt curve through the start point, mid point and end point of the feat geometry. _Curve = feat.Shape as ICurve; _OrigSegs = _Curve as ISegmentCollection; _MidPoint = new PointClass(); _Curve.QueryPoint(esriSegmentExtension.esriNoExtension, 0.5, true, _MidPoint); _NewLine = new CircularArcClass(); _NewLine.ConstructThreePoints(_Curve.FromPoint, _MidPoint, _Curve.ToPoint, false); _Curve2 = _NewLine as ICurve; //Check that the segments are within the tolerance. _bSegCheck = false; if (checkTol) { for (int lLoop = 1; lLoop < _OrigSegs.SegmentCount; lLoop++) { _Seg = _OrigSegs.get_Segment(lLoop); _Curve2.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, _Seg.FromPoint, false, _MidPoint, ref _Dist, ref _Dist1, ref _Side); _Curve2.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, _Seg.ToPoint, false, _MidPoint, ref _Dist, ref _Dist2, ref _Side); if (_Dist1 > _Tolerance | _Dist2 > _Tolerance) { _bSegCheck = true; break; } } } if (!_bSegCheck) { //Check for a topology. if (_TopoGraph != null) { _EdgeEnum = GetParents(feat, _TopoGraph); if (_EdgeEnum == null) { //not sure what i need to add, but to get here something went wrong. } else { object Missing = Type.Missing; _Path.AddSegment(_NewLine as ISegment, ref Missing, ref Missing); switch (_EdgeEnum.Count) { case 1: _EdgeEnum.Reset(); _TopoEdge = _EdgeEnum.Next(); _Updated = UpdateEdge(_TopoGraph, _TopoEdge, _Path); if (_Updated) { UpdateField(feat, true); lCount++; } break; case 2: _EdgeEnum.Reset(); _TopoEdge = _EdgeEnum.Next(); do { _SomeLine = _TopoEdge.Geometry as IPolyline; double X1 = _Path.get_Segment(0).FromPoint.X; double Y1 = _Path.get_Segment(0).FromPoint.Y; double X2 = _Path.get_Segment(0).ToPoint.X; double Y2 = _Path.get_Segment(0).ToPoint.Y; if (X1 == _SomeLine.FromPoint.X & Y1 == _SomeLine.FromPoint.Y & X2 == _SomeLine.ToPoint.X & Y2 == _SomeLine.FromPoint.Y) { _Updated = UpdateEdge(_TopoGraph, _TopoEdge, _Path); if (_Updated) { UpdateField(feat, true); lCount++; } break; } _TopoEdge = _EdgeEnum.Next(); } while (_TopoEdge != null); break; default: break; } _EdgeEnum = null; } } else { //the current feature is not part of a topo, so just update it. _Polyline = new PolylineClass(); object Missing = Type.Missing; _Polyline.AddSegment(_NewLine as ISegment, ref Missing, ref 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. //IZAware zAware = _Polyline as IZAware; //zAware.ZAware = true; feat.Shape = _Polyline as IGeometry; UpdateField(feat, false); feat.Store(); lCount++; if (_InvalidEnv == null) { _InvalidEnv = feat.Shape.Envelope; } else { _InvalidEnv.Union(feat.Shape.Envelope); } } } } feat = _EnumFeat.Next(); ArcMap.Application.StatusBar.ProgressBar.Step(); } while (feat != null); if (lCount == 0) { MessageBox.Show("No features were updated."); _Editor.AbortOperation(); } else { MessageBox.Show(lCount + " feature(s) updated"); _Editor.StopOperation("Update Curves"); } if (_InvalidEnv != null) { IMxDocument _Doc = ArcMap.Application.Document as IMxDocument; _Doc.ActiveView.PartialRefresh(ESRI.ArcGIS.Carto.esriViewDrawPhase.esriViewAll, null, _InvalidEnv); } ArcMap.Application.StatusBar.ProgressBar.Hide(); } catch(Exception e) { MessageBox.Show("Error in updating the Curve, make sure you are not using a shapefile." + e.Message); ArcMap.Application.StatusBar.ProgressBar.Hide(); return; } } /// <summary> /// Checks the field type and converts the update value to the correct type and updates the feature. /// </summary> /// <param name="feat"></param> /// <param name="shouldStore"></param> private void UpdateField(IFeature feat, bool shouldStore) { try { int lFieldIndex = 0; if (_sFieldName != "<none>") { lFieldIndex = feat.Fields.FindField(_sFieldName); if (lFieldIndex > -1) { _UpdateValue = textBoxvalue.Text; switch (feat.Fields.get_Field(lFieldIndex).Type) { case esriFieldType.esriFieldTypeString: feat.set_Value(lFieldIndex, _UpdateValue.ToString()); break; case esriFieldType.esriFieldTypeInteger | esriFieldType.esriFieldTypeSmallInteger: feat.set_Value(lFieldIndex, Convert.ToInt32(_UpdateValue)); break; case esriFieldType.esriFieldTypeDouble | esriFieldType.esriFieldTypeSingle: feat.set_Value(lFieldIndex, Convert.ToDouble(_UpdateValue)); break; default: break; } if (shouldStore) feat.Store(); } } } catch { return; } } private bool UpdateEdge(ITopologyGraph topoGraph, ITopologyEdge _TopoEdge, ISegmentCollection _Path) { try { ISegmentCollection _NewSegs = _TopoEdge.Geometry as ISegmentCollection; IEnvelope _Invalid = new EnvelopeClass(); int inCount = _NewSegs.SegmentCount; topoGraph.SetEdgeGeometry(_TopoEdge, _Path as IPath); topoGraph.Post(out _Invalid); if (_InvalidEnv == null) { _InvalidEnv = _Invalid; } else { _InvalidEnv.Union(_Invalid); } _NewSegs = _TopoEdge.Geometry as ISegmentCollection; if (_NewSegs.SegmentCount == 1 & inCount > 1) { return true; } else return false; } catch (Exception e) { MessageBox.Show("Error in updating the topo edge " + e.Message); return false; } } /// <summary> /// Gets an enum of the parent edges for the feature. /// </summary> /// <param name="feat"></param> /// <param name="topoGraph"></param> /// <returns></returns> private IEnumTopologyEdge GetParents(IFeature feat, ITopologyGraph topoGraph) { IFeatureClass fFC = feat.Class as IFeatureClass; IEnumTopologyEdge _EnumTopoEdge = topoGraph.GetParentEdges(fFC, feat.OID); if (_EnumTopoEdge == null) { topoGraph.SetEmpty(); topoGraph.Build(feat.Shape.Envelope, false); _EnumTopoEdge = topoGraph.GetParentEdges(fFC, feat.OID); } else { if (_EnumTopoEdge.Count > 1) { topoGraph.DeletePseudoNodesFromSelection(); } } return _EnumTopoEdge; } /// <summary> /// Check to see if the line is straight. So we do NOT convert straight lines to polycurves. /// </summary> /// <param name="feat"></param> private bool IsStraight(IFeature feat) { try { if (feat.Shape.GeometryType != esriGeometryType.esriGeometryPolyline) return true; ISpatialReference _SR = feat.Shape.SpatialReference; IPolycurve _PolyCurve = feat.ShapeCopy as IPolycurve; ISegmentCollection _SegColl = _PolyCurve as ISegmentCollection; double _x; double _y; double _units; _SR.GetFalseOriginAndUnits(out _x, out _y, out _units); _PolyCurve.Generalize(2 / _units); if (_SegColl.SegmentCount == 1) { return true; } else { return false; } } catch (Exception e) { MessageBox.Show("Error in checking straight " + e.Message); return false; } } /// <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> private ITopologyGraph TopologyCheck(IObjectClass oBJClass) { try { ITopologyClass topoClass = oBJClass as ITopologyClass; ITopologyGraph topoGraph; if (topoClass.IsInTopology) { //Check to see if the class of the selected feature is part of the a topology. if (topoClass.Topology.Cache != null) { return topoGraph = topoClass.Topology.Cache as ITopologyGraph; } else { return topoGraph = null; } } else { //Check to see if the class of the selected feature is part of a map topology. UID mUID = new UIDClass(); mUID.Value = "esriEditor.TopologyExtension"; ITopologyExtension topoExt = ArcMap.Application.FindExtensionByCLSID(mUID) as ITopologyExtension; IMapTopology mapTopo = topoExt.MapTopology; IFeatureClass featClass = oBJClass as IFeatureClass; int lID = mapTopo.FindClass(featClass); if (lID > -1) { return topoGraph = mapTopo.Cache; } else { return topoGraph = null; } } } catch (Exception e) { Console.WriteLine("Error checking topology" + e); return null; } } } }