arcgissamples\geodatabase\SimplifyShapefileGeometry.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.geodatabase; import java.io.File; import java.io.IOException; import com.esri.arcgis.datasourcesfile.ShapefileWorkspaceFactory; import com.esri.arcgis.geodatabase.Feature; import com.esri.arcgis.geodatabase.FeatureClass; import com.esri.arcgis.geodatabase.FeatureCursor; import com.esri.arcgis.geodatabase.Field; import com.esri.arcgis.geodatabase.Fields; import com.esri.arcgis.geodatabase.Workspace; import com.esri.arcgis.geodatabase.esriFeatureType; import com.esri.arcgis.geodatabase.esriFieldType; import com.esri.arcgis.geometry.IGeometry; import com.esri.arcgis.geometry.ITopologicalOperator2; import com.esri.arcgis.geometry.Multipoint; import com.esri.arcgis.geometry.Point; import com.esri.arcgis.geometry.Polygon; import com.esri.arcgis.geometry.Polyline; import com.esri.arcgis.geometry.esriGeometryType; import com.esri.arcgis.system.AoInitialize; import com.esri.arcgis.system.Cleaner; import com.esri.arcgis.system.EngineInitializer; import com.esri.arcgis.system.esriLicenseProductCode; import com.esri.arcgis.system.esriLicenseStatus; public class SimplifyShapefileGeometry { public SimplifyShapefileGeometry(){ } /** * Main Method - The console application entry point. * * @param args String[] Command line argument */ public static void main(String[] args){ System.out.println("Starting SimplifyShapefile - An ArcObjects SDK Developer Sample"); try{ //Initialize engine console application EngineInitializer.initializeEngine(); //Initialize ArcGIS license AoInitialize aoInit = new AoInitialize(); initializeArcGISLicenses(aoInit); //Get DEVKITHOME Home String devKitHome = System.getenv("AGSDEVKITJAVA"); //Data access setup String srcShapefilePath = devKitHome + "java" + File.separator + "samples" + File.separator + "data" + File.separator + "usa"; String srcShapefileName = "states.shp"; //Data output setup String simplifiedShapefilePath = getOutputDir() + File.separator + "simplifyshapefile"; String simplifiedShapefileName = "simplified.shp"; File simplifiedShapefilePathFile = new File(simplifiedShapefilePath); simplifiedShapefilePathFile.mkdir(); File simplifiedShapefileFile = new File(simplifiedShapefilePathFile, simplifiedShapefileName); if (simplifiedShapefileFile.exists()) { System.out.println("Output datafile already exists: " + simplifiedShapefileFile.getAbsolutePath()); System.out.println("Delete it (plus .shx and .dbf files) and rerun"); System.exit(-1); } SimplifyShapefileGeometry thisSampleApp = new SimplifyShapefileGeometry(); thisSampleApp.cleanShapefile(srcShapefilePath, srcShapefileName, simplifiedShapefilePath, simplifiedShapefileName); System.out.println("Done. Output shapefile created in " + simplifiedShapefileFile.getAbsolutePath()); //Ensure any ESRI libraries are unloaded in the correct order aoInit.shutdown(); }catch(Exception e){ System.out.println("Error: " + e.getMessage()); System.out.println("Sample failed. Exiting..."); e.printStackTrace(); System.exit(-1); } } /** * Checks to see if an ArcGIS Engine Runtime license or an ArcView License * is available. If so, then the appropriate ArcGIS License is initialized. * * @param aoInit The AoInitialize object instantiated in the main method. */ private static void initializeArcGISLicenses(AoInitialize aoInit) { try { if (aoInit.isProductCodeAvailable(esriLicenseProductCode.esriLicenseProductCodeEngine) == esriLicenseStatus.esriLicenseAvailable) aoInit.initialize(esriLicenseProductCode.esriLicenseProductCodeEngine); else if (aoInit.isProductCodeAvailable(esriLicenseProductCode.esriLicenseProductCodeArcView) == esriLicenseStatus.esriLicenseAvailable) aoInit.initialize(esriLicenseProductCode.esriLicenseProductCodeArcView); else{ System.err.println("Could not initialize an Engine or ArcView license. Exiting application."); System.exit(-1); } } catch (Exception e) {e.printStackTrace();} } /** * Create a clean shapefile from a potentially unclean one, * by cleaning each of its features. * * @param inPath path to the source shapefile * @param inName name of the source shapefile * @param outPath path to the clean shapefile * @param outName name of the clean shapefile * @throws IOException for most any error that could occur */ private void cleanShapefile(String inPath, String inName, String outPath, String outName) throws IOException { try { // Get the feature class for the input shapefile. FeatureClass inFeatureClass = getShapefileFeatureClass(inPath, inName); // Create a new feature class (and shapefile) FeatureClass outFeatureClass = createNewFeatureClass(inFeatureClass, outPath, outName); // Create output shapefile feature cursor and buffer, and output feature cursor FeatureCursor outFeatureCursor = new FeatureCursor(outFeatureClass.IFeatureClass_insert(true)); Feature outFeatureBuffer = (Feature) outFeatureClass.createFeatureBuffer(); FeatureCursor featureCursor = new FeatureCursor(inFeatureClass.search(null, true)); // Using the feature cursors loop through each feature in the input feature class // creating a simplified shape geometry for it, and cause it to be written to the output // feature class. int totalFeatureCount = inFeatureClass.featureCount(null); int featureCount = 1; Feature feature = (Feature) featureCursor.nextFeature(); while (feature != null) { // If the feature has an invalid shape, create a new empty one if (feature.getShape() == null) { feature.setShapeByRef(createNewGeometry(outFeatureClass)); } // The topological operator methods are needed to simplify this // feature, and so we do some casting here to get access to those // methods. The feature has a shape, such as polygon or polyline, // but we don't know which shape it is, and we don't care, as long // as it implements those methods. Note that though we cast to // an ITopologicalOperator2. Note that Point features, and // other features will cause an exception to be thrown, since these // cannot be cleaned. Only polygon, polyline, multipoint, and // multipatch geometries can be cleaned. IGeometry srcShapeGeometry = feature.getShape(); if (!(srcShapeGeometry instanceof ITopologicalOperator2)) { continue; } ITopologicalOperator2 simplifiedShape = (ITopologicalOperator2) srcShapeGeometry; simplifiedShape.setIsKnownSimple(false); simplifiedShape.simplify(); // Copy the field values of the original feature to the new feature, except // for OID and geometry fields, which should be different from the original. Fields fields = (Fields) feature.getFields(); for (int fieldCount = 0; fieldCount < fields.getFieldCount(); fieldCount++) { Field field = (Field) fields.getField(fieldCount); if ((field.getType() != esriFieldType.esriFieldTypeGeometry) && (field.getType() != esriFieldType.esriFieldTypeOID) && (field.isEditable())) { outFeatureBuffer.setValue(fieldCount, feature.getValue(fieldCount)); } } outFeatureBuffer.setShapeByRef((IGeometry)simplifiedShape); outFeatureCursor.insertFeature(outFeatureBuffer); System.out.println(featureCount + " of " + totalFeatureCount + " features processed."); featureCount++; feature = (Feature) featureCursor.nextFeature(); } outFeatureCursor.flush(); Cleaner.release(outFeatureCursor); outFeatureBuffer = null; outFeatureCursor = null; }catch (IOException e) { System.out.println("Error cleaning or creating shapefile."); throw e; } } /** * Get the shapefile feature class for a data path and feature class name. * Note that point feature shapefiles will not be processed. An exception * will be thrown later. * * @param path path to the shapefile * @param name the feature class name * @return IFeatureClass object representing the shapefile feature class * @throws IOException if feature class could not be obtained */ private FeatureClass getShapefileFeatureClass(String path, String name) throws IOException { try { ShapefileWorkspaceFactory shapefileWorkspaceFactory = new ShapefileWorkspaceFactory(); Workspace workspace = new Workspace(shapefileWorkspaceFactory.openFromFile(path, 0)); FeatureClass featureClass = new FeatureClass(workspace.openFeatureClass(name)); if (featureClass.getShapeType() == esriGeometryType.esriGeometryPoint) { System.out.println("Point feature shapefiles are not processed."); System.out.println("Exiting..."); System.exit(-1); } return featureClass; }catch (IOException e) { System.out.println("Couldn't access feature class :" + name + " in " + path); throw e; } } /** * Get a shapefile's workspace, creating it if necessary. * * @param path the path to the shapefile * @return IFeatureWorkspace the feature workspace for the specified path * @throws IOException */ private Workspace getShapefileWorkspace(String path) throws IOException { try{ ShapefileWorkspaceFactory shapefileWorkspaceFactory = new ShapefileWorkspaceFactory(); Workspace workspace = new Workspace(shapefileWorkspaceFactory.openFromFile(path, 0)); return workspace; }catch (IOException e) { System.out.println("Couldn't access feature workspace for shapefile data path: " + path); throw e; } } /** * Create a new output shapefile's feature class based on the fields of * an input feature class. * * @param inFeatureClass feature class of input shapefile * @param outPath path of output shapefile * @param outName name of output shapefile * @return IFeatureClass object representing the output shapefile's feature class * @throws IOException if couldn't create a new shapefile */ private FeatureClass createNewFeatureClass(FeatureClass inFeatureClass, String outPath, String outName) throws IOException { try { Workspace workspace = getShapefileWorkspace(outPath); // Clone the fields from the input feature class to be used in the new feature class Fields fields = (Fields) inFeatureClass.getFields(); Fields clonedFields = (Fields) fields.esri_clone(); FeatureClass newFeatureClass = new FeatureClass(workspace.createFeatureClass(outName, clonedFields, null, null, esriFeatureType.esriFTSimple, inFeatureClass.getShapeFieldName(), "")); return newFeatureClass; }catch (IOException e) { System.out.println("Couldn't create new shapefile."); throw e; } } /** * Create an object having the geometry that matches a feature class' shape type, * and return its IGeometry interface. * * @param featureClass * @return IGeometry the geometry interface of the geometric element created * @throws IOException if couldn't create the geometric element */ private IGeometry createNewGeometry(FeatureClass featureClass) throws IOException { try { switch (featureClass.getShapeType()) { case esriGeometryType.esriGeometryPoint: return new Point(); case esriGeometryType.esriGeometryMultipoint: return new Multipoint(); case esriGeometryType.esriGeometryPolyline: return new Polyline(); case esriGeometryType.esriGeometryPolygon: return new Polygon(); } return null; }catch (IOException e) { System.out.println("Couldn't create the geometric element."); throw e; } } /** * Convenience method to generate an output directory based on the operating * system that the sample is being executed on. * * @return A path to the new directory is return */ private static String getOutputDir() { String userDir; //Get the operating systems user profile or home location depending //on which operating system this sample is executed on. if(System.getProperty("os.name").toLowerCase().indexOf("win") > -1){ userDir = System.getenv("UserProfile"); }else{ userDir = System.getenv("HOME"); } String outputDir = userDir + File.separator + "arcgis_sample_output"; System.out.println("Creating output directory - " + outputDir); new File(outputDir).mkdir(); return outputDir; } }