Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsgdalutils.cpp
3 : : ----------------
4 : : begin : September 2018
5 : : copyright : (C) 2018 Even Rouault
6 : : email : even.rouault at spatialys.com
7 : : ***************************************************************************
8 : : * *
9 : : * This program is free software; you can redistribute it and/or modify *
10 : : * it under the terms of the GNU General Public License as published by *
11 : : * the Free Software Foundation; either version 2 of the License, or *
12 : : * (at your option) any later version. *
13 : : * *
14 : : ***************************************************************************/
15 : :
16 : : #include "qgsgdalutils.h"
17 : : #include "qgslogger.h"
18 : : #include "qgsnetworkaccessmanager.h"
19 : : #include "qgssettings.h"
20 : :
21 : : #define CPL_SUPRESS_CPLUSPLUS //#spellok
22 : : #include "gdal.h"
23 : : #include "gdalwarper.h"
24 : : #include "cpl_string.h"
25 : :
26 : : #include <QNetworkProxy>
27 : : #include <QString>
28 : : #include <QImage>
29 : :
30 : 0 : bool QgsGdalUtils::supportsRasterCreate( GDALDriverH driver )
31 : : {
32 : 0 : QString driverShortName = GDALGetDriverShortName( driver );
33 : 0 : if ( driverShortName == QLatin1String( "SQLite" ) )
34 : : {
35 : : // it supports Create() but only for vector side
36 : 0 : return false;
37 : : }
38 : 0 : char **driverMetadata = GDALGetMetadata( driver, nullptr );
39 : 0 : return CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) &&
40 : 0 : CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER, false );
41 : 0 : }
42 : :
43 : 0 : gdal::dataset_unique_ptr QgsGdalUtils::createSingleBandMemoryDataset( GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs )
44 : : {
45 : 0 : return createMultiBandMemoryDataset( dataType, 1, extent, width, height, crs );
46 : : }
47 : :
48 : 0 : gdal::dataset_unique_ptr QgsGdalUtils::createMultiBandMemoryDataset( GDALDataType dataType, int bands, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs )
49 : : {
50 : 0 : GDALDriverH hDriverMem = GDALGetDriverByName( "MEM" );
51 : 0 : if ( !hDriverMem )
52 : : {
53 : 0 : return gdal::dataset_unique_ptr();
54 : : }
55 : :
56 : 0 : gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem, "", width, height, bands, dataType, nullptr ) );
57 : :
58 : 0 : double cellSizeX = extent.width() / width;
59 : 0 : double cellSizeY = extent.height() / height;
60 : : double geoTransform[6];
61 : 0 : geoTransform[0] = extent.xMinimum();
62 : 0 : geoTransform[1] = cellSizeX;
63 : 0 : geoTransform[2] = 0;
64 : 0 : geoTransform[3] = extent.yMinimum() + ( cellSizeY * height );
65 : 0 : geoTransform[4] = 0;
66 : 0 : geoTransform[5] = -cellSizeY;
67 : :
68 : 0 : GDALSetProjection( hSrcDS.get(), crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED_GDAL ).toLatin1().constData() );
69 : 0 : GDALSetGeoTransform( hSrcDS.get(), geoTransform );
70 : 0 : return hSrcDS;
71 : 0 : }
72 : :
73 : 0 : gdal::dataset_unique_ptr QgsGdalUtils::createSingleBandTiffDataset( const QString &filename, GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs )
74 : : {
75 : 0 : double cellSizeX = extent.width() / width;
76 : 0 : double cellSizeY = extent.height() / height;
77 : : double geoTransform[6];
78 : 0 : geoTransform[0] = extent.xMinimum();
79 : 0 : geoTransform[1] = cellSizeX;
80 : 0 : geoTransform[2] = 0;
81 : 0 : geoTransform[3] = extent.yMinimum() + ( cellSizeY * height );
82 : 0 : geoTransform[4] = 0;
83 : 0 : geoTransform[5] = -cellSizeY;
84 : :
85 : 0 : GDALDriverH hDriver = GDALGetDriverByName( "GTiff" );
86 : 0 : if ( !hDriver )
87 : : {
88 : 0 : return gdal::dataset_unique_ptr();
89 : : }
90 : :
91 : : // Create the output file.
92 : 0 : gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, filename.toLocal8Bit().constData(), width, height, 1, dataType, nullptr ) );
93 : 0 : if ( !hDstDS )
94 : : {
95 : 0 : return gdal::dataset_unique_ptr();
96 : : }
97 : :
98 : : // Write out the projection definition.
99 : 0 : GDALSetProjection( hDstDS.get(), crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED_GDAL ).toLatin1().constData() );
100 : 0 : GDALSetGeoTransform( hDstDS.get(), geoTransform );
101 : 0 : return hDstDS;
102 : 0 : }
103 : :
104 : 0 : gdal::dataset_unique_ptr QgsGdalUtils::imageToMemoryDataset( const QImage &image )
105 : : {
106 : 0 : if ( image.isNull() )
107 : 0 : return nullptr;
108 : :
109 : 0 : const QRgb *rgb = reinterpret_cast<const QRgb *>( image.constBits() );
110 : 0 : GDALDriverH hDriverMem = GDALGetDriverByName( "MEM" );
111 : 0 : if ( !hDriverMem )
112 : : {
113 : 0 : return nullptr;
114 : : }
115 : 0 : gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem, "", image.width(), image.height(), 0, GDT_Byte, nullptr ) );
116 : :
117 : 0 : char **papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
118 : 0 : << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
119 : 0 : << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
120 : 0 : << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) + 2 ) );
121 : 0 : GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
122 : 0 : CSLDestroy( papszOptions );
123 : :
124 : 0 : papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
125 : 0 : << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
126 : 0 : << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
127 : 0 : << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) + 1 ) );
128 : 0 : GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
129 : 0 : CSLDestroy( papszOptions );
130 : :
131 : 0 : papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
132 : 0 : << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
133 : 0 : << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
134 : 0 : << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) ) );
135 : 0 : GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
136 : 0 : CSLDestroy( papszOptions );
137 : :
138 : 0 : papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
139 : 0 : << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
140 : 0 : << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
141 : 0 : << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) + 3 ) );
142 : 0 : GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
143 : 0 : CSLDestroy( papszOptions );
144 : :
145 : 0 : return hSrcDS;
146 : 0 : }
147 : :
148 : 0 : bool QgsGdalUtils::resampleSingleBandRaster( GDALDatasetH hSrcDS, GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, const char *pszCoordinateOperation )
149 : : {
150 : 0 : gdal::warp_options_unique_ptr psWarpOptions( GDALCreateWarpOptions() );
151 : 0 : psWarpOptions->hSrcDS = hSrcDS;
152 : 0 : psWarpOptions->hDstDS = hDstDS;
153 : :
154 : 0 : psWarpOptions->nBandCount = 1;
155 : 0 : psWarpOptions->panSrcBands = reinterpret_cast< int * >( CPLMalloc( sizeof( int ) * 1 ) );
156 : 0 : psWarpOptions->panDstBands = reinterpret_cast< int * >( CPLMalloc( sizeof( int ) * 1 ) );
157 : 0 : psWarpOptions->panSrcBands[0] = 1;
158 : 0 : psWarpOptions->panDstBands[0] = 1;
159 : :
160 : 0 : psWarpOptions->eResampleAlg = resampleAlg;
161 : :
162 : : // Establish reprojection transformer.
163 : 0 : char **papszOptions = nullptr;
164 : 0 : if ( pszCoordinateOperation != nullptr )
165 : 0 : papszOptions = CSLSetNameValue( papszOptions, "COORDINATE_OPERATION", pszCoordinateOperation );
166 : 0 : psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
167 : 0 : CSLDestroy( papszOptions );
168 : :
169 : 0 : if ( ! psWarpOptions->pTransformerArg )
170 : : {
171 : 0 : return false;
172 : : }
173 : :
174 : 0 : psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
175 : :
176 : : // Initialize and execute the warp operation.
177 : 0 : GDALWarpOperation oOperation;
178 : 0 : oOperation.Initialize( psWarpOptions.get() );
179 : :
180 : 0 : const bool retVal { oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ) == CE_None };
181 : 0 : GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
182 : 0 : return retVal;
183 : 0 : }
184 : :
185 : 0 : QImage QgsGdalUtils::resampleImage( const QImage &image, QSize outputSize, GDALRIOResampleAlg resampleAlg )
186 : : {
187 : 0 : gdal::dataset_unique_ptr srcDS = QgsGdalUtils::imageToMemoryDataset( image );
188 : 0 : if ( !srcDS )
189 : 0 : return QImage();
190 : :
191 : : GDALRasterIOExtraArg extra;
192 : 0 : INIT_RASTERIO_EXTRA_ARG( extra );
193 : 0 : extra.eResampleAlg = resampleAlg;
194 : :
195 : 0 : QImage res( outputSize, image.format() );
196 : 0 : if ( res.isNull() )
197 : 0 : return QImage();
198 : :
199 : 0 : GByte *rgb = reinterpret_cast<GByte *>( res.bits() );
200 : :
201 : 0 : CPLErr err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 1 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 2, outputSize.width(),
202 : 0 : outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
203 : 0 : if ( err != CE_None )
204 : : {
205 : 0 : QgsDebugMsg( QStringLiteral( "failed to read red band" ) );
206 : 0 : return QImage();
207 : : }
208 : :
209 : 0 : err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 2 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 1, outputSize.width(),
210 : 0 : outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
211 : 0 : if ( err != CE_None )
212 : : {
213 : 0 : QgsDebugMsg( QStringLiteral( "failed to read green band" ) );
214 : 0 : return QImage();
215 : : }
216 : :
217 : 0 : err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 3 ), GF_Read, 0, 0, image.width(), image.height(), rgb, outputSize.width(),
218 : 0 : outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
219 : 0 : if ( err != CE_None )
220 : : {
221 : 0 : QgsDebugMsg( QStringLiteral( "failed to read blue band" ) );
222 : 0 : return QImage();
223 : : }
224 : :
225 : 0 : err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 4 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 3, outputSize.width(),
226 : 0 : outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
227 : 0 : if ( err != CE_None )
228 : : {
229 : 0 : QgsDebugMsg( QStringLiteral( "failed to read alpha band" ) );
230 : 0 : return QImage();
231 : : }
232 : :
233 : 0 : return res;
234 : 0 : }
235 : :
236 : 0 : QString QgsGdalUtils::helpCreationOptionsFormat( const QString &format )
237 : : {
238 : 0 : QString message;
239 : 0 : GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
240 : 0 : if ( myGdalDriver )
241 : : {
242 : : // first report details and help page
243 : 0 : char **GDALmetadata = GDALGetMetadata( myGdalDriver, nullptr );
244 : 0 : message += QLatin1String( "Format Details:\n" );
245 : 0 : message += QStringLiteral( " Extension: %1\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
246 : 0 : message += QStringLiteral( " Short Name: %1" ).arg( GDALGetDriverShortName( myGdalDriver ) );
247 : 0 : message += QStringLiteral( " / Long Name: %1\n" ).arg( GDALGetDriverLongName( myGdalDriver ) );
248 : 0 : message += QStringLiteral( " Help page: http://www.gdal.org/%1\n\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_HELPTOPIC ) );
249 : :
250 : : // next get creation options
251 : : // need to serialize xml to get newlines, should we make the basic xml prettier?
252 : 0 : CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
253 : : GDAL_DMD_CREATIONOPTIONLIST, "" ) );
254 : 0 : char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
255 : 0 : if ( pszFormattedXML )
256 : 0 : message += QString( pszFormattedXML );
257 : 0 : if ( psCOL )
258 : 0 : CPLDestroyXMLNode( psCOL );
259 : 0 : if ( pszFormattedXML )
260 : 0 : CPLFree( pszFormattedXML );
261 : 0 : }
262 : 0 : return message;
263 : 0 : }
264 : :
265 : 0 : char **QgsGdalUtils::papszFromStringList( const QStringList &list )
266 : : {
267 : 0 : char **papszRetList = nullptr;
268 : 0 : const auto constList = list;
269 : 0 : for ( const QString &elem : constList )
270 : : {
271 : 0 : papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
272 : : }
273 : 0 : return papszRetList;
274 : 0 : }
275 : :
276 : 0 : QString QgsGdalUtils::validateCreationOptionsFormat( const QStringList &createOptions, const QString &format )
277 : : {
278 : 0 : GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
279 : 0 : if ( ! myGdalDriver )
280 : 0 : return QStringLiteral( "invalid GDAL driver" );
281 : :
282 : 0 : char **papszOptions = papszFromStringList( createOptions );
283 : : // get error string?
284 : 0 : int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
285 : 0 : CSLDestroy( papszOptions );
286 : :
287 : 0 : if ( !ok )
288 : 0 : return QStringLiteral( "Failed GDALValidateCreationOptions() test" );
289 : 0 : return QString();
290 : 0 : }
291 : :
292 : : #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,2,0)
293 : :
294 : : GDALDatasetH GDALAutoCreateWarpedVRTEx( GDALDatasetH hSrcDS, const char *pszSrcWKT, const char *pszDstWKT, GDALResampleAlg eResampleAlg,
295 : : double dfMaxError, const GDALWarpOptions *psOptionsIn, char **papszTransformerOptions )
296 : : {
297 : : VALIDATE_POINTER1( hSrcDS, "GDALAutoCreateWarpedVRT", nullptr );
298 : :
299 : : /* -------------------------------------------------------------------- */
300 : : /* Populate the warp options. */
301 : : /* -------------------------------------------------------------------- */
302 : : GDALWarpOptions *psWO = nullptr;
303 : : if ( psOptionsIn != nullptr )
304 : : psWO = GDALCloneWarpOptions( psOptionsIn );
305 : : else
306 : : psWO = GDALCreateWarpOptions();
307 : :
308 : : psWO->eResampleAlg = eResampleAlg;
309 : :
310 : : psWO->hSrcDS = hSrcDS;
311 : :
312 : : GDALWarpInitDefaultBandMapping( psWO, GDALGetRasterCount( hSrcDS ) );
313 : :
314 : : /* -------------------------------------------------------------------- */
315 : : /* Setup no data values */
316 : : /* -------------------------------------------------------------------- */
317 : : for ( int i = 0; i < psWO->nBandCount; i++ )
318 : : {
319 : : GDALRasterBandH rasterBand = GDALGetRasterBand( psWO->hSrcDS, psWO->panSrcBands[i] );
320 : :
321 : : int hasNoDataValue;
322 : : double noDataValue = GDALGetRasterNoDataValue( rasterBand, &hasNoDataValue );
323 : :
324 : : if ( hasNoDataValue )
325 : : {
326 : : // Check if the nodata value is out of range
327 : : int bClamped = FALSE;
328 : : int bRounded = FALSE;
329 : : CPL_IGNORE_RET_VAL(
330 : : GDALAdjustValueToDataType( GDALGetRasterDataType( rasterBand ),
331 : : noDataValue, &bClamped, &bRounded ) );
332 : : if ( !bClamped )
333 : : {
334 : : GDALWarpInitNoDataReal( psWO, -1e10 );
335 : :
336 : : psWO->padfSrcNoDataReal[i] = noDataValue;
337 : : psWO->padfDstNoDataReal[i] = noDataValue;
338 : : }
339 : : }
340 : : }
341 : :
342 : : if ( psWO->padfDstNoDataReal != nullptr )
343 : : {
344 : : if ( CSLFetchNameValue( psWO->papszWarpOptions, "INIT_DEST" ) == nullptr )
345 : : {
346 : : psWO->papszWarpOptions =
347 : : CSLSetNameValue( psWO->papszWarpOptions, "INIT_DEST", "NO_DATA" );
348 : : }
349 : : }
350 : :
351 : : /* -------------------------------------------------------------------- */
352 : : /* Create the transformer. */
353 : : /* -------------------------------------------------------------------- */
354 : : psWO->pfnTransformer = GDALGenImgProjTransform;
355 : :
356 : : char **papszOptions = nullptr;
357 : : if ( pszSrcWKT != nullptr )
358 : : papszOptions = CSLSetNameValue( papszOptions, "SRC_SRS", pszSrcWKT );
359 : : if ( pszDstWKT != nullptr )
360 : : papszOptions = CSLSetNameValue( papszOptions, "DST_SRS", pszDstWKT );
361 : : papszOptions = CSLMerge( papszOptions, papszTransformerOptions );
362 : : psWO->pTransformerArg =
363 : : GDALCreateGenImgProjTransformer2( psWO->hSrcDS, nullptr,
364 : : papszOptions );
365 : : CSLDestroy( papszOptions );
366 : :
367 : : if ( psWO->pTransformerArg == nullptr )
368 : : {
369 : : GDALDestroyWarpOptions( psWO );
370 : : return nullptr;
371 : : }
372 : :
373 : : /* -------------------------------------------------------------------- */
374 : : /* Figure out the desired output bounds and resolution. */
375 : : /* -------------------------------------------------------------------- */
376 : : double adfDstGeoTransform[6] = { 0.0 };
377 : : int nDstPixels = 0;
378 : : int nDstLines = 0;
379 : : CPLErr eErr =
380 : : GDALSuggestedWarpOutput( hSrcDS, psWO->pfnTransformer,
381 : : psWO->pTransformerArg,
382 : : adfDstGeoTransform, &nDstPixels, &nDstLines );
383 : : if ( eErr != CE_None )
384 : : {
385 : : GDALDestroyTransformer( psWO->pTransformerArg );
386 : : GDALDestroyWarpOptions( psWO );
387 : : return nullptr;
388 : : }
389 : :
390 : : /* -------------------------------------------------------------------- */
391 : : /* Update the transformer to include an output geotransform */
392 : : /* back to pixel/line coordinates. */
393 : : /* */
394 : : /* -------------------------------------------------------------------- */
395 : : GDALSetGenImgProjTransformerDstGeoTransform(
396 : : psWO->pTransformerArg, adfDstGeoTransform );
397 : :
398 : : /* -------------------------------------------------------------------- */
399 : : /* Do we want to apply an approximating transformation? */
400 : : /* -------------------------------------------------------------------- */
401 : : if ( dfMaxError > 0.0 )
402 : : {
403 : : psWO->pTransformerArg =
404 : : GDALCreateApproxTransformer( psWO->pfnTransformer,
405 : : psWO->pTransformerArg,
406 : : dfMaxError );
407 : : psWO->pfnTransformer = GDALApproxTransform;
408 : : GDALApproxTransformerOwnsSubtransformer( psWO->pTransformerArg, TRUE );
409 : : }
410 : :
411 : : /* -------------------------------------------------------------------- */
412 : : /* Create the VRT file. */
413 : : /* -------------------------------------------------------------------- */
414 : : GDALDatasetH hDstDS
415 : : = GDALCreateWarpedVRT( hSrcDS, nDstPixels, nDstLines,
416 : : adfDstGeoTransform, psWO );
417 : :
418 : : GDALDestroyWarpOptions( psWO );
419 : :
420 : : if ( pszDstWKT != nullptr )
421 : : GDALSetProjection( hDstDS, pszDstWKT );
422 : : else if ( pszSrcWKT != nullptr )
423 : : GDALSetProjection( hDstDS, pszSrcWKT );
424 : : else if ( GDALGetGCPCount( hSrcDS ) > 0 )
425 : : GDALSetProjection( hDstDS, GDALGetGCPProjection( hSrcDS ) );
426 : : else
427 : : GDALSetProjection( hDstDS, GDALGetProjectionRef( hSrcDS ) );
428 : :
429 : : return hDstDS;
430 : : }
431 : : #endif
432 : :
433 : :
434 : 0 : GDALDatasetH QgsGdalUtils::rpcAwareAutoCreateWarpedVrt(
435 : : GDALDatasetH hSrcDS,
436 : : const char *pszSrcWKT,
437 : : const char *pszDstWKT,
438 : : GDALResampleAlg eResampleAlg,
439 : : double dfMaxError,
440 : : const GDALWarpOptions *psOptionsIn )
441 : : {
442 : 0 : char **opts = nullptr;
443 : 0 : if ( GDALGetMetadata( hSrcDS, "RPC" ) )
444 : : {
445 : : // well-behaved RPC should have height offset a good value for RPC_HEIGHT
446 : 0 : const char *heightOffStr = GDALGetMetadataItem( hSrcDS, "HEIGHT_OFF", "RPC" );
447 : 0 : if ( heightOffStr )
448 : 0 : opts = CSLAddNameValue( opts, "RPC_HEIGHT", heightOffStr );
449 : 0 : }
450 : :
451 : 0 : return GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
452 : : }
453 : :
454 : 0 : void *QgsGdalUtils::rpcAwareCreateTransformer( GDALDatasetH hSrcDS, GDALDatasetH hDstDS, char **papszOptions )
455 : : {
456 : 0 : char **opts = CSLDuplicate( papszOptions );
457 : 0 : if ( GDALGetMetadata( hSrcDS, "RPC" ) )
458 : : {
459 : : // well-behaved RPC should have height offset a good value for RPC_HEIGHT
460 : 0 : const char *heightOffStr = GDALGetMetadataItem( hSrcDS, "HEIGHT_OFF", "RPC" );
461 : 0 : if ( heightOffStr )
462 : 0 : opts = CSLAddNameValue( opts, "RPC_HEIGHT", heightOffStr );
463 : 0 : }
464 : 0 : void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
465 : 0 : CSLDestroy( opts );
466 : 0 : return transformer;
467 : : }
468 : :
469 : : #ifndef QT_NO_NETWORKPROXY
470 : 64 : void QgsGdalUtils::setupProxy()
471 : : {
472 : : // Check proxy configuration, they are application level but
473 : : // instead of adding an API and complex signal/slot connections
474 : : // given the limited cost of checking them on every provider instantiation
475 : : // we can do it here so that new settings are applied whenever a new layer
476 : : // is created.
477 : 64 : QgsSettings settings;
478 : : // Check that proxy is enabled
479 : 128 : if ( settings.value( QStringLiteral( "proxy/proxyEnabled" ), false ).toBool() )
480 : : {
481 : : // Get the first configured proxy
482 : 0 : QList<QNetworkProxy> proxies( QgsNetworkAccessManager::instance()->proxyFactory()->queryProxy( ) );
483 : 0 : if ( ! proxies.isEmpty() )
484 : : {
485 : 0 : QNetworkProxy proxy( proxies.first() );
486 : : // TODO/FIXME: check excludes (the GDAL config options are global, we need a per-connection config option)
487 : : //QStringList excludes;
488 : : //excludes = settings.value( QStringLiteral( "proxy/proxyExcludedUrls" ), "" ).toStringList();
489 : :
490 : 0 : QString proxyHost( proxy.hostName() );
491 : 0 : qint16 proxyPort( proxy.port() );
492 : :
493 : 0 : QString proxyUser( proxy.user() );
494 : 0 : QString proxyPassword( proxy.password() );
495 : :
496 : 0 : if ( ! proxyHost.isEmpty() )
497 : : {
498 : 0 : QString connection( proxyHost );
499 : 0 : if ( proxyPort )
500 : : {
501 : 0 : connection += ':' + QString::number( proxyPort );
502 : 0 : }
503 : 0 : CPLSetConfigOption( "GDAL_HTTP_PROXY", connection.toUtf8() );
504 : 0 : if ( ! proxyUser.isEmpty( ) )
505 : : {
506 : 0 : QString credentials( proxyUser );
507 : 0 : if ( ! proxyPassword.isEmpty( ) )
508 : : {
509 : 0 : credentials += ':' + proxyPassword;
510 : 0 : }
511 : 0 : CPLSetConfigOption( "GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
512 : 0 : }
513 : 0 : }
514 : 0 : }
515 : 0 : }
516 : 64 : }
517 : : #endif
|