1 : /******************************************************************************
2 : * $Id: gdalwarp.cpp 25229 2012-11-16 19:06:58Z rouault $
3 : *
4 : * Project: High Performance Image Reprojector
5 : * Purpose: Test program for high performance warper API.
6 : * Author: Frank Warmerdam <warmerdam@pobox.com>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, i3 - information integration and imaging
10 : * Fort Collin, CO
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "gdalwarper.h"
32 : #include "cpl_string.h"
33 : #include "ogr_spatialref.h"
34 : #include "ogr_api.h"
35 : #include "commonutils.h"
36 : #include <vector>
37 :
38 : CPL_CVSID("$Id: gdalwarp.cpp 25229 2012-11-16 19:06:58Z rouault $");
39 :
40 : static void
41 : LoadCutline( const char *pszCutlineDSName, const char *pszCLayer,
42 : const char *pszCWHERE, const char *pszCSQL,
43 : void **phCutlineRet );
44 : static void
45 : TransformCutlineToSource( GDALDatasetH hSrcDS, void *hCutline,
46 : char ***ppapszWarpOptions, char **papszTO );
47 :
48 : static GDALDatasetH
49 : GDALWarpCreateOutput( char **papszSrcFiles, const char *pszFilename,
50 : const char *pszFormat, char **papszTO,
51 : char ***ppapszCreateOptions, GDALDataType eDT,
52 : void ** phTransformArg,
53 : GDALDatasetH* phSrcDS );
54 :
55 : static void
56 : RemoveConflictingMetadata( GDALMajorObjectH hObj, char **papszMetadata,
57 : const char *pszValueConflict );
58 :
59 : static double dfMinX=0.0, dfMinY=0.0, dfMaxX=0.0, dfMaxY=0.0;
60 : static double dfXRes=0.0, dfYRes=0.0;
61 : static int bTargetAlignedPixels = FALSE;
62 : static int nForcePixels=0, nForceLines=0, bQuiet = FALSE;
63 : static int bEnableDstAlpha = FALSE, bEnableSrcAlpha = FALSE;
64 :
65 : static int bVRT = FALSE;
66 :
67 : /******************************************************************************/
68 : /*! \page gdalwarp gdalwarp
69 :
70 : image reprojection and warping utility
71 :
72 : \section gdalwarp_synopsis SYNOPSIS
73 :
74 : \htmlonly
75 : Usage:
76 : \endhtmlonly
77 :
78 : \verbatim
79 : gdalwarp [--help-general] [--formats]
80 : [-s_srs srs_def] [-t_srs srs_def] [-to "NAME=VALUE"]
81 : [-order n | -tps | -rpc | -geoloc] [-et err_threshold]
82 : [-refine_gcps tolerance [minimum_gcps]]
83 : [-te xmin ymin xmax ymax] [-tr xres yres] [-tap] [-ts width height]
84 : [-wo "NAME=VALUE"] [-ot Byte/Int16/...] [-wt Byte/Int16]
85 : [-srcnodata "value [value...]"] [-dstnodata "value [value...]"] -dstalpha
86 : [-r resampling_method] [-wm memory_in_mb] [-multi] [-q]
87 : [-cutline datasource] [-cl layer] [-cwhere expression]
88 : [-csql statement] [-cblend dist_in_pixels] [-crop_to_cutline]
89 : [-of format] [-co "NAME=VALUE"]* [-overwrite]
90 : [-nomd] [-cvmd meta_conflict_value]
91 : srcfile* dstfile
92 : \endverbatim
93 :
94 : \section gdalwarp_description DESCRIPTION
95 :
96 : <p>
97 : The gdalwarp utility is an image mosaicing, reprojection and warping
98 : utility. The program can reproject to any supported projection,
99 : and can also apply GCPs stored with the image if the image is "raw"
100 : with control information.
101 :
102 : <p>
103 : <dl>
104 : <dt> <b>-s_srs</b> <em>srs def</em>:</dt><dd> source spatial reference set.
105 : The coordinate systems that can be passed are anything supported by the
106 : OGRSpatialReference.SetFromUserInput() call, which includes EPSG PCS and GCSes
107 : (ie. EPSG:4296), PROJ.4 declarations (as above), or the name of a .prf file
108 : containing well known text.</dd>
109 : <dt> <b>-t_srs</b> <em>srs_def</em>:</dt><dd> target spatial reference set.
110 : The coordinate systems that can be passed are anything supported by the
111 : OGRSpatialReference.SetFromUserInput() call, which includes EPSG PCS and GCSes
112 : (ie. EPSG:4296), PROJ.4 declarations (as above), or the name of a .prf file
113 : containing well known text.</dd>
114 : <dt> <b>-to</b> <em>NAME=VALUE</em>:</dt><dd> set a transformer option suitable
115 : to pass to GDALCreateGenImgProjTransformer2(). </dd>
116 : <dt> <b>-order</b> <em>n</em>:</dt><dd> order of polynomial used for warping
117 : (1 to 3). The default is to select a polynomial order based on the number of
118 : GCPs.</dd>
119 : <dt> <b>-tps</b>:</dt><dd>Force use of thin plate spline transformer based on
120 : available GCPs.</dd>
121 : <dt> <b>-rpc</b>:</dt> <dd>Force use of RPCs.</dd>
122 : <dt> <b>-geoloc</b>:</dt><dd>Force use of Geolocation Arrays.</dd>
123 : <dt> <b>-et</b> <em>err_threshold</em>:</dt><dd> error threshold for
124 : transformation approximation (in pixel units - defaults to 0.125).</dd>
125 : <dt> <b>-refine_gcps</b> <em>tolerance minimum_gcps</em>:</dt><dd> (GDAL >= 1.9.0) refines the GCPs by automatically eliminating outliers.
126 : Outliers will be eliminated until minimum_gcps are left or when no outliers can be detected.
127 : The tolerance is passed to adjust when a GCP will be eliminated.
128 : Not that GCP refinement only works with polynomial interpolation.
129 : The tolerance is in pixel units if no projection is available, otherwise it is in SRS units.
130 : If minimum_gcps is not provided, the minimum GCPs according to the polynomial model is used.</dd>
131 : <dt> <b>-te</b> <em>xmin ymin xmax ymax</em>:</dt><dd> set georeferenced
132 : extents of output file to be created (in target SRS).</dd>
133 : <dt> <b>-tr</b> <em>xres yres</em>:</dt><dd> set output file resolution (in
134 : target georeferenced units)</dd>
135 : <dt> <b>-tap</b>:</dt><dd> (GDAL >= 1.8.0) (target aligned pixels) align
136 : the coordinates of the extent of the output file to the values of the -tr,
137 : such that the aligned extent includes the minimum extent.</dd>
138 : <dt> <b>-ts</b> <em>width height</em>:</dt><dd> set output file size in
139 : pixels and lines. If width or height is set to 0, the other dimension will be
140 : guessed from the computed resolution. Note that -ts cannot be used with -tr</dd>
141 : <dt> <b>-wo</b> <em>"NAME=VALUE"</em>:</dt><dd> Set a warp options. The
142 : GDALWarpOptions::papszWarpOptions docs show all options. Multiple
143 : <b>-wo</b> options may be listed.</dd>
144 : <dt> <b>-ot</b> <em>type</em>:</dt><dd> For the output bands to be of the
145 : indicated data type.</dd>
146 : <dt> <b>-wt</b> <em>type</em>:</dt><dd> Working pixel data type. The data type
147 : of pixels in the source image and destination image buffers.</dd>
148 : <dt> <b>-r</b> <em>resampling_method</em>:</dt><dd> Resampling method to use. Available methods are:
149 : <dl>
150 : <dt><b>near</b></dt>: <dd>nearest neighbour resampling (default, fastest
151 : algorithm, worst interpolation quality).</dd>
152 : <dt><b>bilinear</b></dt>: <dd>bilinear resampling.</dd>
153 : <dt><b>cubic</b></dt>: <dd>cubic resampling.</dd>
154 : <dt><b>cubicspline</b></dt>: <dd>cubic spline resampling.</dd>
155 : <dt><b>lanczos</b></dt>: <dd>Lanczos windowed sinc resampling.</dd>
156 : </dl>
157 : <dt> <b>-srcnodata</b> <em>value [value...]</em>:</dt><dd> Set nodata masking
158 : values for input bands (different values can be supplied for each band). If
159 : more than one value is supplied all values should be quoted to keep them
160 : together as a single operating system argument. Masked values will not be
161 : used in interpolation. Use a value of <tt>None</tt> to ignore intrinsic nodata settings on the source dataset.</dd>
162 : <dt> <b>-dstnodata</b> <em>value [value...]</em>:</dt><dd> Set nodata values
163 : for output bands (different values can be supplied for each band). If more
164 : than one value is supplied all values should be quoted to keep them together
165 : as a single operating system argument. New files will be initialized to this
166 : value and if possible the nodata value will be recorded in the output
167 : file.</dd>
168 : <dt> <b>-dstalpha</b>:</dt><dd> Create an output alpha band to identify
169 : nodata (unset/transparent) pixels. </dd>
170 : <dt> <b>-wm</b> <em>memory_in_mb</em>:</dt><dd> Set the amount of memory (in
171 : megabytes) that the warp API is allowed to use for caching.</dd>
172 : <dt> <b>-multi</b>:</dt><dd> Use multithreaded warping implementation.
173 : Multiple threads will be used to process chunks of image and perform
174 : input/output operation simultaneously.</dd>
175 : <dt> <b>-q</b>:</dt><dd> Be quiet.</dd>
176 : <dt> <b>-of</b> <em>format</em>:</dt><dd> Select the output format. The default is GeoTIFF (GTiff). Use the short format name. </dd>
177 : <dt> <b>-co</b> <em>"NAME=VALUE"</em>:</dt><dd> passes a creation option to
178 : the output format driver. Multiple <b>-co</b> options may be listed. See
179 : format specific documentation for legal creation options for each format.
180 : </dd>
181 :
182 : <dt> <b>-cutline</b> <em>datasource</em>:</dt><dd>Enable use of a blend cutline from the name OGR support datasource.</dd>
183 : <dt> <b>-cl</b> <em>layername</em>:</dt><dd>Select the named layer from the
184 : cutline datasource.</dd>
185 : <dt> <b>-cwhere</b> <em>expression</em>:</dt><dd>Restrict desired cutline features based on attribute query.</dd>
186 : <dt> <b>-csql</b> <em>query</em>:</dt><dd>Select cutline features using an SQL query instead of from a layer with -cl.</dd>
187 : <dt> <b>-cblend</b> <em>distance</em>:</dt><dd>Set a blend distance to use to blend over cutlines (in pixels).</dd>
188 : <dt> <b>-crop_to_cutline</b>:</dt><dd>(GDAL >= 1.8.0) Crop the extent of the target dataset to the extent of the cutline.</dd>
189 : <dt> <b>-overwrite</b>:</dt><dd>(GDAL >= 1.8.0) Overwrite the target dataset if it already exists.</dd>
190 : <dt> <b>-nomd</b>:</dt><dd>(GDAL >= 1.10.0) Do not copy metadata. Without this option, dataset and band metadata
191 : (as well as some band information) will be copied from the first source dataset.
192 : Items that differ between source datasets will be set to * (see -cvmd option).</dd>
193 : <dt> <b>-cvmd</b> <em>meta_conflict_value</em>:</dt><dd>(GDAL >= 1.10.0)
194 : Value to set metadata items that conflict between source datasets (default is "*"). Use "" to remove conflicting items. </dd>
195 :
196 : <dt> <em>srcfile</em>:</dt><dd> The source file name(s). </dd>
197 : <dt> <em>dstfile</em>:</dt><dd> The destination file name. </dd>
198 : </dl>
199 :
200 : Mosaicing into an existing output file is supported if the output file
201 : already exists. The spatial extent of the existing file will not
202 : be modified to accomodate new data, so you may have to remove it in that case, or
203 : use the -overwrite option.
204 :
205 : Polygon cutlines may be used as a mask to restrict the area of the destination file
206 : that may be updated, including blending. If the OGR layer containing the cutline
207 : features has no explicit SRS, the cutline features must be in the georeferenced
208 : units of the destination file. When outputing to a not yet existing target dataset,
209 : its extent will be the one of the original raster unless -te or -crop_to_cutline are
210 : specified.
211 :
212 : <p>
213 : \section gdalwarp_example EXAMPLE
214 :
215 : For instance, an eight bit spot scene stored in GeoTIFF with
216 : control points mapping the corners to lat/long could be warped to a UTM
217 : projection with a command like this:<p>
218 :
219 : \verbatim
220 : gdalwarp -t_srs '+proj=utm +zone=11 +datum=WGS84' raw_spot.tif utm11.tif
221 : \endverbatim
222 :
223 : For instance, the second channel of an ASTER image stored in HDF with
224 : control points mapping the corners to lat/long could be warped to a UTM
225 : projection with a command like this:<p>
226 :
227 : \verbatim
228 : gdalwarp HDF4_SDS:ASTER_L1B:"pg-PR1B0000-2002031402_100_001":2 pg-PR1B0000-2002031402_100_001_2.tif
229 : \endverbatim
230 :
231 : \if man
232 : \section gdalwarp_author AUTHORS
233 : Frank Warmerdam <warmerdam@pobox.com>, Silke Reimer <silke@intevation.de>
234 : \endif
235 : */
236 :
237 : /************************************************************************/
238 : /* GDALExit() */
239 : /* This function exits and cleans up GDAL and OGR resources */
240 : /* Perhaps it should be added to C api and used in all apps? */
241 : /************************************************************************/
242 :
243 1 : static int GDALExit( int nCode )
244 : {
245 1 : const char *pszDebug = CPLGetConfigOption("CPL_DEBUG",NULL);
246 1 : if( pszDebug && (EQUAL(pszDebug,"ON") || EQUAL(pszDebug,"") ) )
247 : {
248 0 : GDALDumpOpenDatasets( stderr );
249 0 : CPLDumpSharedList( NULL );
250 : }
251 :
252 1 : GDALDestroyDriverManager();
253 :
254 : #ifdef OGR_ENABLED
255 1 : OGRCleanupAll();
256 : #endif
257 :
258 1 : exit( nCode );
259 : }
260 :
261 : /************************************************************************/
262 : /* Usage() */
263 : /************************************************************************/
264 :
265 1 : static void Usage()
266 :
267 : {
268 : printf(
269 : "Usage: gdalwarp [--help-general] [--formats]\n"
270 : " [-s_srs srs_def] [-t_srs srs_def] [-to \"NAME=VALUE\"]\n"
271 : " [-order n | -tps | -rpc | -geoloc] [-et err_threshold]\n"
272 : " [-refine_gcps tolerance [minimum_gcps]]\n"
273 : " [-te xmin ymin xmax ymax] [-tr xres yres] [-tap] [-ts width height]\n"
274 : " [-wo \"NAME=VALUE\"] [-ot Byte/Int16/...] [-wt Byte/Int16]\n"
275 : " [-srcnodata \"value [value...]\"] [-dstnodata \"value [value...]\"] -dstalpha\n"
276 : " [-r resampling_method] [-wm memory_in_mb] [-multi] [-q]\n"
277 : " [-cutline datasource] [-cl layer] [-cwhere expression]\n"
278 : " [-csql statement] [-cblend dist_in_pixels] [-crop_to_cutline]\n"
279 : " [-of format] [-co \"NAME=VALUE\"]* [-overwrite]\n"
280 : " [-nomd] [-cvmd meta_conflict_value]\n"
281 : " srcfile* dstfile\n"
282 : "\n"
283 : "Available resampling methods:\n"
284 1 : " near (default), bilinear, cubic, cubicspline, lanczos.\n" );
285 1 : GDALExit( 1 );
286 0 : }
287 :
288 : /************************************************************************/
289 : /* SanitizeSRS */
290 : /************************************************************************/
291 :
292 13 : char *SanitizeSRS( const char *pszUserInput )
293 :
294 : {
295 : OGRSpatialReferenceH hSRS;
296 13 : char *pszResult = NULL;
297 :
298 13 : CPLErrorReset();
299 :
300 13 : hSRS = OSRNewSpatialReference( NULL );
301 13 : if( OSRSetFromUserInput( hSRS, pszUserInput ) == OGRERR_NONE )
302 13 : OSRExportToWkt( hSRS, &pszResult );
303 : else
304 : {
305 : CPLError( CE_Failure, CPLE_AppDefined,
306 : "Translating source or target SRS failed:\n%s",
307 0 : pszUserInput );
308 0 : GDALExit( 1 );
309 : }
310 :
311 13 : OSRDestroySpatialReference( hSRS );
312 :
313 13 : return pszResult;
314 : }
315 :
316 : /************************************************************************/
317 : /* main() */
318 : /************************************************************************/
319 :
320 273 : int main( int argc, char ** argv )
321 :
322 : {
323 : GDALDatasetH hDstDS;
324 273 : const char *pszFormat = "GTiff";
325 273 : int bFormatExplicitelySet = FALSE;
326 273 : char **papszSrcFiles = NULL;
327 273 : char *pszDstFilename = NULL;
328 273 : int bCreateOutput = FALSE, i;
329 273 : void *hTransformArg, *hGenImgProjArg=NULL, *hApproxArg=NULL;
330 273 : char **papszWarpOptions = NULL;
331 273 : double dfErrorThreshold = 0.125;
332 273 : double dfWarpMemoryLimit = 0.0;
333 273 : GDALTransformerFunc pfnTransformer = NULL;
334 273 : char **papszCreateOptions = NULL;
335 273 : GDALDataType eOutputType = GDT_Unknown, eWorkingType = GDT_Unknown;
336 273 : GDALResampleAlg eResampleAlg = GRA_NearestNeighbour;
337 273 : const char *pszSrcNodata = NULL;
338 273 : const char *pszDstNodata = NULL;
339 273 : int bMulti = FALSE;
340 273 : char **papszTO = NULL;
341 273 : char *pszCutlineDSName = NULL;
342 273 : char *pszCLayer = NULL, *pszCWHERE = NULL, *pszCSQL = NULL;
343 273 : void *hCutline = NULL;
344 273 : int bHasGotErr = FALSE;
345 273 : int bCropToCutline = FALSE;
346 273 : int bOverwrite = FALSE;
347 273 : int bCopyMetadata = TRUE;
348 273 : int bCopyBandInfo = TRUE;
349 273 : const char *pszMDConflictValue = "*";
350 :
351 : /* Check that we are running against at least GDAL 1.6 */
352 : /* Note to developers : if we use newer API, please change the requirement */
353 273 : if (atoi(GDALVersionInfo("VERSION_NUM")) < 1600)
354 : {
355 : fprintf(stderr, "At least, GDAL >= 1.6.0 is required for this version of %s, "
356 0 : "which was compiled against GDAL %s\n", argv[0], GDAL_RELEASE_NAME);
357 0 : GDALExit(1);
358 : }
359 :
360 : /* Must process GDAL_SKIP before GDALAllRegister(), but we can't call */
361 : /* GDALGeneralCmdLineProcessor before it needs the drivers to be registered */
362 : /* for the --format or --formats options */
363 1450 : for( i = 1; i < argc; i++ )
364 : {
365 1177 : if( EQUAL(argv[i],"--config") && i + 2 < argc && EQUAL(argv[i + 1], "GDAL_SKIP") )
366 : {
367 0 : CPLSetConfigOption( argv[i+1], argv[i+2] );
368 :
369 0 : i += 2;
370 : }
371 : }
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* Register standard GDAL drivers, and process generic GDAL */
375 : /* command options. */
376 : /* -------------------------------------------------------------------- */
377 273 : GDALAllRegister();
378 273 : argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
379 273 : if( argc < 1 )
380 0 : GDALExit( -argc );
381 :
382 : /* -------------------------------------------------------------------- */
383 : /* Parse arguments. */
384 : /* -------------------------------------------------------------------- */
385 1127 : for( i = 1; i < argc; i++ )
386 : {
387 855 : if( EQUAL(argv[i],"-tps") || EQUAL(argv[i],"-rpc") || EQUAL(argv[i],"-geoloc") )
388 : {
389 2 : const char* pszMethod = CSLFetchNameValue(papszTO, "METHOD");
390 2 : if (pszMethod)
391 : fprintf(stderr, "Warning: only one METHOD can be used. Method %s is already defined.\n",
392 0 : pszMethod);
393 2 : const char* pszMAX_GCP_ORDER = CSLFetchNameValue(papszTO, "MAX_GCP_ORDER");
394 2 : if (pszMAX_GCP_ORDER)
395 : fprintf(stderr, "Warning: only one METHOD can be used. -order %s option was specified, so it is likely that GCP_POLYNOMIAL was implied.\n",
396 0 : pszMAX_GCP_ORDER);
397 : }
398 :
399 855 : if( EQUAL(argv[i], "--utility_version") )
400 : {
401 : printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
402 1 : argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
403 1 : return 0;
404 : }
405 866 : else if( EQUAL(argv[i],"-co") && i < argc-1 )
406 : {
407 12 : papszCreateOptions = CSLAddString( papszCreateOptions, argv[++i] );
408 12 : bCreateOutput = TRUE;
409 : }
410 848 : else if( EQUAL(argv[i],"-wo") && i < argc-1 )
411 : {
412 6 : papszWarpOptions = CSLAddString( papszWarpOptions, argv[++i] );
413 : }
414 836 : else if( EQUAL(argv[i],"-multi") )
415 : {
416 1 : bMulti = TRUE;
417 : }
418 836 : else if( EQUAL(argv[i],"-q") || EQUAL(argv[i],"-quiet"))
419 : {
420 1 : bQuiet = TRUE;
421 : }
422 834 : else if( EQUAL(argv[i],"-dstalpha") )
423 : {
424 2 : bEnableDstAlpha = TRUE;
425 : }
426 832 : else if( EQUAL(argv[i],"-srcalpha") )
427 : {
428 0 : bEnableSrcAlpha = TRUE;
429 : }
430 837 : else if( EQUAL(argv[i],"-of") && i < argc-1 )
431 : {
432 5 : pszFormat = argv[++i];
433 5 : bFormatExplicitelySet = TRUE;
434 5 : bCreateOutput = TRUE;
435 5 : if( EQUAL(pszFormat,"VRT") )
436 4 : bVRT = TRUE;
437 : }
438 840 : else if( EQUAL(argv[i],"-t_srs") && i < argc-1 )
439 : {
440 13 : char *pszSRS = SanitizeSRS(argv[++i]);
441 13 : papszTO = CSLSetNameValue( papszTO, "DST_SRS", pszSRS );
442 13 : CPLFree( pszSRS );
443 : }
444 814 : else if( EQUAL(argv[i],"-s_srs") && i < argc-1 )
445 : {
446 0 : char *pszSRS = SanitizeSRS(argv[++i]);
447 0 : papszTO = CSLSetNameValue( papszTO, "SRC_SRS", pszSRS );
448 0 : CPLFree( pszSRS );
449 : }
450 814 : else if( EQUAL(argv[i],"-order") && i < argc-1 )
451 : {
452 0 : const char* pszMethod = CSLFetchNameValue(papszTO, "METHOD");
453 0 : if (pszMethod)
454 : fprintf(stderr, "Warning: only one METHOD can be used. Method %s is already defined\n",
455 0 : pszMethod);
456 0 : papszTO = CSLSetNameValue( papszTO, "MAX_GCP_ORDER", argv[++i] );
457 : }
458 814 : else if( EQUAL(argv[i],"-refine_gcps") && i < argc-1 )
459 : {
460 0 : papszTO = CSLSetNameValue( papszTO, "REFINE_TOLERANCE", argv[++i] );
461 0 : if(atof(argv[i]) < 0)
462 : {
463 0 : printf( "The tolerance for -refine_gcps may not be negative\n");
464 0 : Usage();
465 : }
466 0 : if (i < argc-1 && atoi(argv[i+1]) >= 0 && isdigit(argv[i+1][0]))
467 : {
468 0 : papszTO = CSLSetNameValue( papszTO, "REFINE_MINIMUM_GCPS", argv[++i] );
469 : }
470 : else
471 : {
472 0 : papszTO = CSLSetNameValue( papszTO, "REFINE_MINIMUM_GCPS", "-1" );
473 : }
474 : }
475 814 : else if( EQUAL(argv[i],"-tps") )
476 : {
477 2 : papszTO = CSLSetNameValue( papszTO, "METHOD", "GCP_TPS" );
478 : }
479 812 : else if( EQUAL(argv[i],"-rpc") )
480 : {
481 0 : papszTO = CSLSetNameValue( papszTO, "METHOD", "RPC" );
482 : }
483 812 : else if( EQUAL(argv[i],"-geoloc") )
484 : {
485 0 : papszTO = CSLSetNameValue( papszTO, "METHOD", "GEOLOC_ARRAY" );
486 : }
487 812 : else if( EQUAL(argv[i],"-to") && i < argc-1 )
488 : {
489 0 : papszTO = CSLAddString( papszTO, argv[++i] );
490 : }
491 814 : else if( EQUAL(argv[i],"-et") && i < argc-1 )
492 : {
493 2 : dfErrorThreshold = CPLAtofM(argv[++i]);
494 : }
495 819 : else if( EQUAL(argv[i],"-wm") && i < argc-1 )
496 : {
497 9 : if( CPLAtofM(argv[i+1]) < 10000 )
498 1 : dfWarpMemoryLimit = CPLAtofM(argv[i+1]) * 1024 * 1024;
499 : else
500 8 : dfWarpMemoryLimit = CPLAtofM(argv[i+1]);
501 9 : i++;
502 : }
503 802 : else if( EQUAL(argv[i],"-srcnodata") && i < argc-1 )
504 : {
505 1 : pszSrcNodata = argv[++i];
506 : }
507 801 : else if( EQUAL(argv[i],"-dstnodata") && i < argc-1 )
508 : {
509 1 : pszDstNodata = argv[++i];
510 : }
511 803 : else if( EQUAL(argv[i],"-tr") && i < argc-2 )
512 : {
513 4 : dfXRes = CPLAtofM(argv[++i]);
514 4 : dfYRes = fabs(CPLAtofM(argv[++i]));
515 4 : if( dfXRes == 0 || dfYRes == 0 )
516 : {
517 0 : printf( "Wrong value for -tr parameters\n");
518 0 : Usage();
519 : }
520 4 : bCreateOutput = TRUE;
521 : }
522 795 : else if( EQUAL(argv[i],"-tap") )
523 : {
524 2 : bTargetAlignedPixels = TRUE;
525 : }
526 794 : else if( EQUAL(argv[i],"-ot") && i < argc-1 )
527 : {
528 : int iType;
529 :
530 12 : for( iType = 1; iType < GDT_TypeCount; iType++ )
531 : {
532 22 : if( GDALGetDataTypeName((GDALDataType)iType) != NULL
533 11 : && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
534 : argv[i+1]) )
535 : {
536 1 : eOutputType = (GDALDataType) iType;
537 : }
538 : }
539 :
540 1 : if( eOutputType == GDT_Unknown )
541 : {
542 0 : printf( "Unknown output pixel type: %s\n", argv[i+1] );
543 0 : Usage();
544 : }
545 1 : i++;
546 1 : bCreateOutput = TRUE;
547 : }
548 792 : else if( EQUAL(argv[i],"-wt") && i < argc-1 )
549 : {
550 : int iType;
551 :
552 0 : for( iType = 1; iType < GDT_TypeCount; iType++ )
553 : {
554 0 : if( GDALGetDataTypeName((GDALDataType)iType) != NULL
555 0 : && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
556 : argv[i+1]) )
557 : {
558 0 : eWorkingType = (GDALDataType) iType;
559 : }
560 : }
561 :
562 0 : if( eWorkingType == GDT_Unknown )
563 : {
564 0 : printf( "Unknown output pixel type: %s\n", argv[i+1] );
565 0 : Usage();
566 : }
567 0 : i++;
568 : }
569 801 : else if( EQUAL(argv[i],"-ts") && i < argc-2 )
570 : {
571 9 : nForcePixels = atoi(argv[++i]);
572 9 : nForceLines = atoi(argv[++i]);
573 9 : bCreateOutput = TRUE;
574 : }
575 786 : else if( EQUAL(argv[i],"-te") && i < argc-4 )
576 : {
577 3 : dfMinX = CPLAtofM(argv[++i]);
578 3 : dfMinY = CPLAtofM(argv[++i]);
579 3 : dfMaxX = CPLAtofM(argv[++i]);
580 3 : dfMaxY = CPLAtofM(argv[++i]);
581 3 : bCreateOutput = TRUE;
582 : }
583 780 : else if( EQUAL(argv[i],"-rn") )
584 1 : eResampleAlg = GRA_NearestNeighbour;
585 :
586 779 : else if( EQUAL(argv[i],"-rb") )
587 2 : eResampleAlg = GRA_Bilinear;
588 :
589 777 : else if( EQUAL(argv[i],"-rc") )
590 1 : eResampleAlg = GRA_Cubic;
591 :
592 776 : else if( EQUAL(argv[i],"-rcs") )
593 1 : eResampleAlg = GRA_CubicSpline;
594 :
595 997 : else if( EQUAL(argv[i],"-r") && i < argc - 1 )
596 : {
597 222 : if ( EQUAL(argv[++i], "near") )
598 44 : eResampleAlg = GRA_NearestNeighbour;
599 178 : else if ( EQUAL(argv[i], "bilinear") )
600 45 : eResampleAlg = GRA_Bilinear;
601 133 : else if ( EQUAL(argv[i], "cubic") )
602 44 : eResampleAlg = GRA_Cubic;
603 89 : else if ( EQUAL(argv[i], "cubicspline") )
604 44 : eResampleAlg = GRA_CubicSpline;
605 45 : else if ( EQUAL(argv[i], "lanczos") )
606 45 : eResampleAlg = GRA_Lanczos;
607 : else
608 : {
609 0 : printf( "Unknown resampling method: \"%s\".\n", argv[i] );
610 0 : Usage();
611 : }
612 : }
613 :
614 556 : else if( EQUAL(argv[i],"-cutline") && i < argc-1 )
615 : {
616 3 : pszCutlineDSName = argv[++i];
617 : }
618 550 : else if( EQUAL(argv[i],"-cwhere") && i < argc-1 )
619 : {
620 0 : pszCWHERE = argv[++i];
621 : }
622 553 : else if( EQUAL(argv[i],"-cl") && i < argc-1 )
623 : {
624 3 : pszCLayer = argv[++i];
625 : }
626 547 : else if( EQUAL(argv[i],"-csql") && i < argc-1 )
627 : {
628 0 : pszCSQL = argv[++i];
629 : }
630 547 : else if( EQUAL(argv[i],"-cblend") && i < argc-1 )
631 : {
632 : papszWarpOptions =
633 : CSLSetNameValue( papszWarpOptions,
634 0 : "CUTLINE_BLEND_DIST", argv[++i] );
635 : }
636 547 : else if( EQUAL(argv[i],"-crop_to_cutline") )
637 : {
638 0 : bCropToCutline = TRUE;
639 0 : bCreateOutput = TRUE;
640 : }
641 547 : else if( EQUAL(argv[i],"-overwrite") )
642 2 : bOverwrite = TRUE;
643 545 : else if( EQUAL(argv[i],"-nomd") )
644 : {
645 0 : bCopyMetadata = FALSE;
646 0 : bCopyBandInfo = FALSE;
647 : }
648 545 : else if( EQUAL(argv[i],"-cvmd") && i < argc-1 )
649 0 : pszMDConflictValue = argv[++i];
650 :
651 545 : else if( argv[i][0] == '-' )
652 0 : Usage();
653 :
654 : else
655 545 : papszSrcFiles = CSLAddString( papszSrcFiles, argv[i] );
656 : }
657 : /* -------------------------------------------------------------------- */
658 : /* Check that incompatible options are not used */
659 : /* -------------------------------------------------------------------- */
660 :
661 272 : if ((nForcePixels != 0 || nForceLines != 0) &&
662 : (dfXRes != 0 && dfYRes != 0))
663 : {
664 0 : printf( "-tr and -ts options cannot be used at the same time\n");
665 0 : Usage();
666 : }
667 :
668 272 : if (bTargetAlignedPixels && dfXRes == 0 && dfYRes == 0)
669 : {
670 1 : printf( "-tap option cannot be used without using -tr\n");
671 1 : Usage();
672 : }
673 :
674 : /* -------------------------------------------------------------------- */
675 : /* The last filename in the file list is really our destination */
676 : /* file. */
677 : /* -------------------------------------------------------------------- */
678 271 : if( CSLCount(papszSrcFiles) > 1 )
679 : {
680 271 : pszDstFilename = papszSrcFiles[CSLCount(papszSrcFiles)-1];
681 271 : papszSrcFiles[CSLCount(papszSrcFiles)-1] = NULL;
682 : }
683 :
684 271 : if( pszDstFilename == NULL )
685 0 : Usage();
686 :
687 271 : if( bVRT && CSLCount(papszSrcFiles) > 1 )
688 : {
689 : fprintf(stderr, "Warning: gdalwarp -of VRT just takes into account "
690 : "the first source dataset.\nIf all source datasets "
691 : "are in the same projection, try making a mosaic of\n"
692 : "them with gdalbuildvrt, and use the resulting "
693 0 : "VRT file as the input of\ngdalwarp -of VRT.\n");
694 : }
695 :
696 : /* -------------------------------------------------------------------- */
697 : /* Does the output dataset already exist? */
698 : /* -------------------------------------------------------------------- */
699 :
700 : /* FIXME ? source filename=target filename and -overwrite is definitely */
701 : /* an error. But I can't imagine of a valid case (without -overwrite), */
702 : /* where it would make sense. In doubt, let's keep that dubious possibility... */
703 541 : if ( CSLCount(papszSrcFiles) == 1 &&
704 270 : strcmp(papszSrcFiles[0], pszDstFilename) == 0 && bOverwrite)
705 : {
706 0 : fprintf(stderr, "Source and destination datasets must be different.\n");
707 0 : GDALExit( 1 );
708 : }
709 :
710 271 : CPLPushErrorHandler( CPLQuietErrorHandler );
711 271 : hDstDS = GDALOpen( pszDstFilename, GA_Update );
712 271 : CPLPopErrorHandler();
713 :
714 271 : if( hDstDS != NULL && bOverwrite )
715 : {
716 1 : GDALClose(hDstDS);
717 1 : hDstDS = NULL;
718 : }
719 :
720 271 : if( hDstDS != NULL && bCreateOutput )
721 : {
722 : fprintf( stderr,
723 : "Output dataset %s exists,\n"
724 : "but some commandline options were provided indicating a new dataset\n"
725 : "should be created. Please delete existing dataset and run again.\n",
726 0 : pszDstFilename );
727 0 : GDALExit( 1 );
728 : }
729 :
730 : /* Avoid overwriting an existing destination file that cannot be opened in */
731 : /* update mode with a new GTiff file */
732 271 : if ( hDstDS == NULL && !bOverwrite )
733 : {
734 268 : CPLPushErrorHandler( CPLQuietErrorHandler );
735 268 : hDstDS = GDALOpen( pszDstFilename, GA_ReadOnly );
736 268 : CPLPopErrorHandler();
737 :
738 268 : if (hDstDS)
739 : {
740 : fprintf( stderr,
741 : "Output dataset %s exists, but cannot be opened in update mode\n",
742 0 : pszDstFilename );
743 0 : GDALClose(hDstDS);
744 0 : GDALExit( 1 );
745 : }
746 : }
747 :
748 : /* -------------------------------------------------------------------- */
749 : /* If we have a cutline datasource read it and attach it in the */
750 : /* warp options. */
751 : /* -------------------------------------------------------------------- */
752 271 : if( pszCutlineDSName != NULL )
753 : {
754 : LoadCutline( pszCutlineDSName, pszCLayer, pszCWHERE, pszCSQL,
755 3 : &hCutline );
756 : }
757 :
758 : #ifdef OGR_ENABLED
759 271 : if ( bCropToCutline && hCutline != NULL )
760 : {
761 0 : OGRGeometryH hCutlineGeom = OGR_G_Clone( (OGRGeometryH) hCutline );
762 0 : OGRSpatialReferenceH hCutlineSRS = OGR_G_GetSpatialReference( hCutlineGeom );
763 0 : const char *pszThisTargetSRS = CSLFetchNameValue( papszTO, "DST_SRS" );
764 0 : OGRCoordinateTransformationH hCT = NULL;
765 0 : if (hCutlineSRS == NULL)
766 : {
767 : /* We suppose it is in target coordinates */
768 : }
769 0 : else if (pszThisTargetSRS != NULL)
770 : {
771 0 : OGRSpatialReferenceH hTargetSRS = OSRNewSpatialReference(NULL);
772 0 : if( OSRImportFromWkt( hTargetSRS, (char **)&pszThisTargetSRS ) != CE_None )
773 : {
774 0 : fprintf(stderr, "Cannot compute bounding box of cutline.\n");
775 0 : GDALExit(1);
776 : }
777 :
778 0 : hCT = OCTNewCoordinateTransformation(hCutlineSRS, hTargetSRS);
779 :
780 0 : OSRDestroySpatialReference(hTargetSRS);
781 : }
782 0 : else if (pszThisTargetSRS == NULL)
783 : {
784 0 : if (papszSrcFiles[0] != NULL)
785 : {
786 0 : GDALDatasetH hSrcDS = GDALOpen(papszSrcFiles[0], GA_ReadOnly);
787 0 : if (hSrcDS == NULL)
788 : {
789 0 : fprintf(stderr, "Cannot compute bounding box of cutline.\n");
790 0 : GDALExit(1);
791 : }
792 :
793 0 : OGRSpatialReferenceH hRasterSRS = NULL;
794 0 : const char *pszProjection = NULL;
795 :
796 0 : if( GDALGetProjectionRef( hSrcDS ) != NULL
797 : && strlen(GDALGetProjectionRef( hSrcDS )) > 0 )
798 0 : pszProjection = GDALGetProjectionRef( hSrcDS );
799 0 : else if( GDALGetGCPProjection( hSrcDS ) != NULL )
800 0 : pszProjection = GDALGetGCPProjection( hSrcDS );
801 :
802 0 : if( pszProjection == NULL )
803 : {
804 0 : fprintf(stderr, "Cannot compute bounding box of cutline.\n");
805 0 : GDALExit(1);
806 : }
807 :
808 0 : hRasterSRS = OSRNewSpatialReference(NULL);
809 0 : if( OSRImportFromWkt( hRasterSRS, (char **)&pszProjection ) != CE_None )
810 : {
811 0 : fprintf(stderr, "Cannot compute bounding box of cutline.\n");
812 0 : GDALExit(1);
813 : }
814 :
815 0 : hCT = OCTNewCoordinateTransformation(hCutlineSRS, hRasterSRS);
816 :
817 0 : OSRDestroySpatialReference(hRasterSRS);
818 :
819 0 : GDALClose(hSrcDS);
820 : }
821 : else
822 : {
823 0 : fprintf(stderr, "Cannot compute bounding box of cutline.\n");
824 0 : GDALExit(1);
825 : }
826 : }
827 :
828 0 : if (hCT)
829 : {
830 0 : OGR_G_Transform( hCutlineGeom, hCT );
831 :
832 0 : OCTDestroyCoordinateTransformation(hCT);
833 : }
834 :
835 0 : OGREnvelope sEnvelope;
836 0 : OGR_G_GetEnvelope(hCutlineGeom, &sEnvelope);
837 :
838 0 : dfMinX = sEnvelope.MinX;
839 0 : dfMinY = sEnvelope.MinY;
840 0 : dfMaxX = sEnvelope.MaxX;
841 0 : dfMaxY = sEnvelope.MaxY;
842 :
843 0 : OGR_G_DestroyGeometry(hCutlineGeom);
844 : }
845 : #endif
846 :
847 : /* -------------------------------------------------------------------- */
848 : /* If not, we need to create it. */
849 : /* -------------------------------------------------------------------- */
850 271 : int bInitDestSetForFirst = FALSE;
851 :
852 271 : void* hUniqueTransformArg = NULL;
853 271 : GDALDatasetH hUniqueSrcDS = NULL;
854 :
855 271 : if( hDstDS == NULL )
856 : {
857 270 : if (!bQuiet && !bFormatExplicitelySet)
858 265 : CheckExtensionConsistency(pszDstFilename, pszFormat);
859 :
860 : hDstDS = GDALWarpCreateOutput( papszSrcFiles, pszDstFilename,pszFormat,
861 : papszTO, &papszCreateOptions,
862 : eOutputType, &hUniqueTransformArg,
863 270 : &hUniqueSrcDS);
864 270 : bCreateOutput = TRUE;
865 :
866 270 : if( CSLFetchNameValue( papszWarpOptions, "INIT_DEST" ) == NULL
867 : && pszDstNodata == NULL )
868 : {
869 : papszWarpOptions = CSLSetNameValue(papszWarpOptions,
870 268 : "INIT_DEST", "0");
871 268 : bInitDestSetForFirst = TRUE;
872 : }
873 2 : else if( CSLFetchNameValue( papszWarpOptions, "INIT_DEST" ) == NULL )
874 : {
875 : papszWarpOptions = CSLSetNameValue(papszWarpOptions,
876 1 : "INIT_DEST", "NO_DATA" );
877 1 : bInitDestSetForFirst = TRUE;
878 : }
879 :
880 270 : CSLDestroy( papszCreateOptions );
881 270 : papszCreateOptions = NULL;
882 : }
883 :
884 271 : if( hDstDS == NULL )
885 0 : GDALExit( 1 );
886 :
887 : /* -------------------------------------------------------------------- */
888 : /* Loop over all source files, processing each in turn. */
889 : /* -------------------------------------------------------------------- */
890 : int iSrc;
891 :
892 1078 : for( iSrc = 0; papszSrcFiles[iSrc] != NULL; iSrc++ )
893 : {
894 : GDALDatasetH hSrcDS;
895 :
896 : /* -------------------------------------------------------------------- */
897 : /* Open this file. */
898 : /* -------------------------------------------------------------------- */
899 272 : if (hUniqueSrcDS)
900 269 : hSrcDS = hUniqueSrcDS;
901 : else
902 3 : hSrcDS = GDALOpen( papszSrcFiles[iSrc], GA_ReadOnly );
903 :
904 272 : if( hSrcDS == NULL )
905 0 : GDALExit( 2 );
906 :
907 : /* -------------------------------------------------------------------- */
908 : /* Check that there's at least one raster band */
909 : /* -------------------------------------------------------------------- */
910 272 : if ( GDALGetRasterCount(hSrcDS) == 0 )
911 : {
912 0 : fprintf(stderr, "Input file %s has no raster bands.\n", papszSrcFiles[iSrc] );
913 0 : GDALExit( 1 );
914 : }
915 :
916 272 : if( !bQuiet )
917 271 : printf( "Processing input file %s.\n", papszSrcFiles[iSrc] );
918 :
919 : /* -------------------------------------------------------------------- */
920 : /* Get the metadata of the first source DS and copy it to the */
921 : /* destination DS. Copy Band-level metadata and other info, only */
922 : /* if source and destination band count are equal. Any values that */
923 : /* conflict between source datasets are set to pszMDConflictValue. */
924 : /* -------------------------------------------------------------------- */
925 272 : if ( bCopyMetadata )
926 : {
927 272 : char **papszMetadata = NULL;
928 272 : const char *pszSrcInfo = NULL;
929 272 : const char *pszDstInfo = NULL;
930 272 : GDALRasterBandH hSrcBand = NULL;
931 272 : GDALRasterBandH hDstBand = NULL;
932 :
933 : /* copy metadata from first dataset */
934 272 : if ( iSrc == 0 )
935 : {
936 271 : CPLDebug("WARP", "Copying metadata from first source to destination dataset");
937 : /* copy dataset-level metadata */
938 271 : papszMetadata = GDALGetMetadata( hSrcDS, NULL );
939 271 : if ( CSLCount(papszMetadata) > 0 ) {
940 271 : if ( GDALSetMetadata( hDstDS, papszMetadata, NULL ) != CE_None )
941 : fprintf( stderr,
942 0 : "Warning: error copying metadata to destination dataset.\n" );
943 : }
944 : /* copy band-level metadata and other info */
945 271 : if ( GDALGetRasterCount( hSrcDS ) == GDALGetRasterCount( hDstDS ) )
946 : {
947 566 : for ( int iBand = 0; iBand < GDALGetRasterCount( hSrcDS ); iBand++ )
948 : {
949 297 : hSrcBand = GDALGetRasterBand( hSrcDS, iBand + 1 );
950 297 : hDstBand = GDALGetRasterBand( hDstDS, iBand + 1 );
951 : /* copy metadata */
952 297 : papszMetadata = GDALGetMetadata( hSrcBand, NULL);
953 297 : if ( CSLCount(papszMetadata) > 0 )
954 8 : GDALSetMetadata( hDstBand, papszMetadata, NULL );
955 : /* copy other info (Description, Unit Type) - what else? */
956 297 : if ( bCopyBandInfo ) {
957 297 : pszSrcInfo = GDALGetDescription( hSrcBand );
958 297 : if( pszSrcInfo != NULL && strlen(pszSrcInfo) > 0 )
959 0 : GDALSetDescription( hDstBand, pszSrcInfo );
960 297 : pszSrcInfo = GDALGetRasterUnitType( hSrcBand );
961 297 : if( pszSrcInfo != NULL && strlen(pszSrcInfo) > 0 )
962 0 : GDALSetRasterUnitType( hDstBand, pszSrcInfo );
963 : }
964 : }
965 : }
966 : }
967 : /* remove metadata that conflicts between datasets */
968 : else
969 : {
970 : CPLDebug("WARP",
971 1 : "Removing conflicting metadata from destination dataset (source #%d)", iSrc );
972 : /* remove conflicting dataset-level metadata */
973 1 : RemoveConflictingMetadata( hDstDS, GDALGetMetadata( hSrcDS, NULL ), pszMDConflictValue );
974 :
975 : /* remove conflicting copy band-level metadata and other info */
976 1 : if ( GDALGetRasterCount( hSrcDS ) == GDALGetRasterCount( hDstDS ) )
977 : {
978 2 : for ( int iBand = 0; iBand < GDALGetRasterCount( hSrcDS ); iBand++ )
979 : {
980 1 : hSrcBand = GDALGetRasterBand( hSrcDS, iBand + 1 );
981 1 : hDstBand = GDALGetRasterBand( hDstDS, iBand + 1 );
982 : /* remove conflicting metadata */
983 1 : RemoveConflictingMetadata( hDstBand, GDALGetMetadata( hSrcBand, NULL ), pszMDConflictValue );
984 : /* remove conflicting info */
985 1 : if ( bCopyBandInfo ) {
986 1 : pszSrcInfo = GDALGetDescription( hSrcBand );
987 1 : pszDstInfo = GDALGetDescription( hDstBand );
988 1 : if( ! ( pszSrcInfo != NULL && strlen(pszSrcInfo) > 0 &&
989 : pszDstInfo != NULL && strlen(pszDstInfo) > 0 &&
990 : EQUAL( pszSrcInfo, pszDstInfo ) ) )
991 1 : GDALSetDescription( hDstBand, "" );
992 1 : pszSrcInfo = GDALGetRasterUnitType( hSrcBand );
993 1 : pszDstInfo = GDALGetRasterUnitType( hDstBand );
994 1 : if( ! ( pszSrcInfo != NULL && strlen(pszSrcInfo) > 0 &&
995 : pszDstInfo != NULL && strlen(pszDstInfo) > 0 &&
996 : EQUAL( pszSrcInfo, pszDstInfo ) ) )
997 1 : GDALSetRasterUnitType( hDstBand, "" );
998 : }
999 : }
1000 : }
1001 : }
1002 : }
1003 :
1004 : /* -------------------------------------------------------------------- */
1005 : /* Warns if the file has a color table and something more */
1006 : /* complicated than nearest neighbour resampling is asked */
1007 : /* -------------------------------------------------------------------- */
1008 :
1009 272 : if ( eResampleAlg != GRA_NearestNeighbour &&
1010 : GDALGetRasterColorTable(GDALGetRasterBand(hSrcDS, 1)) != NULL)
1011 : {
1012 0 : if( !bQuiet )
1013 : fprintf( stderr, "Warning: Input file %s has a color table, which will likely lead to "
1014 : "bad results when using a resampling method other than "
1015 : "nearest neighbour. Converting the dataset prior to 24/32 bit "
1016 0 : "is advised.\n", papszSrcFiles[iSrc] );
1017 : }
1018 :
1019 : /* -------------------------------------------------------------------- */
1020 : /* Do we have a source alpha band? */
1021 : /* -------------------------------------------------------------------- */
1022 272 : if( GDALGetRasterColorInterpretation(
1023 : GDALGetRasterBand(hSrcDS,GDALGetRasterCount(hSrcDS)) )
1024 : == GCI_AlphaBand
1025 : && !bEnableSrcAlpha )
1026 : {
1027 1 : bEnableSrcAlpha = TRUE;
1028 1 : if( !bQuiet )
1029 : printf( "Using band %d of source image as alpha.\n",
1030 1 : GDALGetRasterCount(hSrcDS) );
1031 : }
1032 :
1033 : /* -------------------------------------------------------------------- */
1034 : /* Create a transformation object from the source to */
1035 : /* destination coordinate system. */
1036 : /* -------------------------------------------------------------------- */
1037 272 : if (hUniqueTransformArg)
1038 269 : hTransformArg = hGenImgProjArg = hUniqueTransformArg;
1039 : else
1040 : hTransformArg = hGenImgProjArg =
1041 3 : GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszTO );
1042 :
1043 272 : if( hTransformArg == NULL )
1044 0 : GDALExit( 1 );
1045 :
1046 272 : pfnTransformer = GDALGenImgProjTransform;
1047 :
1048 : /* -------------------------------------------------------------------- */
1049 : /* Warp the transformer with a linear approximator unless the */
1050 : /* acceptable error is zero. */
1051 : /* -------------------------------------------------------------------- */
1052 272 : if( dfErrorThreshold != 0.0 )
1053 : {
1054 : hTransformArg = hApproxArg =
1055 : GDALCreateApproxTransformer( GDALGenImgProjTransform,
1056 270 : hGenImgProjArg, dfErrorThreshold);
1057 270 : pfnTransformer = GDALApproxTransform;
1058 : }
1059 :
1060 : /* -------------------------------------------------------------------- */
1061 : /* Clear temporary INIT_DEST settings after the first image. */
1062 : /* -------------------------------------------------------------------- */
1063 272 : if( bInitDestSetForFirst && iSrc == 1 )
1064 : papszWarpOptions = CSLSetNameValue( papszWarpOptions,
1065 1 : "INIT_DEST", NULL );
1066 :
1067 : /* -------------------------------------------------------------------- */
1068 : /* Setup warp options. */
1069 : /* -------------------------------------------------------------------- */
1070 272 : GDALWarpOptions *psWO = GDALCreateWarpOptions();
1071 :
1072 272 : psWO->papszWarpOptions = CSLDuplicate(papszWarpOptions);
1073 272 : psWO->eWorkingDataType = eWorkingType;
1074 272 : psWO->eResampleAlg = eResampleAlg;
1075 :
1076 272 : psWO->hSrcDS = hSrcDS;
1077 272 : psWO->hDstDS = hDstDS;
1078 :
1079 272 : psWO->pfnTransformer = pfnTransformer;
1080 272 : psWO->pTransformerArg = hTransformArg;
1081 :
1082 272 : if( !bQuiet )
1083 271 : psWO->pfnProgress = GDALTermProgress;
1084 :
1085 272 : if( dfWarpMemoryLimit != 0.0 )
1086 9 : psWO->dfWarpMemoryLimit = dfWarpMemoryLimit;
1087 :
1088 : /* -------------------------------------------------------------------- */
1089 : /* Setup band mapping. */
1090 : /* -------------------------------------------------------------------- */
1091 272 : if( bEnableSrcAlpha )
1092 1 : psWO->nBandCount = GDALGetRasterCount(hSrcDS) - 1;
1093 : else
1094 271 : psWO->nBandCount = GDALGetRasterCount(hSrcDS);
1095 :
1096 272 : psWO->panSrcBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
1097 272 : psWO->panDstBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
1098 :
1099 575 : for( i = 0; i < psWO->nBandCount; i++ )
1100 : {
1101 303 : psWO->panSrcBands[i] = i+1;
1102 303 : psWO->panDstBands[i] = i+1;
1103 : }
1104 :
1105 : /* -------------------------------------------------------------------- */
1106 : /* Setup alpha bands used if any. */
1107 : /* -------------------------------------------------------------------- */
1108 272 : if( bEnableSrcAlpha )
1109 1 : psWO->nSrcAlphaBand = GDALGetRasterCount(hSrcDS);
1110 :
1111 272 : if( !bEnableDstAlpha
1112 : && GDALGetRasterCount(hDstDS) == psWO->nBandCount+1
1113 : && GDALGetRasterColorInterpretation(
1114 : GDALGetRasterBand(hDstDS,GDALGetRasterCount(hDstDS)))
1115 : == GCI_AlphaBand )
1116 : {
1117 1 : if( !bQuiet )
1118 : printf( "Using band %d of destination image as alpha.\n",
1119 1 : GDALGetRasterCount(hDstDS) );
1120 :
1121 1 : bEnableDstAlpha = TRUE;
1122 : }
1123 :
1124 272 : if( bEnableDstAlpha )
1125 3 : psWO->nDstAlphaBand = GDALGetRasterCount(hDstDS);
1126 :
1127 : /* -------------------------------------------------------------------- */
1128 : /* Setup NODATA options. */
1129 : /* -------------------------------------------------------------------- */
1130 272 : if( pszSrcNodata != NULL && !EQUALN(pszSrcNodata,"n",1) )
1131 : {
1132 1 : char **papszTokens = CSLTokenizeString( pszSrcNodata );
1133 1 : int nTokenCount = CSLCount(papszTokens);
1134 :
1135 : psWO->padfSrcNoDataReal = (double *)
1136 1 : CPLMalloc(psWO->nBandCount*sizeof(double));
1137 : psWO->padfSrcNoDataImag = (double *)
1138 1 : CPLMalloc(psWO->nBandCount*sizeof(double));
1139 :
1140 4 : for( i = 0; i < psWO->nBandCount; i++ )
1141 : {
1142 3 : if( i < nTokenCount )
1143 : {
1144 1 : CPLStringToComplex( papszTokens[i],
1145 : psWO->padfSrcNoDataReal + i,
1146 2 : psWO->padfSrcNoDataImag + i );
1147 : }
1148 : else
1149 : {
1150 2 : psWO->padfSrcNoDataReal[i] = psWO->padfSrcNoDataReal[i-1];
1151 2 : psWO->padfSrcNoDataImag[i] = psWO->padfSrcNoDataImag[i-1];
1152 : }
1153 : }
1154 :
1155 1 : CSLDestroy( papszTokens );
1156 :
1157 : psWO->papszWarpOptions = CSLSetNameValue(psWO->papszWarpOptions,
1158 1 : "UNIFIED_SRC_NODATA", "YES" );
1159 : }
1160 :
1161 : /* -------------------------------------------------------------------- */
1162 : /* If -srcnodata was not specified, but the data has nodata */
1163 : /* values, use them. */
1164 : /* -------------------------------------------------------------------- */
1165 272 : if( pszSrcNodata == NULL )
1166 : {
1167 271 : int bHaveNodata = FALSE;
1168 271 : double dfReal = 0.0;
1169 :
1170 562 : for( i = 0; !bHaveNodata && i < psWO->nBandCount; i++ )
1171 : {
1172 291 : GDALRasterBandH hBand = GDALGetRasterBand( hSrcDS, i+1 );
1173 291 : dfReal = GDALGetRasterNoDataValue( hBand, &bHaveNodata );
1174 : }
1175 :
1176 271 : if( bHaveNodata )
1177 : {
1178 2 : if( !bQuiet )
1179 : {
1180 1 : if (CPLIsNan(dfReal))
1181 : printf( "Using internal nodata values (eg. nan) for image %s.\n",
1182 0 : papszSrcFiles[iSrc] );
1183 : else
1184 : printf( "Using internal nodata values (eg. %g) for image %s.\n",
1185 1 : dfReal, papszSrcFiles[iSrc] );
1186 : }
1187 : psWO->padfSrcNoDataReal = (double *)
1188 2 : CPLMalloc(psWO->nBandCount*sizeof(double));
1189 : psWO->padfSrcNoDataImag = (double *)
1190 2 : CPLMalloc(psWO->nBandCount*sizeof(double));
1191 :
1192 13 : for( i = 0; i < psWO->nBandCount; i++ )
1193 : {
1194 11 : GDALRasterBandH hBand = GDALGetRasterBand( hSrcDS, i+1 );
1195 :
1196 11 : dfReal = GDALGetRasterNoDataValue( hBand, &bHaveNodata );
1197 :
1198 11 : if( bHaveNodata )
1199 : {
1200 11 : psWO->padfSrcNoDataReal[i] = dfReal;
1201 11 : psWO->padfSrcNoDataImag[i] = 0.0;
1202 : }
1203 : else
1204 : {
1205 0 : psWO->padfSrcNoDataReal[i] = -123456.789;
1206 0 : psWO->padfSrcNoDataImag[i] = 0.0;
1207 : }
1208 : }
1209 : }
1210 : }
1211 :
1212 : /* -------------------------------------------------------------------- */
1213 : /* If the output dataset was created, and we have a destination */
1214 : /* nodata value, go through marking the bands with the information.*/
1215 : /* -------------------------------------------------------------------- */
1216 272 : if( pszDstNodata != NULL )
1217 : {
1218 1 : char **papszTokens = CSLTokenizeString( pszDstNodata );
1219 1 : int nTokenCount = CSLCount(papszTokens);
1220 :
1221 : psWO->padfDstNoDataReal = (double *)
1222 1 : CPLMalloc(psWO->nBandCount*sizeof(double));
1223 : psWO->padfDstNoDataImag = (double *)
1224 1 : CPLMalloc(psWO->nBandCount*sizeof(double));
1225 :
1226 2 : for( i = 0; i < psWO->nBandCount; i++ )
1227 : {
1228 1 : if( i < nTokenCount )
1229 : {
1230 1 : CPLStringToComplex( papszTokens[i],
1231 : psWO->padfDstNoDataReal + i,
1232 2 : psWO->padfDstNoDataImag + i );
1233 : }
1234 : else
1235 : {
1236 0 : psWO->padfDstNoDataReal[i] = psWO->padfDstNoDataReal[i-1];
1237 0 : psWO->padfDstNoDataImag[i] = psWO->padfDstNoDataImag[i-1];
1238 : }
1239 :
1240 1 : GDALRasterBandH hBand = GDALGetRasterBand( hDstDS, i+1 );
1241 1 : int bClamped = FALSE, bRounded = FALSE;
1242 :
1243 : #define CLAMP(val,type,minval,maxval) \
1244 : do { if (val < minval) { bClamped = TRUE; val = minval; } \
1245 : else if (val > maxval) { bClamped = TRUE; val = maxval; } \
1246 : else if (val != (type)val) { bRounded = TRUE; val = (type)(val + 0.5); } } \
1247 : while(0)
1248 :
1249 1 : switch(GDALGetRasterDataType(hBand))
1250 : {
1251 : case GDT_Byte:
1252 1 : CLAMP(psWO->padfDstNoDataReal[i], GByte,
1253 : 0.0, 255.0);
1254 1 : break;
1255 : case GDT_Int16:
1256 0 : CLAMP(psWO->padfDstNoDataReal[i], GInt16,
1257 : -32768.0, 32767.0);
1258 0 : break;
1259 : case GDT_UInt16:
1260 0 : CLAMP(psWO->padfDstNoDataReal[i], GUInt16,
1261 : 0.0, 65535.0);
1262 0 : break;
1263 : case GDT_Int32:
1264 0 : CLAMP(psWO->padfDstNoDataReal[i], GInt32,
1265 : -2147483648.0, 2147483647.0);
1266 0 : break;
1267 : case GDT_UInt32:
1268 0 : CLAMP(psWO->padfDstNoDataReal[i], GUInt32,
1269 : 0.0, 4294967295.0);
1270 : break;
1271 : default:
1272 : break;
1273 : }
1274 :
1275 1 : if (bClamped)
1276 : {
1277 : printf( "for band %d, destination nodata value has been clamped "
1278 : "to %.0f, the original value being out of range.\n",
1279 0 : i + 1, psWO->padfDstNoDataReal[i]);
1280 : }
1281 1 : else if(bRounded)
1282 : {
1283 : printf("for band %d, destination nodata value has been rounded "
1284 : "to %.0f, %s being an integer datatype.\n",
1285 : i + 1, psWO->padfDstNoDataReal[i],
1286 0 : GDALGetDataTypeName(GDALGetRasterDataType(hBand)));
1287 : }
1288 :
1289 1 : if( bCreateOutput )
1290 : {
1291 : GDALSetRasterNoDataValue(
1292 : GDALGetRasterBand( hDstDS, psWO->panDstBands[i] ),
1293 1 : psWO->padfDstNoDataReal[i] );
1294 : }
1295 : }
1296 :
1297 1 : CSLDestroy( papszTokens );
1298 : }
1299 :
1300 : /* -------------------------------------------------------------------- */
1301 : /* If we have a cutline, transform it into the source */
1302 : /* pixel/line coordinate system and insert into warp options. */
1303 : /* -------------------------------------------------------------------- */
1304 272 : if( hCutline != NULL )
1305 : {
1306 : TransformCutlineToSource( hSrcDS, hCutline,
1307 : &(psWO->papszWarpOptions),
1308 3 : papszTO );
1309 : }
1310 :
1311 : /* -------------------------------------------------------------------- */
1312 : /* If we are producing VRT output, then just initialize it with */
1313 : /* the warp options and write out now rather than proceeding */
1314 : /* with the operations. */
1315 : /* -------------------------------------------------------------------- */
1316 272 : if( bVRT )
1317 : {
1318 4 : if( GDALInitializeWarpedVRT( hDstDS, psWO ) != CE_None )
1319 0 : GDALExit( 1 );
1320 :
1321 4 : GDALClose( hDstDS );
1322 4 : GDALClose( hSrcDS );
1323 :
1324 : /* The warped VRT will clean itself the transformer used */
1325 : /* So we have only to destroy the hGenImgProjArg if we */
1326 : /* have wrapped it inside the hApproxArg */
1327 4 : if (pfnTransformer == GDALApproxTransform)
1328 : {
1329 3 : if( hGenImgProjArg != NULL )
1330 3 : GDALDestroyGenImgProjTransformer( hGenImgProjArg );
1331 : }
1332 :
1333 4 : GDALDestroyWarpOptions( psWO );
1334 :
1335 4 : CPLFree( pszDstFilename );
1336 4 : CSLDestroy( argv );
1337 4 : CSLDestroy( papszSrcFiles );
1338 4 : CSLDestroy( papszWarpOptions );
1339 4 : CSLDestroy( papszTO );
1340 :
1341 4 : GDALDumpOpenDatasets( stderr );
1342 :
1343 4 : GDALDestroyDriverManager();
1344 :
1345 4 : return 0;
1346 : }
1347 :
1348 : /* -------------------------------------------------------------------- */
1349 : /* Initialize and execute the warp. */
1350 : /* -------------------------------------------------------------------- */
1351 268 : GDALWarpOperation oWO;
1352 :
1353 268 : if( oWO.Initialize( psWO ) == CE_None )
1354 : {
1355 : CPLErr eErr;
1356 268 : if( bMulti )
1357 : eErr = oWO.ChunkAndWarpMulti( 0, 0,
1358 : GDALGetRasterXSize( hDstDS ),
1359 1 : GDALGetRasterYSize( hDstDS ) );
1360 : else
1361 : eErr = oWO.ChunkAndWarpImage( 0, 0,
1362 : GDALGetRasterXSize( hDstDS ),
1363 267 : GDALGetRasterYSize( hDstDS ) );
1364 268 : if (eErr != CE_None)
1365 0 : bHasGotErr = TRUE;
1366 : }
1367 :
1368 : /* -------------------------------------------------------------------- */
1369 : /* Cleanup */
1370 : /* -------------------------------------------------------------------- */
1371 268 : if( hApproxArg != NULL )
1372 267 : GDALDestroyApproxTransformer( hApproxArg );
1373 :
1374 268 : if( hGenImgProjArg != NULL )
1375 268 : GDALDestroyGenImgProjTransformer( hGenImgProjArg );
1376 :
1377 268 : GDALDestroyWarpOptions( psWO );
1378 :
1379 268 : GDALClose( hSrcDS );
1380 268 : }
1381 :
1382 : /* -------------------------------------------------------------------- */
1383 : /* Final Cleanup. */
1384 : /* -------------------------------------------------------------------- */
1385 267 : CPLErrorReset();
1386 267 : GDALFlushCache( hDstDS );
1387 267 : if( CPLGetLastErrorType() != CE_None )
1388 0 : bHasGotErr = TRUE;
1389 267 : GDALClose( hDstDS );
1390 :
1391 267 : CPLFree( pszDstFilename );
1392 267 : CSLDestroy( argv );
1393 267 : CSLDestroy( papszSrcFiles );
1394 267 : CSLDestroy( papszWarpOptions );
1395 267 : CSLDestroy( papszTO );
1396 :
1397 267 : GDALDumpOpenDatasets( stderr );
1398 :
1399 267 : GDALDestroyDriverManager();
1400 :
1401 : #ifdef OGR_ENABLED
1402 267 : if( hCutline != NULL )
1403 3 : OGR_G_DestroyGeometry( (OGRGeometryH) hCutline );
1404 267 : OGRCleanupAll();
1405 : #endif
1406 :
1407 267 : return (bHasGotErr) ? 1 : 0;
1408 : }
1409 :
1410 : /************************************************************************/
1411 : /* GDALWarpCreateOutput() */
1412 : /* */
1413 : /* Create the output file based on various commandline options, */
1414 : /* and the input file. */
1415 : /* If there's just one source file, then *phTransformArg and */
1416 : /* *phSrcDS will be set, in order them to be reused by main */
1417 : /* function. This saves dataset re-opening, and above all transform*/
1418 : /* recomputation, which can be expensive in the -tps case */
1419 : /************************************************************************/
1420 :
1421 : static GDALDatasetH
1422 270 : GDALWarpCreateOutput( char **papszSrcFiles, const char *pszFilename,
1423 : const char *pszFormat, char **papszTO,
1424 : char ***ppapszCreateOptions, GDALDataType eDT,
1425 : void ** phTransformArg,
1426 : GDALDatasetH* phSrcDS)
1427 :
1428 :
1429 : {
1430 : GDALDriverH hDriver;
1431 : GDALDatasetH hDstDS;
1432 : void *hTransformArg;
1433 270 : GDALColorTableH hCT = NULL;
1434 270 : double dfWrkMinX=0, dfWrkMaxX=0, dfWrkMinY=0, dfWrkMaxY=0;
1435 270 : double dfWrkResX=0, dfWrkResY=0;
1436 270 : int nDstBandCount = 0;
1437 270 : std::vector<GDALColorInterp> apeColorInterpretations;
1438 :
1439 : /* If (-ts and -te) or (-tr and -te) are specified, we don't need to compute the suggested output extent */
1440 : int bNeedsSuggestedWarpOutput =
1441 : !( ((nForcePixels != 0 && nForceLines != 0) || (dfXRes != 0 && dfYRes != 0)) &&
1442 270 : !(dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0) );
1443 :
1444 270 : *phTransformArg = NULL;
1445 270 : *phSrcDS = NULL;
1446 :
1447 : /* -------------------------------------------------------------------- */
1448 : /* Find the output driver. */
1449 : /* -------------------------------------------------------------------- */
1450 270 : hDriver = GDALGetDriverByName( pszFormat );
1451 270 : if( hDriver == NULL
1452 : || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL )
1453 : {
1454 : int iDr;
1455 :
1456 : printf( "Output driver `%s' not recognised or does not support\n",
1457 0 : pszFormat );
1458 : printf( "direct output file creation. The following format drivers are configured\n"
1459 0 : "and support direct output:\n" );
1460 :
1461 0 : for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
1462 : {
1463 0 : GDALDriverH hDriver = GDALGetDriver(iDr);
1464 :
1465 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL) != NULL )
1466 : {
1467 : printf( " %s: %s\n",
1468 : GDALGetDriverShortName( hDriver ),
1469 0 : GDALGetDriverLongName( hDriver ) );
1470 : }
1471 : }
1472 0 : printf( "\n" );
1473 0 : GDALExit( 1 );
1474 : }
1475 :
1476 : /* -------------------------------------------------------------------- */
1477 : /* For virtual output files, we have to set a special subclass */
1478 : /* of dataset to create. */
1479 : /* -------------------------------------------------------------------- */
1480 270 : if( bVRT )
1481 : *ppapszCreateOptions =
1482 : CSLSetNameValue( *ppapszCreateOptions, "SUBCLASS",
1483 4 : "VRTWarpedDataset" );
1484 :
1485 : /* -------------------------------------------------------------------- */
1486 : /* Loop over all input files to collect extents. */
1487 : /* -------------------------------------------------------------------- */
1488 : int iSrc;
1489 270 : char *pszThisTargetSRS = (char*)CSLFetchNameValue( papszTO, "DST_SRS" );
1490 270 : if( pszThisTargetSRS != NULL )
1491 12 : pszThisTargetSRS = CPLStrdup( pszThisTargetSRS );
1492 :
1493 541 : for( iSrc = 0; papszSrcFiles[iSrc] != NULL; iSrc++ )
1494 : {
1495 : GDALDatasetH hSrcDS;
1496 271 : const char *pszThisSourceSRS = CSLFetchNameValue(papszTO,"SRC_SRS");
1497 :
1498 271 : hSrcDS = GDALOpen( papszSrcFiles[iSrc], GA_ReadOnly );
1499 271 : if( hSrcDS == NULL )
1500 0 : GDALExit( 1 );
1501 :
1502 : /* -------------------------------------------------------------------- */
1503 : /* Check that there's at least one raster band */
1504 : /* -------------------------------------------------------------------- */
1505 271 : if ( GDALGetRasterCount(hSrcDS) == 0 )
1506 : {
1507 0 : fprintf(stderr, "Input file %s has no raster bands.\n", papszSrcFiles[iSrc] );
1508 0 : GDALExit( 1 );
1509 : }
1510 :
1511 271 : if( eDT == GDT_Unknown )
1512 269 : eDT = GDALGetRasterDataType(GDALGetRasterBand(hSrcDS,1));
1513 :
1514 : /* -------------------------------------------------------------------- */
1515 : /* If we are processing the first file, and it has a color */
1516 : /* table, then we will copy it to the destination file. */
1517 : /* -------------------------------------------------------------------- */
1518 271 : if( iSrc == 0 )
1519 : {
1520 270 : nDstBandCount = GDALGetRasterCount(hSrcDS);
1521 270 : hCT = GDALGetRasterColorTable( GDALGetRasterBand(hSrcDS,1) );
1522 270 : if( hCT != NULL )
1523 : {
1524 0 : hCT = GDALCloneColorTable( hCT );
1525 0 : if( !bQuiet )
1526 : printf( "Copying color table from %s to new file.\n",
1527 0 : papszSrcFiles[iSrc] );
1528 : }
1529 :
1530 572 : for(int iBand = 0; iBand < nDstBandCount; iBand++)
1531 : {
1532 : apeColorInterpretations.push_back(
1533 302 : GDALGetRasterColorInterpretation(GDALGetRasterBand(hSrcDS,iBand+1)) );
1534 : }
1535 : }
1536 :
1537 : /* -------------------------------------------------------------------- */
1538 : /* Get the sourcesrs from the dataset, if not set already. */
1539 : /* -------------------------------------------------------------------- */
1540 271 : if( pszThisSourceSRS == NULL )
1541 : {
1542 271 : const char *pszMethod = CSLFetchNameValue( papszTO, "METHOD" );
1543 :
1544 271 : if( GDALGetProjectionRef( hSrcDS ) != NULL
1545 : && strlen(GDALGetProjectionRef( hSrcDS )) > 0
1546 : && (pszMethod == NULL || EQUAL(pszMethod,"GEOTRANSFORM")) )
1547 254 : pszThisSourceSRS = GDALGetProjectionRef( hSrcDS );
1548 :
1549 17 : else if( GDALGetGCPProjection( hSrcDS ) != NULL
1550 : && strlen(GDALGetGCPProjection(hSrcDS)) > 0
1551 : && GDALGetGCPCount( hSrcDS ) > 1
1552 : && (pszMethod == NULL || EQUALN(pszMethod,"GCP_",4)) )
1553 15 : pszThisSourceSRS = GDALGetGCPProjection( hSrcDS );
1554 2 : else if( pszMethod != NULL && EQUAL(pszMethod,"RPC") )
1555 0 : pszThisSourceSRS = SRS_WKT_WGS84;
1556 : else
1557 2 : pszThisSourceSRS = "";
1558 : }
1559 :
1560 271 : if( pszThisTargetSRS == NULL )
1561 258 : pszThisTargetSRS = CPLStrdup( pszThisSourceSRS );
1562 :
1563 : /* -------------------------------------------------------------------- */
1564 : /* Create a transformation object from the source to */
1565 : /* destination coordinate system. */
1566 : /* -------------------------------------------------------------------- */
1567 : hTransformArg =
1568 271 : GDALCreateGenImgProjTransformer2( hSrcDS, NULL, papszTO );
1569 :
1570 271 : if( hTransformArg == NULL )
1571 : {
1572 0 : CPLFree( pszThisTargetSRS );
1573 0 : GDALClose( hSrcDS );
1574 0 : return NULL;
1575 : }
1576 :
1577 271 : GDALTransformerInfo* psInfo = (GDALTransformerInfo*)hTransformArg;
1578 :
1579 : /* -------------------------------------------------------------------- */
1580 : /* Get approximate output definition. */
1581 : /* -------------------------------------------------------------------- */
1582 271 : if( bNeedsSuggestedWarpOutput )
1583 : {
1584 : double adfThisGeoTransform[6];
1585 : double adfExtent[4];
1586 : int nThisPixels, nThisLines;
1587 :
1588 269 : if ( GDALSuggestedWarpOutput2( hSrcDS,
1589 : psInfo->pfnTransform, hTransformArg,
1590 : adfThisGeoTransform,
1591 : &nThisPixels, &nThisLines,
1592 : adfExtent, 0 ) != CE_None )
1593 : {
1594 0 : CPLFree( pszThisTargetSRS );
1595 0 : GDALClose( hSrcDS );
1596 0 : return NULL;
1597 : }
1598 :
1599 269 : if ( CPLGetConfigOption( "CHECK_WITH_INVERT_PROJ", NULL ) == NULL )
1600 : {
1601 269 : double MinX = adfExtent[0];
1602 269 : double MaxX = adfExtent[2];
1603 269 : double MaxY = adfExtent[3];
1604 269 : double MinY = adfExtent[1];
1605 269 : int bSuccess = TRUE;
1606 :
1607 : /* Check that the the edges of the target image are in the validity area */
1608 : /* of the target projection */
1609 : #define N_STEPS 20
1610 : int i,j;
1611 5818 : for(i=0;i<=N_STEPS && bSuccess;i++)
1612 : {
1613 121978 : for(j=0;j<=N_STEPS && bSuccess;j++)
1614 : {
1615 116429 : double dfRatioI = i * 1.0 / N_STEPS;
1616 116429 : double dfRatioJ = j * 1.0 / N_STEPS;
1617 116429 : double expected_x = (1 - dfRatioI) * MinX + dfRatioI * MaxX;
1618 116429 : double expected_y = (1 - dfRatioJ) * MinY + dfRatioJ * MaxY;
1619 116429 : double x = expected_x;
1620 116429 : double y = expected_y;
1621 116429 : double z = 0;
1622 : /* Target SRS coordinates to source image pixel coordinates */
1623 116429 : if (!psInfo->pfnTransform(hTransformArg, TRUE, 1, &x, &y, &z, &bSuccess) || !bSuccess)
1624 0 : bSuccess = FALSE;
1625 : /* Source image pixel coordinates to target SRS coordinates */
1626 116429 : if (!psInfo->pfnTransform(hTransformArg, FALSE, 1, &x, &y, &z, &bSuccess) || !bSuccess)
1627 0 : bSuccess = FALSE;
1628 116429 : if (fabs(x - expected_x) > (MaxX - MinX) / nThisPixels ||
1629 : fabs(y - expected_y) > (MaxY - MinY) / nThisLines)
1630 5 : bSuccess = FALSE;
1631 : }
1632 : }
1633 :
1634 : /* If not, retry with CHECK_WITH_INVERT_PROJ=TRUE that forces ogrct.cpp */
1635 : /* to check the consistency of each requested projection result with the */
1636 : /* invert projection */
1637 269 : if (!bSuccess)
1638 : {
1639 5 : CPLSetConfigOption( "CHECK_WITH_INVERT_PROJ", "TRUE" );
1640 5 : CPLDebug("WARP", "Recompute out extent with CHECK_WITH_INVERT_PROJ=TRUE");
1641 :
1642 5 : if( GDALSuggestedWarpOutput2( hSrcDS,
1643 : psInfo->pfnTransform, hTransformArg,
1644 : adfThisGeoTransform,
1645 : &nThisPixels, &nThisLines,
1646 : adfExtent, 0 ) != CE_None )
1647 : {
1648 0 : CPLFree( pszThisTargetSRS );
1649 0 : GDALClose( hSrcDS );
1650 0 : return NULL;
1651 : }
1652 : }
1653 : }
1654 :
1655 : /* -------------------------------------------------------------------- */
1656 : /* Expand the working bounds to include this region, ensure the */
1657 : /* working resolution is no more than this resolution. */
1658 : /* -------------------------------------------------------------------- */
1659 537 : if( dfWrkMaxX == 0.0 && dfWrkMinX == 0.0 )
1660 : {
1661 268 : dfWrkMinX = adfExtent[0];
1662 268 : dfWrkMaxX = adfExtent[2];
1663 268 : dfWrkMaxY = adfExtent[3];
1664 268 : dfWrkMinY = adfExtent[1];
1665 268 : dfWrkResX = adfThisGeoTransform[1];
1666 268 : dfWrkResY = ABS(adfThisGeoTransform[5]);
1667 : }
1668 : else
1669 : {
1670 1 : dfWrkMinX = MIN(dfWrkMinX,adfExtent[0]);
1671 1 : dfWrkMaxX = MAX(dfWrkMaxX,adfExtent[2]);
1672 1 : dfWrkMaxY = MAX(dfWrkMaxY,adfExtent[3]);
1673 1 : dfWrkMinY = MIN(dfWrkMinY,adfExtent[1]);
1674 1 : dfWrkResX = MIN(dfWrkResX,adfThisGeoTransform[1]);
1675 1 : dfWrkResY = MIN(dfWrkResY,ABS(adfThisGeoTransform[5]));
1676 : }
1677 : }
1678 :
1679 540 : if (iSrc == 0 && papszSrcFiles[1] == NULL)
1680 : {
1681 269 : *phTransformArg = hTransformArg;
1682 269 : *phSrcDS = hSrcDS;
1683 : }
1684 : else
1685 : {
1686 2 : GDALDestroyGenImgProjTransformer( hTransformArg );
1687 2 : GDALClose( hSrcDS );
1688 : }
1689 : }
1690 :
1691 : /* -------------------------------------------------------------------- */
1692 : /* Did we have any usable sources? */
1693 : /* -------------------------------------------------------------------- */
1694 270 : if( nDstBandCount == 0 )
1695 : {
1696 : CPLError( CE_Failure, CPLE_AppDefined,
1697 0 : "No usable source images." );
1698 0 : CPLFree( pszThisTargetSRS );
1699 0 : return NULL;
1700 : }
1701 :
1702 : /* -------------------------------------------------------------------- */
1703 : /* Turn the suggested region into a geotransform and suggested */
1704 : /* number of pixels and lines. */
1705 : /* -------------------------------------------------------------------- */
1706 270 : double adfDstGeoTransform[6] = { 0, 0, 0, 0, 0, 0 };
1707 270 : int nPixels = 0, nLines = 0;
1708 :
1709 270 : if( bNeedsSuggestedWarpOutput )
1710 : {
1711 268 : adfDstGeoTransform[0] = dfWrkMinX;
1712 268 : adfDstGeoTransform[1] = dfWrkResX;
1713 268 : adfDstGeoTransform[2] = 0.0;
1714 268 : adfDstGeoTransform[3] = dfWrkMaxY;
1715 268 : adfDstGeoTransform[4] = 0.0;
1716 268 : adfDstGeoTransform[5] = -1 * dfWrkResY;
1717 :
1718 268 : nPixels = (int) ((dfWrkMaxX - dfWrkMinX) / dfWrkResX + 0.5);
1719 268 : nLines = (int) ((dfWrkMaxY - dfWrkMinY) / dfWrkResY + 0.5);
1720 : }
1721 :
1722 : /* -------------------------------------------------------------------- */
1723 : /* Did the user override some parameters? */
1724 : /* -------------------------------------------------------------------- */
1725 274 : if( dfXRes != 0.0 && dfYRes != 0.0 )
1726 : {
1727 4 : if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
1728 : {
1729 3 : dfMinX = adfDstGeoTransform[0];
1730 3 : dfMaxX = adfDstGeoTransform[0] + adfDstGeoTransform[1] * nPixels;
1731 3 : dfMaxY = adfDstGeoTransform[3];
1732 3 : dfMinY = adfDstGeoTransform[3] + adfDstGeoTransform[5] * nLines;
1733 : }
1734 :
1735 4 : if ( bTargetAlignedPixels )
1736 : {
1737 1 : dfMinX = floor(dfMinX / dfXRes) * dfXRes;
1738 1 : dfMaxX = ceil(dfMaxX / dfXRes) * dfXRes;
1739 1 : dfMinY = floor(dfMinY / dfYRes) * dfYRes;
1740 1 : dfMaxY = ceil(dfMaxY / dfYRes) * dfYRes;
1741 : }
1742 :
1743 4 : nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes);
1744 4 : nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes);
1745 4 : adfDstGeoTransform[0] = dfMinX;
1746 4 : adfDstGeoTransform[3] = dfMaxY;
1747 4 : adfDstGeoTransform[1] = dfXRes;
1748 4 : adfDstGeoTransform[5] = -dfYRes;
1749 : }
1750 :
1751 275 : else if( nForcePixels != 0 && nForceLines != 0 )
1752 : {
1753 9 : if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
1754 : {
1755 8 : dfMinX = dfWrkMinX;
1756 8 : dfMaxX = dfWrkMaxX;
1757 8 : dfMaxY = dfWrkMaxY;
1758 8 : dfMinY = dfWrkMinY;
1759 : }
1760 :
1761 9 : dfXRes = (dfMaxX - dfMinX) / nForcePixels;
1762 9 : dfYRes = (dfMaxY - dfMinY) / nForceLines;
1763 :
1764 9 : adfDstGeoTransform[0] = dfMinX;
1765 9 : adfDstGeoTransform[3] = dfMaxY;
1766 9 : adfDstGeoTransform[1] = dfXRes;
1767 9 : adfDstGeoTransform[5] = -dfYRes;
1768 :
1769 9 : nPixels = nForcePixels;
1770 9 : nLines = nForceLines;
1771 : }
1772 :
1773 257 : else if( nForcePixels != 0 )
1774 : {
1775 0 : if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
1776 : {
1777 0 : dfMinX = dfWrkMinX;
1778 0 : dfMaxX = dfWrkMaxX;
1779 0 : dfMaxY = dfWrkMaxY;
1780 0 : dfMinY = dfWrkMinY;
1781 : }
1782 :
1783 0 : dfXRes = (dfMaxX - dfMinX) / nForcePixels;
1784 0 : dfYRes = dfXRes;
1785 :
1786 0 : adfDstGeoTransform[0] = dfMinX;
1787 0 : adfDstGeoTransform[3] = dfMaxY;
1788 0 : adfDstGeoTransform[1] = dfXRes;
1789 0 : adfDstGeoTransform[5] = -dfYRes;
1790 :
1791 0 : nPixels = nForcePixels;
1792 0 : nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes);
1793 : }
1794 :
1795 257 : else if( nForceLines != 0 )
1796 : {
1797 0 : if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
1798 : {
1799 0 : dfMinX = dfWrkMinX;
1800 0 : dfMaxX = dfWrkMaxX;
1801 0 : dfMaxY = dfWrkMaxY;
1802 0 : dfMinY = dfWrkMinY;
1803 : }
1804 :
1805 0 : dfYRes = (dfMaxY - dfMinY) / nForceLines;
1806 0 : dfXRes = dfYRes;
1807 :
1808 0 : adfDstGeoTransform[0] = dfMinX;
1809 0 : adfDstGeoTransform[3] = dfMaxY;
1810 0 : adfDstGeoTransform[1] = dfXRes;
1811 0 : adfDstGeoTransform[5] = -dfYRes;
1812 :
1813 0 : nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes);
1814 0 : nLines = nForceLines;
1815 : }
1816 :
1817 257 : else if( dfMinX != 0.0 || dfMinY != 0.0 || dfMaxX != 0.0 || dfMaxY != 0.0 )
1818 : {
1819 1 : dfXRes = adfDstGeoTransform[1];
1820 1 : dfYRes = fabs(adfDstGeoTransform[5]);
1821 :
1822 1 : nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes);
1823 1 : nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes);
1824 :
1825 1 : dfXRes = (dfMaxX - dfMinX) / nPixels;
1826 1 : dfYRes = (dfMaxY - dfMinY) / nLines;
1827 :
1828 1 : adfDstGeoTransform[0] = dfMinX;
1829 1 : adfDstGeoTransform[3] = dfMaxY;
1830 1 : adfDstGeoTransform[1] = dfXRes;
1831 1 : adfDstGeoTransform[5] = -dfYRes;
1832 : }
1833 :
1834 : /* -------------------------------------------------------------------- */
1835 : /* Do we want to generate an alpha band in the output file? */
1836 : /* -------------------------------------------------------------------- */
1837 270 : if( bEnableSrcAlpha )
1838 0 : nDstBandCount--;
1839 :
1840 270 : if( bEnableDstAlpha )
1841 2 : nDstBandCount++;
1842 :
1843 : /* -------------------------------------------------------------------- */
1844 : /* Create the output file. */
1845 : /* -------------------------------------------------------------------- */
1846 270 : if( !bQuiet )
1847 269 : printf( "Creating output file that is %dP x %dL.\n", nPixels, nLines );
1848 :
1849 : hDstDS = GDALCreate( hDriver, pszFilename, nPixels, nLines,
1850 270 : nDstBandCount, eDT, *ppapszCreateOptions );
1851 :
1852 270 : if( hDstDS == NULL )
1853 : {
1854 0 : CPLFree( pszThisTargetSRS );
1855 0 : return NULL;
1856 : }
1857 :
1858 : /* -------------------------------------------------------------------- */
1859 : /* Write out the projection definition. */
1860 : /* -------------------------------------------------------------------- */
1861 270 : GDALSetProjection( hDstDS, pszThisTargetSRS );
1862 270 : GDALSetGeoTransform( hDstDS, adfDstGeoTransform );
1863 :
1864 270 : if (*phTransformArg != NULL)
1865 269 : GDALSetGenImgProjTransformerDstGeoTransform( *phTransformArg, adfDstGeoTransform);
1866 :
1867 : /* -------------------------------------------------------------------- */
1868 : /* Try to set color interpretation of source bands to target */
1869 : /* dataset. */
1870 : /* FIXME? We should likely do that for other drivers than VRT */
1871 : /* but it might create spurious .aux.xml files (at least with HFA, */
1872 : /* and netCDF) */
1873 : /* -------------------------------------------------------------------- */
1874 270 : if( bVRT )
1875 : {
1876 4 : int nBandsToCopy = (int)apeColorInterpretations.size();
1877 4 : if ( bEnableSrcAlpha )
1878 0 : nBandsToCopy --;
1879 15 : for(int iBand = 0; iBand < nBandsToCopy; iBand++)
1880 : {
1881 : GDALSetRasterColorInterpretation(
1882 : GDALGetRasterBand( hDstDS, iBand + 1 ),
1883 11 : apeColorInterpretations[iBand] );
1884 : }
1885 : }
1886 :
1887 : /* -------------------------------------------------------------------- */
1888 : /* Try to set color interpretation of output file alpha band. */
1889 : /* -------------------------------------------------------------------- */
1890 270 : if( bEnableDstAlpha )
1891 : {
1892 : GDALSetRasterColorInterpretation(
1893 : GDALGetRasterBand( hDstDS, nDstBandCount ),
1894 2 : GCI_AlphaBand );
1895 : }
1896 :
1897 : /* -------------------------------------------------------------------- */
1898 : /* Copy the color table, if required. */
1899 : /* -------------------------------------------------------------------- */
1900 270 : if( hCT != NULL )
1901 : {
1902 0 : GDALSetRasterColorTable( GDALGetRasterBand(hDstDS,1), hCT );
1903 0 : GDALDestroyColorTable( hCT );
1904 : }
1905 :
1906 270 : CPLFree( pszThisTargetSRS );
1907 270 : return hDstDS;
1908 : }
1909 :
1910 : /************************************************************************/
1911 : /* GeoTransform_Transformer() */
1912 : /* */
1913 : /* Convert points from georef coordinates to pixel/line based */
1914 : /* on a geotransform. */
1915 : /************************************************************************/
1916 :
1917 : class CutlineTransformer : public OGRCoordinateTransformation
1918 6 : {
1919 : public:
1920 :
1921 : void *hSrcImageTransformer;
1922 :
1923 0 : virtual OGRSpatialReference *GetSourceCS() { return NULL; }
1924 9 : virtual OGRSpatialReference *GetTargetCS() { return NULL; }
1925 :
1926 0 : virtual int Transform( int nCount,
1927 : double *x, double *y, double *z = NULL ) {
1928 : int nResult;
1929 :
1930 0 : int *pabSuccess = (int *) CPLCalloc(sizeof(int),nCount);
1931 0 : nResult = TransformEx( nCount, x, y, z, pabSuccess );
1932 0 : CPLFree( pabSuccess );
1933 :
1934 0 : return nResult;
1935 : }
1936 :
1937 3 : virtual int TransformEx( int nCount,
1938 : double *x, double *y, double *z = NULL,
1939 : int *pabSuccess = NULL ) {
1940 : return GDALGenImgProjTransform( hSrcImageTransformer, TRUE,
1941 3 : nCount, x, y, z, pabSuccess );
1942 : }
1943 : };
1944 :
1945 :
1946 : /************************************************************************/
1947 : /* LoadCutline() */
1948 : /* */
1949 : /* Load blend cutline from OGR datasource. */
1950 : /************************************************************************/
1951 :
1952 : static void
1953 3 : LoadCutline( const char *pszCutlineDSName, const char *pszCLayer,
1954 : const char *pszCWHERE, const char *pszCSQL,
1955 : void **phCutlineRet )
1956 :
1957 : {
1958 : #ifndef OGR_ENABLED
1959 : CPLError( CE_Failure, CPLE_AppDefined,
1960 : "Request to load a cutline failed, this build does not support OGR features.\n" );
1961 : GDALExit( 1 );
1962 : #else // def OGR_ENABLED
1963 3 : OGRRegisterAll();
1964 :
1965 : /* -------------------------------------------------------------------- */
1966 : /* Open source vector dataset. */
1967 : /* -------------------------------------------------------------------- */
1968 : OGRDataSourceH hSrcDS;
1969 :
1970 3 : hSrcDS = OGROpen( pszCutlineDSName, FALSE, NULL );
1971 3 : if( hSrcDS == NULL )
1972 0 : GDALExit( 1 );
1973 :
1974 : /* -------------------------------------------------------------------- */
1975 : /* Get the source layer */
1976 : /* -------------------------------------------------------------------- */
1977 3 : OGRLayerH hLayer = NULL;
1978 :
1979 3 : if( pszCSQL != NULL )
1980 0 : hLayer = OGR_DS_ExecuteSQL( hSrcDS, pszCSQL, NULL, NULL );
1981 3 : else if( pszCLayer != NULL )
1982 3 : hLayer = OGR_DS_GetLayerByName( hSrcDS, pszCLayer );
1983 : else
1984 0 : hLayer = OGR_DS_GetLayer( hSrcDS, 0 );
1985 :
1986 3 : if( hLayer == NULL )
1987 : {
1988 0 : fprintf( stderr, "Failed to identify source layer from datasource.\n" );
1989 0 : GDALExit( 1 );
1990 : }
1991 :
1992 : /* -------------------------------------------------------------------- */
1993 : /* Apply WHERE clause if there is one. */
1994 : /* -------------------------------------------------------------------- */
1995 3 : if( pszCWHERE != NULL )
1996 0 : OGR_L_SetAttributeFilter( hLayer, pszCWHERE );
1997 :
1998 : /* -------------------------------------------------------------------- */
1999 : /* Collect the geometries from this layer, and build list of */
2000 : /* burn values. */
2001 : /* -------------------------------------------------------------------- */
2002 : OGRFeatureH hFeat;
2003 3 : OGRGeometryH hMultiPolygon = OGR_G_CreateGeometry( wkbMultiPolygon );
2004 :
2005 3 : OGR_L_ResetReading( hLayer );
2006 :
2007 9 : while( (hFeat = OGR_L_GetNextFeature( hLayer )) != NULL )
2008 : {
2009 3 : OGRGeometryH hGeom = OGR_F_GetGeometryRef(hFeat);
2010 :
2011 3 : if( hGeom == NULL )
2012 : {
2013 0 : fprintf( stderr, "ERROR: Cutline feature without a geometry.\n" );
2014 0 : GDALExit( 1 );
2015 : }
2016 :
2017 3 : OGRwkbGeometryType eType = wkbFlatten(OGR_G_GetGeometryType( hGeom ));
2018 :
2019 3 : if( eType == wkbPolygon )
2020 3 : OGR_G_AddGeometry( hMultiPolygon, hGeom );
2021 0 : else if( eType == wkbMultiPolygon )
2022 : {
2023 : int iGeom;
2024 :
2025 0 : for( iGeom = 0; iGeom < OGR_G_GetGeometryCount( hGeom ); iGeom++ )
2026 : {
2027 : OGR_G_AddGeometry( hMultiPolygon,
2028 0 : OGR_G_GetGeometryRef(hGeom,iGeom) );
2029 : }
2030 : }
2031 : else
2032 : {
2033 0 : fprintf( stderr, "ERROR: Cutline not of polygon type.\n" );
2034 0 : GDALExit( 1 );
2035 : }
2036 :
2037 3 : OGR_F_Destroy( hFeat );
2038 : }
2039 :
2040 3 : if( OGR_G_GetGeometryCount( hMultiPolygon ) == 0 )
2041 : {
2042 0 : fprintf( stderr, "ERROR: Did not get any cutline features.\n" );
2043 0 : GDALExit( 1 );
2044 : }
2045 :
2046 : /* -------------------------------------------------------------------- */
2047 : /* Ensure the coordinate system gets set on the geometry. */
2048 : /* -------------------------------------------------------------------- */
2049 : OGR_G_AssignSpatialReference(
2050 3 : hMultiPolygon, OGR_L_GetSpatialRef(hLayer) );
2051 :
2052 3 : *phCutlineRet = (void *) hMultiPolygon;
2053 :
2054 : /* -------------------------------------------------------------------- */
2055 : /* Cleanup */
2056 : /* -------------------------------------------------------------------- */
2057 3 : if( pszCSQL != NULL )
2058 0 : OGR_DS_ReleaseResultSet( hSrcDS, hLayer );
2059 :
2060 3 : OGR_DS_Destroy( hSrcDS );
2061 : #endif
2062 3 : }
2063 :
2064 : /************************************************************************/
2065 : /* TransformCutlineToSource() */
2066 : /* */
2067 : /* Transform cutline from its SRS to source pixel/line coordinates.*/
2068 : /************************************************************************/
2069 : static void
2070 3 : TransformCutlineToSource( GDALDatasetH hSrcDS, void *hCutline,
2071 : char ***ppapszWarpOptions, char **papszTO_In )
2072 :
2073 : {
2074 : #ifdef OGR_ENABLED
2075 3 : OGRGeometryH hMultiPolygon = OGR_G_Clone( (OGRGeometryH) hCutline );
2076 3 : char **papszTO = CSLDuplicate( papszTO_In );
2077 :
2078 : /* -------------------------------------------------------------------- */
2079 : /* Checkout that SRS are the same. */
2080 : /* -------------------------------------------------------------------- */
2081 3 : OGRSpatialReferenceH hRasterSRS = NULL;
2082 3 : const char *pszProjection = NULL;
2083 :
2084 3 : if( GDALGetProjectionRef( hSrcDS ) != NULL
2085 : && strlen(GDALGetProjectionRef( hSrcDS )) > 0 )
2086 3 : pszProjection = GDALGetProjectionRef( hSrcDS );
2087 0 : else if( GDALGetGCPProjection( hSrcDS ) != NULL )
2088 0 : pszProjection = GDALGetGCPProjection( hSrcDS );
2089 :
2090 3 : if( pszProjection != NULL )
2091 : {
2092 3 : hRasterSRS = OSRNewSpatialReference(NULL);
2093 3 : if( OSRImportFromWkt( hRasterSRS, (char **)&pszProjection ) != CE_None )
2094 : {
2095 0 : OSRDestroySpatialReference(hRasterSRS);
2096 0 : hRasterSRS = NULL;
2097 : }
2098 : }
2099 :
2100 3 : OGRSpatialReferenceH hCutlineSRS = OGR_G_GetSpatialReference( hMultiPolygon );
2101 3 : if( hRasterSRS != NULL && hCutlineSRS != NULL )
2102 : {
2103 : /* ok, we will reproject */
2104 : }
2105 0 : else if( hRasterSRS != NULL && hCutlineSRS == NULL )
2106 : {
2107 : fprintf(stderr,
2108 : "Warning : the source raster dataset has a SRS, but the cutline features\n"
2109 : "not. We assume that the cutline coordinates are expressed in the destination SRS.\n"
2110 0 : "If not, cutline results may be incorrect.\n");
2111 : }
2112 0 : else if( hRasterSRS == NULL && hCutlineSRS != NULL )
2113 : {
2114 : fprintf(stderr,
2115 : "Warning : the input vector layer has a SRS, but the source raster dataset does not.\n"
2116 0 : "Cutline results may be incorrect.\n");
2117 : }
2118 :
2119 3 : if( hRasterSRS != NULL )
2120 3 : OSRDestroySpatialReference(hRasterSRS);
2121 :
2122 : /* -------------------------------------------------------------------- */
2123 : /* Extract the cutline SRS WKT. */
2124 : /* -------------------------------------------------------------------- */
2125 3 : if( hCutlineSRS != NULL )
2126 : {
2127 3 : char *pszCutlineSRS_WKT = NULL;
2128 :
2129 3 : OSRExportToWkt( hCutlineSRS, &pszCutlineSRS_WKT );
2130 3 : papszTO = CSLSetNameValue( papszTO, "DST_SRS", pszCutlineSRS_WKT );
2131 3 : CPLFree( pszCutlineSRS_WKT );
2132 : }
2133 :
2134 : /* -------------------------------------------------------------------- */
2135 : /* It may be unwise to let the mask geometry be re-wrapped by */
2136 : /* the CENTER_LONG machinery as this can easily screw up world */
2137 : /* spanning masks and invert the mask topology. */
2138 : /* -------------------------------------------------------------------- */
2139 3 : papszTO = CSLSetNameValue( papszTO, "INSERT_CENTER_LONG", "FALSE" );
2140 :
2141 : /* -------------------------------------------------------------------- */
2142 : /* Transform the geometry to pixel/line coordinates. */
2143 : /* -------------------------------------------------------------------- */
2144 3 : CutlineTransformer oTransformer;
2145 :
2146 : /* The cutline transformer will *invert* the hSrcImageTransformer */
2147 : /* so it will convert from the cutline SRS to the source pixel/line */
2148 : /* coordinates */
2149 : oTransformer.hSrcImageTransformer =
2150 3 : GDALCreateGenImgProjTransformer2( hSrcDS, NULL, papszTO );
2151 :
2152 3 : CSLDestroy( papszTO );
2153 :
2154 3 : if( oTransformer.hSrcImageTransformer == NULL )
2155 0 : GDALExit( 1 );
2156 :
2157 : OGR_G_Transform( hMultiPolygon,
2158 3 : (OGRCoordinateTransformationH) &oTransformer );
2159 :
2160 3 : GDALDestroyGenImgProjTransformer( oTransformer.hSrcImageTransformer );
2161 :
2162 : /* -------------------------------------------------------------------- */
2163 : /* Convert aggregate geometry into WKT. */
2164 : /* -------------------------------------------------------------------- */
2165 3 : char *pszWKT = NULL;
2166 :
2167 3 : OGR_G_ExportToWkt( hMultiPolygon, &pszWKT );
2168 3 : OGR_G_DestroyGeometry( hMultiPolygon );
2169 :
2170 : *ppapszWarpOptions = CSLSetNameValue( *ppapszWarpOptions,
2171 3 : "CUTLINE", pszWKT );
2172 3 : CPLFree( pszWKT );
2173 : #endif
2174 3 : }
2175 :
2176 : static void
2177 2 : RemoveConflictingMetadata( GDALMajorObjectH hObj, char **papszMetadata,
2178 : const char *pszValueConflict )
2179 : {
2180 2 : if ( hObj == NULL ) return;
2181 :
2182 2 : char *pszKey = NULL;
2183 : const char *pszValueRef;
2184 : const char *pszValueComp;
2185 2 : char ** papszMetadataRef = CSLDuplicate( papszMetadata );
2186 2 : int nCount = CSLCount( papszMetadataRef );
2187 :
2188 3 : for( int i = 0; i < nCount; i++ )
2189 : {
2190 1 : pszValueRef = CPLParseNameValue( papszMetadataRef[i], &pszKey );
2191 1 : pszValueComp = GDALGetMetadataItem( hObj, pszKey, NULL );
2192 1 : if ( ( pszValueRef == NULL || pszValueComp == NULL ||
2193 : ! EQUAL( pszValueRef, pszValueComp ) ) &&
2194 : ! EQUAL( pszValueComp, pszValueConflict ) ) {
2195 0 : GDALSetMetadataItem( hObj, pszKey, pszValueConflict, NULL );
2196 : }
2197 1 : CPLFree( pszKey );
2198 : }
2199 :
2200 2 : CSLDestroy( papszMetadataRef );
2201 : }
|