/****************************************************************************** * $Id: gdalbuildvrt.cpp rouault $ * * Project: GDAL Utilities * Purpose: Commandline application to build VRT datasets from raster products or content of SHP tile index * Author: Even Rouault, even.rouault at mines-paris.org * ****************************************************************************** * Copyright (c) 2007, Even Rouault * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "gdal_proxy.h" #include "cpl_string.h" #include "ogrsf_frmts/shape/shapefil.h" #include "vrt/gdal_vrt.h" CPL_CVSID("$Id: gdalbuildvrt.cpp rouault $"); #define GEOTRSFRM_TOPLEFT_X 0 #define GEOTRSFRM_WE_RES 1 #define GEOTRSFRM_ROTATION_PARAM1 2 #define GEOTRSFRM_TOPLEFT_Y 3 #define GEOTRSFRM_ROTATION_PARAM2 4 #define GEOTRSFRM_NS_RES 5 typedef enum { LOWEST_RESOLUTION, HIGHEST_RESOLUTION, AVERAGE_RESOLUTION } ResolutionStrategy; typedef struct { int isFileOK; int nRasterXSize; int nRasterYSize; double adfGeoTransform[6]; int nBlockXSize; int nBlockYSize; } DatasetProperty; typedef struct { GDALColorInterp colorInterpretation; GDALDataType dataType; GDALColorTableH colorTable; int bHasNoData; double noDataValue; } BandProperty; /************************************************************************/ /* Usage() */ /************************************************************************/ static void Usage() { fprintf(stdout, "%s", "Usage: gdalbuildvrt [-tileindex field_name] [-resolution {highest,lowest,average}]\n" " output.vrt {[inputfile]* | -input_file_list my_liste.txt}\n" "\n" "eg.\n" " % gdalbuildvrt doq_index.vrt doq/*.tif\n" " % gdalbuildvrt -input_file_list my_liste.txt doq_index.vrt\n" "\n" "NOTES:\n" " o The default tile index field is 'location' unless otherwise specified by -tileindex.\n" " o In case the resolution of all input files is not the same, the -resolution flag.\n" " enable the user to control the way the output resolution is computed. average is the default.\n" " o Input files may be any valid GDAL dataset or a GDAL raster tile index.\n" " o For a GDAL raster tile index, all entries will be added to the VRT.\n" " o If one GDAL dataset is made of several subdatasets, they will be added to the VRT " " rather than the dataset itself.\n" " o Only datasets of same projection and band characteristics may be added to the VRT.\n"); exit( 1 ); } void build_vrt(const char* pszOutputFilename, int* pnInputFiles, char*** pppszInputFilenames, ResolutionStrategy resolutionStrategy) { char* projectionRef = NULL; int nBands = 0; BandProperty* bandProperties = NULL; double minX = 0, minY = 0, maxX = 0, maxY = 0; int i,j; double we_res = 0; double ns_res = 0; int rasterXSize; int rasterYSize; int nCount = 0; int bFirst = TRUE; VRTDatasetH hVRTDS = NULL; char** ppszInputFilenames = *pppszInputFilenames; int nInputFiles = *pnInputFiles; DatasetProperty* psDatasetProperties = (DatasetProperty*) CPLMalloc(nInputFiles*sizeof(DatasetProperty)); for(i=0;i 0 ) { psDatasetProperties = (DatasetProperty*) CPLMalloc((nInputFiles+CSLCount(papszMetadata))*sizeof(DatasetProperty)); ppszInputFilenames = (char**)CPLRealloc(ppszInputFilenames, sizeof(char*) * (nInputFiles+CSLCount(papszMetadata))); int count = 1; char subdatasetNameKey[256]; sprintf(subdatasetNameKey, "SUBDATASET_%d_NAME", count); while(*papszMetadata != NULL) { if (EQUALN(*papszMetadata, subdatasetNameKey, strlen(subdatasetNameKey))) { ppszInputFilenames[nInputFiles++] = CPLStrdup(*papszMetadata+strlen(subdatasetNameKey)+1); count++; sprintf(subdatasetNameKey, "SUBDATASET_%d_NAME", count); } papszMetadata++; } GDALClose(hDS); continue; } const char* proj = GDALGetProjectionRef(hDS); GDALGetGeoTransform(hDS, psDatasetProperties[i].adfGeoTransform); if (psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_ROTATION_PARAM1] != 0 || psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_ROTATION_PARAM2] != 0) { fprintf( stderr, "gdalbuildvrt does not support rotated geo transforms. Skipping %s\n", dsFileName); GDALClose(hDS); continue; } if (psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES] >= 0) { fprintf( stderr, "gdalbuildvrt does not support positive NS resolution. Skipping %s\n", dsFileName); GDALClose(hDS); continue; } psDatasetProperties[i].nRasterXSize = GDALGetRasterXSize(hDS); psDatasetProperties[i].nRasterYSize = GDALGetRasterYSize(hDS); double product_minX = psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_TOPLEFT_X]; double product_maxY = psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_TOPLEFT_Y]; double product_maxX = product_minX + GDALGetRasterXSize(hDS) * psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES]; double product_minY = product_maxY + GDALGetRasterYSize(hDS) * psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES]; GDALGetBlockSize(GDALGetRasterBand( hDS, 1 ), &psDatasetProperties[i].nBlockXSize, &psDatasetProperties[i].nBlockYSize); if (bFirst) { if (proj) projectionRef = CPLStrdup(proj); minX = product_minX; minY = product_minY; maxX = product_maxX; maxY = product_maxY; nBands = GDALGetRasterCount(hDS); bandProperties = (BandProperty*)CPLMalloc(nBands*sizeof(BandProperty)); for(j=0;j maxX) maxX = product_maxX; if (product_maxY > maxY) maxY = product_maxY; } if (resolutionStrategy == AVERAGE_RESOLUTION) { we_res += psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES]; ns_res += psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES]; } else { if (bFirst) { we_res = psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES]; ns_res = psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES]; } else if (resolutionStrategy == HIGHEST_RESOLUTION) { we_res = MIN(we_res, psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES]); ns_res = MIN(ns_res, psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES]); } else { we_res = MAX(we_res, psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_WE_RES]); ns_res = MAX(ns_res, psDatasetProperties[i].adfGeoTransform[GEOTRSFRM_NS_RES]); } } psDatasetProperties[i].isFileOK = 1; nCount ++; bFirst = FALSE; GDALClose(hDS); } else { fprintf( stderr, "Warning : can't open %s. Skipping it\n", dsFileName); } } *pppszInputFilenames = ppszInputFilenames; *pnInputFiles = nInputFiles; if (nCount == 0) goto end; if (resolutionStrategy == AVERAGE_RESOLUTION) { we_res /= nCount; ns_res /= nCount; } rasterXSize = (int)(0.5 + (maxX - minX) / we_res); rasterYSize = (int)(0.5 + (maxY - minY) / -ns_res); hVRTDS = VRTCreate(rasterXSize, rasterYSize); GDALSetDescription(hVRTDS, pszOutputFilename); if (projectionRef) { GDALSetProjection(hVRTDS, projectionRef); } double adfGeoTransform[6]; adfGeoTransform[GEOTRSFRM_TOPLEFT_X] = minX; adfGeoTransform[GEOTRSFRM_WE_RES] = we_res; adfGeoTransform[GEOTRSFRM_ROTATION_PARAM1] = 0; adfGeoTransform[GEOTRSFRM_TOPLEFT_Y] = maxY; adfGeoTransform[GEOTRSFRM_ROTATION_PARAM2] = 0; adfGeoTransform[GEOTRSFRM_NS_RES] = ns_res; GDALSetGeoTransform(hVRTDS, adfGeoTransform); for(j=0;j