arcgissamples\editing\CustomVertexTools.java
/* 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. * */ package arcgissamples.editing; import java.io.IOException; import com.esri.arcgis.carto.IActiveView; import com.esri.arcgis.carto.IFeatureLayer; import com.esri.arcgis.carto.IFeatureSelection; import com.esri.arcgis.carto.esriViewDrawPhase; import com.esri.arcgis.controls.BaseTool; import com.esri.arcgis.controls.EngineEditor; import com.esri.arcgis.controls.HookHelper; import com.esri.arcgis.controls.IEngineEditTask; import com.esri.arcgis.controls.esriEngineEditState; import com.esri.arcgis.geodatabase.ICursor; import com.esri.arcgis.geodatabase.IDataset; import com.esri.arcgis.geodatabase.IFeature; import com.esri.arcgis.geodatabase.IFeatureCursor; import com.esri.arcgis.geodatabase.IFeatureCursorProxy; import com.esri.arcgis.geodatabase.ISelectionSet; import com.esri.arcgis.geodatabase.esriWorkspaceType; import com.esri.arcgis.geometry.IGeometry; import com.esri.arcgis.geometry.IGeometryCollection; import com.esri.arcgis.geometry.IHitTest; import com.esri.arcgis.geometry.IPoint; import com.esri.arcgis.geometry.IPointCollection; import com.esri.arcgis.geometry.ITopologicalOperator; import com.esri.arcgis.geometry.Point; import com.esri.arcgis.geometry.esriGeometryHitPartType; import com.esri.arcgis.geometry.esriGeometryType; import com.esri.arcgis.interop.AutomationException; import com.esri.arcgis.systemUI.ICommandSubType; class CustomVertexTools extends BaseTool implements ICommandSubType { private static final long serialVersionUID = -418758068047848768L; private EngineEditor editor; private HookHelper hookHelper; private IEngineEditTask currentEditTask; private int type; @Override public void onCreate(Object hook) { super.onCreate(hook); try { this.hookHelper = new HookHelper(); this.hookHelper.setHookByRef(hook); this.editor = new EngineEditor(); } catch (Exception e) { e.printStackTrace(); } } @Override public void onClick() { try { // find the Modify Feature task and set it as the current task // so the vertices will be automatically highlighted when tool is // clicked for (int i = 0; i < editor.getTaskCount() ; i++) { IEngineEditTask editTask = editor.getTask(i); if (editTask.getName().equalsIgnoreCase("Modify Feature")) { this.currentEditTask = editTask; editor.setCurrentTaskByRef(editTask); break; } } } catch (Exception e) { e.printStackTrace(); } } @Override public void onMouseUp(int button, int shift, int x, int y) { try { // get layer being edited IFeatureLayer featureLayer = (IFeatureLayer) editor.getTargetLayer(); // modify the geometry appropriately for each sub-typed command // get the currently selected feature IFeatureSelection featureSelection = (IFeatureSelection) featureLayer; ISelectionSet selectionSet = featureSelection.getSelectionSet(); ICursor cursor[] = new ICursor[1]; selectionSet.search(null, true, cursor); IFeatureCursor featureCursor = new IFeatureCursorProxy(cursor[0]); // the enabled property has already checked that only 1 feature is // selected IFeature feature = featureCursor.nextFeature(); // Take a copy of geometry for the selected feature IGeometry editShape = feature.getShapeCopy(); // location clicked as a point object IPoint clickedPt = hookHelper.getActiveView().getScreenDisplay() .getDisplayTransformation().toMapPoint(x, y); IHitTest hitShape = (IHitTest) editShape; IPoint hitPoint = new Point(); double[] hitDistance = { -1 }; int[] hitPartIndex = { -1 }; int[] hitSegmentIndex = { -1 }; boolean[] bRightSide = { false }; int hitPartType = esriGeometryHitPartType.esriGeometryPartNone; // the searchRadius is the maximum distance away, in map units, from // the shape that will be used // for the test - change to an appropriate value. double searchRadius = 1; switch (type) { case 1: // Insert Vertex hitPartType = esriGeometryHitPartType.esriGeometryPartBoundary; break; case 2: // Delete Vertex hitPartType = esriGeometryHitPartType.esriGeometryPartVertex; break; } hitShape.hitTest(clickedPt, searchRadius, hitPartType, hitPoint, hitDistance, hitPartIndex, hitSegmentIndex, bRightSide); // check whether the HitTest was successful (i.e within the search // radius) if (!hitPoint.isEmpty()) { // Get the PointCollection for a specific path or ring by // hitPartIndex to handle multi-part features IGeometryCollection geometryCol = (IGeometryCollection) editShape; IPointCollection pathOrRingPointCollection = (IPointCollection) geometryCol .getGeometry(hitPartIndex[0]); switch (this.type) { case 1: // Insert Vertex // add new vertex to the path or ring PointCollection pathOrRingPointCollection.addPoint(clickedPt, null, hitSegmentIndex[0]); break; case 2: // Delete Vertex. // delete a vertex from the path or ring PointCollection pathOrRingPointCollection.removePoints(hitSegmentIndex[0], 1); break; } // remove the old PointCollection from the GeometryCollection // and replace with the new one geometryCol.removeGeometries(hitPartIndex[0], 1); geometryCol.addGeometry((IGeometry) pathOrRingPointCollection, hitPartIndex[0], null); // Ensure that the modified shape is topologically correct ITopologicalOperator topoOp = (ITopologicalOperator) editShape; topoOp.simplify(); try { editor.startOperation(); feature.setShapeByRef(editShape); feature.store(); editor.stopOperation("Add Vertex"); } catch (Exception ex) { editor.abortOperation(); ex.printStackTrace(); } } // Due to the behaviour of the Modify Task the following code is // required to // ensure that any changes are displayed immediately depending on // data source type IDataset dataset = (IDataset) featureLayer; int datasetType = dataset.getWorkspace().getType(); if ((datasetType == esriWorkspaceType.esriFileSystemWorkspace) || (dataset.getCategory() .equalsIgnoreCase("File Geodatabase Feature Class"))) { this.currentEditTask.onFinishSketch(); editor.setCurrentTaskByRef(this.currentEditTask); } else { this.onClick(); } IActiveView activeView = (IActiveView) editor.getMap(); activeView.partialRefresh(esriViewDrawPhase.esriViewGeography, featureLayer, activeView.getExtent()); } catch (Exception ex) { ex.printStackTrace(); } } @Override public boolean isEnabled() { try { if (editor.getEditState() == esriEngineEditState.esriEngineStateNotEditing) { return false; } // check for appropriate geometry types int geomType = ((IFeatureLayer) editor.getTargetLayer()) .getFeatureClass().getShapeType(); if ((geomType != esriGeometryType.esriGeometryPolygon) && (geomType != esriGeometryType.esriGeometryPolyline)) { return false; } // check that only one feature is currently selected IFeatureSelection featureSelection = (IFeatureSelection) editor .getTargetLayer(); ISelectionSet selectionSet = featureSelection.getSelectionSet(); if (selectionSet.getCount() != 1) { return false; } return true; } catch (Exception e) { e.printStackTrace(); return false; } } public int getCount() throws IOException, AutomationException { // The number of subtypes in this tool return 2; } public void setSubType(int index) throws IOException, AutomationException { type = index; this.category = "Vertex Cmds (Java)"; switch (type) { case 1: // Insert Vertex using the custom command this.caption = "Insert vertex (custom)"; this.message = "Insert vertex at clicked location using custom command"; this.toolTip = "Insert vertex at clicked location using custom command"; this.name = "VertexCommands_CustomInsertVertex"; this.cursorPath = this.getClass().getClassLoader().getResource( "InsertVertexCursor.cur").getPath(); this.bitmapPath = this.getClass().getClassLoader().getResource( "InsertVertex.bmp").getPath(); if(System.getProperty("os.name").toLowerCase().indexOf("win")>-1){ this.cursorPath =this.cursorPath.substring(1).replaceAll("%20"," "); this.bitmapPath =this.bitmapPath.substring(1).replaceAll("%20"," "); } break; case 2: // Delete vertex at clicked location using the custom command this.caption = "Delete vertex (custom)"; this.message = "Delete vertex at clicked location using custom command"; this.toolTip = "Delete vertex at clicked location using custom command"; this.name = "VertexCommands_CustomDeleteVertex"; this.cursorPath = this.getClass().getClassLoader().getResource( "DeleteVertexCursor.cur").getPath(); ; this.bitmapPath = this.getClass().getClassLoader().getResource( "DeleteVertex.bmp").getPath(); if(System.getProperty("os.name").toLowerCase().indexOf("win")>-1){ this.cursorPath =this.cursorPath.substring(1).replaceAll("%20"," "); this.bitmapPath =this.bitmapPath.substring(1).replaceAll("%20"," "); } break; } } }