/** * DisplayTypes.java * * --Copyright notice-- * * Copyright (c) School of Geography, University of Leeds. * http://www.geog.leeds.ac.uk/ * This software is licensed under 'The Artistic License' which can be found at * the Open Source Initiative website at... * http://www.opensource.org/licenses/artistic-license.php * Please note that the optional Clause 8 does not apply to this code. * * The Standard Version source code, and associated documentation can be found at... * [online] http://www.ccg.leeds.ac.uk/software/ * * This code contains Progress Bar code by Marc Mettes: * http://inversionconsulting.blogspot.com/2008/03/java-jdialog-and-jprogressbar-example.html * licenced under the Creative Commons Attribution License 3.0: * http://creativecommons.org/licenses/by/3.0/us/ * * --End of Copyright notice-- * **/ package uk.ac.leeds.ccg.boundarytypeanalyst; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.UnknownHostException; import java.text.DateFormat; import java.util.Date; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import com.esri.arcgis.addins.desktop.Button; import com.esri.arcgis.arcmapui.IMxDocument; import com.esri.arcgis.carto.FeatureLayer; import com.esri.arcgis.carto.IActiveView; import com.esri.arcgis.carto.IAttributeTable; import com.esri.arcgis.carto.IElement; import com.esri.arcgis.carto.IEnumLayer; import com.esri.arcgis.carto.IFeatureLayer; import com.esri.arcgis.carto.IFeatureSelection; import com.esri.arcgis.carto.IGeoFeatureLayer; import com.esri.arcgis.carto.IGraphicsContainer; import com.esri.arcgis.carto.ILayer; import com.esri.arcgis.carto.IMap; import com.esri.arcgis.carto.IPageLayout; import com.esri.arcgis.carto.MapSelection; import com.esri.arcgis.carto.PageLayout; import com.esri.arcgis.carto.TopologyLayer; import com.esri.arcgis.carto.esriViewDrawPhase; import com.esri.arcgis.datasourcesGDB.AccessWorkspaceFactory; import com.esri.arcgis.datasourcesfile.ShapefileWorkspaceFactory; import com.esri.arcgis.display.IDisplay; import com.esri.arcgis.framework.IApplication; import com.esri.arcgis.framework.IDocument; import com.esri.arcgis.geodatabase.Feature; import com.esri.arcgis.geodatabase.FeatureClass; import com.esri.arcgis.geodatabase.Field; import com.esri.arcgis.geodatabase.ICursor; import com.esri.arcgis.geodatabase.IEnumFeature; import com.esri.arcgis.geodatabase.IFeature; import com.esri.arcgis.geodatabase.IFeatureClass; import com.esri.arcgis.geodatabase.IFeatureClassProxy; import com.esri.arcgis.geodatabase.IFeatureCursor; import com.esri.arcgis.geodatabase.IFeatureDatasetProxy; import com.esri.arcgis.geodatabase.IFeatureWorkspace; import com.esri.arcgis.geodatabase.IField; import com.esri.arcgis.geodatabase.IFieldEdit; import com.esri.arcgis.geodatabase.IFields; import com.esri.arcgis.geodatabase.IQueryFilter; import com.esri.arcgis.geodatabase.IRow; import com.esri.arcgis.geodatabase.ISelectionSet; import com.esri.arcgis.geodatabase.ITopology; import com.esri.arcgis.geodatabase.ITopologyGraph; import com.esri.arcgis.geodatabase.IWorkspace; import com.esri.arcgis.geodatabase.IWorkspace2; import com.esri.arcgis.geodatabase.IWorkspaceEdit; import com.esri.arcgis.geodatabase.IWorkspaceFactory; import com.esri.arcgis.geodatabase.IWorkspaceProxy; import com.esri.arcgis.geodatabase.QueryFilter; import com.esri.arcgis.geodatabase.Workspace; import com.esri.arcgis.geodatabase.esriDatasetType; import com.esri.arcgis.geometry.AffineTransformation2D; import com.esri.arcgis.geometry.IAffineTransformation2D; 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.IPolyline; import com.esri.arcgis.geometry.ISegmentCollection; import com.esri.arcgis.geometry.ISpatialReference; import com.esri.arcgis.geometry.ITransform2D; import com.esri.arcgis.geometry.Path; import com.esri.arcgis.geometry.Point; import com.esri.arcgis.geometry.Polyline; import com.esri.arcgis.geometry.SpatialReferenceEnvironment; import com.esri.arcgis.geometry.esriTransformDirection; import com.esri.arcgis.geoprocessing.GeoProcessor; import com.esri.arcgis.geoprocessing.tools.datamanagementtools.CreateFeatureclass; import com.esri.arcgis.interop.AutomationException; import com.esri.arcgis.interop.Cleaner; import com.esri.arcgis.system.esriDrawPhase; import javax.swing.JButton; /** * ArcGIS button addin to displace each boundary type for visualisation. * Displaces all layers present in a map when first opened. Builds new displaced datasets, containing displaced boundaries. * Displays these and turns off originals. Popup dialog allows the process to be repeated on original data and the * setting of x and y displacements. Features can be individually displaced by selecting them. *

* ToDo: Rebuild so displaced datasets can be used as original data, allowing selected elements to be displaced differently. * ToDo: See DisplacementGUI ToDos. * @author Andrew Evans * @version 0.1 */ public class DisplayTypes extends Button implements ActionListener { private IApplication app; private IMxDocument mxDoc; private IMap map; private IGeoFeatureLayer[] iGeoFeaturelayers; private TopologyLayer topologyLayer; private IFeatureDatasetProxy ifeatureDatasetProxyGot; private IWorkspaceProxy iWorkspaceProxy; private IWorkspace iWorkspace; private IFeatureWorkspace ifeatureWorkspace; private IFeatureDatasetProxy ifeatureDatasetProxyOpened; private IFeatureClassProxy[] iFeatureClassProxys; private ITopology it; private ITopologyGraph iTopologyGraph; private boolean debug = false; // Change in BoundaryTypeAnalysis. private boolean select = false; // Change in BoundaryTypeAnalysis. private BoundaryTypeAnalyst extension; private JProgressBar pb = new JProgressBar(0, 100); private javax.swing.JDialog dialog; private IActiveView docActiveView = null; private IWorkspaceEdit iwe = null; private GeoProcessor gp = null; private double xOffset = 100000.0; private double yOffset = 100000.0; private DisplacementGUI spinnerDialog = null; // Initialisation methods ------------------------------------------------------- /** * Called when the button is clicked. * * @exception java.io.IOException if there are interop problems. * @exception com.esri.arcgis.interop.AutomationException if the component throws an ArcObjects exception. */ @Override public void onClick() throws IOException, AutomationException { extension = BoundaryTypeAnalyst.getInstance(); initialiseMapVariables(); showSpinners(); } /** * Shows a DisplacementGUI, the event model of which (listened here) controls the remaining flow. */ private void showSpinners() { spinnerDialog = new DisplacementGUI(this); spinnerDialog.setVisible(true); } /** * If the action isn't "finished", sets up a progress bar and displaces boundaries. */ @Override public void actionPerformed(ActionEvent e) { if ( ((JButton) e.getSource()).getText().equals("Finished")) { spinnerDialog.dispose(); return; } else { xOffset = spinnerDialog.getXValue(); yOffset = spinnerDialog.getYValue(); initProgressBar(); displayTypes(); } } /** * Sets up map objects, feature class and layer arrays. */ private void initialiseMapVariables() { Object[] variables = extension.getVariables(); app = (IApplication) variables[0]; mxDoc = (IMxDocument) variables[1]; map = (IMap) variables[2]; iGeoFeaturelayers = (IGeoFeatureLayer[]) variables[3]; topologyLayer = (TopologyLayer) variables[4]; ifeatureDatasetProxyGot = (IFeatureDatasetProxy) variables[5]; iWorkspaceProxy = (IWorkspaceProxy) variables[6]; iWorkspace = (IWorkspace) variables[7]; ifeatureWorkspace = (IFeatureWorkspace) variables[8]; ifeatureDatasetProxyOpened = (IFeatureDatasetProxy) variables[9]; iFeatureClassProxys = (IFeatureClassProxy[]) variables[10]; it = (ITopology) variables[11]; iTopologyGraph = (ITopologyGraph) variables[12]; debug = ((Boolean) variables[13]).booleanValue(); select = ((Boolean) variables[14]).booleanValue(); iwe = (IWorkspaceEdit) ifeatureWorkspace; // Get current map ActiveView try { docActiveView = (IActiveView) mxDoc.getFocusMap(); } catch (AutomationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // GeoProcessor for building layers. try { gp = new GeoProcessor(); gp.setOverwriteOutput(true); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // If the map has been processed before, strip out the results. They only cause issues if layers. try { int count = 0; for (int i = 0; i < iGeoFeaturelayers.length; i++) { if (iGeoFeaturelayers[i].getName().startsWith("Exploded_") == false) count++; } IGeoFeatureLayer[] iGeoFeaturelayersTemp = new IGeoFeatureLayer[count]; count = 0; for (int i = 0; i < iGeoFeaturelayers.length; i++) { if (iGeoFeaturelayers[i].getName().startsWith("Exploded_") == false) { iGeoFeaturelayersTemp[count] = iGeoFeaturelayers[i]; count++; } } iGeoFeaturelayers = iGeoFeaturelayersTemp; } catch (AutomationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Sets up progress bar. */ public void initProgressBar() { pb.setPreferredSize(new Dimension(175, 20)); pb.setString("Working"); pb.setStringPainted(true); pb.setValue(0); JLabel label = new JLabel("Progress: "); JPanel center_panel = new JPanel(); center_panel.add(label); center_panel.add(pb); dialog = new javax.swing.JDialog((java.awt.Frame) null, "Displaying Types"); dialog.getContentPane().add(center_panel, BorderLayout.CENTER); dialog.pack(); dialog.setVisible(true); dialog.setLocationRelativeTo(null); // center on screen dialog.toFront(); // raise above other java windows pb.setValue(0); } /** * Does the bulk of the layer-level stuff. */ private void displayTypes() { try { if (debug) System.out.println("Starting Displaying Types"); // Start editing session. try { iwe.startEditing(true); } catch (AutomationException e2) { // TODO Auto-generated catch block e2.printStackTrace(); } catch (IOException e2) { // TODO Auto-generated catch block e2.printStackTrace(); } // Check whether anything selected. If so, we'll just process these in each layer. // Note that when the map has selected features, some layers may not, so we need to use the // mapSelection, not each layer's selections, which could end up with some layers being processed // as if there were no map selections. int numSelectedMapFeatures = map.getSelectionCount(); // Loop through each boundary type processing features. IFeature feature = null; for (int i = 0; i < iGeoFeaturelayers.length; i++) { // Run through the features in each boundary type. if (debug) System.out.println("Processing " + iGeoFeaturelayers[i].getFeatureClass().getAliasName()); pb.setValue((int) ((100.0 / iGeoFeaturelayers.length) * i)); int numSelectedLayerFeatures = ((FeatureLayer) iGeoFeaturelayers[i]).getSelectionSet().getCount(); IEnumFeature selectedFeatures = null; // Delete any old process results layer. // Note that this (and other code) causes problems with processing results layers (see ToDos). IEnumLayer layers = map.getLayers(null, true); ILayer layer = layers.next(); while (layer != null) { if (layer.getName().equals("Exploded_" + iGeoFeaturelayers[i].getFeatureClass().getAliasName())) { map.deleteLayer(layer); } layer = layers.next(); } // Make new layer to contain results. This also involves making a new FeatureClass in the geodatabase. // Needs "Exploded_" as a variable. FeatureLayer newLayer = new FeatureLayer(); newLayer.setName("Exploded_" + iGeoFeaturelayers[i].getFeatureClass().getAliasName()); String path = iWorkspaceProxy.getPathName(); IFeatureClass fc = null; // If it already exists, empty it, otherwise, make it new. if (((IWorkspace2)iWorkspace).isNameExists(esriDatasetType.esriDTFeatureClass, newLayer.getName())) { fc = ((IFeatureWorkspace) iWorkspace).openFeatureClass(newLayer.getName()); IFeatureCursor updateCursor = fc.IFeatureClass_update(null, false); IFeature f = null; while ((f = updateCursor.nextFeature()) != null){ updateCursor.deleteFeature(); } Cleaner.release(updateCursor); } else { CreateFeatureclass createFCTool = new CreateFeatureclass(path, newLayer.getName()); createFCTool.setGeometryType("polyline"); ISpatialReference spatialReference = map.getSpatialReference(); createFCTool.setSpatialReference(spatialReference); gp.execute(createFCTool, null); fc = ((IFeatureWorkspace) iWorkspace).openFeatureClass(newLayer.getName()); } newLayer.setFeatureClassByRef(fc); map.addLayer(newLayer); // Process the selected features, or all features if none selected. IQueryFilter queryFilter = new QueryFilter(); if (numSelectedLayerFeatures > 0) { ISelectionSet layerSelection = ((FeatureLayer) iGeoFeaturelayers[i]).getSelectionSet(); ICursor[] cursors = new ICursor[1]; layerSelection.search(queryFilter, false, cursors); ICursor cursor = cursors[0]; feature = (IFeature) cursor.nextRow(); while (feature != null) { processFeature(feature, newLayer, xOffset * i, yOffset * i); feature = (IFeature) cursor.nextRow(); } Cleaner.release(cursor); } else { if (numSelectedMapFeatures == 0) { IFeatureCursor cursor = null; cursor = iGeoFeaturelayers[i].search(queryFilter, false); feature = cursor.nextFeature(); while (feature != null) { if (debug) System.out.println("Processing " + iGeoFeaturelayers[i].getFeatureClass().getAliasName()); processFeature(feature, newLayer, xOffset * i, yOffset * i); feature = cursor.nextFeature(); } Cleaner.release(cursor); } } } // This comment just because this is useful code to store somewhere at some point. // IDisplay id = docActiveView.getScreenDisplay(); // iGeoFeaturelayers[i].draw(esriDrawPhase.esriDPGeography, id, // null); //int ii = docActiveView.getScreenDisplay().getHWnd(); // Set the old layers as off in TOC. for (int i = 0; i < iGeoFeaturelayers.length; i++) { iGeoFeaturelayers[i].setVisible(false); } // Update map to reflect TOC changes. map.clearSelection(); docActiveView.contentsChanged(); mxDoc.updateContents(); docActiveView.refresh(); iwe.stopEditing(true); dialog.dispose(); } catch (AutomationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Does the bulk of the feature-level stuff. */ private void processFeature(IFeature feature, FeatureLayer newLayer, double xOffset, double yOffset) { try { if (debug) System.out.println(feature.getOID()); // Copy the points out of the original feature, then tranform them. IPolyline originalLine; originalLine = (IPolyline) feature.getShapeCopy(); IPointCollection originalPointsCopy = new Path(); originalPointsCopy .addPointCollection((IPointCollection) originalLine); // Debug check on original location. if (debug) { IPoint p = originalPointsCopy.getPoint(0); System.out.println(p.getX()); } ITransform2D docTransform2D = (ITransform2D) originalPointsCopy; docTransform2D.move(xOffset, yOffset); Feature newFeature = (Feature) newLayer.getFeatureClass().createFeature(); Polyline polylineNew = new Polyline(); polylineNew.addPointCollection(originalPointsCopy); // Just useful code. /** int numbPoints = originalPointsCopy.getPointCount(); ISpatialReference spatialReference = map.getSpatialReference(); Point newPoint = null; Point oldPoint = null; for (int i = 0; i < numbPoints; i++) { newPoint = new Point(); oldPoint = (Point) originalPointsCopy.getPoint(i); newPoint.project(spatialReference); newPoint.setX(oldPoint.getX() + xOffset); newPoint.setY(oldPoint.getY() + yOffset); polylineNew.updatePoint(i, newPoint); } **/ // Edit the new feature and save. iwe.startEditOperation(); newFeature.setShapeByRef(polylineNew); newFeature.store(); iwe.stopEditOperation(); // Debug check on final location. if (debug) { IPolyline polyline = (IPolyline) newFeature.getShapeCopy(); Path polylineTest = new Path(); polylineTest.addPointCollection((IPointCollection) polyline); IPoint p2 = polylineTest.getPoint(0); System.out.println(p2.getX()); } } catch (AutomationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // End of class }