mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-19 22:03:51 -06:00
1648 lines
63 KiB
C++
1648 lines
63 KiB
C++
/******************************************************************************
|
|
* $Id: vrtwarped.cpp 28292 2015-01-05 19:35:55Z rouault $
|
|
*
|
|
* Project: Virtual GDAL Datasets
|
|
* Purpose: Implementation of VRTWarpedRasterBand *and VRTWarpedDataset.
|
|
* Author: Frank Warmerdam <warmerdam@pobox.com>
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
|
|
* Copyright (c) 2008-2013, Even Rouault <even dot rouault at mines-paris dot org>
|
|
*
|
|
* 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 "vrtdataset.h"
|
|
#include "cpl_minixml.h"
|
|
#include "cpl_string.h"
|
|
#include "gdalwarper.h"
|
|
#include "gdal_alg_priv.h"
|
|
#include <cassert>
|
|
|
|
CPL_CVSID("$Id: vrtwarped.cpp 28292 2015-01-05 19:35:55Z rouault $");
|
|
|
|
/************************************************************************/
|
|
/* GDALAutoCreateWarpedVRT() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* Create virtual warped dataset automatically.
|
|
*
|
|
* This function will create a warped virtual file representing the
|
|
* input image warped into the target coordinate system. A GenImgProj
|
|
* transformation is created to accomplish any required GCP/Geotransform
|
|
* warp and reprojection to the target coordinate system. The output virtual
|
|
* dataset will be "northup" in the target coordinate system. The
|
|
* GDALSuggestedWarpOutput() function is used to determine the bounds and
|
|
* resolution of the output virtual file which should be large enough to
|
|
* include all the input image
|
|
*
|
|
* Note that the constructed GDALDatasetH will acquire one or more references
|
|
* to the passed in hSrcDS. Reference counting semantics on the source
|
|
* dataset should be honoured. That is, don't just GDALClose() it unless it
|
|
* was opened with GDALOpenShared().
|
|
*
|
|
* The returned dataset will have no associated filename for itself. If you
|
|
* want to write the virtual dataset description to a file, use the
|
|
* GDALSetDescription() function (or SetDescription() method) on the dataset
|
|
* to assign a filename before it is closed.
|
|
*
|
|
* @param hSrcDS The source dataset.
|
|
*
|
|
* @param pszSrcWKT The coordinate system of the source image. If NULL, it
|
|
* will be read from the source image.
|
|
*
|
|
* @param pszDstWKT The coordinate system to convert to. If NULL no change
|
|
* of coordinate system will take place.
|
|
*
|
|
* @param eResampleAlg One of GRA_NearestNeighbour, GRA_Bilinear, GRA_Cubic,
|
|
* GRA_CubicSpline, GRA_Lanczos, GRA_Average or GRA_Mode.
|
|
* Controls the sampling method used.
|
|
*
|
|
* @param dfMaxError Maximum error measured in input pixels that is allowed in
|
|
* approximating the transformation (0.0 for exact calculations).
|
|
*
|
|
* @param psOptionsIn Additional warp options, normally NULL.
|
|
*
|
|
* @return NULL on failure, or a new virtual dataset handle on success.
|
|
*/
|
|
|
|
GDALDatasetH CPL_STDCALL
|
|
GDALAutoCreateWarpedVRT( GDALDatasetH hSrcDS,
|
|
const char *pszSrcWKT,
|
|
const char *pszDstWKT,
|
|
GDALResampleAlg eResampleAlg,
|
|
double dfMaxError,
|
|
const GDALWarpOptions *psOptionsIn )
|
|
|
|
{
|
|
GDALWarpOptions *psWO;
|
|
int i;
|
|
|
|
VALIDATE_POINTER1( hSrcDS, "GDALAutoCreateWarpedVRT", NULL );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Populate the warp options. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( psOptionsIn != NULL )
|
|
psWO = GDALCloneWarpOptions( psOptionsIn );
|
|
else
|
|
psWO = GDALCreateWarpOptions();
|
|
|
|
psWO->eResampleAlg = eResampleAlg;
|
|
|
|
psWO->hSrcDS = hSrcDS;
|
|
|
|
psWO->nBandCount = GDALGetRasterCount( hSrcDS );
|
|
psWO->panSrcBands = (int *) CPLMalloc(sizeof(int) * psWO->nBandCount);
|
|
psWO->panDstBands = (int *) CPLMalloc(sizeof(int) * psWO->nBandCount);
|
|
|
|
for( i = 0; i < psWO->nBandCount; i++ )
|
|
{
|
|
psWO->panSrcBands[i] = i+1;
|
|
psWO->panDstBands[i] = i+1;
|
|
}
|
|
|
|
/* TODO: should fill in no data where available */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the transformer. */
|
|
/* -------------------------------------------------------------------- */
|
|
psWO->pfnTransformer = GDALGenImgProjTransform;
|
|
psWO->pTransformerArg =
|
|
GDALCreateGenImgProjTransformer( psWO->hSrcDS, pszSrcWKT,
|
|
NULL, pszDstWKT,
|
|
TRUE, 1.0, 0 );
|
|
|
|
if( psWO->pTransformerArg == NULL )
|
|
{
|
|
GDALDestroyWarpOptions( psWO );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Figure out the desired output bounds and resolution. */
|
|
/* -------------------------------------------------------------------- */
|
|
double adfDstGeoTransform[6];
|
|
int nDstPixels, nDstLines;
|
|
CPLErr eErr;
|
|
|
|
eErr =
|
|
GDALSuggestedWarpOutput( hSrcDS, psWO->pfnTransformer,
|
|
psWO->pTransformerArg,
|
|
adfDstGeoTransform, &nDstPixels, &nDstLines );
|
|
if( eErr != CE_None )
|
|
{
|
|
GDALDestroyTransformer( psWO->pTransformerArg );
|
|
GDALDestroyWarpOptions( psWO );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Update the transformer to include an output geotransform */
|
|
/* back to pixel/line coordinates. */
|
|
/* */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALSetGenImgProjTransformerDstGeoTransform(
|
|
psWO->pTransformerArg, adfDstGeoTransform );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Do we want to apply an approximating transformation? */
|
|
/* -------------------------------------------------------------------- */
|
|
if( dfMaxError > 0.0 )
|
|
{
|
|
psWO->pTransformerArg =
|
|
GDALCreateApproxTransformer( psWO->pfnTransformer,
|
|
psWO->pTransformerArg,
|
|
dfMaxError );
|
|
psWO->pfnTransformer = GDALApproxTransform;
|
|
GDALApproxTransformerOwnsSubtransformer(psWO->pTransformerArg, TRUE);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the VRT file. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALDatasetH hDstDS;
|
|
|
|
hDstDS = GDALCreateWarpedVRT( hSrcDS, nDstPixels, nDstLines,
|
|
adfDstGeoTransform, psWO );
|
|
|
|
GDALDestroyWarpOptions( psWO );
|
|
|
|
if( pszDstWKT != NULL )
|
|
GDALSetProjection( hDstDS, pszDstWKT );
|
|
else if( pszSrcWKT != NULL )
|
|
GDALSetProjection( hDstDS, pszSrcWKT );
|
|
else if( GDALGetGCPCount( hSrcDS ) > 0 )
|
|
GDALSetProjection( hDstDS, GDALGetGCPProjection( hSrcDS ) );
|
|
else
|
|
GDALSetProjection( hDstDS, GDALGetProjectionRef( hSrcDS ) );
|
|
|
|
return hDstDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALCreateWarpedVRT() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* Create virtual warped dataset.
|
|
*
|
|
* This function will create a warped virtual file representing the
|
|
* input image warped based on a provided transformation. Output bounds
|
|
* and resolution are provided explicitly.
|
|
*
|
|
* Note that the constructed GDALDatasetH will acquire one or more references
|
|
* to the passed in hSrcDS. Reference counting semantics on the source
|
|
* dataset should be honoured. That is, don't just GDALClose() it unless it
|
|
* was opened with GDALOpenShared().
|
|
*
|
|
* @param hSrcDS The source dataset.
|
|
*
|
|
* @param nPixels Width of the virtual warped dataset to create
|
|
*
|
|
* @param nLines Height of the virtual warped dataset to create
|
|
*
|
|
* @param padfGeoTransform Geotransform matrix of the virtual warped dataset to create
|
|
*
|
|
* @param psOptions Warp options. Must be different from NULL.
|
|
*
|
|
* @return NULL on failure, or a new virtual dataset handle on success.
|
|
*/
|
|
|
|
GDALDatasetH CPL_STDCALL
|
|
GDALCreateWarpedVRT( GDALDatasetH hSrcDS,
|
|
int nPixels, int nLines, double *padfGeoTransform,
|
|
GDALWarpOptions *psOptions )
|
|
|
|
{
|
|
VALIDATE_POINTER1( hSrcDS, "GDALCreateWarpedVRT", NULL );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the VRTDataset and populate it with bands. */
|
|
/* -------------------------------------------------------------------- */
|
|
VRTWarpedDataset *poDS = new VRTWarpedDataset( nPixels, nLines );
|
|
int i;
|
|
|
|
psOptions->hDstDS = (GDALDatasetH) poDS;
|
|
|
|
poDS->SetGeoTransform( padfGeoTransform );
|
|
|
|
for( i = 0; i < psOptions->nBandCount; i++ )
|
|
{
|
|
VRTWarpedRasterBand *poBand;
|
|
GDALRasterBand *poSrcBand = (GDALRasterBand *)
|
|
GDALGetRasterBand( hSrcDS, i+1 );
|
|
|
|
poDS->AddBand( poSrcBand->GetRasterDataType(), NULL );
|
|
|
|
poBand = (VRTWarpedRasterBand *) poDS->GetRasterBand( i+1 );
|
|
poBand->CopyCommonInfoFrom( poSrcBand );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize the warp on the VRTWarpedDataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->Initialize( psOptions );
|
|
|
|
return (GDALDatasetH) poDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* VRTWarpedDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* VRTWarpedDataset() */
|
|
/************************************************************************/
|
|
|
|
VRTWarpedDataset::VRTWarpedDataset( int nXSize, int nYSize )
|
|
: VRTDataset( nXSize, nYSize )
|
|
|
|
{
|
|
poWarper = NULL;
|
|
nBlockXSize = MIN(nXSize, 512);
|
|
nBlockYSize = MIN(nYSize, 128);
|
|
eAccess = GA_Update;
|
|
|
|
nOverviewCount = 0;
|
|
papoOverviews = NULL;
|
|
nSrcOvrLevel = -2;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~VRTWarpedDataset() */
|
|
/************************************************************************/
|
|
|
|
VRTWarpedDataset::~VRTWarpedDataset()
|
|
|
|
{
|
|
CloseDependentDatasets();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CloseDependentDatasets() */
|
|
/************************************************************************/
|
|
|
|
int VRTWarpedDataset::CloseDependentDatasets()
|
|
{
|
|
FlushCache();
|
|
|
|
int bHasDroppedRef = VRTDataset::CloseDependentDatasets();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup overviews. */
|
|
/* -------------------------------------------------------------------- */
|
|
int iOverview;
|
|
|
|
for( iOverview = 0; iOverview < nOverviewCount; iOverview++ )
|
|
{
|
|
GDALDatasetH hDS = (GDALDatasetH) papoOverviews[iOverview];
|
|
|
|
if( GDALDereferenceDataset( hDS ) < 1 )
|
|
{
|
|
GDALReferenceDataset( hDS );
|
|
GDALClose( hDS );
|
|
bHasDroppedRef = TRUE;
|
|
}
|
|
}
|
|
|
|
CPLFree( papoOverviews );
|
|
nOverviewCount = 0;
|
|
papoOverviews = NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup warper if one is in effect. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poWarper != NULL )
|
|
{
|
|
const GDALWarpOptions *psWO = poWarper->GetOptions();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* We take care to only call GDALClose() on psWO->hSrcDS if the */
|
|
/* reference count drops to zero. This is makes it so that we */
|
|
/* can operate reference counting semantics more-or-less */
|
|
/* properly even if the dataset isn't open in shared mode, */
|
|
/* though we require that the caller also honour the reference */
|
|
/* counting semantics even though it isn't a shared dataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( psWO->hSrcDS != NULL )
|
|
{
|
|
if( GDALDereferenceDataset( psWO->hSrcDS ) < 1 )
|
|
{
|
|
GDALReferenceDataset( psWO->hSrcDS );
|
|
GDALClose( psWO->hSrcDS );
|
|
bHasDroppedRef = TRUE;
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* We are responsible for cleaning up the transformer outselves. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( psWO->pTransformerArg != NULL )
|
|
GDALDestroyTransformer( psWO->pTransformerArg );
|
|
|
|
delete poWarper;
|
|
poWarper = NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Destroy the raster bands if they exist. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( int iBand = 0; iBand < nBands; iBand++ )
|
|
{
|
|
delete papoBands[iBand];
|
|
}
|
|
nBands = 0;
|
|
|
|
return bHasDroppedRef;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetSrcOverviewLevel() */
|
|
/************************************************************************/
|
|
|
|
CPLErr VRTWarpedDataset::SetMetadataItem( const char *pszName, const char *pszValue,
|
|
const char *pszDomain )
|
|
|
|
{
|
|
|
|
if( (pszDomain == NULL || EQUAL(pszDomain, "")) && EQUAL(pszName, "SrcOvrLevel") )
|
|
{
|
|
int nOldValue = nSrcOvrLevel;
|
|
if( EQUAL(pszValue, "AUTO") )
|
|
nSrcOvrLevel = -2;
|
|
else if( EQUALN(pszValue,"AUTO-",5) )
|
|
nSrcOvrLevel = -2-atoi(pszValue + 5);
|
|
else if( EQUAL(pszValue, "NONE") )
|
|
nSrcOvrLevel = -1;
|
|
else if( CPLGetValueType(pszValue) == CPL_VALUE_INTEGER )
|
|
nSrcOvrLevel = atoi(pszValue);
|
|
if( nSrcOvrLevel != nOldValue )
|
|
SetNeedsFlush();
|
|
return CE_None;
|
|
}
|
|
return VRTDataset::SetMetadataItem(pszName, pszValue, pszDomain);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Initialize() */
|
|
/* */
|
|
/* Initialize a dataset from passed in warp options. */
|
|
/************************************************************************/
|
|
|
|
CPLErr VRTWarpedDataset::Initialize( void *psWO )
|
|
|
|
{
|
|
if( poWarper != NULL )
|
|
delete poWarper;
|
|
|
|
poWarper = new GDALWarpOperation();
|
|
|
|
GDALWarpOptions* psWO_Dup = GDALCloneWarpOptions((GDALWarpOptions *) psWO);
|
|
|
|
/* Avoid errors when adding an alpha band, but source dataset has */
|
|
/* no alpha band (#4571) */
|
|
if (CSLFetchNameValue( psWO_Dup->papszWarpOptions, "INIT_DEST" ) == NULL)
|
|
psWO_Dup->papszWarpOptions = CSLSetNameValue(psWO_Dup->papszWarpOptions, "INIT_DEST", "0");
|
|
|
|
// The act of initializing this warped dataset with this warp options
|
|
// will result in our assuming ownership of a reference to the
|
|
// hSrcDS.
|
|
|
|
if( ((GDALWarpOptions *) psWO)->hSrcDS != NULL )
|
|
GDALReferenceDataset( psWO_Dup->hSrcDS );
|
|
|
|
CPLErr eErr = poWarper->Initialize( psWO_Dup );
|
|
|
|
GDALDestroyWarpOptions(psWO_Dup);
|
|
|
|
return eErr;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CreateImplicitOverviews() */
|
|
/* */
|
|
/* For each overview of the source dataset, create an overview */
|
|
/* in the warped VRT dataset. */
|
|
/************************************************************************/
|
|
|
|
void VRTWarpedDataset::CreateImplicitOverviews()
|
|
{
|
|
if( poWarper == NULL || nOverviewCount != 0 )
|
|
return;
|
|
|
|
const GDALWarpOptions *psWO = poWarper->GetOptions();
|
|
|
|
if( psWO->hSrcDS == NULL || GDALGetRasterCount(psWO->hSrcDS) == 0 )
|
|
return;
|
|
|
|
GDALDataset* poSrcDS = (GDALDataset*)psWO->hSrcDS;
|
|
int nOvrCount = poSrcDS->GetRasterBand(1)->GetOverviewCount();
|
|
for(int iOvr = 0; iOvr < nOvrCount; iOvr++)
|
|
{
|
|
int bDeleteSrcOvrDataset = FALSE;
|
|
GDALDataset* poSrcOvrDS = poSrcDS;
|
|
if( nSrcOvrLevel < -2 )
|
|
{
|
|
if( iOvr + nSrcOvrLevel + 2 >= 0 )
|
|
{
|
|
bDeleteSrcOvrDataset = TRUE;
|
|
poSrcOvrDS = GDALCreateOverviewDataset(poSrcDS,
|
|
iOvr + nSrcOvrLevel + 2, FALSE, FALSE);
|
|
}
|
|
}
|
|
else if( nSrcOvrLevel == -2 )
|
|
{
|
|
bDeleteSrcOvrDataset = TRUE;
|
|
poSrcOvrDS = GDALCreateOverviewDataset(poSrcDS, iOvr, FALSE, FALSE);
|
|
}
|
|
else if( nSrcOvrLevel >= 0 )
|
|
{
|
|
bDeleteSrcOvrDataset = TRUE;
|
|
poSrcOvrDS = GDALCreateOverviewDataset(poSrcDS, nSrcOvrLevel, TRUE, FALSE);
|
|
}
|
|
if( poSrcOvrDS == NULL )
|
|
break;
|
|
|
|
double dfSrcRatioX = (double)poSrcDS->GetRasterXSize() / poSrcOvrDS->GetRasterXSize();
|
|
double dfSrcRatioY = (double)poSrcDS->GetRasterYSize() / poSrcOvrDS->GetRasterYSize();
|
|
double dfTargetRatio = (double)poSrcDS->GetRasterXSize() /
|
|
poSrcDS->GetRasterBand(1)->GetOverview(iOvr)->GetXSize();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Figure out the desired output bounds and resolution. */
|
|
/* -------------------------------------------------------------------- */
|
|
double adfDstGeoTransform[6];
|
|
int nDstPixels, nDstLines;
|
|
|
|
nDstPixels = (int)(nRasterXSize / dfTargetRatio + 0.5);
|
|
nDstLines = (int)(nRasterYSize / dfTargetRatio + 0.5);
|
|
GetGeoTransform(adfDstGeoTransform);
|
|
if( adfDstGeoTransform[2] == 0.0 && adfDstGeoTransform[4] == 0.0 )
|
|
{
|
|
adfDstGeoTransform[1] *= (double)nRasterXSize / nDstPixels;
|
|
adfDstGeoTransform[5] *= (double)nRasterYSize / nDstLines;
|
|
}
|
|
else
|
|
{
|
|
adfDstGeoTransform[1] *= dfTargetRatio;
|
|
adfDstGeoTransform[2] *= dfTargetRatio;
|
|
adfDstGeoTransform[4] *= dfTargetRatio;
|
|
adfDstGeoTransform[5] *= dfTargetRatio;
|
|
}
|
|
|
|
if( nDstPixels < 1 || nDstLines < 1 )
|
|
{
|
|
if( bDeleteSrcOvrDataset )
|
|
delete poSrcOvrDS;
|
|
break;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create transformer and warping options. */
|
|
/* -------------------------------------------------------------------- */
|
|
void *pTransformerArg = GDALCreateSimilarTransformer(psWO->pTransformerArg,
|
|
dfSrcRatioX,
|
|
dfSrcRatioY);
|
|
if( pTransformerArg == NULL )
|
|
{
|
|
if( bDeleteSrcOvrDataset )
|
|
delete poSrcOvrDS;
|
|
break;
|
|
}
|
|
|
|
GDALWarpOptions* psWOOvr = GDALCloneWarpOptions( psWO );
|
|
psWOOvr->hSrcDS = (GDALDatasetH)poSrcOvrDS;
|
|
psWOOvr->pfnTransformer = psWO->pfnTransformer;
|
|
psWOOvr->pTransformerArg = pTransformerArg;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Update the transformer to include an output geotransform */
|
|
/* back to pixel/line coordinates. */
|
|
/* */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALSetTransformerDstGeoTransform(
|
|
psWOOvr->pTransformerArg, adfDstGeoTransform );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the VRT file. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALDatasetH hDstDS;
|
|
|
|
hDstDS = GDALCreateWarpedVRT( (GDALDatasetH)poSrcOvrDS,
|
|
nDstPixels, nDstLines,
|
|
adfDstGeoTransform, psWOOvr );
|
|
|
|
if( bDeleteSrcOvrDataset )
|
|
GDALDereferenceDataset( (GDALDatasetH)poSrcOvrDS );
|
|
|
|
GDALDestroyWarpOptions(psWOOvr);
|
|
|
|
if( hDstDS == NULL )
|
|
{
|
|
GDALDestroyTransformer( pTransformerArg );
|
|
break;
|
|
}
|
|
|
|
nOverviewCount++;
|
|
papoOverviews = (VRTWarpedDataset **)
|
|
CPLRealloc( papoOverviews, sizeof(void*) * nOverviewCount );
|
|
|
|
papoOverviews[nOverviewCount-1] = (VRTWarpedDataset*)hDstDS;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetFileList() */
|
|
/************************************************************************/
|
|
|
|
char** VRTWarpedDataset::GetFileList()
|
|
{
|
|
char** papszFileList = GDALDataset::GetFileList();
|
|
|
|
if( poWarper != NULL )
|
|
{
|
|
const GDALWarpOptions *psWO = poWarper->GetOptions();
|
|
const char* pszFilename;
|
|
|
|
if( psWO->hSrcDS != NULL &&
|
|
(pszFilename =
|
|
((GDALDataset*)psWO->hSrcDS)->GetDescription()) != NULL )
|
|
{
|
|
VSIStatBufL sStat;
|
|
if( VSIStatL( pszFilename, &sStat ) == 0 )
|
|
{
|
|
papszFileList = CSLAddString(papszFileList, pszFilename);
|
|
}
|
|
}
|
|
}
|
|
|
|
return papszFileList;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* VRTWarpedOverviewTransformer */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
typedef struct {
|
|
GDALTransformerInfo sTI;
|
|
|
|
GDALTransformerFunc pfnBaseTransformer;
|
|
void *pBaseTransformerArg;
|
|
int bOwnSubtransformer;
|
|
|
|
double dfXOverviewFactor;
|
|
double dfYOverviewFactor;
|
|
} VWOTInfo;
|
|
|
|
|
|
static
|
|
void* VRTCreateWarpedOverviewTransformer( GDALTransformerFunc pfnBaseTransformer,
|
|
void *pBaseTransformArg,
|
|
double dfXOverviewFactor,
|
|
double dfYOverviewFactor );
|
|
static
|
|
void VRTDestroyWarpedOverviewTransformer(void* pTransformArg);
|
|
|
|
static
|
|
int VRTWarpedOverviewTransform( void *pTransformArg, int bDstToSrc,
|
|
int nPointCount,
|
|
double *padfX, double *padfY, double *padfZ,
|
|
int *panSuccess );
|
|
|
|
#if 0
|
|
/************************************************************************/
|
|
/* VRTSerializeWarpedOverviewTransformer() */
|
|
/************************************************************************/
|
|
|
|
static CPLXMLNode *
|
|
VRTSerializeWarpedOverviewTransformer( void *pTransformArg )
|
|
|
|
{
|
|
CPLXMLNode *psTree;
|
|
VWOTInfo *psInfo = (VWOTInfo *) pTransformArg;
|
|
|
|
psTree = CPLCreateXMLNode( NULL, CXT_Element, "WarpedOverviewTransformer" );
|
|
|
|
CPLCreateXMLElementAndValue( psTree, "XFactor",
|
|
CPLString().Printf("%g",psInfo->dfXOverviewFactor) );
|
|
CPLCreateXMLElementAndValue( psTree, "YFactor",
|
|
CPLString().Printf("%g",psInfo->dfYOverviewFactor) );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Capture underlying transformer. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLXMLNode *psTransformerContainer;
|
|
CPLXMLNode *psTransformer;
|
|
|
|
psTransformerContainer =
|
|
CPLCreateXMLNode( psTree, CXT_Element, "BaseTransformer" );
|
|
|
|
psTransformer = GDALSerializeTransformer( psInfo->pfnBaseTransformer,
|
|
psInfo->pBaseTransformerArg );
|
|
if( psTransformer != NULL )
|
|
CPLAddXMLChild( psTransformerContainer, psTransformer );
|
|
|
|
return psTree;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* VRTWarpedOverviewTransformerOwnsSubtransformer() */
|
|
/************************************************************************/
|
|
|
|
static void VRTWarpedOverviewTransformerOwnsSubtransformer( void *pTransformArg,
|
|
int bOwnFlag )
|
|
{
|
|
VWOTInfo *psInfo =
|
|
(VWOTInfo *) pTransformArg;
|
|
|
|
psInfo->bOwnSubtransformer = bOwnFlag;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* VRTDeserializeWarpedOverviewTransformer() */
|
|
/************************************************************************/
|
|
|
|
void* VRTDeserializeWarpedOverviewTransformer( CPLXMLNode *psTree )
|
|
|
|
{
|
|
double dfXOverviewFactor = CPLAtof(CPLGetXMLValue( psTree, "XFactor", "1" ));
|
|
double dfYOverviewFactor = CPLAtof(CPLGetXMLValue( psTree, "YFactor", "1" ));
|
|
CPLXMLNode *psContainer;
|
|
GDALTransformerFunc pfnBaseTransform = NULL;
|
|
void *pBaseTransformerArg = NULL;
|
|
|
|
psContainer = CPLGetXMLNode( psTree, "BaseTransformer" );
|
|
|
|
if( psContainer != NULL && psContainer->psChild != NULL )
|
|
{
|
|
GDALDeserializeTransformer( psContainer->psChild,
|
|
&pfnBaseTransform,
|
|
&pBaseTransformerArg );
|
|
|
|
}
|
|
|
|
if( pfnBaseTransform == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Cannot get base transform for scaled coord transformer." );
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
void *pApproxCBData =
|
|
VRTCreateWarpedOverviewTransformer( pfnBaseTransform,
|
|
pBaseTransformerArg,
|
|
dfXOverviewFactor,
|
|
dfYOverviewFactor );
|
|
VRTWarpedOverviewTransformerOwnsSubtransformer( pApproxCBData, TRUE );
|
|
|
|
return pApproxCBData;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* VRTCreateWarpedOverviewTransformer() */
|
|
/************************************************************************/
|
|
|
|
static
|
|
void* VRTCreateWarpedOverviewTransformer( GDALTransformerFunc pfnBaseTransformer,
|
|
void *pBaseTransformerArg,
|
|
double dfXOverviewFactor,
|
|
double dfYOverviewFactor)
|
|
|
|
{
|
|
VWOTInfo *psSCTInfo;
|
|
|
|
if (pfnBaseTransformer == NULL)
|
|
return NULL;
|
|
|
|
psSCTInfo = (VWOTInfo*)
|
|
CPLMalloc(sizeof(VWOTInfo));
|
|
psSCTInfo->pfnBaseTransformer = pfnBaseTransformer;
|
|
psSCTInfo->pBaseTransformerArg = pBaseTransformerArg;
|
|
psSCTInfo->dfXOverviewFactor = dfXOverviewFactor;
|
|
psSCTInfo->dfYOverviewFactor = dfYOverviewFactor;
|
|
psSCTInfo->bOwnSubtransformer = FALSE;
|
|
|
|
memcpy( psSCTInfo->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
|
|
psSCTInfo->sTI.pszClassName = "VRTWarpedOverviewTransformer";
|
|
psSCTInfo->sTI.pfnTransform = VRTWarpedOverviewTransform;
|
|
psSCTInfo->sTI.pfnCleanup = VRTDestroyWarpedOverviewTransformer;
|
|
#if 0
|
|
psSCTInfo->sTI.pfnSerialize = VRTSerializeWarpedOverviewTransformer;
|
|
#endif
|
|
return psSCTInfo;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* VRTDestroyWarpedOverviewTransformer() */
|
|
/************************************************************************/
|
|
|
|
static
|
|
void VRTDestroyWarpedOverviewTransformer(void* pTransformArg)
|
|
{
|
|
VWOTInfo *psInfo = (VWOTInfo *) pTransformArg;
|
|
|
|
if( psInfo->bOwnSubtransformer )
|
|
GDALDestroyTransformer( psInfo->pBaseTransformerArg );
|
|
|
|
CPLFree( psInfo );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* VRTWarpedOverviewTransform() */
|
|
/************************************************************************/
|
|
|
|
static
|
|
int VRTWarpedOverviewTransform( void *pTransformArg, int bDstToSrc,
|
|
int nPointCount,
|
|
double *padfX, double *padfY, double *padfZ,
|
|
int *panSuccess )
|
|
|
|
{
|
|
VWOTInfo *psInfo = (VWOTInfo *) pTransformArg;
|
|
int i, bSuccess;
|
|
|
|
if( bDstToSrc )
|
|
{
|
|
for( i = 0; i < nPointCount; i++ )
|
|
{
|
|
padfX[i] *= psInfo->dfXOverviewFactor;
|
|
padfY[i] *= psInfo->dfYOverviewFactor;
|
|
}
|
|
}
|
|
|
|
bSuccess = psInfo->pfnBaseTransformer( psInfo->pBaseTransformerArg,
|
|
bDstToSrc,
|
|
nPointCount, padfX, padfY, padfZ,
|
|
panSuccess );
|
|
|
|
if( !bDstToSrc )
|
|
{
|
|
for( i = 0; i < nPointCount; i++ )
|
|
{
|
|
padfX[i] /= psInfo->dfXOverviewFactor;
|
|
padfY[i] /= psInfo->dfYOverviewFactor;
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* BuildOverviews() */
|
|
/* */
|
|
/* For overviews, we actually just build a whole new dataset */
|
|
/* with an extra layer of transformation on the warper used to */
|
|
/* accomplish downsampling by the desired factor. */
|
|
/************************************************************************/
|
|
|
|
CPLErr
|
|
VRTWarpedDataset::IBuildOverviews( CPL_UNUSED const char *pszResampling,
|
|
int nOverviews,
|
|
int *panOverviewList,
|
|
CPL_UNUSED int nListBands,
|
|
CPL_UNUSED int *panBandList,
|
|
GDALProgressFunc pfnProgress,
|
|
void * pProgressData )
|
|
{
|
|
if( poWarper == NULL )
|
|
return CE_Failure;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initial progress result. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( !pfnProgress( 0.0, NULL, pProgressData ) )
|
|
{
|
|
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
|
|
return CE_Failure;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Establish which of the overview levels we already have, and */
|
|
/* which are new. */
|
|
/* -------------------------------------------------------------------- */
|
|
int i, nNewOverviews, *panNewOverviewList = NULL;
|
|
|
|
nNewOverviews = 0;
|
|
panNewOverviewList = (int *) CPLCalloc(sizeof(int),nOverviews);
|
|
for( i = 0; i < nOverviews; i++ )
|
|
{
|
|
int j;
|
|
|
|
for( j = 0; j < nOverviewCount; j++ )
|
|
{
|
|
int nOvFactor;
|
|
GDALDataset *poOverview = papoOverviews[j];
|
|
|
|
nOvFactor = GDALComputeOvFactor(poOverview->GetRasterXSize(),
|
|
GetRasterXSize(),
|
|
poOverview->GetRasterYSize(),
|
|
GetRasterYSize());
|
|
|
|
if( nOvFactor == panOverviewList[i]
|
|
|| nOvFactor == GDALOvLevelAdjust2( panOverviewList[i],
|
|
GetRasterXSize(),
|
|
GetRasterYSize() ) )
|
|
panOverviewList[i] *= -1;
|
|
}
|
|
|
|
if( panOverviewList[i] > 0 )
|
|
panNewOverviewList[nNewOverviews++] = panOverviewList[i];
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create each missing overview (we don't need to do anything */
|
|
/* to update existing overviews). */
|
|
/* -------------------------------------------------------------------- */
|
|
for( i = 0; i < nNewOverviews; i++ )
|
|
{
|
|
int nOXSize, nOYSize, iBand;
|
|
VRTWarpedDataset *poOverviewDS;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* What size should this overview be. */
|
|
/* -------------------------------------------------------------------- */
|
|
nOXSize = (GetRasterXSize() + panNewOverviewList[i] - 1)
|
|
/ panNewOverviewList[i];
|
|
|
|
nOYSize = (GetRasterYSize() + panNewOverviewList[i] - 1)
|
|
/ panNewOverviewList[i];
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Find the most appropriate base dataset onto which to build the */
|
|
/* new one. The preference will be an overview dataset with a ratio*/
|
|
/* greater than ours, and which is not using */
|
|
/* VRTWarpedOverviewTransform, since those ones are slow. The other*/
|
|
/* ones are based on overviews of the source dataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
VRTWarpedDataset* poBaseDataset = this;
|
|
for( int j = 0; j < nOverviewCount; j++ )
|
|
{
|
|
if( papoOverviews[j]->GetRasterXSize() > nOXSize &&
|
|
papoOverviews[j]->poWarper->GetOptions()->pfnTransformer !=
|
|
VRTWarpedOverviewTransform &&
|
|
papoOverviews[j]->GetRasterXSize() < poBaseDataset->GetRasterXSize() )
|
|
{
|
|
poBaseDataset = papoOverviews[j];
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the overview dataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
poOverviewDS = new VRTWarpedDataset( nOXSize, nOYSize );
|
|
|
|
for( iBand = 0; iBand < GetRasterCount(); iBand++ )
|
|
{
|
|
GDALRasterBand *poOldBand = GetRasterBand(iBand+1);
|
|
VRTWarpedRasterBand *poNewBand =
|
|
new VRTWarpedRasterBand( poOverviewDS, iBand+1,
|
|
poOldBand->GetRasterDataType() );
|
|
|
|
poNewBand->CopyCommonInfoFrom( poOldBand );
|
|
poOverviewDS->SetBand( iBand+1, poNewBand );
|
|
}
|
|
|
|
nOverviewCount++;
|
|
papoOverviews = (VRTWarpedDataset **)
|
|
CPLRealloc( papoOverviews, sizeof(void*) * nOverviewCount );
|
|
|
|
papoOverviews[nOverviewCount-1] = poOverviewDS;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Prepare update transformation information that will apply */
|
|
/* the overview decimation. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALWarpOptions *psWO = (GDALWarpOptions *) poBaseDataset->poWarper->GetOptions();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize the new dataset with adjusted warp options, and */
|
|
/* then restore to original condition. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALTransformerFunc pfnTransformerBase = psWO->pfnTransformer;
|
|
void* pTransformerBaseArg = psWO->pTransformerArg;
|
|
|
|
psWO->pfnTransformer = VRTWarpedOverviewTransform;
|
|
psWO->pTransformerArg = VRTCreateWarpedOverviewTransformer(
|
|
pfnTransformerBase,
|
|
pTransformerBaseArg,
|
|
poBaseDataset->GetRasterXSize() / (double) nOXSize,
|
|
poBaseDataset->GetRasterYSize() / (double) nOYSize );
|
|
|
|
poOverviewDS->Initialize( psWO );
|
|
|
|
psWO->pfnTransformer = pfnTransformerBase;
|
|
psWO->pTransformerArg = pTransformerBaseArg;
|
|
}
|
|
|
|
CPLFree( panNewOverviewList );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Progress finished. */
|
|
/* -------------------------------------------------------------------- */
|
|
pfnProgress( 1.0, NULL, pProgressData );
|
|
|
|
SetNeedsFlush();
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALInitializeWarpedVRT() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* Set warp info on virtual warped dataset.
|
|
*
|
|
* Initializes all the warping information for a virtual warped dataset.
|
|
*
|
|
* This method is the same as the C++ method VRTWarpedDataset::Initialize().
|
|
*
|
|
* @param hDS dataset previously created with the VRT driver, and a
|
|
* SUBCLASS of "VRTWarpedDataset".
|
|
*
|
|
* @param psWO the warp options to apply. Note that ownership of the
|
|
* transformation information is taken over by the function though everything
|
|
* else remains the property of the caller.
|
|
*
|
|
* @return CE_None on success or CE_Failure if an error occurs.
|
|
*/
|
|
|
|
CPLErr CPL_STDCALL
|
|
GDALInitializeWarpedVRT( GDALDatasetH hDS, GDALWarpOptions *psWO )
|
|
|
|
{
|
|
VALIDATE_POINTER1( hDS, "GDALInitializeWarpedVRT", CE_Failure );
|
|
|
|
return ((VRTWarpedDataset *) hDS)->Initialize( psWO );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* XMLInit() */
|
|
/************************************************************************/
|
|
|
|
CPLErr VRTWarpedDataset::XMLInit( CPLXMLNode *psTree, const char *pszVRTPath )
|
|
|
|
{
|
|
CPLErr eErr;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize blocksize before calling sub-init so that the */
|
|
/* band initializers can get it from the dataset object when */
|
|
/* they are created. */
|
|
/* -------------------------------------------------------------------- */
|
|
nBlockXSize = atoi(CPLGetXMLValue(psTree,"BlockXSize","512"));
|
|
nBlockYSize = atoi(CPLGetXMLValue(psTree,"BlockYSize","128"));
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize all the general VRT stuff. This will even */
|
|
/* create the VRTWarpedRasterBands and initialize them. */
|
|
/* -------------------------------------------------------------------- */
|
|
eErr = VRTDataset::XMLInit( psTree, pszVRTPath );
|
|
|
|
if( eErr != CE_None )
|
|
return eErr;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Find the GDALWarpOptions XML tree. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLXMLNode *psOptionsTree;
|
|
psOptionsTree = CPLGetXMLNode( psTree, "GDALWarpOptions" );
|
|
if( psOptionsTree == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Count not find required GDALWarpOptions in XML." );
|
|
return CE_Failure;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Adjust the SourceDataset in the warp options to take into */
|
|
/* account that it is relative to the VRT if appropriate. */
|
|
/* -------------------------------------------------------------------- */
|
|
int bRelativeToVRT =
|
|
atoi(CPLGetXMLValue(psOptionsTree,
|
|
"SourceDataset.relativeToVRT", "0" ));
|
|
|
|
const char *pszRelativePath = CPLGetXMLValue(psOptionsTree,
|
|
"SourceDataset", "" );
|
|
char *pszAbsolutePath;
|
|
|
|
if( bRelativeToVRT )
|
|
pszAbsolutePath =
|
|
CPLStrdup(CPLProjectRelativeFilename( pszVRTPath,
|
|
pszRelativePath ) );
|
|
else
|
|
pszAbsolutePath = CPLStrdup(pszRelativePath);
|
|
|
|
CPLSetXMLValue( psOptionsTree, "SourceDataset", pszAbsolutePath );
|
|
CPLFree( pszAbsolutePath );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* And instantiate the warp options, and corresponding warp */
|
|
/* operation. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALWarpOptions *psWO;
|
|
|
|
psWO = GDALDeserializeWarpOptions( psOptionsTree );
|
|
if( psWO == NULL )
|
|
return CE_Failure;
|
|
|
|
/* Avoid errors when adding an alpha band, but source dataset has */
|
|
/* no alpha band (#4571) */
|
|
if (CSLFetchNameValue( psWO->papszWarpOptions, "INIT_DEST" ) == NULL)
|
|
psWO->papszWarpOptions = CSLSetNameValue(psWO->papszWarpOptions, "INIT_DEST", "0");
|
|
|
|
this->eAccess = GA_Update;
|
|
|
|
if( psWO->hDstDS != NULL )
|
|
{
|
|
GDALClose( psWO->hDstDS );
|
|
psWO->hDstDS = NULL;
|
|
}
|
|
|
|
psWO->hDstDS = this;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Instantiate the warp operation. */
|
|
/* -------------------------------------------------------------------- */
|
|
poWarper = new GDALWarpOperation();
|
|
|
|
eErr = poWarper->Initialize( psWO );
|
|
if( eErr != CE_None)
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* We are responsible for cleaning up the transformer outselves. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( psWO->pTransformerArg != NULL )
|
|
{
|
|
GDALDestroyTransformer( psWO->pTransformerArg );
|
|
psWO->pTransformerArg = NULL;
|
|
}
|
|
|
|
if( psWO->hSrcDS != NULL )
|
|
{
|
|
GDALClose( psWO->hSrcDS );
|
|
psWO->hSrcDS = NULL;
|
|
}
|
|
}
|
|
|
|
GDALDestroyWarpOptions( psWO );
|
|
if( eErr != CE_None )
|
|
{
|
|
delete poWarper;
|
|
poWarper = NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Deserialize SrcOvrLevel */
|
|
/* -------------------------------------------------------------------- */
|
|
const char* pszSrcOvrLevel = CPLGetXMLValue( psTree, "SrcOvrLevel", NULL );
|
|
if( pszSrcOvrLevel != NULL )
|
|
{
|
|
SetMetadataItem("SrcOvrLevel", pszSrcOvrLevel);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Generate overviews, if appropriate. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
CreateImplicitOverviews();
|
|
|
|
/* OverviewList is historical, and quite inefficient, since it uses */
|
|
/* the full resolution source dataset, so only build it afterwards */
|
|
char **papszTokens = CSLTokenizeString(
|
|
CPLGetXMLValue( psTree, "OverviewList", "" ));
|
|
int iOverview;
|
|
|
|
for( iOverview = 0;
|
|
papszTokens != NULL && papszTokens[iOverview] != NULL;
|
|
iOverview++ )
|
|
{
|
|
int nOvFactor = atoi(papszTokens[iOverview]);
|
|
|
|
if (nOvFactor > 0)
|
|
BuildOverviews( "NEAREST", 1, &nOvFactor, 0, NULL, NULL, NULL );
|
|
else
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"Bad value for overview factor : %s", papszTokens[iOverview]);
|
|
}
|
|
|
|
CSLDestroy( papszTokens );
|
|
|
|
return eErr;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SerializeToXML() */
|
|
/************************************************************************/
|
|
|
|
CPLXMLNode *VRTWarpedDataset::SerializeToXML( const char *pszVRTPath )
|
|
|
|
{
|
|
CPLXMLNode *psTree;
|
|
|
|
psTree = VRTDataset::SerializeToXML( pszVRTPath );
|
|
|
|
if( psTree == NULL )
|
|
return psTree;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Set subclass. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLCreateXMLNode(
|
|
CPLCreateXMLNode( psTree, CXT_Attribute, "subClass" ),
|
|
CXT_Text, "VRTWarpedDataset" );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Serialize the block size. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLCreateXMLElementAndValue( psTree, "BlockXSize",
|
|
CPLSPrintf( "%d", nBlockXSize ) );
|
|
CPLCreateXMLElementAndValue( psTree, "BlockYSize",
|
|
CPLSPrintf( "%d", nBlockYSize ) );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Serialize the overview list (only for non implicit overviews) */
|
|
/* -------------------------------------------------------------------- */
|
|
if( nOverviewCount > 0 )
|
|
{
|
|
char *pszOverviewList;
|
|
int iOverview;
|
|
|
|
int nSrcDSOvrCount = 0;
|
|
if( poWarper != NULL && poWarper->GetOptions() != NULL &&
|
|
poWarper->GetOptions()->hSrcDS != NULL &&
|
|
GDALGetRasterCount(poWarper->GetOptions()->hSrcDS) > 0 )
|
|
{
|
|
nSrcDSOvrCount = ((GDALDataset*)poWarper->GetOptions()->hSrcDS)->
|
|
GetRasterBand(1)->GetOverviewCount();
|
|
}
|
|
|
|
if( nOverviewCount != nSrcDSOvrCount )
|
|
{
|
|
pszOverviewList = (char *) CPLMalloc(nOverviewCount*8 + 10);
|
|
pszOverviewList[0] = '\0';
|
|
for( iOverview = 0; iOverview < nOverviewCount; iOverview++ )
|
|
{
|
|
int nOvFactor;
|
|
|
|
nOvFactor = (int)
|
|
(0.5+GetRasterXSize()
|
|
/ (double) papoOverviews[iOverview]->GetRasterXSize());
|
|
|
|
sprintf( pszOverviewList + strlen(pszOverviewList),
|
|
"%d ", nOvFactor );
|
|
}
|
|
|
|
CPLCreateXMLElementAndValue( psTree, "OverviewList", pszOverviewList );
|
|
|
|
CPLFree( pszOverviewList );
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Serialize source overview level. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( nSrcOvrLevel != -2 )
|
|
{
|
|
if( nSrcOvrLevel < -2 )
|
|
CPLCreateXMLElementAndValue( psTree, "SrcOvrLevel", CPLSPrintf("AUTO%d", nSrcOvrLevel+2) );
|
|
else if( nSrcOvrLevel == -1 )
|
|
CPLCreateXMLElementAndValue( psTree, "SrcOvrLevel", "NONE" );
|
|
else
|
|
CPLCreateXMLElementAndValue( psTree, "SrcOvrLevel", CPLSPrintf("%d", nSrcOvrLevel) );
|
|
}
|
|
|
|
/* ==================================================================== */
|
|
/* Serialize the warp options. */
|
|
/* ==================================================================== */
|
|
CPLXMLNode *psWOTree;
|
|
|
|
if( poWarper != NULL )
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* We reset the destination dataset name so it doesn't get */
|
|
/* written out in the serialize warp options. */
|
|
/* -------------------------------------------------------------------- */
|
|
char *pszSavedName = CPLStrdup(GetDescription());
|
|
SetDescription("");
|
|
|
|
psWOTree = GDALSerializeWarpOptions( poWarper->GetOptions() );
|
|
CPLAddXMLChild( psTree, psWOTree );
|
|
|
|
SetDescription( pszSavedName );
|
|
CPLFree( pszSavedName );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* We need to consider making the source dataset relative to */
|
|
/* the VRT file if possible. Adjust accordingly. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLXMLNode *psSDS = CPLGetXMLNode( psWOTree, "SourceDataset" );
|
|
int bRelativeToVRT = FALSE;
|
|
VSIStatBufL sStat;
|
|
|
|
if( VSIStatExL( psSDS->psChild->pszValue, &sStat,
|
|
VSI_STAT_EXISTS_FLAG) == 0 )
|
|
{
|
|
char *pszRelativePath;
|
|
|
|
pszRelativePath = CPLStrdup(
|
|
CPLExtractRelativePath( pszVRTPath, psSDS->psChild->pszValue,
|
|
&bRelativeToVRT ) );
|
|
|
|
CPLFree( psSDS->psChild->pszValue );
|
|
psSDS->psChild->pszValue = pszRelativePath;
|
|
}
|
|
|
|
CPLCreateXMLNode(
|
|
CPLCreateXMLNode( psSDS, CXT_Attribute, "relativeToVRT" ),
|
|
CXT_Text, bRelativeToVRT ? "1" : "0" );
|
|
}
|
|
|
|
return psTree;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetBlockSize() */
|
|
/************************************************************************/
|
|
|
|
void VRTWarpedDataset::GetBlockSize( int *pnBlockXSize, int *pnBlockYSize )
|
|
|
|
{
|
|
assert( NULL != pnBlockXSize );
|
|
assert( NULL != pnBlockYSize );
|
|
|
|
*pnBlockXSize = nBlockXSize;
|
|
*pnBlockYSize = nBlockYSize;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ProcessBlock() */
|
|
/* */
|
|
/* Warp a single requested block, and then push each band of */
|
|
/* the result into the block cache. */
|
|
/************************************************************************/
|
|
|
|
CPLErr VRTWarpedDataset::ProcessBlock( int iBlockX, int iBlockY )
|
|
|
|
{
|
|
if( poWarper == NULL )
|
|
return CE_Failure;
|
|
|
|
const GDALWarpOptions *psWO = poWarper->GetOptions();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Allocate block of memory large enough to hold all the bands */
|
|
/* for this block. */
|
|
/* -------------------------------------------------------------------- */
|
|
int iBand;
|
|
GByte *pabyDstBuffer;
|
|
int nDstBufferSize;
|
|
int nWordSize = (GDALGetDataTypeSize(psWO->eWorkingDataType) / 8);
|
|
|
|
// FIXME? : risk of overflow in multiplication if nBlockXSize or nBlockYSize are very large
|
|
nDstBufferSize = nBlockXSize * nBlockYSize * psWO->nBandCount * nWordSize;
|
|
|
|
pabyDstBuffer = (GByte *) VSIMalloc(nDstBufferSize);
|
|
|
|
if( pabyDstBuffer == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_OutOfMemory,
|
|
"Out of memory allocating %d byte buffer in VRTWarpedDataset::ProcessBlock()",
|
|
nDstBufferSize );
|
|
return CE_Failure;
|
|
}
|
|
|
|
memset( pabyDstBuffer, 0, nDstBufferSize );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Process INIT_DEST option to initialize the buffer prior to */
|
|
/* warping into it. */
|
|
/* NOTE:The following code is 99% similar in gdalwarpoperation.cpp and */
|
|
/* vrtwarped.cpp. Be careful to keep it in sync ! */
|
|
/* -------------------------------------------------------------------- */
|
|
const char *pszInitDest = CSLFetchNameValue( psWO->papszWarpOptions,
|
|
"INIT_DEST" );
|
|
|
|
if( pszInitDest != NULL && !EQUAL(pszInitDest, "") )
|
|
{
|
|
char **papszInitValues =
|
|
CSLTokenizeStringComplex( pszInitDest, ",", FALSE, FALSE );
|
|
int nInitCount = CSLCount(papszInitValues);
|
|
|
|
for( iBand = 0; iBand < psWO->nBandCount; iBand++ )
|
|
{
|
|
double adfInitRealImag[2];
|
|
GByte *pBandData;
|
|
int nBandSize = nBlockXSize * nBlockYSize * nWordSize;
|
|
const char *pszBandInit = papszInitValues[MIN(iBand,nInitCount-1)];
|
|
|
|
if( EQUAL(pszBandInit,"NO_DATA")
|
|
&& psWO->padfDstNoDataReal != NULL )
|
|
{
|
|
adfInitRealImag[0] = psWO->padfDstNoDataReal[iBand];
|
|
adfInitRealImag[1] = psWO->padfDstNoDataImag[iBand];
|
|
}
|
|
else
|
|
{
|
|
CPLStringToComplex( pszBandInit,
|
|
adfInitRealImag + 0, adfInitRealImag + 1);
|
|
}
|
|
|
|
pBandData = ((GByte *) pabyDstBuffer) + iBand * nBandSize;
|
|
|
|
if( psWO->eWorkingDataType == GDT_Byte )
|
|
memset( pBandData,
|
|
MAX(0,MIN(255,(int)adfInitRealImag[0])),
|
|
nBandSize);
|
|
else if( !CPLIsNan(adfInitRealImag[0]) && adfInitRealImag[0] == 0.0 &&
|
|
!CPLIsNan(adfInitRealImag[1]) && adfInitRealImag[1] == 0.0 )
|
|
{
|
|
memset( pBandData, 0, nBandSize );
|
|
}
|
|
else if( !CPLIsNan(adfInitRealImag[1]) && adfInitRealImag[1] == 0.0 )
|
|
{
|
|
GDALCopyWords( &adfInitRealImag, GDT_Float64, 0,
|
|
pBandData,psWO->eWorkingDataType,nWordSize,
|
|
nBlockXSize * nBlockYSize );
|
|
}
|
|
else
|
|
{
|
|
GDALCopyWords( &adfInitRealImag, GDT_CFloat64, 0,
|
|
pBandData,psWO->eWorkingDataType,nWordSize,
|
|
nBlockXSize * nBlockYSize );
|
|
}
|
|
}
|
|
|
|
CSLDestroy( papszInitValues );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Warp into this buffer. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLErr eErr;
|
|
|
|
int nReqXSize = nBlockXSize;
|
|
if( iBlockX * nBlockXSize + nReqXSize > nRasterXSize )
|
|
nReqXSize = nRasterXSize - iBlockX * nBlockXSize;
|
|
int nReqYSize = nBlockYSize;
|
|
if( iBlockY * nBlockYSize + nReqYSize > nRasterYSize )
|
|
nReqYSize = nRasterYSize - iBlockY * nBlockYSize;
|
|
|
|
eErr =
|
|
poWarper->WarpRegionToBuffer(
|
|
iBlockX * nBlockXSize, iBlockY * nBlockYSize,
|
|
nReqXSize, nReqYSize,
|
|
pabyDstBuffer, psWO->eWorkingDataType );
|
|
|
|
if( eErr != CE_None )
|
|
{
|
|
VSIFree( pabyDstBuffer );
|
|
return eErr;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Copy out into cache blocks for each band. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( iBand = 0; iBand < MIN(nBands, psWO->nBandCount); iBand++ )
|
|
{
|
|
GDALRasterBand *poBand;
|
|
GDALRasterBlock *poBlock;
|
|
|
|
poBand = GetRasterBand(iBand+1);
|
|
poBlock = poBand->GetLockedBlockRef( iBlockX, iBlockY, TRUE );
|
|
|
|
if( poBlock != NULL )
|
|
{
|
|
if ( poBlock->GetDataRef() != NULL )
|
|
{
|
|
if( nReqXSize == nBlockXSize && nReqYSize == nBlockYSize )
|
|
{
|
|
GDALCopyWords( pabyDstBuffer + iBand*nBlockXSize*nBlockYSize*nWordSize,
|
|
psWO->eWorkingDataType, nWordSize,
|
|
poBlock->GetDataRef(),
|
|
poBlock->GetDataType(),
|
|
GDALGetDataTypeSize(poBlock->GetDataType())/8,
|
|
nBlockXSize * nBlockYSize );
|
|
}
|
|
else
|
|
{
|
|
GByte* pabyBlock = (GByte*) poBlock->GetDataRef();
|
|
int nDTSize = GDALGetDataTypeSize(poBlock->GetDataType())/8;
|
|
for(int iY=0;iY<nReqYSize;iY++)
|
|
{
|
|
GDALCopyWords( pabyDstBuffer + iBand*nReqXSize*nReqYSize*nWordSize + iY * nReqXSize*nWordSize,
|
|
psWO->eWorkingDataType, nWordSize,
|
|
pabyBlock + iY * nBlockXSize * nDTSize,
|
|
poBlock->GetDataType(),
|
|
nDTSize,
|
|
nReqXSize );
|
|
}
|
|
}
|
|
}
|
|
|
|
poBlock->DropLock();
|
|
}
|
|
}
|
|
|
|
VSIFree( pabyDstBuffer );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AddBand() */
|
|
/************************************************************************/
|
|
|
|
CPLErr VRTWarpedDataset::AddBand( GDALDataType eType, char **papszOptions )
|
|
|
|
{
|
|
UNREFERENCED_PARAM( papszOptions );
|
|
|
|
SetBand( GetRasterCount() + 1,
|
|
new VRTWarpedRasterBand( this, GetRasterCount() + 1, eType ) );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* VRTWarpedRasterBand */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* VRTWarpedRasterBand() */
|
|
/************************************************************************/
|
|
|
|
VRTWarpedRasterBand::VRTWarpedRasterBand( GDALDataset *poDS, int nBand,
|
|
GDALDataType eType )
|
|
|
|
{
|
|
Initialize( poDS->GetRasterXSize(), poDS->GetRasterYSize() );
|
|
|
|
this->poDS = poDS;
|
|
this->nBand = nBand;
|
|
this->eAccess = GA_Update;
|
|
|
|
((VRTWarpedDataset *) poDS)->GetBlockSize( &nBlockXSize,
|
|
&nBlockYSize );
|
|
|
|
if( eType != GDT_Unknown )
|
|
this->eDataType = eType;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~VRTWarpedRasterBand() */
|
|
/************************************************************************/
|
|
|
|
VRTWarpedRasterBand::~VRTWarpedRasterBand()
|
|
|
|
{
|
|
FlushCache();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IReadBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr VRTWarpedRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
|
|
void * pImage )
|
|
|
|
{
|
|
CPLErr eErr;
|
|
VRTWarpedDataset *poWDS = (VRTWarpedDataset *) poDS;
|
|
GDALRasterBlock *poBlock;
|
|
|
|
poBlock = GetLockedBlockRef( nBlockXOff, nBlockYOff, TRUE );
|
|
if( poBlock == NULL )
|
|
return CE_Failure;
|
|
|
|
eErr = poWDS->ProcessBlock( nBlockXOff, nBlockYOff );
|
|
|
|
if( eErr == CE_None && pImage != poBlock->GetDataRef() )
|
|
{
|
|
int nDataBytes;
|
|
nDataBytes = (GDALGetDataTypeSize(poBlock->GetDataType()) / 8)
|
|
* poBlock->GetXSize() * poBlock->GetYSize();
|
|
memcpy( pImage, poBlock->GetDataRef(), nDataBytes );
|
|
}
|
|
|
|
poBlock->DropLock();
|
|
|
|
return eErr;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IWriteBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr VRTWarpedRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
|
|
void * pImage )
|
|
|
|
{
|
|
CPLErr eErr;
|
|
VRTWarpedDataset *poWDS = (VRTWarpedDataset *) poDS;
|
|
|
|
/* This is a bit tricky. In the case we are warping a VRTWarpedDataset */
|
|
/* with a destination alpha band, IWriteBlock can be called on that alpha */
|
|
/* band by GDALWarpDstAlphaMasker */
|
|
/* We don't need to do anything since the data will be kept in the block */
|
|
/* cache by VRTWarpedRasterBand::IReadBlock */
|
|
if (poWDS->poWarper->GetOptions()->nDstAlphaBand == nBand)
|
|
{
|
|
eErr = CE_None;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, call the superclass method, that will fail of course */
|
|
eErr = VRTRasterBand::IWriteBlock(nBlockXOff, nBlockYOff, pImage);
|
|
}
|
|
|
|
return eErr;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* XMLInit() */
|
|
/************************************************************************/
|
|
|
|
CPLErr VRTWarpedRasterBand::XMLInit( CPLXMLNode * psTree,
|
|
const char *pszVRTPath )
|
|
|
|
{
|
|
return VRTRasterBand::XMLInit( psTree, pszVRTPath );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SerializeToXML() */
|
|
/************************************************************************/
|
|
|
|
CPLXMLNode *VRTWarpedRasterBand::SerializeToXML( const char *pszVRTPath )
|
|
|
|
{
|
|
CPLXMLNode *psTree = VRTRasterBand::SerializeToXML( pszVRTPath );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Set subclass. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLCreateXMLNode(
|
|
CPLCreateXMLNode( psTree, CXT_Attribute, "subClass" ),
|
|
CXT_Text, "VRTWarpedRasterBand" );
|
|
|
|
return psTree;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverviewCount() */
|
|
/************************************************************************/
|
|
|
|
int VRTWarpedRasterBand::GetOverviewCount()
|
|
|
|
{
|
|
VRTWarpedDataset *poWDS = (VRTWarpedDataset *) poDS;
|
|
|
|
poWDS->CreateImplicitOverviews();
|
|
|
|
return poWDS->nOverviewCount;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverview() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterBand *VRTWarpedRasterBand::GetOverview( int iOverview )
|
|
|
|
{
|
|
VRTWarpedDataset *poWDS = (VRTWarpedDataset *) poDS;
|
|
|
|
if( iOverview < 0 || iOverview >= GetOverviewCount() )
|
|
return NULL;
|
|
else
|
|
return poWDS->papoOverviews[iOverview]->GetRasterBand( nBand );
|
|
}
|