/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * Copyright (C) 2003 Vivid Solutions * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.vividsolutions.jump.workbench.ui.plugin; import java.util.Iterator; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jump.feature.AttributeType; import com.vividsolutions.jump.feature.BasicFeature; import com.vividsolutions.jump.feature.Feature; import com.vividsolutions.jump.feature.FeatureDataset; import com.vividsolutions.jump.feature.FeatureSchema; import com.vividsolutions.jump.util.StringUtil; import com.vividsolutions.jump.workbench.WorkbenchContext; import com.vividsolutions.jump.workbench.model.Layer; import com.vividsolutions.jump.workbench.model.StandardCategoryNames; import com.vividsolutions.jump.workbench.plugin.AbstractPlugIn; import com.vividsolutions.jump.workbench.plugin.EnableCheckFactory; import com.vividsolutions.jump.workbench.plugin.MultiEnableCheck; import com.vividsolutions.jump.workbench.plugin.PlugInContext; import com.vividsolutions.jump.workbench.ui.MenuNames; /** * Computes various statistics for selected layers. */ public class FeatureStatisticsPlugIn extends AbstractPlugIn { public static final String nPtsAttr = "nPts"; public static final String nHolesAttr = "nHoles"; public static final String nCompsAttr = "nComponents"; public static final String areaAttr = "area"; public static final String lengthAttr = "length"; public static final String typeAttr = "type"; private static final String jtsGeometryClassPackagePrefix = "com.vividsolutions.jts.geom"; public FeatureStatisticsPlugIn() { } public void initialize(PlugInContext context) throws Exception { FeatureInstaller featureInstaller = new FeatureInstaller(context.getWorkbenchContext()); featureInstaller.addMainMenuItem( this, //exe new String[] {MenuNames.TOOLS, MenuNames.STATISTICS}, //menu path this.getName() + "...", //name methode .getName recieved by AbstractPlugIn false, //checkbox null, //icon createEnableCheck(context.getWorkbenchContext())); //enable check } public static MultiEnableCheck createEnableCheck(WorkbenchContext workbenchContext) { EnableCheckFactory checkFactory = new EnableCheckFactory(workbenchContext); return new MultiEnableCheck() .add(checkFactory.createWindowWithLayerNamePanelMustBeActiveCheck()) .add(checkFactory.createAtLeastNLayersMustBeSelectedCheck(1)); } public static FeatureSchema getStatisticsSchema() { FeatureSchema featureSchema = new FeatureSchema(); featureSchema.addAttribute("GEOMETRY", AttributeType.GEOMETRY); featureSchema.addAttribute(nPtsAttr, AttributeType.INTEGER); featureSchema.addAttribute(nHolesAttr, AttributeType.INTEGER); featureSchema.addAttribute(nCompsAttr, AttributeType.INTEGER); featureSchema.addAttribute(areaAttr, AttributeType.DOUBLE); featureSchema.addAttribute(lengthAttr, AttributeType.DOUBLE); featureSchema.addAttribute(typeAttr, AttributeType.STRING); return featureSchema; } /** * Removes the JTS geometry package prefix from a classname * @param fullClassName * @return the simplified class name */ public static String removeGeometryPackage(String fullClassName) { if (fullClassName.startsWith(jtsGeometryClassPackagePrefix)) { return StringUtil.classNameWithoutQualifiers(fullClassName); } else { return fullClassName; } } public boolean execute(PlugInContext context) throws Exception { //Call #getSelectedLayers before #clear, because #clear will surface //output window. [Jon Aquino] Layer[] selectedLayers = context.getSelectedLayers(); for (int i = 0; i < selectedLayers.length; i++) { featureStatistics(selectedLayers[i], context); } return true; } private void featureStatistics(final Layer layer, PlugInContext context) { FeatureSchema statsSchema = getStatisticsSchema(); FeatureDataset statsFC = new FeatureDataset(statsSchema); for (Iterator i = layer.getFeatureCollectionWrapper().iterator(); i.hasNext();) { Feature f = (Feature) i.next(); Geometry g = f.getGeometry(); double area = g.getArea(); double length = g.getLength(); // these both need work - need to recurse into geometries // work done by mmichaud on 2010-12-12 //int comps = 0; //int holes = 0; int[] comps_and_holes = new int[]{0,0}; comps_and_holes = recurse(g, comps_and_holes); int comps = comps_and_holes[0]; int holes = comps_and_holes[1]; //if (g instanceof GeometryCollection) { // comps = ((GeometryCollection) g).getNumGeometries(); //} Coordinate[] pts = g.getCoordinates(); //int holes = 0; // //if (g instanceof Polygon) { // holes = ((Polygon) g).getNumInteriorRing(); //} Feature statsf = new BasicFeature(statsSchema); // this aliases the geometry of the input feature, but this shouldn't matter, // since if geometries are edited they should be completely replaced statsf.setAttribute("GEOMETRY", g); statsf.setAttribute(nPtsAttr, new Integer(pts.length)); statsf.setAttribute(nHolesAttr, new Integer(holes)); statsf.setAttribute(nCompsAttr, new Integer(comps)); statsf.setAttribute(areaAttr, new Double(area)); statsf.setAttribute(lengthAttr, new Double(length)); statsf.setAttribute(typeAttr, removeGeometryPackage(g.getClass().getName())); statsFC.add(statsf); } Layer statsLayer = context.addLayer(StandardCategoryNames.QA, "Statistics-" + layer.getName(), statsFC); statsLayer.setStyles(layer.cloneStyles()); } private int[] recurse(Geometry g, int[] comps_holes) { if (g instanceof GeometryCollection) { for (int i = 0 ; i < g.getNumGeometries() ; i++) { comps_holes = recurse(g.getGeometryN(i), comps_holes); } } else { comps_holes[0]++; if (g instanceof Polygon) { comps_holes[1] += ((Polygon)g).getNumInteriorRing(); } } return comps_holes; } }