private void DWIntersect(CPolyline pBSCpl, ref List <CPoint> cptlt, double dblIgnorableDis) { IPointCollection4 pCol = new PolylineClass(); for (int i = 0; i < cptlt.Count; i++) { cptlt[i].SetPoint(); pCol.AddPoint(cptlt[i].pPoint); } IPolyline5 ipl = pCol as IPolyline5; pBSCpl.SetPolyline(); IRelationalOperator pRel = pBSCpl.pPolyline as IRelationalOperator; bool isCrosses = pRel.Crosses(ipl); if (isCrosses == true) { ITopologicalOperator pTop = pBSCpl.pPolyline as ITopologicalOperator; IGeometry pGeoIntersect = pTop.Intersect(ipl, esriGeometryDimension.esriGeometry0Dimension); IPointCollection4 pColIntersect = pGeoIntersect as IPointCollection4; double dblMaxDis = 0; for (int j = 0; j < pColIntersect.PointCount; j++) { double dblDis = CGeoFunc.CalDistanceFromStartPoint(ipl, pColIntersect.get_Point(j), false); if (dblDis > dblMaxDis) { dblMaxDis = dblDis; } } ICurve pSubCurve; ipl.GetSubcurve(dblMaxDis, ipl.Length, false, out pSubCurve); //IPolyline5 Cutipl = pSubCurve as IPolyline5; IPointCollection4 iplCutCol = pSubCurve as IPointCollection4; //the new first segment IPointCollection4 pSegCol = new PolylineClass(); pSegCol.AddPoint(ipl.FromPoint, _Missing, _Missing); pSegCol.AddPoint(iplCutCol.get_Point(1), _Missing, _Missing); IPolyline5 seg = pSegCol as IPolyline5; bool isCrossesSeg; int intIndex = 0; while (intIndex < iplCutCol.PointCount - 1) { intIndex++; pSegCol.UpdatePoint(1, iplCutCol.get_Point(intIndex)); isCrossesSeg = pRel.Crosses(seg); if (isCrossesSeg == false) { iplCutCol.RemovePoints(1, intIndex - 1); iplCutCol.UpdatePoint(0, ipl.FromPoint); break; } if (seg.Length >= dblIgnorableDis) { double dblOriginalIntersectionDis = CGeoFunc.CalDistanceFromStartPoint(pBSCpl.pPolyline, pCol.get_Point(0), false); double dblRealisticIntersectionDis = CGeoFunc.CalDistanceFromStartPoint(pBSCpl.pPolyline, iplCutCol.get_Point(0), false); IPointCollection4 pColBSCpl = pBSCpl.pPolyline as IPointCollection4; double dblSumDis = 0; for (int i = 0; i < pColBSCpl.PointCount - 1; i++) { double dblDis = CGeoFunc.CalDis(pColBSCpl.get_Point(i), pColBSCpl.get_Point(i + 1)); dblSumDis += dblDis; if (dblSumDis >= dblRealisticIntersectionDis) { double dblDisPre = Math.Abs(dblSumDis - dblDis - dblOriginalIntersectionDis); double dblDisNext = Math.Abs(dblSumDis - dblOriginalIntersectionDis); IPoint intersectpt = new PointClass(); if (dblDisPre <= dblDisNext) { intersectpt = pColBSCpl.get_Point(i); } else { intersectpt = pColBSCpl.get_Point(i + 1); } iplCutCol.UpdatePoint(0, intersectpt); break; } } break; } } cptlt = CHelpFunc.GetCptEbByICol(iplCutCol).ToList(); } }
public override void OnClick() { try { //setup a file stream and a stream writer to write out the addresses that do not have a nearby street or a street out of range string path = @"C:\temp\DeleteDupVerts" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm") + ".txt"; System.IO.FileStream fileStream = new System.IO.FileStream(path, FileMode.Create); StreamWriter streamWriter = new StreamWriter(fileStream); streamWriter.WriteLine("UniqueID" + "," + "FeatureOID" + "," + "VertIndex1" + "," + "VertIndex2"); int intUniqueID = 0; bool updatePreviousPnt; int numberOfVerticesRemovedFromPntCollection; int vertexIndexToRemove; // get access to the current arcmap variables clsPushSgidStaticClass.GetCurrentMapDocVariables(); // show the cursor as busy System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; clsGlobals.pGFlayer = null; clsGlobals.arcFeatLayer = null; IFeatureLayer arcFeatureLayerVertPnts = null; IFeatureClass arcFeatureClassVertPnts = null; //var listOfIndexesToRemove = new List<Int32>(); // loop through the map's layers and check for the layer with the targeted name for (int i = 0; i < clsGlobals.pMap.LayerCount; i++) { if (clsGlobals.pMap.Layer[i].Name == "REMOVE_DUP_VERTS") { clsGlobals.pGFlayer = (IGeoFeatureLayer)clsGlobals.pMap.Layer[i]; clsGlobals.arcFeatLayer = (IFeatureLayer)clsGlobals.pMap.Layer[i]; } if (clsGlobals.pMap.Layer[i].Name == "VERT_PNTS") { arcFeatureLayerVertPnts = (IFeatureLayer)clsGlobals.pMap.Layer[i]; arcFeatureClassVertPnts = arcFeatureLayerVertPnts.FeatureClass; } } // make sure the user is editing //get the editor extension UID arcUID = new UID(); arcUID.Value = "esriEditor.Editor"; clsGlobals.arcEditor = clsGlobals.arcApplication.FindExtensionByCLSID(arcUID) as IEditor3; // check if editing first if (clsGlobals.arcEditor.EditState == ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing) { MessageBox.Show("You must be editing in order to remove duplicate vertices.", "Must Be Editing", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } IDataset arcDataset = (IDataset)clsGlobals.arcFeatLayer; IWorkspace arcWorkspace = arcDataset.Workspace; IWorkspaceEdit arcWorkspaceEdit = (IWorkspaceEdit)arcWorkspace; // make sure we're editing the correct workspace if (!(arcWorkspaceEdit.IsBeingEdited())) { MessageBox.Show("You must be editing the REMOVE_DUP_VERTS layer in order to proceed.", "Must Be Editing", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } // get access to the selected features in the user specified layer IDisplayTable arcDisplayTable = (IDisplayTable)clsGlobals.arcFeatLayer; ISelectionSet arcSelectionSet = arcDisplayTable.DisplaySelectionSet; // make sure there's at least one feature selected in the specified layer if (arcSelectionSet.Count == 0) { MessageBox.Show( "You must select at least one feature in the REMOVE_DUP_VERTS layer to spatially assign values to.", "No Features are Selected.", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } // confirm the user wants to edit that layer's fields on the selected records DialogResult dialogResult = MessageBox.Show( "Would you like to proceed with editing " + arcSelectionSet.Count + " features on the REMOVE_DUP_VERTS Layer, removing non-coincident verticies that are within 1 meter of eachother?", "Confirm Edits", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (dialogResult == DialogResult.Yes) { // loop through the selected feature remove_dup_verts layer IEnumIDs arcEnumIDs = arcSelectionSet.IDs; int iD; while ((iD = arcEnumIDs.Next()) != -1) { vertexIndexToRemove = 0; numberOfVerticesRemovedFromPntCollection = 0; clsGlobals.arcFeatureToEditSpatial = clsGlobals.arcFeatLayer.FeatureClass.GetFeature(iD); clsGlobals.arcEditor.StartOperation(); // Loop through this features verticies. // Get the feature's geometry. IGeometry arcEdit_geometry = clsGlobals.arcFeatureToEditSpatial.Shape; IPolyline arcEdit_polyline = arcEdit_geometry as IPolyline; // get a point collection IPointCollection4 pointCollection = (IPointCollection4)arcEdit_polyline; IPoint currPoint = null; IPoint previousPoint = null; // Iterate the point collection array (the first point is the start of the line and last is the end of the line). // I added the numberOfVerticesRemovedFromPntCollection variable in order to preserve the initial point collection iterations (it's needed in order to loop through all the original vertices) for (int i = 0; i < pointCollection.PointCount + numberOfVerticesRemovedFromPntCollection; i++) { // Reset the boolean value. updatePreviousPnt = true; // Reset the number of vertices removed to zero //numberOfVerticesRemovedFromPntCollection = 0; //vertexIndexToRemove = 0; // Get the current point. currPoint = null; // This is the problem as it's setting the current i point, but this should be a reference to the original index //currPoint = pointCollection.get_Point(i); currPoint = pointCollection.get_Point(i - numberOfVerticesRemovedFromPntCollection); //MessageBox.Show("X:" + currPoint.X + " , Y:" + currPoint.Y); // Check if the previous point has been assigned yet (if not, it's the first itteration of this line segment) if (previousPoint != null) { // Check the distance between the currPoint and previousPoint to see if it's less than 1 meter IProximityOperator proximityOperator; IGeometry currGeometry = currPoint; IGeometry previousGeometry = previousPoint; proximityOperator = currGeometry as IProximityOperator; // Check distance to the previous vertex. double distBetweenCurrAndPrevPnt = proximityOperator.ReturnDistance(previousGeometry); // Check if distance is less than 1 meter. if (distBetweenCurrAndPrevPnt <= 3) { //MessageBox.Show(distance.ToString() + " is less than 1 meter."); // Check if the the current point intersects any other vertices, before we delete it. // If it does, then check the current point to see if intersects any other vertices, before we delete it. ISpatialFilter spatialFilterCurr = new SpatialFilterClass(); spatialFilterCurr.Geometry = currGeometry; spatialFilterCurr.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects; IFeatureCursor featureCursorCurr = arcFeatureClassVertPnts.Search(spatialFilterCurr, false); IFeature featureCurr = null; int vertAtCurrPnt = 0; while ((featureCurr = featureCursorCurr.NextFeature()) != null) { vertAtCurrPnt = vertAtCurrPnt + 1; } // Check if we can delete this vertex if (vertAtCurrPnt > 1) { // There's more than one vertex here at the current vertex/point, so we cant' delete it, check the the previous // now check the if we can delete the previous point (as we can't delete the current point b/c it is co-incident) ISpatialFilter spatialFilterPrev = new SpatialFilterClass(); spatialFilterPrev.Geometry = previousGeometry; spatialFilterPrev.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects; IFeatureCursor featureCursorPrev = arcFeatureClassVertPnts.Search(spatialFilterPrev, false); IFeature featurePrev = null; int vertsAtPrevPnt = 0; while ((featurePrev = featureCursorPrev.NextFeature()) != null) { vertsAtPrevPnt = vertsAtPrevPnt + 1; } // Check if we can delete this vertex if (vertsAtPrevPnt > 1) { // can delete this one either, so log it in the text file so we can inspect it manual intUniqueID = intUniqueID + 1; streamWriter.WriteLine(intUniqueID + "," + clsGlobals.arcFeatureToEditSpatial.OID + "," + i + "," + Convert.ToString(i - 1)); //MessageBox.Show("Can't Delete either vertex for this 1 meter duplicate. Help! Need a human!"); } else { // Delete the previous vertex. // Add this index to the list of //listOfIndexesToRemove.Add(i); vertexIndexToRemove = i - numberOfVerticesRemovedFromPntCollection; // test replacing the point collection before we do anything with it //pointCollection.ReplacePointCollection(0,pointCollection.PointCount,pointCollection); //MessageBox.Show("before remove: " + pointCollection.PointCount); // Remove the point from the collection. //pointCollection.RemovePoints(i - 1, 1); pointCollection.RemovePoints(vertexIndexToRemove - 1, 1); //MessageBox.Show("after remove: " + pointCollection.PointCount); // Increment the total number of vertices removed numberOfVerticesRemovedFromPntCollection = numberOfVerticesRemovedFromPntCollection + 1; // reset the point collection, now that the point has been removed //pointCollection.ReplacePointCollection(i, i - pointCollection.PointCount, pointCollection); // Replace the features shape with the newly modified point collection. //clsGlobals.arcFeatureToEditSpatial.Shape = pointCollection as IGeometry; //clsGlobals.arcFeatureToEditSpatial.Store(); } // release the feature cursor System.Runtime.InteropServices.Marshal.ReleaseComObject(featureCursorPrev); } else { // Delete the current vertex // Add this index to the list of //listOfIndexesToRemove.Add(i); vertexIndexToRemove = i - numberOfVerticesRemovedFromPntCollection; // test replacing the point collection before we do anything with it //pointCollection.ReplacePointCollection(0, pointCollection.PointCount, pointCollection); //MessageBox.Show("before remove: " + pointCollection.PointCount); // Remove the point from the collection. //pointCollection.RemovePoints(i, 1); pointCollection.RemovePoints(vertexIndexToRemove, 1); //MessageBox.Show("after remove: " + pointCollection.PointCount); // Increment the total number of vertices removed numberOfVerticesRemovedFromPntCollection = numberOfVerticesRemovedFromPntCollection + 1; // since we are removing this current point, make sure we don't assign it as the previousPoint (in other words keep the active previous point for the next iterattion) updatePreviousPnt = false; // reset the point collection, now that the point has been removed //pointCollection.ReplacePointCollection(i,i- pointCollection.PointCount,pointCollection); // Replace the features shape with the newly modified point collection. //clsGlobals.arcFeatureToEditSpatial.Shape = pointCollection as IGeometry; //clsGlobals.arcFeatureToEditSpatial.Store(); } // release the feature cursor System.Runtime.InteropServices.Marshal.ReleaseComObject(featureCursorCurr); } } // Set this current point to the next point, so next time through the iteration we can check the distance between them. if (updatePreviousPnt) { previousPoint = null; previousPoint = currPoint; } //MessageBox.Show("total times though the loop: " + i); } //// Remove the ID'd verticies from this segment //foreach (var index in listOfIndexesToRemove) //{ // // Remove the point from the collection. // pointCollection.RemovePoints(index, 1); //} // Replace the features shape with the newly modified point collection. clsGlobals.arcFeatureToEditSpatial.Shape = pointCollection as IGeometry; clsGlobals.arcFeatureToEditSpatial.Store(); clsGlobals.arcEditor.StopOperation("RemovedDuplicateVertices"); } //close the stream writer streamWriter.Close(); MessageBox.Show( "Done updating " + arcSelectionSet.Count + " features on the REMOVE_DUP_VERTS Layer, removing non-coincident vertices that were within 1 meter of eachother. Don't forget to save edits if you want to retain the changes.", "Done!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } else if (dialogResult == DialogResult.No) { return; } } catch (Exception ex) { MessageBox.Show("Error Message: " + Environment.NewLine + ex.Message + Environment.NewLine + Environment.NewLine + "Error Source: " + Environment.NewLine + ex.Source + Environment.NewLine + Environment.NewLine + "Error Location:" + Environment.NewLine + ex.StackTrace, "Push Utrans Roads to SGID!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); clsGlobals.arcEditor.StopOperation("RemovedDuplicateVertices"); } }