Clip shapefile by envelope
ClipShapefileByEnv.cpp
// Copyright 2011 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.
// 

  
#include "ClipShapefileByEnv.h"

// Hardcode in the clipping extent
const double c_xMin = -130.0;
const double c_xMax = -114.0;
const double c_yMin = 31.0;
const double c_yMax = 41.5;

int main(int argc, char **argv)
{
  std::cerr << "ClipShapefileByEnv - Environmental Systems Research Institute" 
            << std::endl << std::endl;
  
  if (argc != 3)
  {
    std::cerr << "Usage: ClipShapefileByEnv [input shapefile] [output shapefile]"
              << std::endl;
    AoExit(0);
  }
  char* input = argv[1];
  char* output = argv[2];
  
  if (!InitializeApp())
  {
    AoExit(0);
  }
  
  ClipFile(input, output);
  
  ShutdownApp();
  AoExit(0);
}

HRESULT ClipFile(char* input, char* output)
{
  // path parsing
  CComBSTR srcPath;
  CComBSTR srcName;
  CComBSTR outPath;
  CComBSTR outName;
  HRESULT hr = GetParentDirFromFullPath(input, &srcPath);
  if (FAILED(hr) || srcPath.Length() <= 0)
  {
    std::cerr << "Couldn't get input path." << std::endl;
    return E_FAIL;
  }
  hr = GetFileFromFullPath(input, &srcName);
  if (FAILED(hr) || srcName.Length() <= 0)
  {
    std::cerr << "Couldn't get input file name." << std::endl;
    return E_FAIL;
  }
  hr = GetParentDirFromFullPath(output, &outPath);
  if (FAILED(hr) || outPath.Length() <= 0)
  {
    std::cerr << "Couldn't get output path." << std::endl;
    return E_FAIL;
  }
  hr = GetFileFromFullPath(output, &outName);
  if (FAILED(hr) || outName.Length() <= 0)
  {
    std::cerr << "Couldn't get output file name." << std::endl;
    return E_FAIL;
  }

  // Open the Source shapefile
  IWorkspaceFactoryPtr ipWkspFactory(CLSID_ShapefileWorkspaceFactory);
  IWorkspacePtr ipWksp;
  hr = ipWkspFactory->OpenFromFile(srcPath, 0, &ipWksp);
  if (FAILED(hr) || ipWksp == 0)
  {
    std::wcerr << L"Couldn't open workspace " << (BSTR) srcPath << std::endl;
    return E_FAIL;
  }
  IFeatureClassPtr ipSrcFeatureClass;
  hr = ((IFeatureWorkspacePtr) ipWksp)->OpenFeatureClass(srcName, 
                                                         &ipSrcFeatureClass);
  if (FAILED(hr) || ipSrcFeatureClass == 0)
  {
    std::wcerr << L"Couldn't open feature class " << (BSTR) srcName << std::endl;
    return E_FAIL;
  }

  // Create the target clip shapefile
  IWorkspaceFactoryPtr ipTargetWkspFac(CLSID_ShapefileWorkspaceFactory);
  IWorkspacePtr ipTargetWksp;
  hr = ipTargetWkspFac->OpenFromFile(outPath, 0, &ipTargetWksp);
  if (FAILED(hr) || ipTargetWksp == 0)
  {
    std::wcerr << L"Couldn't open target workspace " << (BSTR) outPath << std::endl;
    return E_FAIL;
  }
  // Get all the details of the source feature class to 
  //     create the target feature class
  IFieldsPtr ipSrcFields;
  ipSrcFeatureClass->get_Fields(&ipSrcFields);
  IUIDPtr ipSrcUID;
  ipSrcFeatureClass->get_CLSID(&ipSrcUID);
  IUIDPtr ipSrcExtUID;
  ipSrcFeatureClass->get_EXTCLSID(&ipSrcExtUID);
  esriFeatureType eFeatureType;
  ipSrcFeatureClass->get_FeatureType(&eFeatureType);
  CComBSTR bstrName;
  ipSrcFeatureClass->get_ShapeFieldName(&bstrName);
  // Create the target shape file
  IFeatureClassPtr ipTargetFC;
  ((IFeatureWorkspacePtr) ipTargetWksp)->CreateFeatureClass(outName, 
                                                            ipSrcFields, 
                                                            ipSrcUID, 
                                                            ipSrcExtUID, 
                                                            eFeatureType, 
                                                            bstrName, 
                                                            CComBSTR(L""), 
                                                            &ipTargetFC);

  // Create Clip Envelop
  IEnvelopePtr ipEnv(CLSID_Envelope);  
  ipEnv->PutCoords(c_xMin, c_yMin, c_xMax, c_yMax);
 
  // Define a spatial query to get only the clip area
  ISpatialFilterPtr ipFilter(CLSID_SpatialFilter);
  IEnvelopePtr ipNewEnv;
  ipEnv->get_Envelope(&ipNewEnv);
  ipFilter->putref_Geometry((IGeometryPtr) ipNewEnv);
  ipFilter->put_GeometryField(bstrName);
  ipFilter->put_SpatialRel(esriSpatialRelIntersects);
  
  // IFeatureCursor interface provides access to a set of features in a feature
  //   class. Get a cursor based on the spatial query
  IFeatureCursorPtr ipFeatureCursor;
  ipSrcFeatureClass->Search((IQueryFilterPtr) ipFilter, 
                            VARIANT_TRUE, &ipFeatureCursor);
  // Loop over all the features and copy them over to the new shapefile
  // Use a feature buffer to insert copied features for performance benefit
  IFeatureCursorPtr ipInsertCursor;
  ipTargetFC->Insert(VARIANT_TRUE, &ipInsertCursor);
  IGeometryPtr ipGeometry;
  IFeatureBufferPtr ipBuffer;
  ipTargetFC->CreateFeatureBuffer(&ipBuffer);
  IFeaturePtr ipFeature;
  IGeometryPtr ipOutGeom;
  while (ipFeatureCursor->NextFeature(&ipFeature) == S_OK && (ipFeature != 0))
  {
    std::cerr << " . ";

    // Get the shape and source to clip it
    ipFeature->get_ShapeCopy(&ipGeometry);
    ((ITopologicalOperatorPtr) ipGeometry)->Clip(ipEnv);
    ((ITopologicalOperatorPtr) ipGeometry)->Buffer(0, &ipOutGeom);
    ipBuffer->putref_Shape(ipOutGeom);
      
    // Get the field count
    IFieldsPtr ipFeatureFields;
    ipFeature->get_Fields(&ipFeatureFields);
    long lNumFields;
    ipFeatureFields->get_FieldCount(&lNumFields);
      
    for (long i = 0; i < lNumFields; i++)
    {
      IFieldPtr ipField;
      ipFeatureFields->get_Field(i, &ipField);
      esriFieldType eType;
      ipField->get_Type(&eType);
      // Ignore the Geometry and the OID field, the geometry is dealt
      //     with earlier and the OID will be generated automatically
      if ((eType != esriFieldTypeOID) && (eType != esriFieldTypeGeometry))
      {
        CComBSTR bstrFieldName;
        ipField->get_Name(&bstrFieldName);
        long lFieldIndex;
        ipFeatureFields->FindField(bstrFieldName, &lFieldIndex);
        
        IFieldsPtr ipBufferFields;
        ipBuffer->get_Fields(&ipBufferFields);
        long lNewFieldIndex;
        ipBufferFields->FindField(bstrFieldName, &lNewFieldIndex);
        
        CComVariant vFeatureVal;
        ipFeature->get_Value(lFieldIndex, &vFeatureVal);
        ipBuffer->put_Value(lNewFieldIndex, vFeatureVal);
      }
    }
      
    CComVariant vID;
    ipInsertCursor->InsertFeature(ipBuffer, &vID);
  }
  
  // Flush the inserts
  ipInsertCursor->Flush();
  
  std::cerr << std::endl;
  return S_OK;
}