OGRErr AODataSource::DeleteLayer( int iLayer ) { if( iLayer < 0 || iLayer >= static_cast<int>(m_layers.size()) ) return OGRERR_FAILURE; // Fetch ArObject Table before deleting OGR layer object ITablePtr ipTable; m_layers[iLayer]->GetTable(&ipTable); std::string name = m_layers[iLayer]->GetLayerDefn()->GetName(); // delete OGR layer delete m_layers[iLayer]; m_layers.erase(m_layers.begin() + iLayer); IDatasetPtr ipDataset = ipTable; HRESULT hr; if (FAILED(hr = ipDataset->Delete())) { CPLError( CE_Warning, CPLE_AppDefined, "%s was not deleted however it has been closed", name.c_str()); AOErr(hr, "Failed deleting dataset"); return OGRERR_FAILURE; } else return OGRERR_NONE; }
int AODataSource::Open(IWorkspace* pWorkspace, const char * pszNewName, int bUpdate ) { CPLAssert( m_nLayers == 0 ); if (bUpdate) { // Start Editing? } m_pszName = CPLStrdup( pszNewName ); m_ipWorkspace = pWorkspace; HRESULT hr; // Anything will be fetched IEnumDatasetPtr ipEnumDataset; if (FAILED(hr = m_ipWorkspace->get_Datasets(esriDTAny, &ipEnumDataset))) { return AOErr(hr, "Failed Opening Workspace Layers"); } return LoadLayers(ipEnumDataset); }
bool OGRGeometryToAOGeometry(OGRGeometry* pOGRGeom, esriGeometry::IGeometry** ppGeometry) { HRESULT hr; *ppGeometry = NULL; GByte* pWKB = NULL; long wkbSize = pOGRGeom->WkbSize(); pWKB = (GByte *) CPLMalloc(wkbSize); if( pOGRGeom->exportToWkb( wkbNDR, pWKB ) != OGRERR_NONE ) { CPLFree (pWKB); CPLError( CE_Failure, CPLE_AppDefined, "Could not export OGR geometry to WKB"); return false; } long bytesRead; esriGeometry::IGeometryFactoryPtr ipGeomFact(esriGeometry::CLSID_GeometryEnvironment); hr = ipGeomFact->CreateGeometryFromWkb(&bytesRead, pWKB, ppGeometry); CPLFree (pWKB); if (FAILED(hr)) { return AOErr(hr, "Failed translating OGR geometry to ESRI Geometry"); } return true; }
bool AOToOGRSpatialReference(esriGeometry::ISpatialReference* pSR, OGRSpatialReference** ppSR) { HRESULT hr; if (pSR == NULL) { CPLError( CE_Warning, CPLE_AppDefined, "ESRI Spatial Reference is NULL"); return false; } esriGeometry::IESRISpatialReferenceGEN2Ptr ipSRGen = pSR; if (ipSRGen == NULL) { CPLError( CE_Warning, CPLE_AppDefined, "ESRI Spatial Reference is Unknown"); return false; } long bufferSize = 0; if (FAILED(hr = ipSRGen->get_ESRISpatialReferenceSize(&bufferSize)) || bufferSize == 0) return false; //should never happen BSTR buffer = ::SysAllocStringLen(NULL,bufferSize); if (FAILED(hr = ipSRGen->ExportToESRISpatialReference2(&buffer, &bufferSize))) { ::SysFreeString(buffer); return AOErr(hr, "Failed to export ESRI string"); } CW2A strESRIWKT(buffer); ::SysFreeString(buffer); if (strlen(strESRIWKT) <= 0) { CPLError( CE_Warning, CPLE_AppDefined, "ESRI Spatial Reference is NULL"); return false; } *ppSR = new OGRSpatialReference(strESRIWKT); OGRErr result = (*ppSR)->morphFromESRI(); if (result == OGRERR_NONE) { return true; } else { delete *ppSR; *ppSR = NULL; CPLError( CE_Failure, CPLE_AppDefined, "Failed morphing from ESRI Geometry: %s", strESRIWKT); return false; } }
bool AOToOGRFields(IFields* pFields, OGRFeatureDefn* pOGRFeatureDef, std::vector<long> & ogrToESRIFieldMapping) { HRESULT hr; long fieldCount; if (FAILED(hr = pFields->get_FieldCount(&fieldCount))) return false; ogrToESRIFieldMapping.clear(); for (long i = 0; i < fieldCount; ++i) { IFieldPtr ipField; if (FAILED(hr = pFields->get_Field(i, &ipField))) return AOErr(hr, "Error getting field"); CComBSTR name; if (FAILED(hr = ipField->get_Name(&name))) return AOErr(hr, "Could not get field name"); esriFieldType fieldType; if (FAILED(hr = ipField->get_Type(&fieldType))) return AOErr(hr, "Error getting field type"); //skip these if (fieldType == esriFieldTypeOID || fieldType == esriFieldTypeGeometry) continue; OGRFieldType ogrType; if (!AOToOGRFieldType(fieldType, &ogrType)) { // field cannot be mapped, skipping it CPLError( CE_Warning, CPLE_AppDefined, "Skipping field %s", CW2A(name) ); continue; } OGRFieldDefn fieldTemplate( CW2A(name), ogrType); pOGRFeatureDef->AddFieldDefn( &fieldTemplate ); ogrToESRIFieldMapping.push_back(i); } CPLAssert(ogrToESRIFieldMapping.size() == pOGRFeatureDef->GetFieldCount()); return true; }
void AOLayer::ResetReading() { HRESULT hr; if (FAILED(hr = m_ipTable->Search(m_ipQF, VARIANT_TRUE, &m_ipCursor))) AOErr(hr, "Error Executing Query"); }
OGRFeature* AOLayer::GetNextFeature() { while (1) //want to skip errors { if (m_ipCursor == NULL) return NULL; HRESULT hr; IRowPtr ipRow; if (FAILED(hr = m_ipCursor->NextRow(&ipRow))) { AOErr(hr, "Failed fetching features"); return NULL; } if (hr == S_FALSE || ipRow == NULL) { // It's OK, we are done fetching return NULL; } OGRFeature* pOGRFeature = NULL; if (!OGRFeatureFromAORow(ipRow, &pOGRFeature)) { long oid = -1; ipRow->get_OID(&oid); std::strstream msg; msg << "Failed translating ArcObjects row [" << oid << "] to OGR Feature"; AOErr(hr, msg.str()); //return NULL; continue; //skip feature } return pOGRFeature; } }
bool AODataSource::LoadLayers(IEnumDataset* pEnumDataset) { HRESULT hr; pEnumDataset->Reset(); IDatasetPtr ipDataset; bool errEncountered = false; while ((S_OK == pEnumDataset->Next(&ipDataset)) && !(ipDataset == NULL)) { IFeatureDatasetPtr ipFD = ipDataset; if (!(ipFD == NULL)) { //We are dealing with a FeatureDataset, need to get IEnumDatasetPtr ipEnumDatasetSubset; if (FAILED(hr = ipFD->get_Subsets(&ipEnumDatasetSubset))) { AOErr(hr, "Failed getting dataset subsets"); errEncountered = true; continue; //skipping } if (LoadLayers(ipEnumDatasetSubset) == false) errEncountered = true; continue; } IFeatureClassPtr ipFC = ipDataset; if (ipFC == NULL) continue; //skip AOLayer* pLayer = new AOLayer; ITablePtr ipTable = ipFC; if (!pLayer->Initialize(ipTable)) { errEncountered = true; continue; } m_layers.push_back(pLayer); } if (errEncountered && m_layers.size() == 0) return false; //all of the ones we tried had errors else return true; //at least one worked }
OGRFeature *AOLayer::GetFeature( long oid ) { HRESULT hr; IRowPtr ipRow; if (FAILED(hr = m_ipTable->GetRow(oid, &ipRow))) { AOErr(hr, "Failed fetching row"); return NULL; } OGRFeature* pOGRFeature = NULL; if (!OGRFeatureFromAORow(ipRow, &pOGRFeature)) { AOErr(hr, "Failed translating ArcObjects row to OGR Feature"); return NULL; } return pOGRFeature; }
int AOLayer::GetFeatureCount( int bForce ) { HRESULT hr; long rowCount = -1; if (FAILED(hr = m_ipTable->RowCount(m_ipQF, &rowCount))) { AOErr(hr, "Failed calculating row count"); return rowCount; } return static_cast<int>(rowCount); }
OGRErr AOLayer::GetExtent (OGREnvelope* psExtent, int bForce) { if (bForce) { return OGRLayer::GetExtent( psExtent, bForce ); } HRESULT hr; IGeoDatasetPtr ipGeoDataset = m_ipTable; esriGeometry::IEnvelopePtr ipEnv = NULL; if (FAILED(hr = ipGeoDataset->get_Extent(&ipEnv)) || ipEnv == NULL) { AOErr(hr, "Failed retrieving extent"); return OGRERR_FAILURE; } double temp; ipEnv->get_XMin(&temp); psExtent->MinX = temp; ipEnv->get_YMin(&temp); psExtent->MinY = temp; ipEnv->get_XMax(&temp); psExtent->MaxX = temp; ipEnv->get_YMax(&temp); psExtent->MaxY = temp; return OGRERR_NONE; }
bool AOGeometryToOGRGeometry(bool forceMulti, esriGeometry::IGeometry* pInAOGeo, OGRSpatialReference* pOGRSR, unsigned char* & pInOutWorkingBuffer, long & inOutBufferSize, OGRGeometry** ppOutGeometry) { HRESULT hr; esriGeometry::IWkbPtr ipWkb = pInAOGeo; long reqSize = 0; if (FAILED(hr = ipWkb->get_WkbSize(&reqSize))) { AOErr(hr, "Error getting Wkb buffer size"); return false; } if (reqSize > inOutBufferSize) { // resize working buffer delete [] pInOutWorkingBuffer; pInOutWorkingBuffer = new unsigned char[reqSize]; inOutBufferSize = reqSize; } if (FAILED(hr = ipWkb->ExportToWkb(&reqSize, pInOutWorkingBuffer))) { AOErr(hr, "Error exporting to WKB buffer"); return false; } OGRGeometry* pOGRGeometry = NULL; OGRErr eErr = OGRGeometryFactory::createFromWkb(pInOutWorkingBuffer, pOGRSR, &pOGRGeometry, reqSize); if (eErr != OGRERR_NONE) { CPLError( CE_Failure, CPLE_AppDefined, "Failed attempting to import ArcGIS WKB Geometry. OGRGeometryFactory err:%d", eErr); return false; } // force geometries to multi if requested // If it is a polygon, force to MultiPolygon since we always produce multipolygons if (wkbFlatten(pOGRGeometry->getGeometryType()) == wkbPolygon) { pOGRGeometry = OGRGeometryFactory::forceToMultiPolygon(pOGRGeometry); } else if (forceMulti) { if (wkbFlatten(pOGRGeometry->getGeometryType()) == wkbLineString) { pOGRGeometry = OGRGeometryFactory::forceToMultiLineString(pOGRGeometry); } else if (wkbFlatten(pOGRGeometry->getGeometryType()) == wkbPoint) { pOGRGeometry = OGRGeometryFactory::forceToMultiPoint(pOGRGeometry); } } *ppOutGeometry = pOGRGeometry; return true; }
bool AOLayer::Initialize(ITable* pTable) { HRESULT hr; m_ipTable = pTable; CComBSTR temp; IDatasetPtr ipDataset = m_ipTable; if (FAILED(hr = ipDataset->get_Name(&temp))) return false; m_pFeatureDefn = new OGRFeatureDefn(CW2A(temp)); //Should I "new" an OGR smart pointer - sample says so, but it doesn't seem right //as long as we use the same compiler & settings in both the ogr build and this //driver, we should be OK m_pFeatureDefn->Reference(); IFeatureClassPtr ipFC = m_ipTable; VARIANT_BOOL hasOID = VARIANT_FALSE; ipFC->get_HasOID(&hasOID); if (hasOID == VARIANT_TRUE) { ipFC->get_OIDFieldName(&temp); m_strOIDFieldName = CW2A(temp); } if (FAILED(hr = ipFC->get_ShapeFieldName(&temp))) return AOErr(hr, "No shape field found!"); m_strShapeFieldName = CW2A(temp); IFieldsPtr ipFields; if (FAILED(hr = ipFC->get_Fields(&ipFields))) return AOErr(hr, "Fields not found!"); long shapeIndex = -1; if (FAILED(hr = ipFields->FindField(temp, &shapeIndex))) return AOErr(hr, "Shape field not found!"); IFieldPtr ipShapeField; if (FAILED(hr = ipFields->get_Field(shapeIndex, &ipShapeField))) return false; // Use GeometryDef to set OGR shapetype and Spatial Reference information // IGeometryDefPtr ipGeoDef; if (FAILED(hr = ipShapeField->get_GeometryDef(&ipGeoDef))) return false; OGRwkbGeometryType ogrGeoType; if (!AOToOGRGeometry(ipGeoDef, &ogrGeoType)) return false; m_pFeatureDefn->SetGeomType(ogrGeoType); if (wkbFlatten(ogrGeoType) == wkbMultiLineString || wkbFlatten(ogrGeoType) == wkbMultiPoint) m_forceMulti = true; // Mapping of Spatial Reference will be passive about errors // (it is possible we won't be able to map some ESRI-specific projections) esriGeometry::ISpatialReferencePtr ipSR = NULL; if (FAILED(hr = ipGeoDef->get_SpatialReference(&ipSR))) { AOErr(hr, "Failed Fetching ESRI spatial reference"); } else { if (!AOToOGRSpatialReference(ipSR, &m_pSRS)) { //report error, but be passive about it CPLError( CE_Warning, CPLE_AppDefined, "Failed Mapping ESRI Spatial Reference"); } } // Map fields // return AOToOGRFields(ipFields, m_pFeatureDefn, m_OGRFieldToESRIField); }
bool AOLayer::OGRFeatureFromAORow(IRow* pRow, OGRFeature** ppFeature) { HRESULT hr; OGRFeature* pOutFeature = new OGRFeature(m_pFeatureDefn); ///////////////////////////////////////////////////////// // Translate OID // long oid = -1; if (FAILED(hr = pRow->get_OID(&oid))) { //this should never happen delete pOutFeature; return false; } pOutFeature->SetFID(oid); ///////////////////////////////////////////////////////// // Translate Geometry // IFeaturePtr ipFeature = pRow; esriGeometry::IGeometryPtr ipGeometry = NULL; if (FAILED(hr = ipFeature->get_Shape(&ipGeometry)) || ipGeometry == NULL) { delete pOutFeature; return AOErr(hr, "Failed retrieving shape from ArcObjects"); } OGRGeometry* pOGRGeo = NULL; if ((!AOGeometryToOGRGeometry(m_forceMulti, ipGeometry, m_pSRS, m_pBuffer, m_bufferSize, &pOGRGeo)) || pOGRGeo == NULL) { delete pOutFeature; return AOErr(hr, "Failed to translate ArcObjects Geometry to OGR Geometry"); } pOutFeature->SetGeometryDirectly(pOGRGeo); ////////////////////////////////////////////////////////// // Map fields // CComVariant val; size_t mappedFieldCount = m_OGRFieldToESRIField.size(); bool foundBadColumn = false; for (size_t i = 0; i < mappedFieldCount; ++i) { long index = m_OGRFieldToESRIField[i]; if (FAILED(hr = pRow->get_Value(index, &val))) { // this should not happen return AOErr(hr, "Failed retrieving row value"); } if (val.vt == VT_NULL) { continue; //leave as unset } // // NOTE: This switch statement needs to be kept in sync with AOToOGRGeometry // since we are only checking for types we mapped in that utility function switch (m_pFeatureDefn->GetFieldDefn(i)->GetType()) { case OFTInteger: { val.ChangeType(VT_I4); pOutFeature->SetField(i, val.intVal); } break; case OFTReal: { val.ChangeType(VT_R8); pOutFeature->SetField(i, val.dblVal); } break; case OFTString: { val.ChangeType(VT_BSTR); pOutFeature->SetField(i, CW2A(val.bstrVal)); } break; /* TODO: Need to get test dataset to implement these leave it as NULL for now case OFTBinary: { // Access as SafeArray with SafeArrayAccessData perhaps? } break; case OFTDateTime: { // Examine test data to figure out how to extract that } break; */ default: { if (!m_supressColumnMappingError) { foundBadColumn = true; CPLError( CE_Warning, CPLE_AppDefined, "Row id: %d col:%d has unhandled col type (%d). Setting to NULL.", oid, i, m_pFeatureDefn->GetFieldDefn(i)->GetType()); } } } } if (foundBadColumn) m_supressColumnMappingError = true; *ppFeature = pOutFeature; return true; }