std::string SpatialReference::getVertical() const { std::string tmp(""); OGRSpatialReference* poSRS = (OGRSpatialReference*)OSRNewSpatialReference(m_wkt.c_str()); char *pszWKT = NULL; OGR_SRSNode* node = poSRS->GetAttrNode("VERT_CS"); if (node && poSRS) { node->exportToWkt(&pszWKT); tmp = pszWKT; CPLFree(pszWKT); OSRDestroySpatialReference(poSRS); } return tmp; }
/** Apply a vertical shift grid to a source (DEM typically) dataset. * * hGridDataset will typically use WGS84 as horizontal datum (but this is * not a requirement) and its values are the values to add to go from geoid * elevations to WGS84 ellipsoidal heights. * * hGridDataset will be on-the-fly reprojected and resampled to the projection * and resolution of hSrcDataset, using bilinear resampling by default. * * Both hSrcDataset and hGridDataset must be single band datasets, and have * a valid geotransform and projection. * * On success, a reference will be taken on hSrcDataset and hGridDataset. * Reference counting semantics on the source and grid datasets should be * honoured. That is, don't just GDALClose() it, unless it was opened with * GDALOpenShared(), but rather use GDALReleaseDataset() if wanting to * immediately release the reference(s) and make the returned dataset the * owner of them. * * Valid use cases: * * \code * hSrcDataset = GDALOpen(...) * hGridDataset = GDALOpen(...) * hDstDataset = GDALApplyVerticalShiftGrid(hSrcDataset, hGridDataset, ...) * GDALReleaseDataset(hSrcDataset); * GDALReleaseDataset(hGridDataset); * if( hDstDataset ) * { * // Do things with hDstDataset * GDALClose(hDstDataset) // will close hSrcDataset and hGridDataset * } * \endcode * * @param hSrcDataset source (DEM) dataset. Must not be NULL. * @param hGridDataset vertical grid shift dataset. Must not be NULL. * @param bInverse if set to FALSE, hGridDataset values will be added to * hSrcDataset. If set to TRUE, they will be subtracted. * @param dfSrcUnitToMeter the factor to convert values from hSrcDataset to * meters (1.0 if source values are in meter). * @param dfDstUnitToMeter the factor to convert shifted values from meter * (1.0 if output values must be in meter). * @param papszOptions list of options, or NULL. Supported options are: * <ul> * <li>RESAMPLING=NEAREST/BILINEAR/CUBIC. Defaults to BILINEAR.</li> * <li>MAX_ERROR=val. Maximum error measured in input pixels that is allowed in * approximating the transformation (0.0 for exact calculations). Defaults * to 0.125</li> * <li>DATATYPE=Byte/UInt16/Int16/Float32/Float64. Output data type. If not * specified will be the same as the one of hSrcDataset. * <li>ERROR_ON_MISSING_VERT_SHIFT=YES/NO. Whether a missing/nodata value in * hGridDataset should cause I/O requests to fail. Default is NO (in which case * 0 will be used) * <li>SRC_SRS=srs_def. Override projection on hSrcDataset; * </ul> * * @return a new dataset corresponding to hSrcDataset adjusted with * hGridDataset, or NULL. If not NULL, it must be closed with GDALClose(). * * @since GDAL 2.2 */ GDALDatasetH GDALApplyVerticalShiftGrid( GDALDatasetH hSrcDataset, GDALDatasetH hGridDataset, int bInverse, double dfSrcUnitToMeter, double dfDstUnitToMeter, const char* const* papszOptions ) { VALIDATE_POINTER1( hSrcDataset, "GDALApplyVerticalShiftGrid", nullptr ); VALIDATE_POINTER1( hGridDataset, "GDALApplyVerticalShiftGrid", nullptr ); double adfSrcGT[6]; if( GDALGetGeoTransform(hSrcDataset, adfSrcGT) != CE_None ) { CPLError(CE_Failure, CPLE_NotSupported, "Source dataset has no geotransform."); return nullptr; } const char* pszSrcProjection = CSLFetchNameValueDef(papszOptions, "SRC_SRS", GDALGetProjectionRef(hSrcDataset)); if( pszSrcProjection == nullptr || pszSrcProjection[0] == '\0' ) { CPLError(CE_Failure, CPLE_NotSupported, "Source dataset has no projection."); return nullptr; } if( GDALGetRasterCount(hSrcDataset) != 1 ) { CPLError(CE_Failure, CPLE_NotSupported, "Only single band source dataset is supported."); return nullptr; } double adfGridGT[6]; if( GDALGetGeoTransform(hGridDataset, adfGridGT) != CE_None ) { CPLError(CE_Failure, CPLE_NotSupported, "Grid dataset has no geotransform."); return nullptr; } const char* pszGridProjection = GDALGetProjectionRef(hGridDataset); if( pszGridProjection == nullptr || pszGridProjection[0] == '\0' ) { CPLError(CE_Failure, CPLE_NotSupported, "Grid dataset has no projection."); return nullptr; } if( GDALGetRasterCount(hGridDataset) != 1 ) { CPLError(CE_Failure, CPLE_NotSupported, "Only single band grid dataset is supported."); return nullptr; } GDALDataType eDT = GDALGetRasterDataType(GDALGetRasterBand(hSrcDataset,1)); const char* pszDataType = CSLFetchNameValue(papszOptions, "DATATYPE"); if( pszDataType ) eDT = GDALGetDataTypeByName(pszDataType); if( eDT == GDT_Unknown ) { CPLError(CE_Failure, CPLE_NotSupported, "Invalid DATATYPE=%s", pszDataType); return nullptr; } const int nSrcXSize = GDALGetRasterXSize(hSrcDataset); const int nSrcYSize = GDALGetRasterYSize(hSrcDataset); OGRSpatialReference oSRS; CPLString osSrcProjection(pszSrcProjection); oSRS.SetFromUserInput(osSrcProjection); if( oSRS.IsCompound() ) { OGR_SRSNode* poNode = oSRS.GetRoot()->GetChild(1); if( poNode != nullptr ) { char* pszWKT = nullptr; poNode->exportToWkt(&pszWKT); osSrcProjection = pszWKT; CPLFree(pszWKT); } } void* hTransform = GDALCreateGenImgProjTransformer3( pszGridProjection, adfGridGT, osSrcProjection, adfSrcGT ); if( hTransform == nullptr ) return nullptr; GDALWarpOptions* psWO = GDALCreateWarpOptions(); psWO->hSrcDS = hGridDataset; psWO->eResampleAlg = GRA_Bilinear; const char* pszResampling = CSLFetchNameValue(papszOptions, "RESAMPLING"); if( pszResampling ) { if( EQUAL(pszResampling, "NEAREST") ) psWO->eResampleAlg = GRA_NearestNeighbour; else if( EQUAL(pszResampling, "BILINEAR") ) psWO->eResampleAlg = GRA_Bilinear; else if( EQUAL(pszResampling, "CUBIC") ) psWO->eResampleAlg = GRA_Cubic; } psWO->eWorkingDataType = GDT_Float32; int bHasNoData = FALSE; const double dfSrcNoData = GDALGetRasterNoDataValue( GDALGetRasterBand(hGridDataset, 1), &bHasNoData ); if( bHasNoData ) { psWO->padfSrcNoDataReal = static_cast<double*>(CPLMalloc(sizeof(double))); psWO->padfSrcNoDataReal[0] = dfSrcNoData; } psWO->padfDstNoDataReal = static_cast<double*>(CPLMalloc(sizeof(double))); const bool bErrorOnMissingShift = CPLFetchBool( papszOptions, "ERROR_ON_MISSING_VERT_SHIFT", false ); psWO->padfDstNoDataReal[0] = (bErrorOnMissingShift) ? -std::numeric_limits<float>::infinity() : 0.0; psWO->papszWarpOptions = CSLSetNameValue(psWO->papszWarpOptions, "INIT_DEST", "NO_DATA"); psWO->pfnTransformer = GDALGenImgProjTransform; psWO->pTransformerArg = hTransform; const double dfMaxError = CPLAtof(CSLFetchNameValueDef(papszOptions, "MAX_ERROR", "0.125")); if( dfMaxError > 0.0 ) { psWO->pTransformerArg = GDALCreateApproxTransformer( psWO->pfnTransformer, psWO->pTransformerArg, dfMaxError ); psWO->pfnTransformer = GDALApproxTransform; GDALApproxTransformerOwnsSubtransformer(psWO->pTransformerArg, TRUE); } psWO->nBandCount = 1; psWO->panSrcBands = static_cast<int *>(CPLMalloc(sizeof(int))); psWO->panSrcBands[0] = 1; psWO->panDstBands = static_cast<int *>(CPLMalloc(sizeof(int))); psWO->panDstBands[0] = 1; VRTWarpedDataset* poReprojectedGrid = new VRTWarpedDataset(nSrcXSize, nSrcYSize); // This takes a reference on hGridDataset CPLErr eErr = poReprojectedGrid->Initialize(psWO); CPLAssert(eErr == CE_None); CPL_IGNORE_RET_VAL(eErr); GDALDestroyWarpOptions(psWO); poReprojectedGrid->SetGeoTransform(adfSrcGT); poReprojectedGrid->AddBand(GDT_Float32, nullptr); GDALApplyVSGDataset* poOutDS = new GDALApplyVSGDataset( reinterpret_cast<GDALDataset*>(hSrcDataset), poReprojectedGrid, eDT, CPL_TO_BOOL(bInverse), dfSrcUnitToMeter, dfDstUnitToMeter, // Undocumented option. For testing only atoi(CSLFetchNameValueDef(papszOptions, "BLOCKSIZE", "256")) ); poReprojectedGrid->ReleaseRef(); if( !poOutDS->IsInitOK() ) { delete poOutDS; return nullptr; } poOutDS->SetDescription( GDALGetDescription( hSrcDataset ) ); return reinterpret_cast<GDALDatasetH>(poOutDS); }