@@ -1553,16 +1553,23 @@ bool GDALTileIndexDataset::Open(GDALOpenInfo *poOpenInfo)
15531553 " 5th value of GeoTransform of %s must be 0" , pszTileName);
15541554 return false ;
15551555 }
1556- if (!(gtTile[GT_NS_RES] < 0 ))
1556+
1557+ const double dfResX = gtTile[GT_WE_RES];
1558+ const double dfResY = gtTile[GT_NS_RES];
1559+ if (!(dfResX > 0 ))
15571560 {
15581561 CPLError (CE_Failure, CPLE_AppDefined,
1559- " 6th value of GeoTransform of %s must be < 0" ,
1562+ " 2nd value of GeoTransform of %s must be > 0" ,
1563+ pszTileName);
1564+ return false ;
1565+ }
1566+ if (!(dfResY != 0 ))
1567+ {
1568+ CPLError (CE_Failure, CPLE_AppDefined,
1569+ " 6th value of GeoTransform of %s must be != 0" ,
15601570 pszTileName);
15611571 return false ;
15621572 }
1563-
1564- const double dfResX = gtTile[GT_WE_RES];
1565- const double dfResY = -gtTile[GT_NS_RES];
15661573
15671574 if (!sEnvelope .IsInit () &&
15681575 m_poLayer->GetExtent (&sEnvelope , /* bForce = */ false ) ==
@@ -1587,7 +1594,8 @@ bool GDALTileIndexDataset::Open(GDALOpenInfo *poOpenInfo)
15871594 return false ;
15881595 }
15891596
1590- const double dfYSize = (sEnvelope .MaxY - sEnvelope .MinY ) / dfResY;
1597+ const double dfYSize =
1598+ (sEnvelope .MaxY - sEnvelope .MinY ) / std::fabs (dfResY);
15911599 if (!(dfYSize >= 0 && dfYSize < INT_MAX))
15921600 {
15931601 CPLError (CE_Failure, CPLE_AppDefined,
@@ -1600,7 +1608,8 @@ bool GDALTileIndexDataset::Open(GDALOpenInfo *poOpenInfo)
16001608 m_gt[GT_ROTATION_PARAM1] = 0 ;
16011609 m_gt[GT_TOPLEFT_Y] = sEnvelope .MaxY ;
16021610 m_gt[GT_ROTATION_PARAM2] = 0 ;
1603- m_gt[GT_NS_RES] = -dfResY;
1611+ m_gt[GT_NS_RES] = -std::fabs (dfResY);
1612+
16041613 nRasterXSize = static_cast <int >(std::ceil (dfXSize));
16051614 nRasterYSize = static_cast <int >(std::ceil (dfYSize));
16061615 }
@@ -1637,6 +1646,12 @@ bool GDALTileIndexDataset::Open(GDALOpenInfo *poOpenInfo)
16371646 {
16381647 m_gt[i] = CPLAtof (aosTokens[i]);
16391648 }
1649+ if (!(m_gt[GT_WE_RES] > 0 ))
1650+ {
1651+ CPLError (CE_Failure, CPLE_AppDefined, " 2nd value of %s must be > 0" ,
1652+ MD_GEOTRANSFORM);
1653+ return false ;
1654+ }
16401655 if (!(m_gt[GT_ROTATION_PARAM1] == 0 ))
16411656 {
16421657 CPLError (CE_Failure, CPLE_AppDefined, " 3rd value of %s must be 0" ,
@@ -1655,7 +1670,6 @@ bool GDALTileIndexDataset::Open(GDALOpenInfo *poOpenInfo)
16551670 MD_GEOTRANSFORM);
16561671 return false ;
16571672 }
1658-
16591673 nRasterXSize = nXSize;
16601674 nRasterYSize = nYSize;
16611675 }
@@ -3492,16 +3506,37 @@ bool GDALTileIndexDataset::GetSourceDesc(const std::string &osTileName,
34923506 if (!GTIDoPaletteExpansionIfNeeded (poTileDS, nBands))
34933507 return false ;
34943508
3495- const OGRSpatialReference *poTileSRS;
3496- if (!m_oSRS.IsEmpty () &&
3497- (poTileSRS = poTileDS->GetSpatialRef ()) != nullptr &&
3509+ bool bWarpVRT = false ;
3510+ bool bExportSRS = false ;
3511+ bool bAddAlphaToVRT = false ;
3512+ const OGRSpatialReference *poTileSRS = poTileDS->GetSpatialRef ();
3513+ GDALGeoTransform tileGT;
3514+ if (!m_oSRS.IsEmpty () && poTileSRS != nullptr &&
34983515 !m_oSRS.IsSame (poTileSRS))
34993516 {
35003517 CPLDebug (" VRT" ,
35013518 " Tile %s has not the same SRS as the VRT. "
35023519 " Proceed to on-the-fly warping" ,
35033520 osTileName.c_str ());
3521+ bWarpVRT = true ;
3522+ bExportSRS = true ;
3523+ bAddAlphaToVRT = true ;
3524+ }
3525+ else if (poTileDS->GetGeoTransform (tileGT) == CE_None &&
3526+ tileGT[GT_NS_RES] > 0 &&
3527+ ((m_oSRS.IsEmpty () && poTileSRS == nullptr ) ||
3528+ (!m_oSRS.IsEmpty () && poTileSRS && m_oSRS.IsSame (poTileSRS))))
35043529
3530+ {
3531+ CPLDebug (" VRT" ,
3532+ " Tile %s is south-up oriented. "
3533+ " Proceed to on-the-fly warping" ,
3534+ osTileName.c_str ());
3535+ bWarpVRT = true ;
3536+ }
3537+
3538+ if (bWarpVRT)
3539+ {
35053540 CPLStringList aosOptions;
35063541 aosOptions.AddString (" -of" );
35073542 aosOptions.AddString (" VRT" );
@@ -3514,25 +3549,29 @@ bool GDALTileIndexDataset::GetSourceDesc(const std::string &osTileName,
35143549 aosOptions.AddString (m_osResampling.c_str ());
35153550 }
35163551
3517- if (m_osWKT. empty () )
3552+ if (bExportSRS )
35183553 {
3519- char *pszWKT = nullptr ;
3520- const char *const apszWKTOptions[] = {" FORMAT=WKT2_2019" ,
3521- nullptr };
3522- m_oSRS.exportToWkt (&pszWKT, apszWKTOptions);
3523- if (pszWKT)
3524- m_osWKT = pszWKT;
3525- CPLFree (pszWKT);
3526- }
3527- if (m_osWKT.empty ())
3528- {
3529- CPLError (CE_Failure, CPLE_AppDefined,
3530- " Cannot export VRT SRS to WKT2" );
3531- return false ;
3532- }
3554+ if (m_osWKT.empty ())
3555+ {
3556+ char *pszWKT = nullptr ;
3557+ const char *const apszWKTOptions[] = {" FORMAT=WKT2_2019" ,
3558+ nullptr };
3559+ m_oSRS.exportToWkt (&pszWKT, apszWKTOptions);
3560+ if (pszWKT)
3561+ m_osWKT = pszWKT;
3562+ CPLFree (pszWKT);
3563+
3564+ if (m_osWKT.empty ())
3565+ {
3566+ CPLError (CE_Failure, CPLE_AppDefined,
3567+ " Cannot export VRT SRS to WKT2" );
3568+ return false ;
3569+ }
3570+ }
35333571
3534- aosOptions.AddString (" -t_srs" );
3535- aosOptions.AddString (m_osWKT.c_str ());
3572+ aosOptions.AddString (" -t_srs" );
3573+ aosOptions.AddString (m_osWKT.c_str ());
3574+ }
35363575
35373576 // First pass to get the extent of the tile in the
35383577 // target VRT SRS
@@ -3592,7 +3631,8 @@ bool GDALTileIndexDataset::GetSourceDesc(const std::string &osTileName,
35923631 aosOptions.AddString (CPLSPrintf (" %.17g" , dfVRTResX));
35933632 aosOptions.AddString (CPLSPrintf (" %.17g" , dfVRTResYAbs));
35943633
3595- aosOptions.AddString (" -dstalpha" );
3634+ if (bAddAlphaToVRT)
3635+ aosOptions.AddString (" -dstalpha" );
35963636
35973637 psWarpOptions = GDALWarpAppOptionsNew (aosOptions.List (), nullptr );
35983638 poWarpDS.reset (GDALDataset::FromHandle (GDALWarp (
0 commit comments