PostGIS  3.7.0dev-r@@SVN_REVISION@@
rt_warp.c
Go to the documentation of this file.
1 /*
2  *
3  * WKTRaster - Raster Types for PostGIS
4  * http://trac.osgeo.org/postgis/wiki/WKTRaster
5  *
6  * Copyright (C) 2013 Bborie Park <dustymugs@gmail.com>
7  * Copyright (C) 2011-2013 Regents of the University of California
8  * <bkpark@ucdavis.edu>
9  * Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo@deimos-space.com>
10  * Copyright (C) 2010-2011 David Zwarg <dzwarg@azavea.com>
11  * Copyright (C) 2009-2011 Pierre Racine <pierre.racine@sbf.ulaval.ca>
12  * Copyright (C) 2009-2011 Mateusz Loskot <mateusz@loskot.net>
13  * Copyright (C) 2008-2009 Sandro Santilli <strk@kbt.io>
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software Foundation,
27  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28  *
29  */
30 
31 #include "../../postgis_config.h"
32 
33 #include "librtcore.h"
34 #include "librtcore_internal.h"
35 
36 /******************************************************************************
37 * rt_raster_gdal_warp()
38 ******************************************************************************/
39 
42 
43  struct {
44  GDALDriverH drv;
45  GDALDatasetH ds;
46  char *srs;
48  } src, dst;
49 
50  GDALWarpOptions *wopts;
51 
52  struct {
53  struct {
54  char **item;
55  int len;
56  } option;
57 
58  struct {
59  void *transform;
60  void *imgproj;
61  void *approx;
62  } arg;
63 
64  GDALTransformerFunc func;
66 
67 };
68 
69 static _rti_warp_arg
71  _rti_warp_arg arg = NULL;
72 
73  arg = rtalloc(sizeof(struct _rti_warp_arg_t));
74  if (arg == NULL) {
75  rterror("_rti_warp_arg_init: Could not allocate memory for _rti_warp_arg");
76  return NULL;
77  }
78 
79  arg->src.drv = NULL;
80  arg->src.destroy_drv = 0;
81  arg->src.ds = NULL;
82  arg->src.srs = NULL;
83 
84  arg->dst.drv = NULL;
85  arg->dst.destroy_drv = 0;
86  arg->dst.ds = NULL;
87  arg->dst.srs = NULL;
88 
89  arg->wopts = NULL;
90 
91  arg->transform.option.item = NULL;
92  arg->transform.option.len = 0;
93 
94  arg->transform.arg.transform = NULL;
95  arg->transform.arg.imgproj = NULL;
96  arg->transform.arg.approx = NULL;
97 
98  arg->transform.func = NULL;
99 
100  return arg;
101 }
102 
103 static void
105  int i = 0;
106 
107  if (arg->dst.ds != NULL)
108  GDALClose(arg->dst.ds);
109  if (arg->dst.srs != NULL)
110  CPLFree(arg->dst.srs);
111 
112  if (arg->dst.drv != NULL && arg->dst.destroy_drv) {
113  GDALDeregisterDriver(arg->dst.drv);
114  GDALDestroyDriver(arg->dst.drv);
115  }
116 
117  if (arg->src.ds != NULL)
118  GDALClose(arg->src.ds);
119  if (arg->src.srs != NULL)
120  CPLFree(arg->src.srs);
121 
122  if (arg->src.drv != NULL && arg->src.destroy_drv) {
123  GDALDeregisterDriver(arg->src.drv);
124  GDALDestroyDriver(arg->src.drv);
125  }
126 
127  if (arg->transform.func == GDALApproxTransform) {
128  if (arg->transform.arg.imgproj != NULL)
129  GDALDestroyGenImgProjTransformer(arg->transform.arg.imgproj);
130  }
131 
132  if (arg->wopts != NULL)
133  GDALDestroyWarpOptions(arg->wopts);
134 
135  if (arg->transform.option.len > 0 && arg->transform.option.item != NULL) {
136  for (i = 0; i < arg->transform.option.len; i++) {
137  if (arg->transform.option.item[i] != NULL)
138  rtdealloc(arg->transform.option.item[i]);
139  }
140  rtdealloc(arg->transform.option.item);
141  }
142 
143  rtdealloc(arg);
144  arg = NULL;
145 }
146 
179  const char *src_srs, const char *dst_srs,
180  double *scale_x, double *scale_y,
181  int *width, int *height,
182  double *ul_xw, double *ul_yw,
183  double *grid_xw, double *grid_yw,
184  double *skew_x, double *skew_y,
185  GDALResampleAlg resample_alg, double max_err
186 ) {
187  CPLErr cplerr;
188  char *dst_options[] = {"SUBCLASS=VRTWarpedDataset", NULL};
189  _rti_warp_arg arg = NULL;
190 
191  GDALRasterBandH band;
192  rt_band rtband = NULL;
193  rt_pixtype pt = PT_END;
194  GDALDataType gdal_pt = GDT_Unknown;
195  double nodata = 0.0;
196 
197  double _gt[6] = {0};
198  double dst_extent[4];
199  rt_envelope extent;
200 
201  int _dim[2] = {0};
202  double _skew[2] = {0};
203  double _scale[2] = {0};
204  int ul_user = 0;
205 
206  rt_raster rast = NULL;
207  int i = 0;
208  int numBands = 0;
209 
210  /* flag indicating that the spatial info is being substituted */
211  int subspatial = 0;
212 
213  RASTER_DEBUG(3, "starting");
214 
215  assert(NULL != raster);
216 
217  /* internal variables */
218  arg = _rti_warp_arg_init();
219  if (arg == NULL) {
220  rterror("rt_raster_gdal_warp: Could not initialize internal variables");
221  return NULL;
222  }
223 
224  /*
225  max_err must be gte zero
226 
227  the value 0.125 is the default used in gdalwarp.cpp on line 283
228  */
229  if (max_err < 0.) max_err = 0.125;
230  RASTER_DEBUGF(4, "max_err = %f", max_err);
231 
232  /* handle srs */
233  if (src_srs != NULL) {
234  /* reprojection taking place */
235  if (dst_srs != NULL && strcmp(src_srs, dst_srs) != 0) {
236  RASTER_DEBUG(4, "Warp operation does include a reprojection");
237  arg->src.srs = rt_util_gdal_convert_sr(src_srs, 0);
238  arg->dst.srs = rt_util_gdal_convert_sr(dst_srs, 0);
239 
240  if (arg->src.srs == NULL || arg->dst.srs == NULL) {
241  rterror("rt_raster_gdal_warp: Could not convert srs values to GDAL accepted format");
243  return NULL;
244  }
245  }
246  /* no reprojection, a stub just for clarity */
247  else {
248  RASTER_DEBUG(4, "Warp operation does NOT include reprojection");
249  }
250  }
251  else if (dst_srs != NULL) {
252  /* dst_srs provided but not src_srs */
253  rterror("rt_raster_gdal_warp: SRS required for input raster if SRS provided for warped raster");
255  return NULL;
256  }
257 
258  /* load raster into a GDAL MEM dataset */
259  arg->src.ds = rt_raster_to_gdal_mem(raster, arg->src.srs, NULL, NULL, 0, &(arg->src.drv), &(arg->src.destroy_drv));
260  if (NULL == arg->src.ds) {
261  rterror("rt_raster_gdal_warp: Could not convert raster to GDAL MEM format");
263  return NULL;
264  }
265  RASTER_DEBUG(3, "raster loaded into GDAL MEM dataset");
266 
267  /* special case when src_srs and dst_srs is NULL and raster's geotransform matrix is default */
268  if (
269  src_srs == NULL && dst_srs == NULL &&
271  ) {
272  double gt[6];
273 
274 #if POSTGIS_DEBUG_LEVEL > 3
275  GDALGetGeoTransform(arg->src.ds, gt);
276  RASTER_DEBUGF(3, "GDAL MEM geotransform: %f, %f, %f, %f, %f, %f",
277  gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
278 #endif
279 
280  /* default geotransform */
282  RASTER_DEBUGF(3, "raster geotransform: %f, %f, %f, %f, %f, %f",
283  gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
284 
285  /* substitute spatial info (lack of) with a real one EPSG:32731 (WGS84/UTM zone 31s) */
286  if (FLT_EQ(gt[0], 0.0) && FLT_EQ(gt[3], 0.0) && FLT_EQ(gt[1], 1.0) && FLT_EQ(gt[5], -1.0) &&
287  FLT_EQ(gt[2], 0.0) && FLT_EQ(gt[4], 0.0))
288  {
289  double ngt[6] = {166021.4431, 0.1, 0, 10000000.0000, 0, -0.1};
290 
291  rtwarn("Raster has default geotransform. Adjusting metadata for use of GDAL Warp API");
292 
293  subspatial = 1;
294 
295  GDALSetGeoTransform(arg->src.ds, ngt);
296  GDALFlushCache(arg->src.ds);
297 
298  /* EPSG:32731 */
299  arg->src.srs = rt_util_gdal_convert_sr("EPSG:32731", 0);
300  arg->dst.srs = rt_util_gdal_convert_sr("EPSG:32731", 0);
301 
302 #if POSTGIS_DEBUG_LEVEL > 3
303  GDALGetGeoTransform(arg->src.ds, gt);
304  RASTER_DEBUGF(3, "GDAL MEM geotransform: %f, %f, %f, %f, %f, %f",
305  gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
306 #endif
307  }
308  }
309 
310  /* set transform options */
311  if (arg->src.srs != NULL || arg->dst.srs != NULL) {
312  arg->transform.option.len = 2;
313  arg->transform.option.item = rtalloc(sizeof(char *) * (arg->transform.option.len + 1));
314  if (NULL == arg->transform.option.item) {
315  rterror("rt_raster_gdal_warp: Could not allocation memory for transform options");
317  return NULL;
318  }
319  memset(arg->transform.option.item, 0, sizeof(char *) * (arg->transform.option.len + 1));
320 
321  for (i = 0; i < arg->transform.option.len; i++) {
322  const char *srs = i ? arg->dst.srs : arg->src.srs;
323  const char *lbl = i ? "DST_SRS=" : "SRC_SRS=";
324  size_t sz = sizeof(char) * (strlen(lbl) + 1);
325  if ( srs ) sz += strlen(srs);
326  arg->transform.option.item[i] = (char *) rtalloc(sz);
327  if (NULL == arg->transform.option.item[i]) {
328  rterror("rt_raster_gdal_warp: Could not allocation memory for transform options");
330  return NULL;
331  }
332  sprintf(arg->transform.option.item[i], "%s%s", lbl, srs ? srs : "");
333  RASTER_DEBUGF(4, "arg->transform.option.item[%d] = %s", i, arg->transform.option.item[i]);
334  }
335  }
336  else
337  arg->transform.option.len = 0;
338 
339  /* transformation object for building dst dataset */
340  arg->transform.arg.transform = GDALCreateGenImgProjTransformer2(arg->src.ds, NULL, arg->transform.option.item);
341  if (NULL == arg->transform.arg.transform) {
342  rterror("rt_raster_gdal_warp: Could not create GDAL transformation object for output dataset creation");
344  return NULL;
345  }
346 
347  /* get approximate output georeferenced bounds and resolution */
348  cplerr = GDALSuggestedWarpOutput2(
349  arg->src.ds, GDALGenImgProjTransform,
350  arg->transform.arg.transform, _gt, &(_dim[0]), &(_dim[1]), dst_extent, 0);
351  if (cplerr != CE_None) {
352  rterror("rt_raster_gdal_warp: Could not get GDAL suggested warp output for output dataset creation");
354  return NULL;
355  }
356  GDALDestroyGenImgProjTransformer(arg->transform.arg.transform);
357  arg->transform.arg.transform = NULL;
358 
359  /*
360  don't use suggested dimensions as use of suggested scales
361  on suggested extent will result in suggested dimensions
362  */
363  _dim[0] = 0;
364  _dim[1] = 0;
365 
366  RASTER_DEBUGF(3, "Suggested geotransform: %f, %f, %f, %f, %f, %f",
367  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
368 
369  /* store extent in easier-to-use object */
370  extent.MinX = dst_extent[0];
371  extent.MinY = dst_extent[1];
372  extent.MaxX = dst_extent[2];
373  extent.MaxY = dst_extent[3];
374 
375  extent.UpperLeftX = dst_extent[0];
376  extent.UpperLeftY = dst_extent[3];
377 
378  RASTER_DEBUGF(3, "Suggested extent: %f, %f, %f, %f",
379  extent.MinX, extent.MinY, extent.MaxX, extent.MaxY);
380 
381  /* scale and width/height are mutually exclusive */
382  if (
383  ((NULL != scale_x) || (NULL != scale_y)) &&
384  ((NULL != width) || (NULL != height))
385  ) {
386  rterror("rt_raster_gdal_warp: Scale X/Y and width/height are mutually exclusive. Only provide one");
388  return NULL;
389  }
390 
391  /* user-defined width */
392  if (NULL != width) {
393  _dim[0] = abs(*width);
394  _scale[0] = fabs((extent.MaxX - extent.MinX) / ((double) _dim[0]));
395  }
396  /* user-defined height */
397  if (NULL != height) {
398  _dim[1] = abs(*height);
399  _scale[1] = fabs((extent.MaxY - extent.MinY) / ((double) _dim[1]));
400  }
401 
402  /* user-defined scale */
403  if (
404  ((NULL != scale_x) && (FLT_NEQ(*scale_x, 0.0))) &&
405  ((NULL != scale_y) && (FLT_NEQ(*scale_y, 0.0)))
406  ) {
407  _scale[0] = fabs(*scale_x);
408  _scale[1] = fabs(*scale_y);
409 
410  /* special override since we changed the original GT scales */
411  if (subspatial) {
412  /*
413  _scale[0] *= 10;
414  _scale[1] *= 10;
415  */
416  _scale[0] /= 10;
417  _scale[1] /= 10;
418  }
419  }
420  else if (
421  ((NULL != scale_x) && (NULL == scale_y)) ||
422  ((NULL == scale_x) && (NULL != scale_y))
423  ) {
424  rterror("rt_raster_gdal_warp: Both X and Y scale values must be provided for scale");
426  return NULL;
427  }
428 
429  /* scale not defined, use suggested */
430  if (FLT_EQ(_scale[0], 0.0) && FLT_EQ(_scale[1], 0.0))
431  {
432  _scale[0] = fabs(_gt[1]);
433  _scale[1] = fabs(_gt[5]);
434  }
435 
436  RASTER_DEBUGF(4, "Using scale: %f x %f", _scale[0], -1 * _scale[1]);
437 
438  /* user-defined skew */
439  if (NULL != skew_x) {
440  _skew[0] = *skew_x;
441 
442  /*
443  negative scale-x affects skew
444  for now, force skew to be in left-right, top-down orientation
445  */
446  if (
447  NULL != scale_x &&
448  *scale_x < 0.
449  ) {
450  _skew[0] *= -1;
451  }
452  }
453  if (NULL != skew_y) {
454  _skew[1] = *skew_y;
455 
456  /*
457  positive scale-y affects skew
458  for now, force skew to be in left-right, top-down orientation
459  */
460  if (
461  NULL != scale_y &&
462  *scale_y > 0.
463  ) {
464  _skew[1] *= -1;
465  }
466  }
467 
468  RASTER_DEBUGF(4, "Using skew: %f x %f", _skew[0], _skew[1]);
469 
470  /* reprocess extent if skewed */
471  if (FLT_NEQ(_skew[0], 0.0) || FLT_NEQ(_skew[1], 0.0))
472  {
473  rt_raster skewedrast;
474 
475  RASTER_DEBUG(3, "Computing skewed extent's envelope");
476 
477  skewedrast = rt_raster_compute_skewed_raster(
478  extent,
479  _skew,
480  _scale,
481  0.01
482  );
483  if (skewedrast == NULL) {
484  rterror("rt_raster_gdal_warp: Could not compute skewed raster");
486  return NULL;
487  }
488 
489  if (_dim[0] == 0)
490  _dim[0] = skewedrast->width;
491  if (_dim[1] == 0)
492  _dim[1] = skewedrast->height;
493 
494  extent.UpperLeftX = skewedrast->ipX;
495  extent.UpperLeftY = skewedrast->ipY;
496 
497  rt_raster_destroy(skewedrast);
498  }
499 
500  /* dimensions not defined, compute */
501  if (!_dim[0])
502  _dim[0] = (int) fmax((fabs(extent.MaxX - extent.MinX) + (_scale[0] / 2.)) / _scale[0], 1);
503  if (!_dim[1])
504  _dim[1] = (int) fmax((fabs(extent.MaxY - extent.MinY) + (_scale[1] / 2.)) / _scale[1], 1);
505 
506  /* temporary raster */
507  rast = rt_raster_new(_dim[0], _dim[1]);
508  if (rast == NULL) {
509  rterror("rt_raster_gdal_warp: Out of memory allocating temporary raster");
511  return NULL;
512  }
513 
514  /* set raster's spatial attributes */
516  rt_raster_set_scale(rast, _scale[0], -1 * _scale[1]);
517  rt_raster_set_skews(rast, _skew[0], _skew[1]);
518 
520  RASTER_DEBUGF(3, "Temp raster's geotransform: %f, %f, %f, %f, %f, %f",
521  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
522  RASTER_DEBUGF(3, "Temp raster's dimensions (width x height): %d x %d",
523  _dim[0], _dim[1]);
524 
525  /* user-defined upper-left corner */
526  if (
527  NULL != ul_xw &&
528  NULL != ul_yw
529  ) {
530  ul_user = 1;
531 
532  RASTER_DEBUGF(4, "Using user-specified upper-left corner: %f, %f", *ul_xw, *ul_yw);
533 
534  /* set upper-left corner */
535  rt_raster_set_offsets(rast, *ul_xw, *ul_yw);
536  extent.UpperLeftX = *ul_xw;
537  extent.UpperLeftY = *ul_yw;
538  }
539  else if (
540  ((NULL != ul_xw) && (NULL == ul_yw)) ||
541  ((NULL == ul_xw) && (NULL != ul_yw))
542  ) {
543  rterror("rt_raster_gdal_warp: Both X and Y upper-left corner values must be provided");
546  return NULL;
547  }
548 
549  /* alignment only considered if upper-left corner not provided */
550  if (
551  !ul_user && (
552  (NULL != grid_xw) || (NULL != grid_yw)
553  )
554  ) {
555 
556  if (
557  ((NULL != grid_xw) && (NULL == grid_yw)) ||
558  ((NULL == grid_xw) && (NULL != grid_yw))
559  ) {
560  rterror("rt_raster_gdal_warp: Both X and Y alignment values must be provided");
563  return NULL;
564  }
565 
566  RASTER_DEBUGF(4, "Aligning extent to user-specified grid: %f, %f", *grid_xw, *grid_yw);
567 
568  do {
569  double _r[2] = {0};
570  double _w[2] = {0};
571 
572  /* raster is already aligned */
573  if (FLT_EQ(*grid_xw, extent.UpperLeftX) && FLT_EQ(*grid_yw, extent.UpperLeftY)) {
574  RASTER_DEBUG(3, "Skipping raster alignment as it is already aligned to grid");
575  break;
576  }
577 
578  extent.UpperLeftX = rast->ipX;
579  extent.UpperLeftY = rast->ipY;
580  rt_raster_set_offsets(rast, *grid_xw, *grid_yw);
581 
582  /* process upper-left corner */
584  rast,
585  extent.UpperLeftX, extent.UpperLeftY,
586  &(_r[0]), &(_r[1]),
587  NULL
588  ) != ES_NONE) {
589  rterror("rt_raster_gdal_warp: Could not compute raster pixel for spatial coordinates");
592  return NULL;
593  }
594 
596  rast,
597  _r[0], _r[1],
598  &(_w[0]), &(_w[1]),
599  NULL
600  ) != ES_NONE) {
601  rterror("rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
602 
605  return NULL;
606  }
607 
608  /* shift occurred */
609  if (FLT_NEQ(_w[0], extent.UpperLeftX)) {
610  if (NULL == width)
611  rast->width++;
612  else if (NULL == scale_x) {
613  double _c[2] = {0};
614 
616 
617  /* get upper-right corner */
619  rast,
620  rast->width, 0,
621  &(_c[0]), &(_c[1]),
622  NULL
623  ) != ES_NONE) {
624  rterror("rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
627  return NULL;
628  }
629 
630  rast->scaleX = fabs((_c[0] - _w[0]) / ((double) rast->width));
631  }
632  }
633  if (FLT_NEQ(_w[1], extent.UpperLeftY)) {
634  if (NULL == height)
635  rast->height++;
636  else if (NULL == scale_y) {
637  double _c[2] = {0};
638 
640 
641  /* get upper-right corner */
643  rast,
644  0, rast->height,
645  &(_c[0]), &(_c[1]),
646  NULL
647  ) != ES_NONE) {
648  rterror("rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
649 
652  return NULL;
653  }
654 
655  rast->scaleY = -1 * fabs((_c[1] - _w[1]) / ((double) rast->height));
656  }
657  }
658 
659  rt_raster_set_offsets(rast, _w[0], _w[1]);
660  RASTER_DEBUGF(4, "aligned offsets: %f x %f", _w[0], _w[1]);
661  }
662  while (0);
663  }
664 
665  /*
666  after this point, rt_envelope extent is no longer used
667  */
668 
669  /* get key attributes from rast */
670  _dim[0] = rast->width;
671  _dim[1] = rast->height;
673 
674  /* scale-x is negative or scale-y is positive */
675  if ((
676  (NULL != scale_x) && (*scale_x < 0.)
677  ) || (
678  (NULL != scale_y) && (*scale_y > 0)
679  )) {
680  double _w[2] = {0};
681 
682  /* negative scale-x */
683  if (
684  (NULL != scale_x) &&
685  (*scale_x < 0.)
686  ) {
688  rast,
689  rast->width, 0,
690  &(_w[0]), &(_w[1]),
691  NULL
692  ) != ES_NONE) {
693  rterror("rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
696  return NULL;
697  }
698 
699  _gt[0] = _w[0];
700  _gt[1] = *scale_x;
701 
702  /* check for skew */
703  if (NULL != skew_x && FLT_NEQ(*skew_x, 0.0))
704  _gt[2] = *skew_x;
705  }
706  /* positive scale-y */
707  if (
708  (NULL != scale_y) &&
709  (*scale_y > 0)
710  ) {
712  rast,
713  0, rast->height,
714  &(_w[0]), &(_w[1]),
715  NULL
716  ) != ES_NONE) {
717  rterror("rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
720  return NULL;
721  }
722 
723  _gt[3] = _w[1];
724  _gt[5] = *scale_y;
725 
726  /* check for skew */
727  if (NULL != skew_y && FLT_NEQ(*skew_y, 0.0))
728  _gt[4] = *skew_y;
729  }
730  }
731 
733  rast = NULL;
734 
735  RASTER_DEBUGF(3, "Applied geotransform: %f, %f, %f, %f, %f, %f",
736  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
737  RASTER_DEBUGF(3, "Raster dimensions (width x height): %d x %d",
738  _dim[0], _dim[1]);
739 
740  if ( _dim[0] == 0 || _dim[1] == 0 ) {
741  rterror("rt_raster_gdal_warp: The width (%d) or height (%d) of the warped raster is zero", _dim[0], _dim[1]);
743  return NULL;
744  }
745 
746  /* load VRT driver */
747  if (!rt_util_gdal_driver_registered("VRT")) {
748  RASTER_DEBUG(3, "Registering VRT driver");
749  GDALRegister_VRT();
750  arg->dst.destroy_drv = 1;
751  }
752  arg->dst.drv = GDALGetDriverByName("VRT");
753  if (NULL == arg->dst.drv) {
754  rterror("rt_raster_gdal_warp: Could not load the output GDAL VRT driver");
756  return NULL;
757  }
758 
759  /* create dst dataset */
760  arg->dst.ds = GDALCreate(arg->dst.drv, "", _dim[0], _dim[1], 0, GDT_Byte, dst_options);
761  if (NULL == arg->dst.ds) {
762  rterror("rt_raster_gdal_warp: Could not create GDAL VRT dataset");
764  return NULL;
765  }
766 
767  /* set dst srs */
768  if (arg->dst.srs != NULL) {
769  cplerr = GDALSetProjection(arg->dst.ds, arg->dst.srs);
770  if (cplerr != CE_None) {
771  rterror("rt_raster_gdal_warp: Could not set projection");
773  return NULL;
774  }
775  RASTER_DEBUGF(3, "Applied SRS: %s", GDALGetProjectionRef(arg->dst.ds));
776  }
777 
778  /* set dst geotransform */
779  cplerr = GDALSetGeoTransform(arg->dst.ds, _gt);
780  if (cplerr != CE_None) {
781  rterror("rt_raster_gdal_warp: Could not set geotransform");
783  return NULL;
784  }
785 
786  /* add bands to dst dataset */
787  numBands = rt_raster_get_num_bands(raster);
788  for (i = 0; i < numBands; i++) {
789  rtband = rt_raster_get_band(raster, i);
790  if (NULL == rtband) {
791  rterror("rt_raster_gdal_warp: Could not get band %d for adding to VRT dataset", i);
793  return NULL;
794  }
795 
796  pt = rt_band_get_pixtype(rtband);
797  gdal_pt = rt_util_pixtype_to_gdal_datatype(pt);
798  if (gdal_pt == GDT_Unknown)
799  rtwarn("rt_raster_gdal_warp: Unknown pixel type for band %d", i);
800 
801  cplerr = GDALAddBand(arg->dst.ds, gdal_pt, NULL);
802  if (cplerr != CE_None) {
803  rterror("rt_raster_gdal_warp: Could not add band to VRT dataset");
805  return NULL;
806  }
807 
808  /* get band to write data to */
809  band = NULL;
810  band = GDALGetRasterBand(arg->dst.ds, i + 1);
811  if (NULL == band) {
812  rterror("rt_raster_gdal_warp: Could not get GDAL band for additional processing");
814  return NULL;
815  }
816 
817  /* set nodata */
818  if (rt_band_get_hasnodata_flag(rtband) != FALSE) {
819  rt_band_get_nodata(rtband, &nodata);
820  if (GDALSetRasterNoDataValue(band, nodata) != CE_None)
821  rtwarn("rt_raster_gdal_warp: Could not set nodata value for band %d", i);
822  RASTER_DEBUGF(3, "nodata value set to %f", GDALGetRasterNoDataValue(band, NULL));
823  }
824  }
825 
826  /* create transformation object */
827  arg->transform.arg.transform = arg->transform.arg.imgproj = GDALCreateGenImgProjTransformer2(
828  arg->src.ds, arg->dst.ds,
829  arg->transform.option.item
830  );
831  if (NULL == arg->transform.arg.transform) {
832  rterror("rt_raster_gdal_warp: Could not create GDAL transformation object");
834  return NULL;
835  }
836  arg->transform.func = GDALGenImgProjTransform;
837 
838  /* use approximate transformation object */
839  if (max_err > 0.0) {
840  arg->transform.arg.transform = arg->transform.arg.approx = GDALCreateApproxTransformer(
841  GDALGenImgProjTransform,
842  arg->transform.arg.imgproj, max_err
843  );
844  if (NULL == arg->transform.arg.transform) {
845  rterror("rt_raster_gdal_warp: Could not create GDAL approximate transformation object");
847  return NULL;
848  }
849 
850  arg->transform.func = GDALApproxTransform;
851  }
852 
853  /* warp options */
854  arg->wopts = GDALCreateWarpOptions();
855  if (NULL == arg->wopts) {
856  rterror("rt_raster_gdal_warp: Could not create GDAL warp options object");
858  return NULL;
859  }
860 
861  /* set options */
862  arg->wopts->eResampleAlg = resample_alg;
863  arg->wopts->hSrcDS = arg->src.ds;
864  arg->wopts->hDstDS = arg->dst.ds;
865  arg->wopts->pfnTransformer = arg->transform.func;
866  arg->wopts->pTransformerArg = arg->transform.arg.transform;
867  arg->wopts->papszWarpOptions = (char **) CPLMalloc(sizeof(char *) * 2);
868 
869  arg->wopts->papszWarpOptions[0] = (char *) CPLMalloc(sizeof(char) * (strlen("INIT_DEST=NO_DATA") + 1));
870  strcpy(arg->wopts->papszWarpOptions[0], "INIT_DEST=NO_DATA");
871  arg->wopts->papszWarpOptions[1] = NULL;
872 
873  /* set band mapping */
874  arg->wopts->nBandCount = numBands;
875  arg->wopts->panSrcBands = (int *) CPLMalloc(sizeof(int) * arg->wopts->nBandCount);
876  arg->wopts->panDstBands = (int *) CPLMalloc(sizeof(int) * arg->wopts->nBandCount);
877  for (i = 0; i < arg->wopts->nBandCount; i++)
878  arg->wopts->panDstBands[i] = arg->wopts->panSrcBands[i] = i + 1;
879 
880  /*
881  * https://trac.osgeo.org/postgis/ticket/5881
882  * In order to call GDALWarp with BAND_INIT=NO_DATA we need to ensure
883  * that the src and dst rasters have nodata values and they are
884  * matched up nicely. This block used by tested with the hasnodata
885  * check on all src raster bands, but now we just do it every time
886  * because that makes sense (any warped raster is likely to have
887  * empty corners on output, and those corners need to be filled with
888  * some kind of NODATA value).
889  */
890  {
891  RASTER_DEBUG(3, "Setting nodata mapping");
892  arg->wopts->padfSrcNoDataReal = (double *) CPLMalloc(numBands * sizeof(double));
893  arg->wopts->padfDstNoDataReal = (double *) CPLMalloc(numBands * sizeof(double));
894  arg->wopts->padfSrcNoDataImag = (double *) CPLMalloc(numBands * sizeof(double));
895  arg->wopts->padfDstNoDataImag = (double *) CPLMalloc(numBands * sizeof(double));
896  if (
897  NULL == arg->wopts->padfSrcNoDataReal ||
898  NULL == arg->wopts->padfDstNoDataReal ||
899  NULL == arg->wopts->padfSrcNoDataImag ||
900  NULL == arg->wopts->padfDstNoDataImag
901  ) {
902  rterror("rt_raster_gdal_warp: Out of memory allocating nodata mapping");
904  return NULL;
905  }
906  for (i = 0; i < numBands; i++) {
908  if (!band) {
909  rterror("rt_raster_gdal_warp: Could not process bands for nodata values");
911  return NULL;
912  }
913 
915  /*
916  based on line 1004 of gdalwarp.cpp
917  the problem is that there is a chance that this number is a legitimate value
918  */
919  arg->wopts->padfSrcNoDataReal[i] = -123456.789;
920  }
921  else {
922  rt_band_get_nodata(band, &(arg->wopts->padfSrcNoDataReal[i]));
923  }
924 
925  arg->wopts->padfDstNoDataReal[i] = arg->wopts->padfSrcNoDataReal[i];
926  arg->wopts->padfDstNoDataImag[i] = arg->wopts->padfSrcNoDataImag[i] = 0.0;
927  RASTER_DEBUGF(4, "Mapped nodata value for band %d: %f (%f) => %f (%f)",
928  i,
929  arg->wopts->padfSrcNoDataReal[i], arg->wopts->padfSrcNoDataImag[i],
930  arg->wopts->padfDstNoDataReal[i], arg->wopts->padfDstNoDataImag[i]
931  );
932  }
933  }
934 
935  /* warp raster */
936  RASTER_DEBUG(3, "Warping raster");
937  cplerr = GDALInitializeWarpedVRT(arg->dst.ds, arg->wopts);
938  if (cplerr != CE_None) {
939  rterror("rt_raster_gdal_warp: Could not warp raster");
941  return NULL;
942  }
943  /*
944  GDALSetDescription(arg->dst.ds, "/tmp/warped.vrt");
945  */
946  GDALFlushCache(arg->dst.ds);
947  RASTER_DEBUG(3, "Raster warped");
948 
949  /* convert gdal dataset to raster */
950  RASTER_DEBUG(3, "Converting GDAL dataset to raster");
951  rast = rt_raster_from_gdal_dataset(arg->dst.ds);
952 
954 
955  if (NULL == rast) {
956  rterror("rt_raster_gdal_warp: Could not warp raster");
957  return NULL;
958  }
959 
960  /* substitute spatial, reset back to default */
961  if (subspatial) {
962  double gt[6] = {0, 1, 0, 0, 0, -1};
963  /* See http://trac.osgeo.org/postgis/ticket/2911 */
964  /* We should probably also tweak rotation here */
965  /* NOTE: the times 10 is because it was divided by 10 in a section above,
966  * I'm not sure the above division was needed */
967  gt[1] = _scale[0] * 10;
968  gt[5] = -1 * _scale[1] * 10;
969 
972  }
973 
974  RASTER_DEBUG(3, "done");
975 
976  return rast;
977 }
978 
#define FALSE
Definition: dbfopen.c:72
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
void rterror(const char *fmt,...) __attribute__((format(printf
Wrappers used for reporting errors and info.
void * rtalloc(size_t size)
Wrappers used for managing memory.
Definition: rt_context.c:191
#define FLT_NEQ(x, y)
Definition: librtcore.h:2423
#define RASTER_DEBUG(level, msg)
Definition: librtcore.h:302
rt_errorstate rt_raster_cell_to_geopoint(rt_raster raster, double xr, double yr, double *xw, double *yw, double *gt)
Convert an xr, yr raster point to an xw, yw point on map.
Definition: rt_raster.c:637
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
Definition: rt_raster.c:360
#define RASTER_DEBUGF(level, msg,...)
Definition: librtcore.h:306
void rt_raster_set_geotransform_matrix(rt_raster raster, double *gt)
Set raster's geotransform using 6-element array.
Definition: rt_raster.c:609
void void void rtwarn(const char *fmt,...) __attribute__((format(printf
void rt_raster_set_scale(rt_raster raster, double scaleX, double scaleY)
Set scale in projection units.
Definition: rt_raster.c:141
char * rt_util_gdal_convert_sr(const char *srs, int proj4)
Definition: rt_util.c:225
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:825
rt_errorstate rt_raster_geopoint_to_cell(rt_raster raster, double xw, double yw, double *xr, double *yr, double *igt)
Convert an xw, yw map point to a xr, yr raster point.
Definition: rt_raster.c:686
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:86
rt_pixtype
Definition: librtcore.h:187
@ PT_END
Definition: librtcore.h:199
void rt_raster_set_skews(rt_raster raster, double skewX, double skewY)
Set skews about the X and Y axis.
Definition: rt_raster.c:172
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
Definition: rt_raster.c:52
GDALDataType rt_util_pixtype_to_gdal_datatype(rt_pixtype pt)
Convert rt_pixtype to GDALDataType.
Definition: rt_util.c:124
rt_raster rt_raster_compute_skewed_raster(rt_envelope extent, double *skew, double *scale, double tolerance)
Definition: rt_raster.c:869
#define FLT_EQ(x, y)
Definition: librtcore.h:2424
rt_raster rt_raster_from_gdal_dataset(GDALDatasetH ds)
Return a raster from a GDAL dataset.
Definition: rt_raster.c:2175
@ ES_NONE
Definition: librtcore.h:182
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:376
int rt_util_gdal_driver_registered(const char *drv)
Definition: rt_util.c:366
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
Definition: rt_raster.c:367
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:2038
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:782
void rtdealloc(void *mem)
Definition: rt_context.c:206
GDALDatasetH rt_raster_to_gdal_mem(rt_raster raster, const char *srs, uint32_t *bandNums, int *excludeNodataValues, int count, GDALDriverH *rtn_drv, int *destroy_rtn_drv)
Return GDAL dataset using GDAL MEM driver from raster.
Definition: rt_raster.c:1813
void rt_raster_get_geotransform_matrix(rt_raster raster, double *gt)
Get 6-element array of raster geotransform matrix.
Definition: rt_raster.c:588
void rt_raster_set_offsets(rt_raster raster, double x, double y)
Set insertion points in projection units.
Definition: rt_raster.c:203
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:385
This library is the generic raster handling section of PostGIS.
band
Definition: ovdump.py:58
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
gt
Definition: window.py:78
static void _rti_warp_arg_destroy(_rti_warp_arg arg)
Definition: rt_warp.c:104
struct _rti_warp_arg_t * _rti_warp_arg
Definition: rt_warp.c:40
static _rti_warp_arg _rti_warp_arg_init()
Definition: rt_warp.c:70
rt_raster rt_raster_gdal_warp(rt_raster raster, const char *src_srs, const char *dst_srs, double *scale_x, double *scale_y, int *width, int *height, double *ul_xw, double *ul_yw, double *grid_xw, double *grid_yw, double *skew_x, double *skew_y, GDALResampleAlg resample_alg, double max_err)
Return a warped raster using GDAL Warp API.
Definition: rt_warp.c:177
struct _rti_warp_arg_t::@20 src
void * imgproj
Definition: rt_warp.c:60
char * srs
Definition: rt_warp.c:46
char ** item
Definition: rt_warp.c:54
GDALDriverH drv
Definition: rt_warp.c:44
struct _rti_warp_arg_t::@20 dst
void * approx
Definition: rt_warp.c:61
struct _rti_warp_arg_t::@21::@22 option
GDALDatasetH ds
Definition: rt_warp.c:45
struct _rti_warp_arg_t::@21::@23 arg
GDALTransformerFunc func
Definition: rt_warp.c:64
void * transform
Definition: rt_warp.c:59
int destroy_drv
Definition: rt_warp.c:47
GDALWarpOptions * wopts
Definition: rt_warp.c:50
double MinX
Definition: librtcore.h:167
double UpperLeftY
Definition: librtcore.h:173
double UpperLeftX
Definition: librtcore.h:172
double MaxX
Definition: librtcore.h:168
double MinY
Definition: librtcore.h:169
double MaxY
Definition: librtcore.h:170
uint16_t width
Definition: librtcore.h:2491
double ipX
Definition: librtcore.h:2485
uint16_t height
Definition: librtcore.h:2492
double ipY
Definition: librtcore.h:2486