diff --git a/gdal/frmts/nitf/nitfdataset.cpp b/gdal/frmts/nitf/nitfdataset.cpp index cda655ec849e..7965a4d5e539 100644 --- a/gdal/frmts/nitf/nitfdataset.cpp +++ b/gdal/frmts/nitf/nitfdataset.cpp @@ -4592,6 +4592,12 @@ NITFDataset::NITFCreateCopy( GDALWriteRPCTXTFile( pszFilename, papszRPC ); } + if( papszRPC != nullptr && + CPLFetchBool(papszFullOptions, "RPCTXT", false)) + { + GDALWriteRPCSensorMLFile( pszFilename, papszRPC ); + } + /* -------------------------------------------------------------------- */ /* Create the output file. */ /* -------------------------------------------------------------------- */ diff --git a/gdal/gcore/gdal_mdreader.cpp b/gdal/gcore/gdal_mdreader.cpp index 0e841010c795..7ad1d288603a 100644 --- a/gdal/gcore/gdal_mdreader.cpp +++ b/gdal/gcore/gdal_mdreader.cpp @@ -646,6 +646,231 @@ char ** GDALLoadRPCFile( const CPLString& soFilePath ) return papszMD; } +/************************************************************************/ +/* GDALWriteRPCSensorMLFile() */ +/************************************************************************/ + +CPLErr GDALWriteRPCSensorMLFile( const char *pszFilename, char **papszMD ) + +{ + CPLString osRPCFilename = pszFilename; + CPLString soPt("."); + size_t found = osRPCFilename.rfind(soPt); + if (found == CPLString::npos) + return CE_Failure; + osRPCFilename.replace (found, osRPCFilename.size() - found, "_RPC_SML.xml"); + if( papszMD == nullptr ) + { + VSIUnlink(osRPCFilename); + return CE_None; + } + +/* -------------------------------------------------------------------- */ +/* Read file and parse. */ +/* -------------------------------------------------------------------- */ + VSILFILE *fp = VSIFOpenL( osRPCFilename, "w" ); + + if( fp == nullptr ) + { + CPLError( CE_Failure, CPLE_OpenFailed, + "Unable to create %s for writing.\n%s", + osRPCFilename.c_str(), CPLGetLastErrorMsg() ); + return CE_Failure; + } + +/* -------------------------------------------------------------------- */ +/* Write RPC values from our RPC metadata. */ +/* -------------------------------------------------------------------- */ + bool bOK = true; + + bOK &= VSIFPrintfL( fp, " 0; + bOK &= VSIFPrintfL( fp, "xmlns:sml=\"http://www.opengis.net/sensorml/2.0\"\n") > 0; + bOK &= VSIFPrintfL( fp, "xmlns:swe=\"http://www.opengis.net/swe/2.0\"\n") > 0; + bOK &= VSIFPrintfL( fp, "xmlns:gml=\"http://www.opengis.net/gml/3.2\"\n") > 0; + bOK &= VSIFPrintfL( fp, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n") > 0; + bOK &= VSIFPrintfL( fp, "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n") > 0; + bOK &= VSIFPrintfL( fp, "xsi:schemaLocation=\"http://www.opengis.net/sensorml/2.0 http://schemas.opengis.net/sensorML/2.0/sensorML.xsd\"\n") > 0; + bOK &= VSIFPrintfL( fp, "definition=\"http://www.opengis.net/def/sensor-model/NTB/2.1/NITF/RPC00B\">\n") > 0; + bOK &= VSIFPrintfL( fp, "urn:ogc:sensor-model:ntb-nitf:2.1:RPC00B\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " TRE\n") > 0; + bOK &= VSIFPrintfL( fp, " RPC00B\n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " Math Function Type\n") > 0; + bOK &= VSIFPrintfL( fp, " Rational Polynomial Coefficients\n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + + for( int i = 0; apszRPCTXTSingleValItems[i] != nullptr; i ++ ) + { + const char *pszRPCVal = CSLFetchNameValue( papszMD, apszRPCTXTSingleValItems[i] ); + if( pszRPCVal == nullptr ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "%s field missing in metadata, %s file not written.", + apszRPCTXTSingleValItems[i], osRPCFilename.c_str() ); + CPL_IGNORE_RET_VAL(VSIFCloseL( fp )); + VSIUnlink( osRPCFilename ); + return CE_Failure; + } + + bOK &= VSIFPrintfL( fp, "\n", apszRPCTXTSingleValItems[i]) > 0; + + bOK &= VSIFPrintfL( fp, " \n", apszRPCTXTSingleValItems[i]) > 0; + bOK &= VSIFPrintfL( fp, " NITF RPC00B %s\n", apszRPCTXTSingleValItems[i]) > 0; + + bOK &= VSIFPrintfL( fp, " %s\n", apszRPCTXTSingleValItems[i], apszRPCTXTSingleValItems[i], apszRPCTXTSingleValItems[i]) > 0; + + +if (strcmp(apszRPCTXTSingleValItems[i],"ERR_BIAS")==0 || + strcmp(apszRPCTXTSingleValItems[i],"ERR_RAND")==0 || + strcmp(apszRPCTXTSingleValItems[i],"HEIGHT_OFF")==0 || + strcmp(apszRPCTXTSingleValItems[i],"HEIGHT_SCALE")==0) +bOK &= VSIFPrintfL( fp, " ") > 0; + +else if (strcmp(apszRPCTXTSingleValItems[i],"LINE_OFF")==0 || +strcmp(apszRPCTXTSingleValItems[i],"SAMP_OFF")==0 || +strcmp(apszRPCTXTSingleValItems[i],"LINE_SCALE")==0 || +strcmp(apszRPCTXTSingleValItems[i],"SAMP_SCALE")==0) +bOK &= VSIFPrintfL( fp, " ") > 0; + +else if (strcmp(apszRPCTXTSingleValItems[i],"LAT_OFF")==0 || +strcmp(apszRPCTXTSingleValItems[i],"LAT_SCALE")==0 || +strcmp(apszRPCTXTSingleValItems[i],"LONG_OFF")==0 || +strcmp(apszRPCTXTSingleValItems[i],"LONG_SCALE")==0) +bOK &= VSIFPrintfL( fp, " ") > 0; + + + bOK &= VSIFPrintfL( fp, "%s\n", pszRPCVal) > 0; + + bOK &= VSIFPrintfL( fp, " \n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + } + + + // start of DataArray + + for( int i = 0; apszRPCTXT20ValItems[i] != nullptr; i ++ ) + { + const char *pszRPCVal = CSLFetchNameValue( papszMD, apszRPCTXT20ValItems[i] ); + if( pszRPCVal == nullptr ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "%s field missing in metadata, %s file not written.", + apszRPCTXTSingleValItems[i], osRPCFilename.c_str() ); + CPL_IGNORE_RET_VAL(VSIFCloseL( fp )); + VSIUnlink( osRPCFilename ); + return CE_Failure; + } + + char **papszItems = CSLTokenizeStringComplex( pszRPCVal, " ,", + FALSE, FALSE ); + + if( CSLCount(papszItems) != 20 ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "%s field is corrupt (not 20 values), %s file not written.\n%s = %s", + apszRPCTXT20ValItems[i], osRPCFilename.c_str(), + apszRPCTXT20ValItems[i], pszRPCVal ); + CPL_IGNORE_RET_VAL(VSIFCloseL( fp )); + VSIUnlink( osRPCFilename ); + CSLDestroy( papszItems ); + return CE_Failure; + } + + +bOK &= VSIFPrintfL( fp, " \n", apszRPCTXT20ValItems[i]) > 0; +bOK &= VSIFPrintfL( fp, " \n", apszRPCTXT20ValItems[i]) > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; +bOK &= VSIFPrintfL( fp, " 20\n") > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; +bOK &= VSIFPrintfL( fp, " \n", apszRPCTXT20ValItems[i]) > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; + + for( int j = 0; j < 20; j++ ) + { + bOK &= VSIFPrintfL( fp, "%s ", papszItems[j] ) > 0; + } + +bOK &= VSIFPrintfL( fp, " \n") > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; +bOK &= VSIFPrintfL( fp, " \n") > 0; + + + + CSLDestroy( papszItems ); + } + + + + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, " The RPC00B Tagged Record Extension contains rational function polynomial coefficients and normalization parameters that define the physical relationship between image coordinates and ground coordinates.\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + bOK &= VSIFPrintfL( fp, "\n") > 0; + + if( VSIFCloseL( fp ) != 0 ) + bOK = false; + + return bOK ? CE_None : CE_Failure; +} + /************************************************************************/ /* GDALWriteRPCTXTFile() */ /************************************************************************/ diff --git a/gdal/gcore/gdal_mdreader.h b/gdal/gcore/gdal_mdreader.h index 751e2c6142ee..5db01860c70d 100644 --- a/gdal/gcore/gdal_mdreader.h +++ b/gdal/gcore/gdal_mdreader.h @@ -216,6 +216,7 @@ bool GDALCheckFileHeader(const CPLString& soFilePath, CPLErr GDALWriteRPBFile( const char *pszFilename, char **papszMD ); CPLErr GDALWriteRPCTXTFile( const char *pszFilename, char **papszMD ); +CPLErr GDALWriteRPCSensorMLFile( const char *pszFilename, char **papszMD ); CPLErr GDALWriteIMDFile( const char *pszFilename, char **papszMD ); #endif //GDAL_MDREADER_H_INCLUDED