Points 2D to 3D
Points2Dto3D.cpp
// 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.
// 

  
#include "Points2Dto3D.h"

int main(int argc, char** argv)
{
  std::cerr << "Points2Dto3D: ArcGIS Engine Developer Sample" << std::endl;
  if (argc != 4) 
  {
    std::cerr << "Usage: Points2Dto3D "
              << "[Input Shapefile] "
              << "[Z Attribute Field Name] "
              << "[Output Shapefile]"
              << std::endl;
    AoExit(0);
  }
  
  char* inputFile = argv[1];
  char* zFieldName = argv[2];
  char* outputFile = argv[3];
  
  if (!InitializeApp())
  {
    AoExit(0);
  }
  
  HRESULT hr = Create3DShape(inputFile, zFieldName, outputFile);
  if (FAILED(hr))
    std::cerr << "Failed 3D Creation" << std::endl;
  else
    std::cerr << "Successful 3D Creation" << std::endl;
  
  ShutdownApp();
  
  AoExit(0);
}

HRESULT Create3DShape(char* inputFile, char* zFieldName, char* outputFile)
{
  // data location variables
  CComBSTR inShapePath;
  CComBSTR inShapeName;
  CComBSTR outShapePath;
  CComBSTR outShapeName;
  
  // Parse the input and output paths
  HRESULT hr = GetParentDirFromFullPath(inputFile, &inShapePath);
  if (FAILED(hr) || inShapePath.Length() <= 0)
  {
    std::cerr << "Couldn't get input path." << std::endl;
    return E_FAIL;
  }
  hr = GetFileFromFullPath(inputFile, &inShapeName);
  if (FAILED(hr) || inShapeName.Length() <= 0)
  {
    std::cerr << "Couldn't get input file." << std::endl;
    return E_FAIL;
  }
  hr = GetParentDirFromFullPath(outputFile, &outShapePath);
  if (FAILED(hr) || outShapePath.Length() <= 0)
  {
    std::cerr << "Couldn't get output path." << std::endl;
    return E_FAIL;
  }
  hr = GetFileFromFullPath(outputFile, &outShapeName);
    if (FAILED(hr) || outShapeName.Length() <= 0)
  {
    std::cerr << "Couldn't get output file." << std::endl;
    return E_FAIL;
  }
  IWorkspaceFactoryPtr ipWkspFac(CLSID_ShapefileWorkspaceFactory);
  IWorkspacePtr ipWksp;
  hr = ipWkspFac->OpenFromFile(inShapePath, 0, &ipWksp);
  if (FAILED(hr) || ipWksp == 0)
  {
    std::wcerr << L"Could not open the workspace " << (BSTR) inShapePath << std::endl;
    return hr;
  }
  IFeatureClassPtr ipInFeatureClass;
  hr = ((IFeatureWorkspacePtr) ipWksp)->OpenFeatureClass(inShapeName, &ipInFeatureClass);
  if (FAILED(hr) || ipInFeatureClass ==0)
  {
    std::wcerr << L"Could not open the feature class " << (BSTR) inShapeName 
               << std::endl;
    return hr;
  }

  // Only support points
  esriGeometryType shape;
  ipInFeatureClass->get_ShapeType(&shape);
  if (shape != esriGeometryPoint)
  {
    std::cerr << "This is not a shapefile of points." << std::endl;
    return E_FAIL;
  }
  else 
    std::cerr << "Proceeding on the points shapefile." << std::endl;
  
  // Create the output feature class if no such on exists already (else error)
  ISpatialReferencePtr ipSpatialRef(CLSID_UnknownCoordinateSystem);
  IFeatureClassPtr ipOutFeatureClass;
  CreateShapefile(esriGeometryPoint, VARIANT_TRUE, VARIANT_TRUE, ipSpatialRef,
                  1000, &ipOutFeatureClass, outShapePath, outShapeName);
  
  // Copy input fields to output feature class w/out overwriting system fields
  IFieldsPtr ipFields;
  ipInFeatureClass->get_Fields(&ipFields);
  long numFields;
  ipFields->get_FieldCount(&numFields);
  IFieldPtr ipFieldTest;
  VARIANT_BOOL varBool;
  esriFieldType fieldType;
  IFieldPtr ipField;
  for (int i = 0; i < numFields - 1; ++i)  
  {
    ipFields->get_Field(i, &ipFieldTest);
    ipFieldTest->get_Editable(&varBool);
    ipFieldTest->get_Type(&fieldType);
    if (varBool && !(fieldType == esriFieldTypeGeometry))
    {
      ipFields->get_Field(i, &ipField);
      ipOutFeatureClass->AddField(ipField);
    }
  }
  
  // Get a cursor off the input feature class
  IFeatureCursorPtr ipInFeatureCursor;
  ipInFeatureClass->Search(NULL, VARIANT_FALSE, &ipInFeatureCursor);
  
  // Get a cursor off the output feature class
  IFeatureBufferPtr ipFeatureBuffer;
  ipOutFeatureClass->CreateFeatureBuffer(&ipFeatureBuffer);
  IFeatureCursorPtr ipEditCursor;
  ipOutFeatureClass->Insert(VARIANT_TRUE, &ipEditCursor);
  
  // loop through the input features, cloning the geometry, looking up and 
  //    adding the z value from the input table and adding the new feature
  //    to the output feature class
  IFeaturePtr ipFeature;
  ipInFeatureCursor->NextFeature(&ipFeature);
  IGeometryPtr ipGeom;
  IClonePtr ipOutClone;
  int counter = 1;
  while(ipFeature != NULL)
  {
    // Get the input geometry and clone it to a z aware geometry
    ipFeature->get_Shape(&ipGeom);
    ((IClonePtr) ipGeom)->Clone(&ipOutClone);
    ((IZAwarePtr) ipOutClone)->put_ZAware(VARIANT_TRUE);
    IFieldsPtr ipFields2Ptr;
    ipFeature->get_Fields(&ipFields2Ptr);
    long zFieldLoc;
    ipFields2Ptr->FindField(CComBSTR(zFieldName), &zFieldLoc);
    if (zFieldLoc < 0)
    {
      std::cerr << "Field " << zFieldName 
                << " was not found in the input feature class" 
                << std::endl;
      return E_FAIL;
    }  
      
    // Get the z values from the attribute table
    IRowBufferPtr ipRowBuffer(ipFeature);
    CComVariant outZ;
    ipRowBuffer->get_Value(zFieldLoc, &outZ);
    double inZ = outZ.dblVal;
    IPointPtr ipOutPoint(ipOutClone);
    ipOutPoint->put_Z(inZ);
    double x, y, z;
    ipOutPoint->get_X(&x);
    ipOutPoint->get_Y(&y);
    ipOutPoint->get_Z(&z);
      
    std::cerr << "Point #: " << counter << " = (" << x << ", " << y 
              << ", " << z << ")" << std::endl;
    ++counter;
    ipFeatureBuffer->putref_Shape((IGeometryPtr) ipOutPoint);
    long index;
    for (int i = 0; i < numFields - 1; ++i)  
    {
      IFieldsPtr ipBufferFields;
      ipFeatureBuffer->get_Fields(&ipBufferFields);
      IFieldsPtr ipInFCFields;
      ipInFeatureClass->get_Fields(&ipInFCFields);
      IFieldPtr ipInField;
      ipInFCFields->get_Field(i, &ipInField);
      CComBSTR fieldName;
      ipInField->get_Name(&fieldName);
      ipBufferFields->FindField(fieldName, &index);
      if (index >= 0)
      {
        IFieldPtr ipTempField;
        ipBufferFields->get_Field(index, &ipTempField);
        VARIANT_BOOL tempBool;
        ipTempField->get_Editable(&tempBool);
        esriFieldType tempType;
        ipTempField->get_Type(&tempType);
        if (tempBool && tempType != esriFieldTypeGeometry)
        {
          VARIANT varBufferVal;
          ipRowBuffer->get_Value(i, &varBufferVal);
          ipFeatureBuffer->put_Value(index, varBufferVal);
        }
      }
    }
      
    CComVariant varID;
    ipEditCursor->InsertFeature(ipFeatureBuffer, &varID); 
    ipInFeatureCursor->NextFeature(&ipFeature);
  }
  
  return S_OK;
}

HRESULT CreateShapefile(esriGeometryType shapeType, VARIANT_BOOL hasM, 
                        VARIANT_BOOL hasZ, ISpatialReference* pSpatialRef, 
                        int gridSize, IFeatureClass** ppOutFeatureClass,
                        BSTR outShapePath, BSTR outShapeName)
{
  IWorkspaceFactoryPtr ipShapeWkspFac(CLSID_ShapefileWorkspaceFactory);
  IPropertySetPtr ipConnectionProperties(CLSID_PropertySet);
  ipConnectionProperties->SetProperty(CComBSTR(L"DATABASE"), 
                                      CComVariant(outShapePath));
  IWorkspacePtr ipShapeWksp;
  HRESULT hr = ipShapeWkspFac->Open(ipConnectionProperties, 0, &ipShapeWksp);
  if (FAILED(hr) || ipShapeWksp == 0)
  {
    std::cerr << "Couldn't open the workspace to create a shapefile." 
              << std::endl;
  }
  IFieldsPtr ipFields(CLSID_Fields);
  IFieldsEditPtr ipFieldsEdit(ipFields);
  IFieldPtr ipField(CLSID_Field);
  IFieldEditPtr ipFieldEdit(ipField);
  
  IGeometryDefEditPtr ipGeoDefEdit(CLSID_GeometryDef);
  ipGeoDefEdit->put_GeometryType(shapeType);
  ipGeoDefEdit->put_HasM(hasM);
  ipGeoDefEdit->put_HasZ(hasZ);
  ipGeoDefEdit->putref_SpatialReference(pSpatialRef);
  ipGeoDefEdit->put_GridCount(1);
  ipGeoDefEdit->put_GridSize(0, gridSize);
  
  ipFieldEdit = IFieldPtr(CLSID_Field);
  ipFieldEdit->put_Name(CComBSTR(L"OBJECTID"));
  ipFieldEdit->put_AliasName(CComBSTR(L"OBJECTID"));
  ipFieldEdit->put_Type(esriFieldTypeOID);
  
  ipField = ipFieldEdit;
  ipFieldsEdit->AddField(ipField);
  
  ipFieldEdit.CreateInstance(CLSID_Field);
  ipFieldEdit->put_Name(CComBSTR(L"SHAPE"));
  ipFieldEdit->put_IsNullable(VARIANT_TRUE);
  ipFieldEdit->put_Type(esriFieldTypeGeometry);
  IGeometryDefPtr ipGeoDef(ipGeoDefEdit);
  ipFieldEdit->putref_GeometryDef(ipGeoDef);
  ipFieldEdit->put_Required(VARIANT_TRUE);
  
  ipField = ipFieldEdit;
  ipFieldsEdit->AddField(ipField);
  
  ((IFeatureWorkspacePtr) ipShapeWksp)->CreateFeatureClass(outShapeName,
                                                           ipFields, 
                                                           NULL, NULL, 
                                                           esriFTSimple, 
                                                           CComBSTR(L"Shape"), 
                                                           CComBSTR(L""), 
                                                           ppOutFeatureClass);

  return S_OK;
}