From ee9e34585a55e4c1ca82bd8ebcf7cd16a42f8479 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 21 Jan 2022 12:06:20 +0100 Subject: [PATCH 1/5] Rename mapgdal.c to .cpp --- CMakeLists.txt | 2 +- mapgdal.c => mapgdal.cpp | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename mapgdal.c => mapgdal.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1abc1d8b00..48b79ab882 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -298,7 +298,7 @@ mapdraw.c maplibxml2.c mapquery.c maputil.c strptime.c mapdrawgdal.c mapraster.c mapuvraster.c mapdummyrenderer.c mapobject.c maprasterquery.c mapwcs.cpp maperror.c mapogcfilter.cpp mapregex.c mapwcs11.cpp mapfile.c mapogcfiltercommon.cpp maprendering.c mapwcs20.cpp mapogcsld.c mapmetadata.c -mapresample.c mapwfs.cpp mapgdal.c mapogcsos.c mapscale.c mapwfs11.cpp mapwfs20.c +mapresample.c mapwfs.cpp mapgdal.cpp mapogcsos.c mapscale.c mapwfs11.cpp mapwfs20.c mapgeomtransform.c mapogroutput.cpp mapwfslayer.c mapagg.cpp mapkml.cpp mapgeomutil.cpp mapkmlrenderer.cpp fontcache.c textlayout.c maputfgrid.cpp mapogr.cpp mapcontour.c mapsmoothing.c mapv8.cpp ${REGEX_SOURCES} kerneldensity.c diff --git a/mapgdal.c b/mapgdal.cpp similarity index 100% rename from mapgdal.c rename to mapgdal.cpp From cfe9cbbdefb72084b5f6f6df5470dbddcbdc25da Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 21 Jan 2022 12:06:21 +0100 Subject: [PATCH 2/5] WCS: support providing metadata items to GDAL output If a Mapfile defines a outputformat that is enabled in a WCS layer, then it is possible to define a per-layer value for GDAL metadata items, both at the dataset level with a syntax like: "wcs_outputformat_{format_name}_mdi_{domain}_{key}" "value" where: - format_name is substituted with the name of the output format - domain is substituted with the GDAL metadata domain into which to write the item. The special value "default" can be used for the default domain - key is the key of the metadata item. For band level metadata items, the syntax is: "wcs_outputformat_{format_name}_mdi_BAND_{band_number}_{domain}_{key}" "value" where band_number is a number between 1 and the number of bands of the dataset of the layer. In case of band selection in WCS output, the code will automatically renumber the band number. netCDF output is a typical use case. For dataset level metadata, the key must be prefix with NC_GLOBAL# e.g. "wcs_outputformat_netCDF_mdi_default_NC_GLOBAL#title" "A succinct description of what is in the dataset" For Band metadata, e.g. "wcs_outputformat_netCDF_mdi_BAND_1_default_NETCDF_VARNAME" "wind" "wcs_outputformat_netCDF_mdi_BAND_1_default_long_name" "wind from direction" "wcs_outputformat_netCDF_mdi_BAND_1_default_standard_name" "wind_from_direction" "wcs_outputformat_netCDF_mdi_BAND_1_default_units" "degree" NETCDF_VARNAME is a special key name recognized by the GDAL netCDF driver to determine the variable name. All other keys are mapped to a netCDF attribute belonging to the corresponding variable. --- mapgdal.cpp | 73 ++++++++++++--- mapwcs.cpp | 87 ++++++++++++++++++ mapwcs.h | 3 + mapwcs20.cpp | 1 + .../wcs_simple_layer_specif_option.tif | Bin 1204 -> 1326 bytes .../wxs/wcs_simple_layer_specific_option.map | 4 + 6 files changed, 154 insertions(+), 14 deletions(-) diff --git a/mapgdal.cpp b/mapgdal.cpp index 1c4858422b..b61fb7b7fc 100644 --- a/mapgdal.cpp +++ b/mapgdal.cpp @@ -140,7 +140,6 @@ int msSaveImageGDAL( mapObj *map, imageObj *image, const char *filenameIn ) GDALDriverH hMemDriver, hOutputDriver; int nBands = 1; int iLine; - char **papszOptions = NULL; outputFormatObj *format = image->format; rasterBufferObj rb; GDALDataType eDataType = GDT_Byte; @@ -414,25 +413,71 @@ int msSaveImageGDAL( mapObj *map, imageObj *image, const char *filenameIn ) GDALSetMetadataItem( hMemDS, "TIFFTAG_RESOLUTIONUNIT", "2", NULL ); } + /* -------------------------------------------------------------------- */ + /* Separate creation options from metadata items. */ + /* -------------------------------------------------------------------- */ + std::vector apszCreationOptions; + for( int i = 0; i < format->numformatoptions; i++ ) + { + char* option = format->formatoptions[i]; + + // MDI stands for MetaDataItem + if( STARTS_WITH(option, "mdi_") ) + { + const char* option_without_band = option + strlen("mdi_"); + GDALMajorObjectH hObject = (GDALMajorObjectH)hMemDS; + if( STARTS_WITH(option_without_band, "BAND_") ) + { + int nBandNumber = atoi(option_without_band + strlen("BAND_")); + if( nBandNumber > 0 && nBandNumber <= nBands ) + { + const char* pszAfterBand = strchr(option_without_band + strlen("BAND_"), '_'); + if( pszAfterBand != NULL ) + { + hObject = (GDALMajorObjectH)GDALGetRasterBand(hMemDS, nBandNumber); + option_without_band = pszAfterBand + 1; + } + } + else { + msDebug("Invalid band number %d in metadata item option %s", nBandNumber, option); + } + } + if( hObject ) { + std::string osDomain(option_without_band); + size_t nUnderscorePos = osDomain.find('_'); + if( nUnderscorePos != std::string::npos ) { + std::string osKeyValue = osDomain.substr(nUnderscorePos + 1); + osDomain.resize(nUnderscorePos); + if( osDomain == "default" ) + osDomain.clear(); + size_t nEqualPos = osKeyValue.find('='); + if( nEqualPos != std::string::npos ) + { + GDALSetMetadataItem(hObject, + osKeyValue.substr(0, nEqualPos).c_str(), + osKeyValue.substr(nEqualPos + 1).c_str(), + osDomain.c_str()); + } + } + else { + msDebug("Invalid format in metadata item option %s", option); + } + } + } + else + { + apszCreationOptions.emplace_back(option); + } + } + apszCreationOptions.emplace_back(nullptr); + /* -------------------------------------------------------------------- */ /* Create a disk image in the selected output format from the */ /* memory image. */ /* -------------------------------------------------------------------- */ - papszOptions = (char**)calloc(sizeof(char *),(format->numformatoptions+1)); - if (papszOptions == NULL) { - msReleaseLock( TLOCK_GDAL ); - msSetError( MS_MEMERR, "Out of memory allocating %u bytes.\n", "msSaveImageGDAL()", - (unsigned int)(sizeof(char *)*(format->numformatoptions+1))); - return MS_FAILURE; - } - - memcpy( papszOptions, format->formatoptions, - sizeof(char *) * format->numformatoptions ); - hOutputDS = GDALCreateCopy( hOutputDriver, filename, hMemDS, FALSE, - papszOptions, NULL, NULL ); + &apszCreationOptions[0], NULL, NULL ); - free( papszOptions ); if( hOutputDS == NULL ) { GDALClose( hMemDS ); diff --git a/mapwcs.cpp b/mapwcs.cpp index fdefc9eefc..6123e2223c 100644 --- a/mapwcs.cpp +++ b/mapwcs.cpp @@ -1740,6 +1740,92 @@ void msWCSApplyDatasetMetadataAsCreationOptions(layerObj* lp, } } +/************************************************************************/ +/* msWCSApplyLayerMetadataItemOptions() */ +/************************************************************************/ + +void msWCSApplyLayerMetadataItemOptions(layerObj* lp, + outputFormatObj* format, + const char* bandlist) + +{ + if( !STARTS_WITH(format->driver, "GDAL/") ) + return; + + const char* pszKey; + char szKeyBeginning[256]; + size_t nKeyBeginningLength; + int nBands = 0; + char** papszBandNumbers = msStringSplit(bandlist, ' ', &nBands); + + snprintf(szKeyBeginning, sizeof(szKeyBeginning), + "wcs_outputformat_%s_mdi_", format->name); + nKeyBeginningLength = strlen(szKeyBeginning); + + // Transform wcs_outputformat_{formatname}_mdi_{key} to mdi_{key} + // and Transform wcs_outputformat_{formatname}_mdi_BAND_X_{key} to mdi_BAND_Y_{key} + // MDI stands for MetaDataItem + + pszKey = msFirstKeyFromHashTable( &(lp->metadata) ); + for( ; pszKey != NULL; + pszKey = msNextKeyFromHashTable( &(lp->metadata), pszKey) ) + { + if( strncmp(pszKey, szKeyBeginning, nKeyBeginningLength) == 0 ) + { + const char* pszValue = msLookupHashTable( &(lp->metadata), pszKey); + const char* pszGDALKey = pszKey + nKeyBeginningLength; + + if( EQUALN(pszGDALKey, "BAND_", strlen("BAND_")) ) + { + /* Remap BAND specific creation option to the real output + * band number, given the band subset of the request */ + int nKeyOriBandNumber = atoi(pszGDALKey + strlen("BAND_")); + int nTargetBandNumber = -1; + int i; + for(i = 0; i < nBands; i++ ) + { + if( nKeyOriBandNumber == atoi(papszBandNumbers[i]) ) + { + nTargetBandNumber = i + 1; + break; + } + } + if( nTargetBandNumber > 0 ) + { + char szModKey[256]; + const char* pszAfterBand = + strchr(pszGDALKey + strlen("BAND_"), '_'); + if( pszAfterBand != NULL ) + { + snprintf(szModKey, sizeof(szModKey), + "mdi_BAND_%d%s", + nTargetBandNumber, + pszAfterBand); + if( lp->debug >= MS_DEBUGLEVEL_VVV ) { + msDebug("Setting GDAL %s=%s metadata item option\n", + szModKey, pszValue); + } + msSetOutputFormatOption(format, szModKey, pszValue); + } + } + } + else + { + char szModKey[256]; + snprintf(szModKey, sizeof(szModKey), + "mdi_%s", pszGDALKey); + if( lp->debug >= MS_DEBUGLEVEL_VVV ) { + msDebug("Setting GDAL %s=%s metadata item option\n", + szModKey, pszValue); + } + msSetOutputFormatOption(format, szModKey, pszValue); + } + } + } + + msFreeCharArray( papszBandNumbers, nBands ); +} + /************************************************************************/ /* msWCSGetCoverage() */ /************************************************************************/ @@ -2144,6 +2230,7 @@ this request. Check wcs/ows_enable_request settings.", "msWCSGetCoverage()", par msSetOutputFormatOption(map->outputformat, "BAND_COUNT", numbands); msWCSApplyLayerCreationOptions(lp, map->outputformat, bandlist); + msWCSApplyLayerMetadataItemOptions(lp, map->outputformat, bandlist); if( lp->tileindex == NULL && lp->data != NULL && strlen(lp->data) > 0 && diff --git a/mapwcs.h b/mapwcs.h index fc203d043e..e1dee39a7e 100644 --- a/mapwcs.h +++ b/mapwcs.h @@ -113,6 +113,9 @@ void msWCSApplyDatasetMetadataAsCreationOptions(layerObj* lp, outputFormatObj* format, const char* bandlist, void* hDSIn); +void msWCSApplyLayerMetadataItemOptions(layerObj* lp, + outputFormatObj* format, + const char* bandlist); /* -------------------------------------------------------------------- */ /* Some WCS 1.1 specific functions from mapwcs11.c */ diff --git a/mapwcs20.cpp b/mapwcs20.cpp index 76099693c3..188c9b0db8 100644 --- a/mapwcs20.cpp +++ b/mapwcs20.cpp @@ -4716,6 +4716,7 @@ this request. Check wcs/ows_enable_request settings.", "msWCSGetCoverage20()", p msSetOutputFormatOption(map->outputformat, "BAND_COUNT", numbands); msWCSApplyLayerCreationOptions(layer, map->outputformat, bandlist); + msWCSApplyLayerMetadataItemOptions(layer, map->outputformat, bandlist); /* check for the interpolation */ /* Defaults to NEAREST */ diff --git a/msautotest/wxs/expected/wcs_simple_layer_specif_option.tif b/msautotest/wxs/expected/wcs_simple_layer_specif_option.tif index a8db9e063eac70bfd83a42d02d86965c2838f096..55f7148c7757c388fd9dc517ebdb532562672de6 100644 GIT binary patch delta 229 zcmdnOxsHp|(^HFqgMooTWFn_4lM>U!06o5cK&~_+D+42tW@DV#V^v=RWHz<%Ft7nd zrU2RN+nE^@fb1hc_QrN5200*`g^7WoVF?pM9+1rk6bAthAOf`W}_NouY_USe*lt&*F+zmlDkV~~wLNDx`p3?vPdQBo*Q%q_?Paty#K Date: Fri, 21 Jan 2022 12:06:22 +0100 Subject: [PATCH 3/5] msautotest compare_result(): special case for netCDF --- msautotest/pymod/testlib.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/msautotest/pymod/testlib.py b/msautotest/pymod/testlib.py index 636e032855..c266596b02 100644 --- a/msautotest/pymod/testlib.py +++ b/msautotest/pymod/testlib.py @@ -97,10 +97,7 @@ def compare_result( filename, this_path = '.' ): # Check image checksums with GDAL if it is available. try: - try: - from osgeo import gdal - except: - import gdal + from osgeo import gdal gdal.PushErrorHandler('CPLQuietErrorHandler') exp_ds = gdal.Open( expected_file ) @@ -117,7 +114,30 @@ def compare_result( filename, this_path = '.' ): match = 0 if match == 1: + + # Special case for netCDF: we need to eliminate NC_GLOBAL#history + # since it contains the current timedate + if exp_ds.GetDriver().GetDescription() == 'netCDF': + if exp_ds.GetGeoTransform() != res_ds.GetGeoTransform(): + return 'nomatch' + if exp_ds.GetProjectionRef() != res_ds.GetProjectionRef(): + return 'nomatch' + exp_md = exp_ds.GetMetadata() + if "NC_GLOBAL#history" in exp_md: + del exp_md['NC_GLOBAL#history'] + got_md = res_ds.GetMetadata() + if 'NC_GLOBAL#history' in got_md: + del got_md['NC_GLOBAL#history'] + if exp_md != got_md: + return 'nomatch' + for band_num in range(1,exp_ds.RasterCount+1): + if res_ds.GetRasterBand(band_num).GetMetadata() != \ + exp_ds.GetRasterBand(band_num).GetMetadata(): + return 'nomatch' + return 'match' + return 'files_differ_image_match' + except: pass From 43fe56e8eb10e6d8655a0b0f0cfd2c2a8a21597b Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 21 Jan 2022 12:06:23 +0100 Subject: [PATCH 4/5] WCS and netCDF input/output: automatically set GDAL/netCDF output metadata itemps from netCDF input dataset metadata (if wcs_outputformat_netCDF_mdi_ not defined) --- mapwcs.cpp | 101 ++++++++++++++++ mapwcs.h | 5 +- mapwcs20.cpp | 3 + msautotest/wxs/data/trmm-2x2.nc | Bin 0 -> 2032 bytes ..._netcdf_input_output_wcs10_get_coverage.nc | Bin 0 -> 2668 bytes ..._netcdf_input_output_wcs20_get_coverage.nc | Bin 0 -> 2644 bytes msautotest/wxs/wcs_netcdf_input_output.map | 111 ++++++++++++++++++ 7 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 msautotest/wxs/data/trmm-2x2.nc create mode 100644 msautotest/wxs/expected/wcs_netcdf_input_output_wcs10_get_coverage.nc create mode 100644 msautotest/wxs/expected/wcs_netcdf_input_output_wcs20_get_coverage.nc create mode 100644 msautotest/wxs/wcs_netcdf_input_output.map diff --git a/mapwcs.cpp b/mapwcs.cpp index 6123e2223c..84187a2ba1 100644 --- a/mapwcs.cpp +++ b/mapwcs.cpp @@ -1826,6 +1826,104 @@ void msWCSApplyLayerMetadataItemOptions(layerObj* lp, msFreeCharArray( papszBandNumbers, nBands ); } +/************************************************************************/ +/* msWCSApplySourceDatasetMetadata() */ +/************************************************************************/ + +void msWCSApplySourceDatasetMetadata(layerObj* lp, + outputFormatObj* format, + const char* bandlist, + void* hDSIn) +{ + /* Automatic forwarding of input dataset metadata if it is netCDF and the */ + /* output is netCDF as well, and wcs_outputformat_netCDF_mdi* are */ + /* not defined. */ + GDALDatasetH hDS = (GDALDatasetH)hDSIn; + if( hDS && GDALGetDatasetDriver(hDS) && + EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hDS)), "netCDF") && + EQUAL(format->driver, "GDAL/netCDF") ) + { + const char* pszKey; + char szKeyBeginning[256]; + size_t nKeyBeginningLength; + int bWCSMetadataFound = MS_FALSE; + + snprintf(szKeyBeginning, sizeof(szKeyBeginning), + "wcs_outputformat_%s_mdi_", format->name); + nKeyBeginningLength = strlen(szKeyBeginning); + + for( pszKey = msFirstKeyFromHashTable( &(lp->metadata) ); + pszKey != NULL; + pszKey = msNextKeyFromHashTable( &(lp->metadata), pszKey) ) + { + if( strncmp(pszKey, szKeyBeginning, nKeyBeginningLength) == 0 ) + { + bWCSMetadataFound = MS_TRUE; + break; + } + } + if( !bWCSMetadataFound ) + { + { + char** papszMD = GDALGetMetadata(hDS, NULL); + if( papszMD ) + { + for( char** papszIter = papszMD; *papszIter; ++papszIter ) + { + if( STARTS_WITH(*papszIter, "NC_GLOBAL#") ) + { + char* pszKey = nullptr; + const char* pszValue = CPLParseNameValue(*papszIter, &pszKey); + if( pszKey && pszValue ) + { + char szKey[256]; + snprintf(szKey, sizeof(szKey), + "mdi_default_%s", pszKey); + msSetOutputFormatOption(format, szKey, pszValue); + } + CPLFree(pszKey); + } + } + } + } + + int nBands = 0; + char** papszBandNumbers = msStringSplit(bandlist, ' ', &nBands); + int i; + for(i = 0; i < nBands; i++ ) + { + int nSrcBand = atoi(papszBandNumbers[i]); + int nDstBand = i + 1; + GDALRasterBandH hBand = GDALGetRasterBand(hDS, nSrcBand); + if( hBand ) + { + char** papszMD = GDALGetMetadata(hBand, NULL); + if( papszMD ) + { + for( char** papszIter = papszMD; *papszIter; ++papszIter ) + { + char* pszKey = nullptr; + const char* pszValue = CPLParseNameValue(*papszIter, &pszKey); + if( pszKey && pszValue && + !EQUAL(pszKey, "grid_name") && + !EQUAL(pszKey, "grid_mapping") ) + { + char szKey[256]; + snprintf(szKey, sizeof(szKey), + "mdi_BAND_%d_default_%s", + nDstBand, pszKey); + msSetOutputFormatOption(format, szKey, pszValue); + } + CPLFree(pszKey); + } + } + } + } + msFreeCharArray( papszBandNumbers, nBands ); + } + } +} + /************************************************************************/ /* msWCSGetCoverage() */ /************************************************************************/ @@ -2244,7 +2342,10 @@ this request. Check wcs/ows_enable_request settings.", "msWCSGetCoverage()", par map, lp, lp->data, szPath, &decrypted_path); msFree(decrypted_path); if( hDS ) + { msWCSApplyDatasetMetadataAsCreationOptions(lp, map->outputformat, bandlist, hDS); + msWCSApplySourceDatasetMetadata(lp, map->outputformat, bandlist, hDS); + } } else { diff --git a/mapwcs.h b/mapwcs.h index e1dee39a7e..48b127f359 100644 --- a/mapwcs.h +++ b/mapwcs.h @@ -116,7 +116,10 @@ void msWCSApplyDatasetMetadataAsCreationOptions(layerObj* lp, void msWCSApplyLayerMetadataItemOptions(layerObj* lp, outputFormatObj* format, const char* bandlist); - +void msWCSApplySourceDatasetMetadata(layerObj* lp, + outputFormatObj* format, + const char* bandlist, + void* hDSIn); /* -------------------------------------------------------------------- */ /* Some WCS 1.1 specific functions from mapwcs11.c */ /* -------------------------------------------------------------------- */ diff --git a/mapwcs20.cpp b/mapwcs20.cpp index 188c9b0db8..9686692494 100644 --- a/mapwcs20.cpp +++ b/mapwcs20.cpp @@ -4758,7 +4758,10 @@ this request. Check wcs/ows_enable_request settings.", "msWCSGetCoverage20()", p map, layer, layer->data, szPath, &decrypted_path); msFree(decrypted_path); if( hDS ) + { msWCSApplyDatasetMetadataAsCreationOptions(layer, map->outputformat, bandlist, hDS); + msWCSApplySourceDatasetMetadata(layer, map->outputformat, bandlist, hDS); + } } else { diff --git a/msautotest/wxs/data/trmm-2x2.nc b/msautotest/wxs/data/trmm-2x2.nc new file mode 100644 index 0000000000000000000000000000000000000000..7788931a4c134f102aa9200303ca1cad5938f2fa GIT binary patch literal 2032 zcmb7FO>g8h7@pm3+u81J1y?}AN04SR`I>&D2UMmMR@zmO3M`yPp4gKyBz9yw)0Q8A z;K-E|2Yv*{y@2=$9QVjiK;pvtI>|Q8ZiUFi^Tx03$B*AH&rVM736Fx+k#$rj896fzUHYllaz_~5%0lF$u*Z2)|nQ6Yj!#gycoNK z?UgWA>8ob!?k~?cBWI~4VN8NBnZ}8KKtdlrNy-#4JQtGj%Z0ie`J)gUvAQTcnL0TR zFGKj=L6mb|5`UkBVG>2j^bk>kmndK+unNMA5B$-1A6f`4@QE$Tcq~=wAd7O^g(ENF zq6SW;)LPhVOiAaYqbyeonvd9M{{I85+$Ub(jC zn(9%Rmbf5j7CJ}Zrcdb=3HAxBisA(PdaEO*UN{9m9C~{ogSt2MN%UbHdAO(nM(G$` z1BZJ_6m)udAjOe&&1(~( zUC-5kvsVAfjT&%Pa!nyk&HtRWdvpC+!;aQ9dMf++xh*y-(9H+TnnKHMIJ+Z z?Bh#(KXETWz7p@l)>klwoZt@G{uAT|6af&92XgBA80WptE^n8br=k=V%%f!TX}5=1 zJM&YK=U>pgs&B1L#Qpu94}JpK&$G8am)}TrAp-&xNw{QcG7*tr|4a+ki=A!MjRQCS zX3p0<*I6u4|!vJ ny?B29w_E-E{I6O@FBD^tYgcZQZ9Kivuc3o%JlII1FIC*6#E{$i2OG$RnCF(xEve{Wxc0LVZT&Ok_NX ziJ{h1o7_9f^VHQeKM9!nbwrQVfN7~nUNJwxVZdI)+G zkwm1tS3naLLDiUMRGlVsElVc(F%?Xc7+SGgLk5+~W;==Ja4y&fkCvQnw0C#FRyeHO zJmMK#_7wZzpR0e3k7nd^8WU3|rr}ym*Rr8+nl9;eT8~LvGHxg7={=(5QL5Dq<^=T` z^-R_@JY9`_g{Z1Z?r%JWiw*pom^Lv?w`RL~6Of=w{2(D23wa!{lf&dh(G?RL$wd?a zfRsDti3xp)GGZyw8w5yLmRoZW#W+KO;DQ??%uZ8Rb{f!3XogOJp1l(%U@3r%(%Lc{ zIfJuGxY(yT`eKKYC7UVJFgc{55-5tqE3p>1l3r^zU0l*}bu<^!JHzV`;3824+haKm zAbM4O85kB@!aw5kH>?ABYjH4MVmxC+9tzwIIMKCh7j2UBh-EoT6$4459Z@32@?OJn z@hiP@ZqGRtO6sS$!6-LMN8q7*^pqG40=q2R1;4)05jEAUfgc>T4$>$_HJwlq4|hE7v0^6`}0P z{8*o|B+~+l33C^t-W&IKcgL-sH|&lEj}ONE!IOh0{W0#i1`X>S*0v8W=sr7FhP4~0 z_izZm#pj~#^SA0=LtNN~XM8NP&{B2PR)}CBqZ!03B&e?GhGsSqeG?k;TJwd>d7Q&K zdlTCGQ^5l-qG<|+#*1mhaJ9g`4SB@#S-?EVsj2MAwRdoMN%vNJI3fX?@R(z5k$QK} zwt30KO9eR11NZTOQ>h?rAT^7hcQY1o;PNUF9zEfbtJG;d8~^gK(7DZ_e2I*C6Cjtf z7+A}N!k*&ikABFbZ((LLOMyHMJ;5fZ0JgfK_PT>!d-S6Ev^OG6yQ*|r?2n(nsCM^9y{b}e=$2l6`Etcd z-7@RAvOnzab>Xz0U@Si7{!tZb-0MJ1M>kL%1L{RJU{g>BO;tA4bO725!Px%n585cWcnL7yr{Q#nJjA=0ImvoGq_kpFyyd z5skU9U05sg;zZ;}FaaNoi}!%bCmUWAzqrWr&%=HtpUXOzIc+UCL1LmI7JM*& z*PyI|koH>UggUG4em51&=PA#@vq|jkFOLvs!`tOy_yrATMG{|!xhuba`00-zFTXeL z9K>J6$#HBDsP9}pD#{lLB0*gU*_?%5z%pO(^em+%*X=F^`;u%XpIe3gEiB0%I5mg& z1IHImaj$J2qo?7^l3D4it>v0i>Md#$az=lBi2%P^f1m*QQz1uxm-0_3A2k2jeDM9# M?;d>f8|HlFU$2FMYXATM literal 0 HcmV?d00001 diff --git a/msautotest/wxs/expected/wcs_netcdf_input_output_wcs20_get_coverage.nc b/msautotest/wxs/expected/wcs_netcdf_input_output_wcs20_get_coverage.nc new file mode 100644 index 0000000000000000000000000000000000000000..58fe4cd440b928cffc8aef37e9bcc3d010c88eb0 GIT binary patch literal 2644 zcmb7GOK%%D5LV(mTtCt#hoV7Hln{DIfc3uh*v%!XBr7W7$dKeFfnhA@T}o!UFK}0~ zUG!YE$6k8wq3G}ErT?SHo{Am|^wJsb%9bB#QCZZG!{Nt|Gs7|4o$VWy; ziBVJZX};)hKnL5ZPeT?5RFpQWSx#{nz<8zI>4T7Kd+m@%G-sqkb4vPg&cuZJjLezH zcoGvst*JJ7e3a*@t7(1`F!ig59;*SX z>?R_KNO`V+CMtreG0mttP3BsbO!8wYm?kl_Vzq`0DwXwi63<~@@DFY+Io)Y*Z-K9H zSh;(|GdS!i_8~qu{}><5$mcXBrcO-5wVJMFL*F!A((ANdkhWypPSVrIM9ZU8s~gM- z>NV<_tZ8|=8v6=SRh2whdj$s@_&G6cVwi5tcJ(G8L6`VJLNXTeIAAA-$% N`3b zC;|W}x6Bh0`VwWtQld8qkgzPb<{*l3h62e2Cq|g9rmk!?pqbDNod7+1D^9>u02!sV zWjJyMXO(cVPjigL79~qQQ>I~ZNJAx16p2@2EpR2h)@-^sq~q%7E~Iyc*CD_~q6)Ud zavDJPs`@f8Otyr7#OLpr2lCcpV?4xo#)#Y$xErveYu7INBII6 zuDltLF{7qrr>4aewe~?`40CD{eu!{H^{d+p(f1Z=`%jGUiQy zT+U)(Ehh?pil09IA&*b>qWcchGB(_N%k_%Q!iXt4gOe-rL!) zzUqxU!)e-8WwiUeI~?>oQb$lzw;D~uYAB}DgdA>|rd6w3N^5WYd@$^f-|SbryQ5xJ zsWx;=uO1v+GgG(BI?n74`#W9OttS|ZkGX$Tg(7zqsOjhinqx-oR|7T$bFfr(qhZ%9 z(=ls?L9=`)^8|4{#eM-U#0wA%BRi0*Pnj> N>bs}k{EBzG@((B2d)fd1 literal 0 HcmV?d00001 diff --git a/msautotest/wxs/wcs_netcdf_input_output.map b/msautotest/wxs/wcs_netcdf_input_output.map new file mode 100644 index 0000000000..40a2d3c8c7 --- /dev/null +++ b/msautotest/wxs/wcs_netcdf_input_output.map @@ -0,0 +1,111 @@ +# +# Test WCS with netCDF input and output +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WCS + +# RUN_PARMS: wcs_netcdf_input_output_wcs10_get_coverage.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&REQUEST=GetCoverage&VERSION=1.0.0&COVERAGE=precipitation&CRS=EPSG:4326&BBOX=-80,-20,-79.5,-19.5&RESX=0.25&RESY=0.25&FORMAT=netCDF" > [RESULT_DEMIME] + +# RUN_PARMS: wcs_netcdf_input_output_wcs20_get_coverage.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&REQUEST=GetCoverage&VERSION=2.0.1&COVERAGEID=precipitation&FORMAT=application/x-netcdf&SUBSET=long(-80,-79.5)&SUBSETTINGCRS=http://www.opengis.net/def/crs/EPSG/0/4326" > [RESULT_DEMIME] + +MAP + +NAME TEST +SIZE 400 300 +EXTENT -180 -90 180 90 +MAXSIZE 5000 + +IMAGETYPE PNG +SHAPEPATH "data" + +OUTPUTFORMAT + NAME netCDF + DRIVER "GDAL/netCDF" + MIMETYPE "application/x-netCDF" + IMAGEMODE Float32 + EXTENSION "nc" +END + +PROJECTION + "init=epsg:4326" +END + +WEB + METADATA + # OWS stuff for server + "ows_updatesequence" "2007-10-30T14:23:38Z" + "ows_title" "First Test Service" + "ows_fees" "NONE" + "ows_accessconstraints" "NONE" + "ows_abstract" "Test Abstract" + "ows_keywordlist" "keyword,list" + "ows_service_onlineresource" "http://198.202.74.215/cgi-bin/wcs_demo" + "ows_contactorganization" "OSGeo" + "ows_contactperson" "Frank Warmerdam" + "ows_contactposition" "Software Developer" + "ows_contactvoicetelephone" "(613) 754-2041" + "ows_contactfacsimiletelephone" "(613) 754-2041x343" + "ows_address" "3594 Foymount Rd" + "ows_city" "Eganville" + "ows_stateorprovince" "Ontario" + "ows_postcode" "K0J 1T0" + "ows_country" "Canada" + "ows_contactelectronicmailaddress" "warmerdam@pobox.com" + "ows_hoursofservice" "0800h - 1600h EST" + "ows_contactinstructions" "during hours of service" + "ows_role" "staff" + "ows_enable_request" "*" + "ows_srs" "EPSG:4326" + + # OGC:WCS + "wcs_label" "Test Label" + "wcs_description" "Test description" + "wcs_onlineresource" "http://devgeo.cciw.ca/cgi-bin/mapserv/ecows" + "wcs_metadatalink_href" "http://devgeo.cciw.ca/index.html" + "wcs_formats" "netCDF" + END +END + +LAYER + NAME precipitation + TYPE raster + STATUS ON + DATA "trmm-2x2.nc" + + PROJECTION + "init=epsg:4326" + END + METADATA + "ows_extent" "-80 -20 -79.5 -19.5" + "wcs_label" "Test label" + "ows_srs" "EPSG:4326" + "wcs_resolution" "0.25 0.25" + "wcs_bandcount" "1" + "wcs_imagemode" "Float32" + "wcs_formats" "netCDF" + "wcs_description" "Test description" + "wcs_metadatalink_href" "http://www.gdal.org/metadata_test_link.html" + "wcs_keywordlist" "test,mapserver" + "wcs_abstract" "abstract" + + # WCS 2.0 stuff + "wcs_native_format" "application/x-netcdf" + "wcs_band_names" "precipitation" + "precipitation_band_interpretation" "interp" + "precipitation_band_uom" "uom" + "precipitation_band_definition" "precipitation" + "precipitation_band_description" "precipitation" + "precipitation_interval" "-100 100" + "precipitation_significant_figures" "1" + + # WCS 1.x stuff + "wcs_nativeformat" "netCDF" + "wcs_rangeset_axes" "bands" + "wcs_rangeset_name" "precipitation" + "wcs_rangeset_label" "Bands" + "wcs_rangeset_description" "precipitation" + + "wcs_rangeset_nullvalue" "-9999.9004" + END +END + +END From a1445667b0ceadb679784879f3a709ddb3566b27 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 21 Jan 2022 12:50:40 +0100 Subject: [PATCH 5/5] Avoid issue on Travis-CI with new wcs_netcdf_input_output.map test --- msautotest/pymod/mstestlib.py | 18 ++++++++++++++++++ msautotest/wxs/wcs_netcdf_input_output.map | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/msautotest/pymod/mstestlib.py b/msautotest/pymod/mstestlib.py index 4fb7e3900a..5c0c50c077 100644 --- a/msautotest/pymod/mstestlib.py +++ b/msautotest/pymod/mstestlib.py @@ -541,6 +541,14 @@ def _run(map, out_file, command, extra_args): else: command = command.replace('[RENDERER]', '' ) + # Used in msautotest/wxs/wcs_netcdf_input_output.map as for some unknown + # reason comparison fails on Travis-CI but not in the github action tests + ignore_comparison_result = False + if '[IGNORE_COMPARISON_RESULT_ON_TRAVIS]' in command: + command = command.replace('[IGNORE_COMPARISON_RESULT_ON_TRAVIS]', '' ) + if 'TRAVIS' in os.environ: + ignore_comparison_result = True + os.environ['MS_PDF_CREATION_DATE'] = 'dummy date' #support for environment variable of type [ENV foo=bar] @@ -648,6 +656,16 @@ def _run(map, out_file, command, extra_args): cmp = compare_result( out_file ) + if cmp != 'match' and ignore_comparison_result: + if not keep_pass: + os.remove( 'result/' + out_file ) + if not quiet: + print(' results do not match, but ignored.') + else: + sys.stdout.write('.') + sys.stdout.flush() + return True, None + if cmp == 'match': if not keep_pass: os.remove( 'result/' + out_file ) diff --git a/msautotest/wxs/wcs_netcdf_input_output.map b/msautotest/wxs/wcs_netcdf_input_output.map index 40a2d3c8c7..a7e137a399 100644 --- a/msautotest/wxs/wcs_netcdf_input_output.map +++ b/msautotest/wxs/wcs_netcdf_input_output.map @@ -3,9 +3,9 @@ # # REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WCS -# RUN_PARMS: wcs_netcdf_input_output_wcs10_get_coverage.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&REQUEST=GetCoverage&VERSION=1.0.0&COVERAGE=precipitation&CRS=EPSG:4326&BBOX=-80,-20,-79.5,-19.5&RESX=0.25&RESY=0.25&FORMAT=netCDF" > [RESULT_DEMIME] +# RUN_PARMS: wcs_netcdf_input_output_wcs10_get_coverage.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&REQUEST=GetCoverage&VERSION=1.0.0&COVERAGE=precipitation&CRS=EPSG:4326&BBOX=-80,-20,-79.5,-19.5&RESX=0.25&RESY=0.25&FORMAT=netCDF" > [RESULT_DEMIME][IGNORE_COMPARISON_RESULT_ON_TRAVIS] -# RUN_PARMS: wcs_netcdf_input_output_wcs20_get_coverage.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&REQUEST=GetCoverage&VERSION=2.0.1&COVERAGEID=precipitation&FORMAT=application/x-netcdf&SUBSET=long(-80,-79.5)&SUBSETTINGCRS=http://www.opengis.net/def/crs/EPSG/0/4326" > [RESULT_DEMIME] +# RUN_PARMS: wcs_netcdf_input_output_wcs20_get_coverage.nc [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WCS&REQUEST=GetCoverage&VERSION=2.0.1&COVERAGEID=precipitation&FORMAT=application/x-netcdf&SUBSET=long(-80,-79.5)&SUBSETTINGCRS=http://www.opengis.net/def/crs/EPSG/0/4326" > [RESULT_DEMIME][IGNORE_COMPARISON_RESULT_ON_TRAVIS] MAP