/** * LineTypeLengths.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.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.text.DateFormat; import java.util.Date; import com.esri.arcgis.addins.desktop.Button; import com.esri.arcgis.arcmapui.IMxDocument; import com.esri.arcgis.carto.IAttributeTable; import com.esri.arcgis.carto.IGeoFeatureLayer; import com.esri.arcgis.carto.IMap; import com.esri.arcgis.carto.TopologyLayer; import com.esri.arcgis.framework.IApplication; import com.esri.arcgis.framework.IDocument; import com.esri.arcgis.geodatabase.IEnumTopologyEdge; import com.esri.arcgis.geodatabase.IFeature; 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.IQueryFilter; import com.esri.arcgis.geodatabase.ITopology; import com.esri.arcgis.geodatabase.ITopologyEdge; import com.esri.arcgis.geodatabase.ITopologyGraph; import com.esri.arcgis.geodatabase.IWorkspace; import com.esri.arcgis.geodatabase.IWorkspaceProxy; import com.esri.arcgis.geodatabase.QueryFilter; import com.esri.arcgis.geometry.IGeometry; import com.esri.arcgis.geometry.Polygon; import com.esri.arcgis.geometry.Polyline; import com.esri.arcgis.interop.AutomationException; import com.esri.arcgis.interop.Cleaner; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; /** * ArcGIS button addin to calculate edge length and area statistics for each boundary type and totals. * Note the areas taken are square and not the convex hull, which may or may not skew statistics. * * @author Andrew Evans * @version 0.1 */ public class LineTypeLengths extends Button { 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 = true; // 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; // 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(); initProgressBar(); lineTypeDensities(); } /** * 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, "Line Type Densities"); dialog.getContentPane().add(center_panel, BorderLayout.CENTER); dialog.pack(); dialog.setVisible(true); dialog.setLocationRelativeTo(null); // centre on screen dialog.toFront(); // raise above other java windows } /** * 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(); } /** * Method for listing length / area statistics associated with polylines. * Note the areas taken are square and not the convex hull, which will skew statistics one way or another. * Reports Type, number of polylines of that type, total length of all lines, total length of topology, * total rectangular area, total length of polylines of that type, rectangular area encompassing that type. * * @todo Need to think about double counting and statistics - unlikely to skew minimums, as minimum distances can be less for neighbour, but maximums? */ private void lineTypeDensities() { try { // Init necessary storage variables. pb.setValue(0); if (debug) System.out.println("Starting lineTypeLengths analysis"); String[] names = new String[iGeoFeaturelayers.length]; double[] lengths = new double[iGeoFeaturelayers.length]; double[] areas = new double[iGeoFeaturelayers.length]; double totalLengthTopo = 0; double totalLengthAll = 0; double xMax = -1; double xMin = -1; double yMax = -1; double yMin = -1; int[] n = new int[iGeoFeaturelayers.length]; double maxArea = 0; // iTopologyGraph.getBuildExtent().getHeight() * iTopologyGraph.getBuildExtent().getWidth(); -- gives zoom extent IQueryFilter queryFilter = new QueryFilter(); IFeature feature = null; IFeatureCursor cursor = null; // Calc topolength IEnumTopologyEdge iEnumTopologyEdges = iTopologyGraph.getEdges(); iEnumTopologyEdges.reset(); ITopologyEdge iTopologyEdge = iEnumTopologyEdges.next(); while (iTopologyEdge != null) { totalLengthTopo = totalLengthTopo + ((Polyline)iTopologyEdge.getGeometry()).getLength(); iTopologyEdge = iEnumTopologyEdges.next(); } if (debug) System.out.println("topolength = " + totalLengthTopo); // Run through layers. double featureLength = 0; for (int i = 0; i < iGeoFeaturelayers.length; i++) { pb.setValue((int)((50.0 / iGeoFeaturelayers.length) * i)); names[i] = iGeoFeaturelayers[i].getFeatureClass().getAliasName(); if (debug) System.out.println("Processing " + names[i]); areas[i] = iGeoFeaturelayers[i].getAreaOfInterest().getHeight() * iGeoFeaturelayers[i].getAreaOfInterest().getWidth(); n[i] = ((IAttributeTable)iGeoFeaturelayers[i]).getAttributeTable().rowCount(queryFilter); cursor = iGeoFeaturelayers[i].search (queryFilter, false); feature = cursor.nextFeature(); while (feature != null) { featureLength = ((Polyline)feature.getShape()).getLength(); lengths[i] = lengths[i] + featureLength; totalLengthAll = totalLengthAll + featureLength; feature = cursor.nextFeature(); } Cleaner.release(cursor); } // Write results File directory = ChangeOutputDirectory.getInstance().getDirectory(); if (debug) System.out.println("Proposed Directory = " + directory); Date now = new Date(System.currentTimeMillis()); String dateString = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(now); String title = ((IDocument)mxDoc).getTitle(); dateString = dateString.replaceAll("[ :]","-"); // Remove some of the date format not allowed in filenames. title = title.replaceAll("[\\/:*?<>|]", ""); // Remove any illegal filename characters from map name. String filepath = directory.getAbsolutePath() + File.separator + title.substring(0,title.lastIndexOf(".")) + "-LineTypeLengths-" + dateString + ".csv"; if (debug) System.out.println("Directory = " + filepath); FileWriter fw = new FileWriter(new File (filepath)); BufferedWriter bw = new BufferedWriter(fw); bw.write("Type,n,totalLengthAll,totalLengthTopo,bltLength,bltRectArea"); bw.newLine(); for (int i = 0; i < iGeoFeaturelayers.length; i++) { bw.write(names[i] + "," + n[i] + ","); bw.write(totalLengthAll + "," + totalLengthTopo + "," + lengths[i] + "," + areas[i]); bw.newLine(); } bw.flush(); bw.close(); dialog.dispose(); } catch (AutomationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }