arcgissamples\geodatabase\SimplifyShapefileGeometry.java—ArcObjects 10.4 Help for Java | ArcGIS for Desktop
Simplify feature geometry for a shapefile
arcgissamples\geodatabase\SimplifyShapefileGeometry.java
/* Copyright 2015 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 at <your ArcGIS install location>/DeveloperKit10.4/userestrictions.txt.
* 
*/
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 Basic 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.esriLicenseProductCodeBasic) 
          == esriLicenseStatus.esriLicenseAvailable)
        aoInit.initialize(esriLicenseProductCode.esriLicenseProductCodeBasic);
      else{
        System.err.println("Could not initialize an Engine or Basic 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;
  }
}