Select features using spatial relationships
arcgissamples\geodatabase\SelectFeatures.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.carto.FeatureLayer;
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.SpatialFilter;
import com.esri.arcgis.geodatabase.Workspace;
import com.esri.arcgis.geodatabase.esriSpatialRelEnum;
import com.esri.arcgis.geometry.Envelope;
import com.esri.arcgis.system.AoInitialize;
import com.esri.arcgis.system.EngineInitializer;
import com.esri.arcgis.system.esriLicenseProductCode;
import com.esri.arcgis.system.esriLicenseStatus;

public class SelectFeatures {

  public SelectFeatures(){
    
  }
  
  /**
   * Main Method - The console application entry point.
   * 
   * @param args String[] Command line argument
   */
  public static void main(String[] args) {
    System.out.println("Starting SpatialRelation - 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 inPath = devKitHome + "java" + File.separator + "samples" + File.separator 
                     + "data" + File.separator + "usa";
      String name = "states.shp";
      
      SelectFeatures selectFeatures = new SelectFeatures();
      selectFeatures.processFeatures(inPath, name);
      
      System.out.println("Done.");      
      
      //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();}
  }

  /**
   * Process features using a spatial relation description string as a spatial filter.
   *
   * @param path shapefile path
   * @param name shapefile name
   * @throws IOException if cannot get shapefile related information.
   */
  private void processFeatures(String path, String name) throws IOException {
    try {
      System.out.println("Using shapefile " + name);

      // Get the feature class and create a feature layer for this shapefile
      // to add selected features to.
      FeatureClass featureClass = getShapefileFeatureClass(path, name);
      
      FeatureLayer featureLayer = new FeatureLayer();
      featureLayer.setFeatureClassByRef(featureClass);
      
      // Create a spatial filter to use for selecting features from this feature class.
      SpatialFilter spatialFilter = createSpatialFilter(featureClass);

      // Perform the search/query/comparison using the spatial filter,
      // creating a feature cursor representing all features passing it,
      // and add those features to the layer.
      int featureCtr = 0;
      FeatureCursor featureCursor = new FeatureCursor(featureClass.search(spatialFilter, false));
      
      Feature feature = (Feature) featureCursor.nextFeature();
      while (feature != null) {
        featureLayer.add(feature);
        
        feature = (Feature) featureCursor.nextFeature();
        
        featureCtr++;
        
        System.out.println("Features added to layer: " + featureCtr + " out of " + featureClass.featureCount(null));
      }
    }catch (IOException e) {
      System.out.println("Could not process shapefile.");
      throw e;
    }
  }
  
  /**
   * Create a spatial filter based on the first feature of a feature class.
   *
   * @param featureClass the feature class containing the feature to use to query against.
   * @return SpatialFilter the spatial filter based on the feature and certain relationships.
   * @throws IOException if couldn't create the spatial filter.
   */
  private SpatialFilter createSpatialFilter(FeatureClass featureClass) throws IOException {
    try {
      // Create an envelope polygon from the first feature.
      Envelope polygon = (Envelope) featureClass.getFeature(0).getExtent();
      
      //Create the spatial relation description string containing "T|F|*" codes
      //to define the relationship between two geometries and their
      //geometric interior, boundary, and exterior relationships, such that
      //it would find those features that intersect with the envelope polygon.
      final String spatialRelationDescription = "TT*TT****";
      
      // Create a spatial filter based on the spatial relation description
      // and the envelope polygon.
      SpatialFilter spatialFilter = new SpatialFilter();
      spatialFilter.setGeometryByRef(polygon);
      spatialFilter.setSpatialRel(esriSpatialRelEnum.esriSpatialRelRelation);
      spatialFilter.setSpatialRelDescription(spatialRelationDescription);
      spatialFilter.setGeometryField(featureClass.getShapeFieldName());
      
      return spatialFilter;
    }catch (IOException e) {
      System.out.println("Couldn't create the spatial filter.");
      throw e;
    }
  }

  /**
   * Get the shapefile feature class for a data path and feature class name.
   *
   * @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 {
    FeatureClass featureClass = null;
    
    try {
      ShapefileWorkspaceFactory shapefileWorkspaceFactory = new ShapefileWorkspaceFactory();
      
      Workspace workspace = new Workspace(shapefileWorkspaceFactory.openFromFile(path, 0));
      
      featureClass = new FeatureClass(workspace.openFeatureClass(name));
    }catch (IOException e) {
      System.out.println("Couldn't access feature class :" + name + " in " + path);
      throw e;
    }
    
    return featureClass;
  }
}