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; }
__declspec(dllexport) int CalculatePairwiseGeodesicDistances(const wchar_t* feature_class, const wchar_t* output_file, const double unit_factor, const bool is_spagedi) { std::ofstream fs(output_file); if (!fs) { std::cerr << "Cannot open the output file." <<std::endl; return -1; } // Convert wchar_t*s to bstring _bstr_t catalogPath(feature_class); // Coinitialize GP utilities class IGPUtilitiesPtr ipUtil(CLSID_GPUtilities); // Feature class holder IFeatureClassPtr ipFeatureclass(0); HRESULT hr; // Try to fetch feature class from catalog path if (FAILED(hr = ipUtil->OpenFeatureClassFromString(catalogPath, &ipFeatureclass))) { fs << "Failed to open: " << catalogPath << std::endl; return -2; } // Set up query and filter IQueryFilterPtr ipFilter(CLSID_QueryFilter); IFeatureCursorPtr ipCursor; IFeaturePtr ipRow; IGeometryPtr ipGeometry; esriGeometryType gt; // coordinate system IGeographicCoordinateSystemPtr pGCS; ISpatialReferenceFactoryPtr pSpatRefFactory(CLSID_SpatialReferenceEnvironment); ISpatialReferencePtr spatialReference; // use meters as default linear units IUnitPtr ipUnit; pSpatRefFactory->CreateUnit(esriSRUnit_Meter, &ipUnit); ILinearUnitPtr linearUnit = ipUnit; // get the feature count to initialize our output matrix long featureCount; ipFeatureclass->FeatureCount(NULL, &featureCount); // initialize the 2d matrix (array of pointers) double** matrix = new double*[featureCount]; IPointArrayPtr ipPointArray; ipPointArray.CreateInstance(CLSID_PointArray); long* oids = new long[featureCount]; // Currently, this is only set to run as a 32-bit process, and // it'll crash if the application tries to use more than ~1.5GB // of memory. Approximate the dimensions that we'd expect to work // and fail if the user exceeds these limits. double arrayMemUsage = (8.0 * pow((double)featureCount, 2)) / pow(1024.0,2); if (arrayMemUsage > 1200) return -3; // Open search cursor on feature class ipFeatureclass->Search(ipFilter, VARIANT_FALSE, &ipCursor); int i = 0; for (ipCursor->NextFeature(&ipRow); ipRow != NULL; ipCursor->NextFeature(&ipRow)) { long oid_val; ipRow->get_OID(&oid_val); oids[i] = oid_val; ipRow->get_Shape(&ipGeometry); IPointPtr ipPoint (ipGeometry); if (i == 0) { // make sure inputs are points ipGeometry->get_GeometryType(>); if (gt != esriGeometryPoint) return -4; } // push the point onto our array ipPointArray->Add(ipPoint); // initialize output matrix element for this point matrix[i] = new double[featureCount]; i++; } // still have a poiner to the last referenced geometry, use // this to set the computation spatial reference. ipGeometry->get_SpatialReference(&spatialReference); // geometry server IGeometryServer2Ptr geomServer; geomServer.CreateInstance(CLSID_GeometryServerImpl); IRelationalOperatorPtr ipRelOp; double distance; for (int i = 0; i < featureCount; i++) { //fs << "at distance calculation for row " << i << std::endl; IPointPtr ipPointFrom; IPointPtr ipPointTo; // "(typeid: " << typeid(coord_vals[i][2]).name() << std::endl; ipPointFrom.CreateInstance(CLSID_Point); ipPointTo.CreateInstance(CLSID_Point); ipPointArray->get_Element(i, &ipPointFrom); // set up a relational operator for this point ipRelOp = ipPointFrom; for (int j = 0; j < featureCount; j++) { if (i == j) { distance = 0; } else if (matrix[j][i] > 0) { //fs << "matrix[j][i] is not NULL, value is `" << matrix[j][i] << // "`, type " << typeid(matrix[j][i]).name() << std::endl; distance = matrix[j][i]; } else { ipPointArray->get_Element(j, &ipPointTo); VARIANT_BOOL bEquals; ipRelOp->Equals(ipPointTo, &bEquals); if (bEquals) { distance = 0; } else { //fs << "try to get geodesic distance..." << std::endl; //double from_x, from_y, to_x, to_y; //ipPointFrom->QueryCoords(&from_x, &from_y); //ipPointTo->QueryCoords(&to_x, &to_y); //fs << "dist from: (" << from_x << "," << from_y << ")" << // " to (" << to_x << "," << to_y << ") with sr `" << // spatialReference << "`, unit factor " << unit_factor << "." << std::endl; geomServer->GetDistanceGeodesic(spatialReference, ipPointFrom, ipPointTo, linearUnit, &distance); // rescale distance by the unit factor (current unit releative to meters) distance = distance * unit_factor; } } matrix[i][j] = distance; } } // two possible output formats: 'standard' and 'SPAGeDi'. const char sep = is_spagedi ? '\t' : ','; if (is_spagedi) { fs << "M" << featureCount << sep; } // write header row for (int h = 0; h < featureCount; h++) { fs << sep << oids[h]; } fs << std::endl; // write out results for (int i = 0; i < featureCount; i++) { fs << oids[i] << sep; for (int j = 0; j < featureCount - 1; j++) { fs << std::fixed << matrix[i][j] << sep; } fs << std::fixed << matrix[i][featureCount - 1] << std::endl; } if (is_spagedi) { fs << "END" << std::endl; } fs.close(); return 0; }