// Other needed: boundary combination orientations // path analysis tools - based on calc shortest paths /** * BoundaryTypeAnalyst.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/ * * --End of Copyright notice-- * **/ // Line type statistics package uk.ac.leeds.ccg.boundarytypeanalyst; import java.io.*; import java.util.Properties; import com.esri.arcgis.addins.desktop.Extension; import com.esri.arcgis.arcmapui.*; import com.esri.arcgis.carto.*; import com.esri.arcgis.catalog.IGxCatalogDefaultDatabase; import com.esri.arcgis.datasourcesGDB.FileGDBWorkspaceFactory; import com.esri.arcgis.datasourcesfile.ShapefileWorkspaceFactory; import com.esri.arcgis.framework.*; import com.esri.arcgis.geodatabase.*; import com.esri.arcgis.geometry.IEnvelope; import com.esri.arcgis.interop.AutomationException; import com.esri.arcgis.system.IName; /** * ArcGIS extension to calculate various topological statistics. * * @author Andrew Evans * @version 0.1 */ public class BoundaryTypeAnalyst extends Extension { private static BoundaryTypeAnalyst bta = null; 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; // Set true for messages private boolean select = false; // Set true to select treated elements on the map for debugging private String directoryString = null; // Initialisation methods ------------------------------------------------------- /** * Public constructor, but for Singleton. Do not use. * Note that unlike a usual singleton the constructor needs to * be public for ArcGIS to work its addIn magic. **/ public BoundaryTypeAnalyst() { bta = this; } /** * Singleton access method. **/ public static BoundaryTypeAnalyst getInstance() { return bta; } /** * Initializes this application extension with the ArcMap application instance it is hosted in. * * This method is automatically called by the host ArcMap application. * It marks the start of the dockable window's lifecycle. * Clients must not call this method. * * @param app is a reference to ArcMap's IApplication interface * @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 init(IApplication app) throws IOException, AutomationException { this.app = app; mxDoc = (IMxDocument)app.getDocument(); //Set up an event to respond to a new document event in ArcMap. ((MxDocument)mxDoc).addIDocumentEventsListener(new IDocumentEventsAdapter(){ @Override public void openDocument(IDocumentEventsOpenDocumentEvent e){ try { map = mxDoc.getFocusMap(); if (map.getLayerCount() > 1) { initialiseMapVariables(); } } catch (AutomationException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } } }); } /** * Sets up map objects, feature class and layer arrays. */ public void initialiseMapVariables(){ try { // Set up arrays of the feature layers (- topology layer) and their classes. iGeoFeaturelayers = new IGeoFeatureLayer[map.getLayerCount() - 1]; iFeatureClassProxys = new IFeatureClassProxy[map.getLayerCount()]; // Loop through layers and set up the above arrays. Also find topology layer. ILayer iLayer = null; int countFeatureLayers = 0; for (int i=0; i < map.getLayerCount(); i++) { iLayer = map.getLayer(i); if (iLayer instanceof TopologyLayer) { topologyLayer = (TopologyLayer) map.getLayer(i); if (debug) System.out.println("topologyLayer = " + topologyLayer.getName()); } else { iGeoFeaturelayers[countFeatureLayers] = (IGeoFeatureLayer) map.getLayer(i); iFeatureClassProxys[countFeatureLayers] = (IFeatureClassProxy) iGeoFeaturelayers[countFeatureLayers].getFeatureClass(); if (debug) System.out.println("iGeoFeaturelayer = " + iGeoFeaturelayers[countFeatureLayers].getName()); if (debug) System.out.println("iFeatureClassProxys = " + iFeatureClassProxys[countFeatureLayers].getAliasName()); countFeatureLayers++; } } // Set up the workspace. ifeatureDatasetProxyGot = (IFeatureDatasetProxy) iGeoFeaturelayers[0].getFeatureClass().getFeatureDataset(); if (ifeatureDatasetProxyGot == null) { IWorkspaceFactory workspaceFactory = new FileGDBWorkspaceFactory () ; IWorkspaceName workspaceName = workspaceFactory.create("c:\temp","tempGDB",null,0); IName name = (IName) workspaceName; iWorkspace = (IWorkspace) name.open(); System.out.println(iWorkspace.getPathName()); } else { iWorkspaceProxy = (IWorkspaceProxy) ifeatureDatasetProxyGot.getWorkspace(); IWorkspaceFactory wf = iWorkspaceProxy.getWorkspaceFactory(); iWorkspace = wf.openFromFile(iWorkspaceProxy.getPathName(), 0); System.out.println(iWorkspaceProxy.getPathName()); } ifeatureWorkspace = (IFeatureWorkspace)iWorkspace; // Unused alternative... //ifeatureDatasetProxyOpened = (IFeatureDatasetProxy) ifeatureWorkspace.openFeatureDataset("Winchester"); // Set up topology and graph. it = topologyLayer.getTopology(); iTopologyGraph = (ITopologyGraph) it.getCache(); IEnvelope ie =((Map)map).getExtent(); iTopologyGraph.build(ie, true); ie = iTopologyGraph.getBuildExtent(); if (debug) System.out.println("Build extent width = " + ie.getWidth()); ie = iTopologyGraph.getExtent(); if (debug) System.out.println("Extent width = " + ie.getWidth()); } catch (AutomationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // Accessor/Mutator methods ------------------------------------------------------- /** * Convenience method for returning all the system and map variables you * might need in one go. The code to get the variables is: *

* *

	 * 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();
	 * 
*

* debug allows debugging console messages.
* select allows map elements to be selected as the code runs - for * debugging * * @return Object array containing variables - see details. */ public Object[] getVariables() { Object[] variables = new Object[15]; variables[0] = (Object) app; variables[1] = (Object) mxDoc; variables[2] = (Object) map; variables[3] = (Object) iGeoFeaturelayers; variables[4] = (Object) topologyLayer; variables[5] = (Object) ifeatureDatasetProxyGot; variables[6] = (Object) iWorkspaceProxy; variables[7] = (Object) iWorkspace; variables[8] = (Object) ifeatureWorkspace; variables[9] = (Object) ifeatureDatasetProxyOpened; variables[10] = (Object) iFeatureClassProxys; variables[11] = (Object) it; variables[12] = (Object) iTopologyGraph; variables[13] = (Object) new Boolean(debug); variables[14] = (Object) new Boolean(select); return variables; } /** * Method to get the output directory. * Returns null if this can't be read from the properties file. * @see readProperties() * @return Path to output directory. */ public String getDirectoryString() { return directoryString; } // Utility methods ------------------------------------------------------- /** * Method to read properties from a file in the directory in which the default geodatabase resides. * If it can't read the file it quietly returns with defaults. Ideally it would check the default geodatabase * with the users, but the use cases are complicated. * This method is called by external classes, in part because calling it at document openning isn't helpful - * there seems to be no guarentee that other addin classes are available to receive the data. */ public void readProperties() { IGxCatalogDefaultDatabase ig = (IGxCatalogDefaultDatabase) app; Properties properties = new Properties(); FileInputStream fis = null; try { String defaultPath = ig.getDefaultDatabaseName().getPathName(); defaultPath = defaultPath.substring(0, defaultPath.lastIndexOf(File.separator)); File propertiesFile = new File(defaultPath + File.separator + "boundaryTypeAnalyst.properties"); if (propertiesFile.exists() && propertiesFile.canRead()) { fis = new FileInputStream(propertiesFile); properties.load(fis); fis.close(); directoryString = properties.getProperty("OutputDirectory"); if (debug) System.out.println("Properties read from " + defaultPath + File.separator + "boundaryTypeAnalyst.properties"); } else { directoryString = null; // Default - forces use of the user directory. } } catch (AutomationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * Method to write properties file to the directory in which the default geodatabase resides. * If it can't write to the file it quietly returns. Ideally it would reset the default geodatabase * but the use cases are complicated. * This method is called by external classes, in part because calling it at shutdown didn't seem to * work, but also because the crash-rate of Arc means it is better to record properties as they change. */ public void writeProperties() { IGxCatalogDefaultDatabase ig = (IGxCatalogDefaultDatabase) app; FileOutputStream fos = null; Properties properties = new Properties(); properties.put("OutputDirectory", ChangeOutputDirectory.getInstance().getDirectory().getAbsolutePath()); try { String defaultPath = ig.getDefaultDatabaseName().getPathName(); defaultPath = defaultPath.substring(0, defaultPath.lastIndexOf(File.separator)); File propertiesFile = new File(defaultPath + File.separator + "boundaryTypeAnalyst.properties"); fos = new FileOutputStream(defaultPath + File.separator + "boundaryTypeAnalyst.properties"); properties.store(fos, null); fos.close(); if (debug) System.out.println("Properties written to " + defaultPath + File.separator + "boundaryTypeAnalyst.properties"); } catch (AutomationException e) { e.printStackTrace(); } catch (IOException e) { if (debug) System.out.println("Can't write properties file"); } } /** * Method for listing the FeatureDataSet and Topology names */ private void getTopologyNames() { try { FeatureDatasetName ifdn = (FeatureDatasetName)ifeatureDatasetProxyGot.getFullName(); System.out.println("name = " + ifdn.getName()); System.out.println("name = " + ifdn.getTopologyNames().next().getName()); } catch (Exception e) { e.printStackTrace(); } } // End of class }