int GDALRPCTransform( void *pTransformArg, int bDstToSrc, int nPointCount, double *padfX, double *padfY, double *padfZ, int *panSuccess ) { VALIDATE_POINTER1( pTransformArg, "GDALRPCTransform", 0 ); GDALRPCTransformInfo *psTransform = (GDALRPCTransformInfo *) pTransformArg; GDALRPCInfo *psRPC = &(psTransform->sRPC); int i; if( psTransform->bReversed ) bDstToSrc = !bDstToSrc; int bands[1] = {1}; int nRasterXSize = 0, nRasterYSize = 0; /* -------------------------------------------------------------------- */ /* Lazy opening of the optionnal DEM file. */ /* -------------------------------------------------------------------- */ if(psTransform->pszDEMPath != NULL && psTransform->bHasTriedOpeningDS == FALSE) { int bIsValid = FALSE; psTransform->bHasTriedOpeningDS = TRUE; psTransform->poDS = (GDALDataset *) GDALOpen( psTransform->pszDEMPath, GA_ReadOnly ); if(psTransform->poDS != NULL && psTransform->poDS->GetRasterCount() >= 1) { const char* pszSpatialRef = psTransform->poDS->GetProjectionRef(); if (pszSpatialRef != NULL && pszSpatialRef[0] != '\0') { OGRSpatialReference* poWGSSpaRef = new OGRSpatialReference(SRS_WKT_WGS84); OGRSpatialReference* poDSSpaRef = new OGRSpatialReference(pszSpatialRef); if(!poWGSSpaRef->IsSame(poDSSpaRef)) psTransform->poCT =OGRCreateCoordinateTransformation( poWGSSpaRef, poDSSpaRef ); delete poWGSSpaRef; delete poDSSpaRef; } if (psTransform->poDS->GetGeoTransform( psTransform->adfGeoTransform) == CE_None && GDALInvGeoTransform( psTransform->adfGeoTransform, psTransform->adfReverseGeoTransform )) { bIsValid = TRUE; } } if (!bIsValid && psTransform->poDS != NULL) { GDALClose(psTransform->poDS); psTransform->poDS = NULL; } } if (psTransform->poDS) { nRasterXSize = psTransform->poDS->GetRasterXSize(); nRasterYSize = psTransform->poDS->GetRasterYSize(); } /* -------------------------------------------------------------------- */ /* The simple case is transforming from lat/long to pixel/line. */ /* Just apply the equations directly. */ /* -------------------------------------------------------------------- */ if( bDstToSrc ) { for( i = 0; i < nPointCount; i++ ) { if(psTransform->poDS) { double dfX, dfY; //check if dem is not in WGS84 and transform points padfX[i], padfY[i] if(psTransform->poCT) { double dfXOrig = padfX[i]; double dfYOrig = padfY[i]; double dfZOrig = padfZ[i]; if (!psTransform->poCT->Transform( 1, &dfXOrig, &dfYOrig, &dfZOrig)) { panSuccess[i] = FALSE; continue; } GDALApplyGeoTransform( psTransform->adfReverseGeoTransform, dfXOrig, dfYOrig, &dfX, &dfY ); } else GDALApplyGeoTransform( psTransform->adfReverseGeoTransform, padfX[i], padfY[i], &dfX, &dfY ); int dX = int(dfX); int dY = int(dfY); if (!(dX >= 0 && dY >= 0 && dX+2 <= nRasterXSize && dY+2 <= nRasterYSize)) { panSuccess[i] = FALSE; continue; } double dfDEMH(0); double dfDeltaX = dfX - dX; double dfDeltaY = dfY - dY; if(psTransform->eResampleAlg == DRA_Cubic) { int dXNew = dX - 1; int dYNew = dY - 1; if (!(dXNew >= 0 && dYNew >= 0 && dXNew + 4 <= nRasterXSize && dYNew + 4 <= nRasterYSize)) { panSuccess[i] = FALSE; continue; } //cubic interpolation int adElevData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dXNew, dYNew, 4, 4, &adElevData, 4, 4, GDT_Int32, 1, bands, 0, 0, 0); if(eErr != CE_None) { panSuccess[i] = FALSE; continue; } double dfSumH(0); for ( int i = 0; i < 5; i++ ) { // Loop across the X axis for ( int j = 0; j < 5; j++ ) { // Calculate the weight for the specified pixel according // to the bicubic b-spline kernel we're using for // interpolation int dKernIndX = j - 1; int dKernIndY = i - 1; double dfPixelWeight = BiCubicKernel(dKernIndX - dfDeltaX) * BiCubicKernel(dKernIndY - dfDeltaY); // Create a sum of all values // adjusted for the pixel's calculated weight dfSumH += adElevData[j + i * 4] * dfPixelWeight; } } dfDEMH = dfSumH; } else if(psTransform->eResampleAlg == DRA_Bilinear) { if (!(dX >= 0 && dY >= 0 && dX + 2 <= nRasterXSize && dY + 2 <= nRasterYSize)) { panSuccess[i] = FALSE; continue; } //bilinear interpolation int anElevData[4] = {0,0,0,0}; CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 2, 2, &anElevData, 2, 2, GDT_Int32, 1, bands, 0, 0, 0); if(eErr != CE_None) { panSuccess[i] = FALSE; continue; } double dfDeltaX1 = 1.0 - dfDeltaX; double dfDeltaY1 = 1.0 - dfDeltaY; double dfXZ1 = anElevData[0] * dfDeltaX1 + anElevData[1] * dfDeltaX; double dfXZ2 = anElevData[2] * dfDeltaX1 + anElevData[3] * dfDeltaX; double dfYZ = dfXZ1 * dfDeltaY1 + dfXZ2 * dfDeltaY; dfDEMH = dfYZ; } else { if (!(dX >= 0 && dY >= 0 && dX <= nRasterXSize && dY <= nRasterYSize)) { panSuccess[i] = FALSE; continue; } CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 1, 1, &dfDEMH, 1, 1, GDT_Int32, 1, bands, 0, 0, 0); if(eErr != CE_None) { panSuccess[i] = FALSE; continue; } } RPCTransformPoint( psRPC, padfX[i], padfY[i], padfZ[i] + (psTransform->dfHeightOffset + dfDEMH) * psTransform->dfHeightScale, padfX + i, padfY + i ); } else RPCTransformPoint( psRPC, padfX[i], padfY[i], padfZ[i] + psTransform->dfHeightOffset * psTransform->dfHeightScale, padfX + i, padfY + i ); panSuccess[i] = TRUE; } return TRUE; } /* -------------------------------------------------------------------- */ /* Compute the inverse (pixel/line/height to lat/long). This */ /* function uses an iterative method from an initial linear */ /* approximation. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nPointCount; i++ ) { double dfResultX, dfResultY; if(psTransform->poDS) { RPCInverseTransformPoint( psTransform, padfX[i], padfY[i], padfZ[i] + psTransform->dfHeightOffset * psTransform->dfHeightScale, &dfResultX, &dfResultY ); double dfX, dfY; //check if dem is not in WGS84 and transform points padfX[i], padfY[i] if(psTransform->poCT) { double dfZ = 0; if (!psTransform->poCT->Transform(1, &dfResultX, &dfResultY, &dfZ)) { panSuccess[i] = FALSE; continue; } } GDALApplyGeoTransform( psTransform->adfReverseGeoTransform, dfResultX, dfResultY, &dfX, &dfY ); int dX = int(dfX); int dY = int(dfY); double dfDEMH(0); double dfDeltaX = dfX - dX; double dfDeltaY = dfY - dY; if(psTransform->eResampleAlg == DRA_Cubic) { int dXNew = dX - 1; int dYNew = dY - 1; if (!(dXNew >= 0 && dYNew >= 0 && dXNew + 4 <= nRasterXSize && dYNew + 4 <= nRasterYSize)) { panSuccess[i] = FALSE; continue; } //cubic interpolation int adElevData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dXNew, dYNew, 4, 4, &adElevData, 4, 4, GDT_Int32, 1, bands, 0, 0, 0); if(eErr != CE_None) { panSuccess[i] = FALSE; continue; } double dfSumH(0); for ( int i = 0; i < 5; i++ ) { // Loop across the X axis for ( int j = 0; j < 5; j++ ) { // Calculate the weight for the specified pixel according // to the bicubic b-spline kernel we're using for // interpolation int dKernIndX = j - 1; int dKernIndY = i - 1; double dfPixelWeight = BiCubicKernel(dKernIndX - dfDeltaX) * BiCubicKernel(dKernIndY - dfDeltaY); // Create a sum of all values // adjusted for the pixel's calculated weight dfSumH += adElevData[j + i * 4] * dfPixelWeight; } } dfDEMH = dfSumH; } else if(psTransform->eResampleAlg == DRA_Bilinear) { if (!(dX >= 0 && dY >= 0 && dX + 2 <= nRasterXSize && dY + 2 <= nRasterYSize)) { panSuccess[i] = FALSE; continue; } //bilinear interpolation int adElevData[4] = {0,0,0,0}; CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 2, 2, &adElevData, 2, 2, GDT_Int32, 1, bands, 0, 0, 0); if(eErr != CE_None) { panSuccess[i] = FALSE; continue; } double dfDeltaX1 = 1.0 - dfDeltaX; double dfDeltaY1 = 1.0 - dfDeltaY; double dfXZ1 = adElevData[0] * dfDeltaX1 + adElevData[1] * dfDeltaX; double dfXZ2 = adElevData[2] * dfDeltaX1 + adElevData[3] * dfDeltaX; double dfYZ = dfXZ1 * dfDeltaY1 + dfXZ2 * dfDeltaY; dfDEMH = dfYZ; } else { if (!(dX >= 0 && dY >= 0 && dX <= nRasterXSize && dY <= nRasterYSize)) { panSuccess[i] = FALSE; continue; } CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 1, 1, &dfDEMH, 1, 1, GDT_Int32, 1, bands, 0, 0, 0); if(eErr != CE_None) { panSuccess[i] = FALSE; continue; } } RPCInverseTransformPoint( psTransform, padfX[i], padfY[i], padfZ[i] + (psTransform->dfHeightOffset + dfDEMH) * psTransform->dfHeightScale, &dfResultX, &dfResultY ); } else { RPCInverseTransformPoint( psTransform, padfX[i], padfY[i], padfZ[i] + psTransform->dfHeightOffset * psTransform->dfHeightScale, &dfResultX, &dfResultY ); } padfX[i] = dfResultX; padfY[i] = dfResultY; panSuccess[i] = TRUE; } return TRUE; }
static int GDALRPCGetDEMHeight( GDALRPCTransformInfo *psTransform, double dfX, double dfY, double* pdfDEMH ) { int bGotNoDataValue = FALSE; double dfNoDataValue = 0; int nRasterXSize = psTransform->poDS->GetRasterXSize(); int nRasterYSize = psTransform->poDS->GetRasterYSize(); dfNoDataValue = psTransform->poDS->GetRasterBand(1)->GetNoDataValue( &bGotNoDataValue ); int bands[1] = {1}; int dX = int(dfX); int dY = int(dfY); double dfDEMH(0); double dfDeltaX = dfX - dX; double dfDeltaY = dfY - dY; if(psTransform->eResampleAlg == DRA_Cubic) { int dXNew = dX - 1; int dYNew = dY - 1; if (!(dXNew >= 0 && dYNew >= 0 && dXNew + 4 <= nRasterXSize && dYNew + 4 <= nRasterYSize)) { return FALSE; } //cubic interpolation double adfElevData[16] = {0}; CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dXNew, dYNew, 4, 4, &adfElevData, 4, 4, GDT_Float64, 1, bands, 0, 0, 0); if(eErr != CE_None) { return FALSE; } double dfSumH(0), dfSumWeight(0); for ( int k_i = 0; k_i < 4; k_i++ ) { // Loop across the X axis for ( int k_j = 0; k_j < 4; k_j++ ) { // Calculate the weight for the specified pixel according // to the bicubic b-spline kernel we're using for // interpolation int dKernIndX = k_j - 1; int dKernIndY = k_i - 1; double dfPixelWeight = BiCubicKernel(dKernIndX - dfDeltaX) * BiCubicKernel(dKernIndY - dfDeltaY); // Create a sum of all values // adjusted for the pixel's calculated weight double dfElev = adfElevData[k_j + k_i * 4]; if( bGotNoDataValue && ARE_REAL_EQUAL(dfNoDataValue, dfElev) ) continue; dfSumH += dfElev * dfPixelWeight; dfSumWeight += dfPixelWeight; } } if( dfSumWeight == 0.0 ) { return FALSE; } dfDEMH = dfSumH / dfSumWeight; } else if(psTransform->eResampleAlg == DRA_Bilinear) { if (!(dX >= 0 && dY >= 0 && dX + 2 <= nRasterXSize && dY + 2 <= nRasterYSize)) { return FALSE; } //bilinear interpolation double adfElevData[4] = {0,0,0,0}; CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 2, 2, &adfElevData, 2, 2, GDT_Float64, 1, bands, 0, 0, 0); if(eErr != CE_None) { return FALSE; } if( bGotNoDataValue ) { // TODO: we could perhaps use a valid sample if there's one int bFoundNoDataElev = FALSE; for(int k_i=0; k_i<4; k_i++) { if( ARE_REAL_EQUAL(dfNoDataValue, adfElevData[k_i]) ) bFoundNoDataElev = TRUE; } if( bFoundNoDataElev ) { return FALSE; } } double dfDeltaX1 = 1.0 - dfDeltaX; double dfDeltaY1 = 1.0 - dfDeltaY; double dfXZ1 = adfElevData[0] * dfDeltaX1 + adfElevData[1] * dfDeltaX; double dfXZ2 = adfElevData[2] * dfDeltaX1 + adfElevData[3] * dfDeltaX; double dfYZ = dfXZ1 * dfDeltaY1 + dfXZ2 * dfDeltaY; dfDEMH = dfYZ; } else { if (!(dX >= 0 && dY >= 0 && dX < nRasterXSize && dY < nRasterYSize)) { return FALSE; } CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 1, 1, &dfDEMH, 1, 1, GDT_Float64, 1, bands, 0, 0, 0); if(eErr != CE_None || (bGotNoDataValue && ARE_REAL_EQUAL(dfNoDataValue, dfDEMH)) ) { return FALSE; } } *pdfDEMH = dfDEMH; return TRUE; }