PostGIS  3.4.0dev-r@@SVN_REVISION@@
rt_raster.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 "librtcore.h"
32 #include "librtcore_internal.h"
33 
34 #include <math.h>
35 
36 #ifndef NAN
37 # define NAN 0.0/0.0
38 #endif
39 
52 rt_raster_new(uint32_t width, uint32_t height) {
53  rt_raster ret = NULL;
54 
55  ret = (rt_raster) rtalloc(sizeof (struct rt_raster_t));
56  if (!ret) {
57  rterror("rt_raster_new: Out of virtual memory creating an rt_raster");
58  return NULL;
59  }
60 
61  RASTER_DEBUGF(3, "Created rt_raster @ %p", ret);
62 
63  if (width > 65535 || height > 65535) {
64  rterror("rt_raster_new: Dimensions requested exceed the maximum (65535 x 65535) permitted for a raster");
65  rt_raster_destroy(ret);
66  return NULL;
67  }
68 
69  ret->width = width;
70  ret->height = height;
71  ret->scaleX = 1;
72  ret->scaleY = -1;
73  ret->ipX = 0.0;
74  ret->ipY = 0.0;
75  ret->skewX = 0.0;
76  ret->skewY = 0.0;
77  ret->srid = SRID_UNKNOWN;
78 
79  ret->numBands = 0;
80  ret->bands = NULL;
81 
82  return ret;
83 }
84 
85 void
87  if (raster == NULL)
88  return;
89 
90  RASTER_DEBUGF(3, "Destroying rt_raster @ %p", raster);
91 
92  if (raster->bands)
93  rtdealloc(raster->bands);
94 
96 }
97 
98 static void
100  int numband = 0;
101  int i = 0;
102  rt_band band = NULL;
103 
104  if (raster == NULL)
105  return;
106 
107  numband = rt_raster_get_num_bands(raster);
108  if (numband < 1)
109  return;
110 
111  for (i = 0; i < numband; i++) {
113  if (NULL == band)
114  continue;
115 
116  if (!rt_band_is_offline(band))
117  continue;
118 
119  rtwarn("Changes made to raster geotransform matrix may affect out-db band data. Returned band data may be incorrect");
120  break;
121  }
122 }
123 
124 uint16_t
126 
127  assert(NULL != raster);
128 
129  return raster->width;
130 }
131 
132 uint16_t
134 
135  assert(NULL != raster);
136 
137  return raster->height;
138 }
139 
140 void
143  double scaleX, double scaleY
144 ) {
145  assert(NULL != raster);
146 
147  raster->scaleX = scaleX;
148  raster->scaleY = scaleY;
149 
151 }
152 
153 double
155 
156 
157  assert(NULL != raster);
158 
159  return raster->scaleX;
160 }
161 
162 double
164 
165 
166  assert(NULL != raster);
167 
168  return raster->scaleY;
169 }
170 
171 void
174  double skewX, double skewY
175 ) {
176  assert(NULL != raster);
177 
178  raster->skewX = skewX;
179  raster->skewY = skewY;
180 
182 }
183 
184 double
186 
187 
188  assert(NULL != raster);
189 
190  return raster->skewX;
191 }
192 
193 double
195 
196 
197  assert(NULL != raster);
198 
199  return raster->skewY;
200 }
201 
202 void
205  double x, double y
206 ) {
207 
208  assert(NULL != raster);
209 
210  raster->ipX = x;
211  raster->ipY = y;
212 
214 }
215 
216 double
218 
219 
220  assert(NULL != raster);
221 
222  return raster->ipX;
223 }
224 
225 double
227 
228 
229  assert(NULL != raster);
230 
231  return raster->ipY;
232 }
233 
234 void
236  double *i_mag, double *j_mag, double *theta_i, double *theta_ij)
237 {
238  double o11, o12, o21, o22 ; /* geotransform coefficients */
239 
240  if (rast == NULL) return ;
241  if ( (i_mag==NULL) || (j_mag==NULL) || (theta_i==NULL) || (theta_ij==NULL))
242  return ;
243 
244  /* retrieve coefficients from raster */
245  o11 = rt_raster_get_x_scale(rast) ;
246  o12 = rt_raster_get_x_skew(rast) ;
247  o21 = rt_raster_get_y_skew(rast) ;
248  o22 = rt_raster_get_y_scale(rast) ;
249 
250  rt_raster_calc_phys_params(o11, o12, o21, o22, i_mag, j_mag, theta_i, theta_ij);
251 }
252 
253 void
254 rt_raster_calc_phys_params(double xscale, double xskew, double yskew, double yscale,
255  double *i_mag, double *j_mag, double *theta_i, double *theta_ij)
256 
257 {
258  double theta_test ;
259 
260  if ( (i_mag==NULL) || (j_mag==NULL) || (theta_i==NULL) || (theta_ij==NULL))
261  return ;
262 
263  /* pixel size in the i direction */
264  *i_mag = sqrt(xscale*xscale + yskew*yskew) ;
265 
266  /* pixel size in the j direction */
267  *j_mag = sqrt(xskew*xskew + yscale*yscale) ;
268 
269  /* Rotation
270  * ========
271  * Two steps:
272  * 1] calculate the magnitude of the angle between the x axis and
273  * the i basis vector.
274  * 2] Calculate the sign of theta_i based on the angle between the y axis
275  * and the i basis vector.
276  */
277  *theta_i = acos(xscale/(*i_mag)) ; /* magnitude */
278  theta_test = acos(yskew/(*i_mag)) ; /* sign */
279  if (theta_test < M_PI_2){
280  *theta_i = -(*theta_i) ;
281  }
282 
283 
284  /* Angular separation of basis vectors
285  * ===================================
286  * Two steps:
287  * 1] calculate the magnitude of the angle between the j basis vector and
288  * the i basis vector.
289  * 2] Calculate the sign of theta_ij based on the angle between the
290  * perpendicular of the i basis vector and the j basis vector.
291  */
292  *theta_ij = acos(((xscale*xskew) + (yskew*yscale))/((*i_mag)*(*j_mag))) ;
293  theta_test = acos( ((-yskew*xskew)+(xscale*yscale)) /
294  ((*i_mag)*(*j_mag)));
295  if (theta_test > M_PI_2) {
296  *theta_ij = -(*theta_ij) ;
297  }
298 }
299 
300 void
301 rt_raster_set_phys_params(rt_raster rast,double i_mag, double j_mag, double theta_i, double theta_ij)
302 {
303  double o11, o12, o21, o22 ; /* calculated geotransform coefficients */
304  int success ;
305 
306  if (rast == NULL) return ;
307 
308  success = rt_raster_calc_gt_coeff(i_mag, j_mag, theta_i, theta_ij,
309  &o11, &o12, &o21, &o22) ;
310 
311  if (success) {
312  rt_raster_set_scale(rast, o11, o22) ;
313  rt_raster_set_skews(rast, o12, o21) ;
314  }
315 }
316 
317 int
318 rt_raster_calc_gt_coeff(double i_mag, double j_mag, double theta_i, double theta_ij,
319  double *xscale, double *xskew, double *yskew, double *yscale)
320 {
321  double f ; /* reflection flag 1.0 or -1.0 */
322  double k_i ; /* shearing coefficient */
323  double s_i, s_j ; /* scaling coefficients */
324  double cos_theta_i, sin_theta_i ;
325 
326  if ( (xscale==NULL) || (xskew==NULL) || (yskew==NULL) || (yscale==NULL)) {
327  return 0;
328  }
329 
330  if ( (theta_ij == 0.0) || (theta_ij == M_PI)) {
331  return 0;
332  }
333 
334  /* Reflection across the i axis */
335  f=1.0 ;
336  if (theta_ij < 0) {
337  f = -1.0;
338  }
339 
340  /* scaling along i axis */
341  s_i = i_mag ;
342 
343  /* shearing parallel to i axis */
344  k_i = tan(f*M_PI_2 - theta_ij) ;
345 
346  /* scaling along j axis */
347  s_j = j_mag / (sqrt(k_i*k_i + 1)) ;
348 
349  /* putting it altogether */
350  cos_theta_i = cos(theta_i) ;
351  sin_theta_i = sin(theta_i) ;
352  *xscale = s_i * cos_theta_i ;
353  *xskew = k_i * s_j * f * cos_theta_i + s_j * f * sin_theta_i ;
354  *yskew = -s_i * sin_theta_i ;
355  *yscale = -k_i * s_j * f * sin_theta_i + s_j * f * cos_theta_i ;
356  return 1;
357 }
358 
359 int32_t
361  assert(NULL != raster);
362 
363  return clamp_srid(raster->srid);
364 }
365 
366 void
368  assert(NULL != raster);
369 
370  raster->srid = clamp_srid(srid);
371 
373 }
374 
375 uint16_t
377 
378 
379  assert(NULL != raster);
380 
381  return raster->numBands;
382 }
383 
384 rt_band
386  assert(NULL != raster);
387 
388  if (n >= raster->numBands || n < 0)
389  return NULL;
390 
391  return raster->bands[n];
392 }
393 
394 /******************************************************************************
395 * rt_raster_add_band()
396 ******************************************************************************/
397 
408 int
410  rt_band *oldbands = NULL;
411  rt_band oldband = NULL;
412  rt_band tmpband = NULL;
413  uint16_t i = 0;
414 
415  assert(NULL != raster);
416  assert(NULL != band);
417 
418  RASTER_DEBUGF(3, "Adding band %p to raster %p", band, raster);
419 
420  if (band->width != raster->width || band->height != raster->height) {
421  rterror("rt_raster_add_band: Can't add a %dx%d band to a %dx%d raster",
422  band->width, band->height, raster->width, raster->height);
423  return -1;
424  }
425 
426  if (index > raster->numBands)
427  index = raster->numBands;
428 
429  if (index < 0)
430  index = 0;
431 
432  oldbands = raster->bands;
433 
434  RASTER_DEBUGF(3, "Oldbands at %p", oldbands);
435 
436  raster->bands = (rt_band*) rtrealloc(raster->bands,
437  sizeof (rt_band)*(raster->numBands + 1)
438  );
439 
440  RASTER_DEBUG(3, "Checking bands");
441 
442  if (NULL == raster->bands) {
443  rterror("rt_raster_add_band: Out of virtual memory "
444  "reallocating band pointers");
445  raster->bands = oldbands;
446  return -1;
447  }
448 
449  RASTER_DEBUGF(4, "realloc returned %p", raster->bands);
450 
451  for (i = 0; i <= raster->numBands; ++i) {
452  if (i == index) {
453  oldband = raster->bands[i];
454  raster->bands[i] = band;
455  } else if (i > index) {
456  tmpband = raster->bands[i];
457  raster->bands[i] = oldband;
458  oldband = tmpband;
459  }
460  }
461 
462  band->raster = raster;
463 
464  raster->numBands++;
465 
466  RASTER_DEBUGF(4, "Raster now has %d bands", raster->numBands);
467 
468  return index;
469 }
470 
471 /******************************************************************************
472 * rt_raster_generate_new_band()
473 ******************************************************************************/
474 
488 int
490  rt_raster raster, rt_pixtype pixtype,
491  double initialvalue, uint32_t hasnodata, double nodatavalue,
492  int index
493 ) {
494  rt_band band = NULL;
495  int width = 0;
496  int height = 0;
497  int numval = 0;
498  int datasize = 0;
499  int oldnumbands = 0;
500  int numbands = 0;
501  void * mem = NULL;
502  int32_t checkvalint = 0;
503  uint32_t checkvaluint = 0;
504  double checkvaldouble = 0;
505  float checkvalfloat = 0;
506  int i;
507 
508 
509  assert(NULL != raster);
510 
511  /* Make sure index is in a valid range */
512  oldnumbands = rt_raster_get_num_bands(raster);
513  if (index < 0)
514  index = 0;
515  else if (index > oldnumbands + 1)
516  index = oldnumbands + 1;
517 
518  /* Determine size of memory block to allocate and allocate it */
519  width = rt_raster_get_width(raster);
520  height = rt_raster_get_height(raster);
521  numval = width * height;
522  datasize = rt_pixtype_size(pixtype) * numval;
523 
524  mem = (int *)rtalloc(datasize);
525  if (!mem) {
526  rterror("rt_raster_generate_new_band: Could not allocate memory for band");
527  return -1;
528  }
529 
530  if (FLT_EQ(initialvalue, 0.0))
531  memset(mem, 0, datasize);
532  else {
533  switch (pixtype)
534  {
535  case PT_1BB:
536  {
537  uint8_t *ptr = mem;
538  uint8_t clamped_initval = rt_util_clamp_to_1BB(initialvalue);
539  for (i = 0; i < numval; i++)
540  ptr[i] = clamped_initval;
541  checkvalint = ptr[0];
542  break;
543  }
544  case PT_2BUI:
545  {
546  uint8_t *ptr = mem;
547  uint8_t clamped_initval = rt_util_clamp_to_2BUI(initialvalue);
548  for (i = 0; i < numval; i++)
549  ptr[i] = clamped_initval;
550  checkvalint = ptr[0];
551  break;
552  }
553  case PT_4BUI:
554  {
555  uint8_t *ptr = mem;
556  uint8_t clamped_initval = rt_util_clamp_to_4BUI(initialvalue);
557  for (i = 0; i < numval; i++)
558  ptr[i] = clamped_initval;
559  checkvalint = ptr[0];
560  break;
561  }
562  case PT_8BSI:
563  {
564  int8_t *ptr = mem;
565  int8_t clamped_initval = rt_util_clamp_to_8BSI(initialvalue);
566  for (i = 0; i < numval; i++)
567  ptr[i] = clamped_initval;
568  checkvalint = ptr[0];
569  break;
570  }
571  case PT_8BUI:
572  {
573  uint8_t *ptr = mem;
574  uint8_t clamped_initval = rt_util_clamp_to_8BUI(initialvalue);
575  for (i = 0; i < numval; i++)
576  ptr[i] = clamped_initval;
577  checkvalint = ptr[0];
578  break;
579  }
580  case PT_16BSI:
581  {
582  int16_t *ptr = mem;
583  int16_t clamped_initval = rt_util_clamp_to_16BSI(initialvalue);
584  for (i = 0; i < numval; i++)
585  ptr[i] = clamped_initval;
586  checkvalint = ptr[0];
587  break;
588  }
589  case PT_16BUI:
590  {
591  uint16_t *ptr = mem;
592  uint16_t clamped_initval = rt_util_clamp_to_16BUI(initialvalue);
593  for (i = 0; i < numval; i++)
594  ptr[i] = clamped_initval;
595  checkvalint = ptr[0];
596  break;
597  }
598  case PT_32BSI:
599  {
600  int32_t *ptr = mem;
601  int32_t clamped_initval = rt_util_clamp_to_32BSI(initialvalue);
602  for (i = 0; i < numval; i++)
603  ptr[i] = clamped_initval;
604  checkvalint = ptr[0];
605  break;
606  }
607  case PT_32BUI:
608  {
609  uint32_t *ptr = mem;
610  uint32_t clamped_initval = rt_util_clamp_to_32BUI(initialvalue);
611  for (i = 0; i < numval; i++)
612  ptr[i] = clamped_initval;
613  checkvaluint = ptr[0];
614  break;
615  }
616  case PT_32BF:
617  {
618  float *ptr = mem;
619  float clamped_initval = rt_util_clamp_to_32F(initialvalue);
620  for (i = 0; i < numval; i++)
621  ptr[i] = clamped_initval;
622  checkvalfloat = ptr[0];
623  break;
624  }
625  case PT_64BF:
626  {
627  double *ptr = mem;
628  for (i = 0; i < numval; i++)
629  ptr[i] = initialvalue;
630  checkvaldouble = ptr[0];
631  break;
632  }
633  default:
634  {
635  rterror("rt_raster_generate_new_band: Unknown pixeltype %d", pixtype);
636  rtdealloc(mem);
637  return -1;
638  }
639  }
640  }
641 
642  /* Overflow checking */
644  initialvalue,
645  checkvalint, checkvaluint,
646  checkvalfloat, checkvaldouble,
647  pixtype
648  );
649 
650  band = rt_band_new_inline(width, height, pixtype, hasnodata, nodatavalue, mem);
651  if (! band) {
652  rterror("rt_raster_generate_new_band: Could not add band to raster. Aborting");
653  rtdealloc(mem);
654  return -1;
655  }
656  rt_band_set_ownsdata_flag(band, 1); /* we DO own this data!!! */
657  index = rt_raster_add_band(raster, band, index);
658  numbands = rt_raster_get_num_bands(raster);
659  if (numbands == oldnumbands || index == -1) {
660  rterror("rt_raster_generate_new_band: Could not add band to raster. Aborting");
662  }
663 
664  /* set isnodata if hasnodata = TRUE and initial value = nodatavalue */
665  if (hasnodata && FLT_EQ(initialvalue, nodatavalue))
667 
668  return index;
669 }
670 
682  double *gt, double *igt
683 ) {
684  double _gt[6] = {0};
685 
686  assert((raster != NULL || gt != NULL));
687  assert(igt != NULL);
688 
689  if (gt == NULL)
691  else
692  memcpy(_gt, gt, sizeof(double) * 6);
693 
694  if (!GDALInvGeoTransform(_gt, igt)) {
695  rterror("rt_raster_get_inverse_geotransform_matrix: Could not compute inverse geotransform matrix");
696  return ES_ERROR;
697  }
698 
699  return ES_NONE;
700 }
701 
709 void
711  double *gt) {
712  assert(NULL != raster);
713  assert(NULL != gt);
714 
715  gt[0] = raster->ipX;
716  gt[1] = raster->scaleX;
717  gt[2] = raster->skewX;
718  gt[3] = raster->ipY;
719  gt[4] = raster->skewY;
720  gt[5] = raster->scaleY;
721 }
722 
730 void
732  double *gt) {
733  assert(NULL != raster);
734  assert(NULL != gt);
735 
736  raster->ipX = gt[0];
737  raster->scaleX = gt[1];
738  raster->skewX = gt[2];
739  raster->ipY = gt[3];
740  raster->skewY = gt[4];
741  raster->scaleY = gt[5];
742 
744 }
745 
761  double xr, double yr,
762  double *xw, double *yw,
763  double *gt
764 ) {
765  double _gt[6] = {0};
766 
767  assert(NULL != raster);
768  assert(NULL != xw && NULL != yw);
769 
770  if (NULL != gt)
771  memcpy(_gt, gt, sizeof(double) * 6);
772 
773  /* scale of matrix is not set */
774  if (FLT_EQ(_gt[1], 0.0) || FLT_EQ(_gt[5], 0.0))
775  {
777  }
778 
779  RASTER_DEBUGF(4, "gt = (%f, %f, %f, %f, %f, %f)",
780  _gt[0],
781  _gt[1],
782  _gt[2],
783  _gt[3],
784  _gt[4],
785  _gt[5]
786  );
787 
788  GDALApplyGeoTransform(_gt, xr, yr, xw, yw);
789  RASTER_DEBUGF(4, "GDALApplyGeoTransform (c -> g) for (%f, %f) = (%f, %f)",
790  xr, yr, *xw, *yw);
791 
792  return ES_NONE;
793 }
794 
810  double xw, double yw,
811  double *xr, double *yr,
812  double *igt
813 ) {
814  double rnd = 0;
815  rt_errorstate err;
816 
817  err = rt_raster_geopoint_to_rasterpoint(raster, xw, yw, xr, yr, igt);
818  if (err != ES_NONE)
819  return err;
820 
821  rnd = ROUND(*xr, 0);
822  if (FLT_EQ(rnd, *xr))
823  *xr = rnd;
824  else
825  *xr = floor(*xr);
826 
827  rnd = ROUND(*yr, 0);
828  if (FLT_EQ(rnd, *yr))
829  *yr = rnd;
830  else
831  *yr = floor(*yr);
832 
833  RASTER_DEBUGF(4, "Corrected GDALApplyGeoTransform (g -> c) for (%f, %f) = (%f, %f)",
834  xw, yw, *xr, *yr);
835 
836  return ES_NONE;
837 }
838 
854  double xw, double yw,
855  double *xr, double *yr,
856  double *igt
857 ) {
858  double _igt[6] = {0};
859 
860  assert(NULL != raster);
861  assert(NULL != xr && NULL != yr);
862 
863  if (igt != NULL)
864  memcpy(_igt, igt, sizeof(double) * 6);
865 
866  /* matrix is not set */
867  if (
868  FLT_EQ(_igt[0], 0.) &&
869  FLT_EQ(_igt[1], 0.) &&
870  FLT_EQ(_igt[2], 0.) &&
871  FLT_EQ(_igt[3], 0.) &&
872  FLT_EQ(_igt[4], 0.) &&
873  FLT_EQ(_igt[5], 0.)
874  ) {
876  rterror("rt_raster_geopoint_to_cell: Could not get inverse geotransform matrix");
877  return ES_ERROR;
878  }
879  }
880 
881  GDALApplyGeoTransform(_igt, xw, yw, xr, yr);
882  RASTER_DEBUGF(4, "GDALApplyGeoTransform (g -> c) for (%f, %f) = (%f, %f)",
883  xw, yw, *xr, *yr);
884 
885  return ES_NONE;
886 }
887 
888 
889 /******************************************************************************
890 * rt_raster_get_envelope()
891 ******************************************************************************/
892 
906  rt_envelope *env
907 ) {
908  int i;
909  int rtn;
910  int set = 0;
911  double _r[2] = {0.};
912  double _w[2] = {0.};
913  double _gt[6] = {0.};
914 
915  assert(raster != NULL);
916  assert(env != NULL);
917 
919 
920  for (i = 0; i < 4; i++) {
921  switch (i) {
922  case 0:
923  _r[0] = 0;
924  _r[1] = 0;
925  break;
926  case 1:
927  _r[0] = 0;
928  _r[1] = raster->height;
929  break;
930  case 2:
931  _r[0] = raster->width;
932  _r[1] = raster->height;
933  break;
934  case 3:
935  _r[0] = raster->width;
936  _r[1] = 0;
937  break;
938  }
939 
941  raster,
942  _r[0], _r[1],
943  &(_w[0]), &(_w[1]),
944  _gt
945  );
946  if (rtn != ES_NONE) {
947  rterror("rt_raster_get_envelope: Could not compute spatial coordinates for raster pixel");
948  return ES_ERROR;
949  }
950 
951  if (!set) {
952  set = 1;
953  env->MinX = _w[0];
954  env->MaxX = _w[0];
955  env->MinY = _w[1];
956  env->MaxY = _w[1];
957  }
958  else {
959  if (_w[0] < env->MinX)
960  env->MinX = _w[0];
961  else if (_w[0] > env->MaxX)
962  env->MaxX = _w[0];
963 
964  if (_w[1] < env->MinY)
965  env->MinY = _w[1];
966  else if (_w[1] > env->MaxY)
967  env->MaxY = _w[1];
968  }
969  }
970 
971  return ES_NONE;
972 }
973 
974 /******************************************************************************
975 * rt_raster_compute_skewed_raster()
976 ******************************************************************************/
977 
978 /*
979  * Compute skewed extent that covers unskewed extent.
980  *
981  * @param envelope : unskewed extent of type rt_envelope
982  * @param skew : pointer to 2-element array (x, y) of skew
983  * @param scale : pointer to 2-element array (x, y) of scale
984  * @param tolerance : value between 0 and 1 where the smaller the tolerance
985  * results in an extent approaching the "minimum" skewed extent.
986  * If value <= 0, tolerance = 0.1. If value > 1, tolerance = 1.
987  *
988  * @return skewed raster who's extent covers unskewed extent, NULL on error
989  */
990 rt_raster
992  rt_envelope extent,
993  double *skew,
994  double *scale,
995  double tolerance
996 ) {
997  uint32_t run = 0;
998  uint32_t max_run = 1;
999  double dbl_run = 0;
1000 
1001  int rtn;
1002  int covers = 0;
1003  rt_raster raster;
1004  double _gt[6] = {0};
1005  double _igt[6] = {0};
1006  int _d[2] = {1, -1};
1007  int _dlast = 0;
1008  int _dlastpos = 0;
1009  double _w[2] = {0};
1010  double _r[2] = {0};
1011  double _xy[2] = {0};
1012  int i;
1013  int j;
1014  int x;
1015  int y;
1016 
1017  LWGEOM *geom = NULL;
1018  GEOSGeometry *sgeom = NULL;
1019  GEOSGeometry *ngeom = NULL;
1020 
1021  if (
1022  (tolerance < 0.) ||
1023  FLT_EQ(tolerance, 0.)
1024  ) {
1025  tolerance = 0.1;
1026  }
1027  else if (tolerance > 1.)
1028  tolerance = 1;
1029 
1030  dbl_run = tolerance;
1031  while (dbl_run < 10) {
1032  dbl_run *= 10.;
1033  max_run *= 10;
1034  }
1035 
1036  /* scale must be provided */
1037  if (scale == NULL)
1038  return NULL;
1039  for (i = 0; i < 2; i++) {
1040  if (FLT_EQ(scale[i], 0.0))
1041  {
1042  rterror("rt_raster_compute_skewed_raster: Scale cannot be zero");
1043  return 0;
1044  }
1045 
1046  if (i < 1)
1047  _gt[1] = fabs(scale[i] * tolerance);
1048  else
1049  _gt[5] = fabs(scale[i] * tolerance);
1050  }
1051  /* conform scale-y to be negative */
1052  _gt[5] *= -1;
1053 
1054  /* skew not provided or skew is zero, return raster of correct dim and spatial attributes */
1055  if ((skew == NULL) || (FLT_EQ(skew[0], 0.0) && FLT_EQ(skew[1], 0.0)))
1056  {
1057  int _dim[2] = {
1058  (int) fmax((fabs(extent.MaxX - extent.MinX) + (fabs(scale[0]) / 2.)) / fabs(scale[0]), 1),
1059  (int) fmax((fabs(extent.MaxY - extent.MinY) + (fabs(scale[1]) / 2.)) / fabs(scale[1]), 1)
1060  };
1061 
1062  raster = rt_raster_new(_dim[0], _dim[1]);
1063  if (raster == NULL) {
1064  rterror("rt_raster_compute_skewed_raster: Could not create output raster");
1065  return NULL;
1066  }
1067 
1068  rt_raster_set_offsets(raster, extent.MinX, extent.MaxY);
1069  rt_raster_set_scale(raster, fabs(scale[0]), -1 * fabs(scale[1]));
1070  rt_raster_set_skews(raster, skew[0], skew[1]);
1071 
1072  return raster;
1073  }
1074 
1075  /* direction to shift upper-left corner */
1076  if (skew[0] > 0.)
1077  _d[0] = -1;
1078  if (skew[1] < 0.)
1079  _d[1] = 1;
1080 
1081  /* geotransform */
1082  _gt[0] = extent.UpperLeftX;
1083  _gt[2] = skew[0] * tolerance;
1084  _gt[3] = extent.UpperLeftY;
1085  _gt[4] = skew[1] * tolerance;
1086 
1087  RASTER_DEBUGF(4, "Initial geotransform: %f, %f, %f, %f, %f, %f",
1088  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]
1089  );
1090  RASTER_DEBUGF(4, "Delta: %d, %d", _d[0], _d[1]);
1091 
1092  /* simple raster */
1093  if ((raster = rt_raster_new(1, 1)) == NULL) {
1094  rterror("rt_raster_compute_skewed_raster: Out of memory allocating extent raster");
1095  return NULL;
1096  }
1098 
1099  /* get inverse geotransform matrix */
1100  if (!GDALInvGeoTransform(_gt, _igt)) {
1101  rterror("rt_raster_compute_skewed_raster: Could not compute inverse geotransform matrix");
1103  return NULL;
1104  }
1105  RASTER_DEBUGF(4, "Inverse geotransform: %f, %f, %f, %f, %f, %f",
1106  _igt[0], _igt[1], _igt[2], _igt[3], _igt[4], _igt[5]
1107  );
1108 
1109  /* shift along axis */
1110  for (i = 0; i < 2; i++) {
1111  covers = 0;
1112  run = 0;
1113 
1114  RASTER_DEBUGF(3, "Shifting along %s axis", i < 1 ? "X" : "Y");
1115 
1116  do {
1117 
1118  /* prevent possible infinite loop */
1119  if (run > max_run) {
1120  rterror("rt_raster_compute_skewed_raster: Could not compute skewed extent due to check preventing infinite loop");
1122  return NULL;
1123  }
1124 
1125  /*
1126  check the four corners that they are covered along the specific axis
1127  pixel column should be >= 0
1128  */
1129  for (j = 0; j < 4; j++) {
1130  switch (j) {
1131  /* upper-left */
1132  case 0:
1133  _xy[0] = extent.MinX;
1134  _xy[1] = extent.MaxY;
1135  break;
1136  /* lower-left */
1137  case 1:
1138  _xy[0] = extent.MinX;
1139  _xy[1] = extent.MinY;
1140  break;
1141  /* lower-right */
1142  case 2:
1143  _xy[0] = extent.MaxX;
1144  _xy[1] = extent.MinY;
1145  break;
1146  /* upper-right */
1147  case 3:
1148  _xy[0] = extent.MaxX;
1149  _xy[1] = extent.MaxY;
1150  break;
1151  }
1152 
1154  raster,
1155  _xy[0], _xy[1],
1156  &(_r[0]), &(_r[1]),
1157  _igt
1158  );
1159  if (rtn != ES_NONE) {
1160  rterror("rt_raster_compute_skewed_raster: Could not compute raster pixel for spatial coordinates");
1162  return NULL;
1163  }
1164 
1165  RASTER_DEBUGF(4, "Point %d at cell %d x %d", j, (int) _r[0], (int) _r[1]);
1166 
1167  /* raster doesn't cover point */
1168  if ((int) _r[i] < 0) {
1169  RASTER_DEBUGF(4, "Point outside of skewed extent: %d", j);
1170  covers = 0;
1171 
1172  if (_dlastpos != j) {
1173  _dlast = (int) _r[i];
1174  _dlastpos = j;
1175  }
1176  else if ((int) _r[i] < _dlast) {
1177  RASTER_DEBUG(4, "Point going in wrong direction. Reversing direction");
1178  _d[i] *= -1;
1179  _dlastpos = -1;
1180  run = 0;
1181  }
1182 
1183  break;
1184  }
1185 
1186  covers++;
1187  }
1188 
1189  if (!covers) {
1190  x = 0;
1191  y = 0;
1192  if (i < 1)
1193  x = _d[i] * fabs(_r[i]);
1194  else
1195  y = _d[i] * fabs(_r[i]);
1196 
1198  raster,
1199  x, y,
1200  &(_w[0]), &(_w[1]),
1201  _gt
1202  );
1203  if (rtn != ES_NONE) {
1204  rterror("rt_raster_compute_skewed_raster: Could not compute spatial coordinates for raster pixel");
1206  return NULL;
1207  }
1208 
1209  /* adjust ul */
1210  if (i < 1)
1211  _gt[0] = _w[i];
1212  else
1213  _gt[3] = _w[i];
1215  RASTER_DEBUGF(4, "Shifted geotransform: %f, %f, %f, %f, %f, %f",
1216  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]
1217  );
1218 
1219  /* get inverse geotransform matrix */
1220  if (!GDALInvGeoTransform(_gt, _igt)) {
1221  rterror("rt_raster_compute_skewed_raster: Could not compute inverse geotransform matrix");
1223  return NULL;
1224  }
1225  RASTER_DEBUGF(4, "Inverse geotransform: %f, %f, %f, %f, %f, %f",
1226  _igt[0], _igt[1], _igt[2], _igt[3], _igt[4], _igt[5]
1227  );
1228  }
1229 
1230  run++;
1231  }
1232  while (!covers);
1233  }
1234 
1235  /* covers test */
1237  raster,
1238  extent.MaxX, extent.MinY,
1239  &(_r[0]), &(_r[1]),
1240  _igt
1241  );
1242  if (rtn != ES_NONE) {
1243  rterror("rt_raster_compute_skewed_raster: Could not compute raster pixel for spatial coordinates");
1245  return NULL;
1246  }
1247 
1248  RASTER_DEBUGF(4, "geopoint %f x %f at cell %d x %d", extent.MaxX, extent.MinY, (int) _r[0], (int) _r[1]);
1249 
1250  raster->width = _r[0];
1251  raster->height = _r[1];
1252 
1253  /* initialize GEOS */
1254  initGEOS(rtinfo, lwgeom_geos_error);
1255 
1256  /* create reference LWPOLY */
1257  {
1258  LWPOLY *npoly = rt_util_envelope_to_lwpoly(extent);
1259  if (npoly == NULL) {
1260  rterror("rt_raster_compute_skewed_raster: Could not build extent's geometry for covers test");
1262  return NULL;
1263  }
1264 
1265  ngeom = (GEOSGeometry *) LWGEOM2GEOS(lwpoly_as_lwgeom(npoly), 0);
1266  lwpoly_free(npoly);
1267  }
1268 
1269  do {
1270  covers = 0;
1271 
1272  /* construct sgeom from raster */
1273  if ((rt_raster_get_convex_hull(raster, &geom) != ES_NONE) || geom == NULL) {
1274  rterror("rt_raster_compute_skewed_raster: Could not build skewed extent's geometry for covers test");
1275  GEOSGeom_destroy(ngeom);
1277  return NULL;
1278  }
1279 
1280  sgeom = (GEOSGeometry *) LWGEOM2GEOS(geom, 0);
1281  lwgeom_free(geom);
1282 
1283  covers = GEOSRelatePattern(sgeom, ngeom, "******FF*");
1284  GEOSGeom_destroy(sgeom);
1285 
1286  if (covers == 2) {
1287  rterror("rt_raster_compute_skewed_raster: Could not run covers test");
1288  GEOSGeom_destroy(ngeom);
1290  return NULL;
1291  }
1292 
1293  if (!covers)
1294  {
1295  raster->width++;
1296  raster->height++;
1297  }
1298  }
1299  while (!covers);
1300 
1301  RASTER_DEBUGF(4, "Skewed extent does cover normal extent with dimensions %d x %d", raster->width, raster->height);
1302 
1303  raster->width = (int) ((((double) raster->width) * fabs(_gt[1]) + fabs(scale[0] / 2.)) / fabs(scale[0]));
1304  raster->height = (int) ((((double) raster->height) * fabs(_gt[5]) + fabs(scale[1] / 2.)) / fabs(scale[1]));
1305  _gt[1] = fabs(scale[0]);
1306  _gt[5] = -1 * fabs(scale[1]);
1307  _gt[2] = skew[0];
1308  _gt[4] = skew[1];
1310 
1311  /* minimize width/height */
1312  for (i = 0; i < 2; i++) {
1313  covers = 1;
1314  do {
1315  if (i < 1)
1316  raster->width--;
1317  else
1318  raster->height--;
1319 
1320  /* construct sgeom from raster */
1321  if ((rt_raster_get_convex_hull(raster, &geom) != ES_NONE) || geom == NULL) {
1322  rterror("rt_raster_compute_skewed_raster: Could not build skewed extent's geometry for minimizing dimensions");
1323  GEOSGeom_destroy(ngeom);
1325  return NULL;
1326  }
1327 
1328  sgeom = (GEOSGeometry *) LWGEOM2GEOS(geom, 0);
1329  lwgeom_free(geom);
1330 
1331  covers = GEOSRelatePattern(sgeom, ngeom, "******FF*");
1332  GEOSGeom_destroy(sgeom);
1333 
1334  if (covers == 2) {
1335  rterror("rt_raster_compute_skewed_raster: Could not run covers test for minimizing dimensions");
1336  GEOSGeom_destroy(ngeom);
1338  return NULL;
1339  }
1340  } while (covers);
1341 
1342  if (i < 1)
1343  raster->width++;
1344  else
1345  raster->height++;
1346 
1347  }
1348 
1349  GEOSGeom_destroy(ngeom);
1350 
1351  return raster;
1352 }
1353 
1361 int
1363  return (!raster || raster->height == 0 || raster->width == 0);
1364 }
1365 
1374 int
1376  return !(NULL == raster || nband >= raster->numBands || nband < 0);
1377 }
1378 
1379 /******************************************************************************
1380 * rt_raster_copy_band()
1381 ******************************************************************************/
1382 
1397 int
1399  rt_raster torast, rt_raster fromrast,
1400  int fromindex, int toindex
1401 ) {
1402  rt_band srcband = NULL;
1403  rt_band dstband = NULL;
1404 
1405  assert(NULL != torast);
1406  assert(NULL != fromrast);
1407 
1408  /* Check raster dimensions */
1409  if (torast->height != fromrast->height || torast->width != fromrast->width) {
1410  rtwarn("rt_raster_copy_band: Attempting to add a band with different width or height");
1411  return -1;
1412  }
1413 
1414  /* Check bands limits */
1415  if (fromrast->numBands < 1) {
1416  rtwarn("rt_raster_copy_band: Second raster has no band");
1417  return -1;
1418  }
1419  else if (fromindex < 0) {
1420  rtwarn("rt_raster_copy_band: Band index for second raster < 0. Defaulted to 0");
1421  fromindex = 0;
1422  }
1423  else if (fromindex >= fromrast->numBands) {
1424  rtwarn("rt_raster_copy_band: Band index for second raster > number of bands, truncated from %u to %u", fromindex, fromrast->numBands - 1);
1425  fromindex = fromrast->numBands - 1;
1426  }
1427 
1428  if (toindex < 0) {
1429  rtwarn("rt_raster_copy_band: Band index for first raster < 0. Defaulted to 0");
1430  toindex = 0;
1431  }
1432  else if (toindex > torast->numBands) {
1433  rtwarn("rt_raster_copy_band: Band index for first raster > number of bands, truncated from %u to %u", toindex, torast->numBands);
1434  toindex = torast->numBands;
1435  }
1436 
1437  /* Get band from source raster */
1438  srcband = rt_raster_get_band(fromrast, fromindex);
1439 
1440  /* duplicate band */
1441  dstband = rt_band_duplicate(srcband);
1442 
1443  /* Add band to the second raster */
1444  return rt_raster_add_band(torast, dstband, toindex);
1445 }
1446 
1447 /******************************************************************************
1448 * rt_raster_from_band()
1449 ******************************************************************************/
1450 
1462 rt_raster
1463 rt_raster_from_band(rt_raster raster, uint32_t *bandNums, int count) {
1464  rt_raster rast = NULL;
1465  int i = 0;
1466  int j = 0;
1467  int idx;
1468  int32_t flag;
1469  double gt[6] = {0.};
1470 
1471  assert(NULL != raster);
1472  assert(NULL != bandNums);
1473 
1474  RASTER_DEBUGF(3, "rt_raster_from_band: source raster has %d bands",
1476 
1477  /* create new raster */
1478  rast = rt_raster_new(raster->width, raster->height);
1479  if (NULL == rast) {
1480  rterror("rt_raster_from_band: Out of memory allocating new raster");
1481  return NULL;
1482  }
1483 
1484  /* copy raster attributes */
1487 
1488  /* srid */
1489  rt_raster_set_srid(rast, raster->srid);
1490 
1491  /* copy bands */
1492  for (i = 0; i < count; i++) {
1493  idx = bandNums[i];
1494  flag = rt_raster_copy_band(rast, raster, idx, i);
1495 
1496  if (flag < 0) {
1497  rterror("rt_raster_from_band: Could not copy band");
1498  for (j = 0; j < i; j++) rt_band_destroy(rast->bands[j]);
1500  return NULL;
1501  }
1502 
1503  RASTER_DEBUGF(3, "rt_raster_from_band: band created at index %d",
1504  flag);
1505  }
1506 
1507  RASTER_DEBUGF(3, "rt_raster_from_band: new raster has %d bands",
1509  return rast;
1510 }
1511 
1512 /******************************************************************************
1513 * rt_raster_replace_band()
1514 ******************************************************************************/
1515 
1525 rt_band
1527  rt_band oldband = NULL;
1528  assert(NULL != raster);
1529  assert(NULL != band);
1530 
1531  if (band->width != raster->width || band->height != raster->height) {
1532  rterror("rt_raster_replace_band: Band does not match raster's dimensions: %dx%d band to %dx%d raster",
1533  band->width, band->height, raster->width, raster->height);
1534  return 0;
1535  }
1536 
1537  if (index >= raster->numBands || index < 0) {
1538  rterror("rt_raster_replace_band: Band index is not valid");
1539  return 0;
1540  }
1541 
1542  oldband = rt_raster_get_band(raster, index);
1543  RASTER_DEBUGF(3, "rt_raster_replace_band: old band at %p", oldband);
1544  RASTER_DEBUGF(3, "rt_raster_replace_band: new band at %p", band);
1545 
1546  raster->bands[index] = band;
1547  RASTER_DEBUGF(3, "rt_raster_replace_band: new band at %p", raster->bands[index]);
1548 
1549  band->raster = raster;
1550  oldband->raster = NULL;
1551 
1552  return oldband;
1553 }
1554 
1555 /******************************************************************************
1556 * rt_raster_clone()
1557 ******************************************************************************/
1558 
1567 rt_raster
1569  rt_raster rtn = NULL;
1570  double gt[6] = {0};
1571 
1572  assert(NULL != raster);
1573 
1574  if (deep) {
1575  int numband = rt_raster_get_num_bands(raster);
1576  uint32_t *nband = NULL;
1577  int i = 0;
1578 
1579  nband = rtalloc(sizeof(uint32_t) * numband);
1580  if (nband == NULL) {
1581  rterror("rt_raster_clone: Could not allocate memory for deep clone");
1582  return NULL;
1583  }
1584  for (i = 0; i < numband; i++)
1585  nband[i] = i;
1586 
1587  rtn = rt_raster_from_band(raster, nband, numband);
1588  rtdealloc(nband);
1589 
1590  return rtn;
1591  }
1592 
1593  rtn = rt_raster_new(
1596  );
1597  if (rtn == NULL) {
1598  rterror("rt_raster_clone: Could not create cloned raster");
1599  return NULL;
1600  }
1601 
1605 
1606  return rtn;
1607 }
1608 
1609 /******************************************************************************
1610 * rt_raster_copy_to_geometry()
1611 ******************************************************************************/
1612 
1615  rt_raster raster,
1616  uint32_t bandnum,
1617  char dim,
1618  rt_resample_type resample,
1619  const LWGEOM *lwgeom_in,
1620  LWGEOM **lwgeom_out
1621  )
1622 {
1623  int has_z = lwgeom_has_z(lwgeom_in);
1624  int has_m = lwgeom_has_m(lwgeom_in);
1625  LWGEOM *lwgeom;
1626  LWPOINTITERATOR* it;
1627  POINT4D p;
1628  double igt[6] = {0};
1629  rt_errorstate err;
1630  rt_band band = NULL;
1631  double nodatavalue = 0.0;
1632 
1633  /* Get the band reference and read the nodatavalue */
1634  band = rt_raster_get_band(raster, bandnum);
1635  if (!band) {
1636  rterror("unable to read requested band");
1637  return ES_ERROR;
1638  }
1639  rt_band_get_nodata(band, &nodatavalue);
1640 
1641  /* Fluff up geometry to have space for our new dimension */
1642  if (dim == 'z') {
1643  if (has_z)
1644  lwgeom = lwgeom_clone(lwgeom_in);
1645  else if (has_m)
1646  lwgeom = lwgeom_force_4d(lwgeom_in, nodatavalue, nodatavalue);
1647  else
1648  lwgeom = lwgeom_force_3dz(lwgeom_in, nodatavalue);
1649  }
1650  else if (dim == 'm') {
1651  if (has_m)
1652  lwgeom = lwgeom_clone(lwgeom_in);
1653  if (has_z)
1654  lwgeom = lwgeom_force_4d(lwgeom_in, nodatavalue, nodatavalue);
1655  else
1656  lwgeom = lwgeom_force_3dm(lwgeom_in, nodatavalue);
1657  }
1658  else {
1659  rterror("unknown value for dim");
1660  return ES_ERROR;
1661  }
1662 
1663  /* Read every point in the geometry */
1664  it = lwpointiterator_create_rw(lwgeom);
1665  while (lwpointiterator_has_next(it))
1666  {
1667  int nodata;
1668  double xr, yr, value;
1669  lwpointiterator_peek(it, &p);
1670 
1671  /* Convert X/Y world coordinates into raster coordinates */
1672  err = rt_raster_geopoint_to_rasterpoint(raster, p.x, p.y, &xr, &yr, igt);
1673  if (err != ES_NONE) continue;
1674 
1675  /* Read the raster value for this point */
1677  band,
1678  xr, yr,
1679  resample,
1680  &value, &nodata
1681  );
1682 
1683  if (err != ES_NONE) {
1684  value = NAN;
1685  }
1686 
1687  /* Copy in the raster value */
1688  if (dim == 'z')
1689  p.z = value;
1690  if (dim == 'm')
1691  p.m = value;
1692 
1694  }
1696 
1697  if (lwgeom_out)
1698  *lwgeom_out = lwgeom;
1699  return ES_NONE;
1700 }
1701 
1702 
1703 /******************************************************************************
1704 * rt_raster_to_gdal()
1705 ******************************************************************************/
1706 
1719 uint8_t*
1721  rt_raster raster, const char *srs,
1722  char *format, char **options, uint64_t *gdalsize
1723 ) {
1724  const char *cc;
1725  const char *vio;
1726 
1727  GDALDriverH src_drv = NULL;
1728  int destroy_src_drv = 0;
1729  GDALDatasetH src_ds = NULL;
1730 
1731  vsi_l_offset rtn_lenvsi;
1732  uint64_t rtn_len = 0;
1733 
1734  GDALDriverH rtn_drv = NULL;
1735  GDALDatasetH rtn_ds = NULL;
1736  uint8_t *rtn = NULL;
1737 
1738  assert(NULL != raster);
1739  assert(NULL != gdalsize);
1740 
1741  /* any supported format is possible */
1743  RASTER_DEBUG(3, "loaded all supported GDAL formats");
1744 
1745  /* output format not specified */
1746  if (format == NULL || !strlen(format))
1747  format = "GTiff";
1748  RASTER_DEBUGF(3, "output format is %s", format);
1749 
1750  /* load raster into a GDAL MEM raster */
1751  src_ds = rt_raster_to_gdal_mem(raster, srs, NULL, NULL, 0, &src_drv, &destroy_src_drv);
1752  if (NULL == src_ds) {
1753  rterror("rt_raster_to_gdal: Could not convert raster to GDAL MEM format");
1754  return 0;
1755  }
1756 
1757  /* load driver */
1758  rtn_drv = GDALGetDriverByName(format);
1759  if (NULL == rtn_drv) {
1760  rterror("rt_raster_to_gdal: Could not load the output GDAL driver");
1761  GDALClose(src_ds);
1762  if (destroy_src_drv) GDALDestroyDriver(src_drv);
1763  return 0;
1764  }
1765  RASTER_DEBUG(3, "Output driver loaded");
1766 
1767  /* CreateCopy support */
1768  cc = GDALGetMetadataItem(rtn_drv, GDAL_DCAP_CREATECOPY, NULL);
1769  /* VirtualIO support */
1770  vio = GDALGetMetadataItem(rtn_drv, GDAL_DCAP_VIRTUALIO, NULL);
1771 
1772  if (cc == NULL || vio == NULL) {
1773  rterror("rt_raster_to_gdal: Output GDAL driver does not support CreateCopy and/or VirtualIO");
1774  GDALClose(src_ds);
1775  if (destroy_src_drv) GDALDestroyDriver(src_drv);
1776  return 0;
1777  }
1778 
1779  /* convert GDAL MEM raster to output format */
1780  RASTER_DEBUG(3, "Copying GDAL MEM raster to memory file in output format");
1781  rtn_ds = GDALCreateCopy(
1782  rtn_drv,
1783  "/vsimem/out.dat", /* should be fine assuming this is in a process */
1784  src_ds,
1785  FALSE, /* should copy be strictly equivelent? */
1786  options, /* format options */
1787  NULL, /* progress function */
1788  NULL /* progress data */
1789  );
1790 
1791  /* close source dataset */
1792  GDALClose(src_ds);
1793  if (destroy_src_drv) GDALDestroyDriver(src_drv);
1794  RASTER_DEBUG(3, "Closed GDAL MEM raster");
1795 
1796  if (NULL == rtn_ds) {
1797  rterror("rt_raster_to_gdal: Could not create the output GDAL dataset");
1798  return 0;
1799  }
1800 
1801  RASTER_DEBUGF(4, "dataset SRS: %s", GDALGetProjectionRef(rtn_ds));
1802 
1803  /* close dataset, this also flushes any pending writes */
1804  GDALClose(rtn_ds);
1805  RASTER_DEBUG(3, "Closed GDAL output raster");
1806 
1807  RASTER_DEBUG(3, "Done copying GDAL MEM raster to memory file in output format");
1808 
1809  /* from memory file to buffer */
1810  RASTER_DEBUG(3, "Copying GDAL memory file to buffer");
1811  rtn = VSIGetMemFileBuffer("/vsimem/out.dat", &rtn_lenvsi, TRUE);
1812  RASTER_DEBUG(3, "Done copying GDAL memory file to buffer");
1813  if (NULL == rtn) {
1814  rterror("rt_raster_to_gdal: Could not create the output GDAL raster");
1815  return 0;
1816  }
1817 
1818  rtn_len = (uint64_t) rtn_lenvsi;
1819  *gdalsize = rtn_len;
1820 
1821  return rtn;
1822 }
1823 
1824 /******************************************************************************
1825 * rt_raster_gdal_drivers()
1826 ******************************************************************************/
1827 
1838 rt_raster_gdal_drivers(uint32_t *drv_count, uint8_t can_write)
1839 {
1840  assert(drv_count != NULL);
1841  uint32_t output_driver = 0;
1843  uint32_t count = (uint32_t)GDALGetDriverCount();
1844 
1845  rt_gdaldriver rtn = (rt_gdaldriver)rtalloc(count * sizeof(struct rt_gdaldriver_t));
1846  if (!rtn)
1847  {
1848  rterror("rt_raster_gdal_drivers: Could not allocate memory for gdaldriver structure");
1849  *drv_count = output_driver;
1850  return NULL;
1851  }
1852 
1853  for (uint32_t i = 0; i < count; i++)
1854  {
1855  GDALDriverH *drv = GDALGetDriver(i);
1856 
1857 #ifdef GDAL_DCAP_RASTER
1858  /* Starting with GDAL 2.0, vector drivers can also be returned */
1859  /* Only keep raster drivers */
1860  const char *is_raster;
1861  is_raster = GDALGetMetadataItem(drv, GDAL_DCAP_RASTER, NULL);
1862  if (!is_raster || !EQUAL(is_raster, "YES"))
1863  continue;
1864 #endif
1865 
1866  /* CreateCopy support */
1867  const char *cc = GDALGetMetadataItem(drv, GDAL_DCAP_CREATECOPY, NULL);
1868  if (can_write && !cc)
1869  continue;
1870 
1871  /* VirtualIO support */
1872  const char *vio = GDALGetMetadataItem(drv, GDAL_DCAP_VIRTUALIO, NULL);
1873  if (can_write && !vio)
1874  continue;
1875 
1876  /* we can always read what GDAL can load */
1877  rtn[output_driver].can_read = 1;
1878  /* we require CreateCopy and VirtualIO support to write to GDAL */
1879  rtn[output_driver].can_write = (cc != NULL && vio != NULL);
1880 
1881  /* index of driver */
1882  rtn[output_driver].idx = i;
1883 
1884  /* short name */
1885  const char *txt = GDALGetDriverShortName(drv);
1886  size_t txt_len = strlen(txt);
1887  txt_len = (txt_len + 1) * sizeof(char);
1888  rtn[output_driver].short_name = (char *)rtalloc(txt_len);
1889  memcpy(rtn[output_driver].short_name, txt, txt_len);
1890 
1891  /* long name */
1892  txt = GDALGetDriverLongName(drv);
1893  txt_len = strlen(txt);
1894  txt_len = (txt_len + 1) * sizeof(char);
1895  rtn[output_driver].long_name = (char *)rtalloc(txt_len);
1896  memcpy(rtn[output_driver].long_name, txt, txt_len);
1897 
1898  /* creation options */
1899  txt = GDALGetDriverCreationOptionList(drv);
1900  txt_len = strlen(txt);
1901  txt_len = (txt_len + 1) * sizeof(char);
1902  rtn[output_driver].create_options = (char *)rtalloc(txt_len);
1903  memcpy(rtn[output_driver].create_options, txt, txt_len);
1904 
1905  output_driver++;
1906  }
1907 
1908  /* free unused memory */
1909  rtn = rtrealloc(rtn, output_driver * sizeof(struct rt_gdaldriver_t));
1910  *drv_count = output_driver;
1911 
1912  return rtn;
1913 }
1914 
1915 /******************************************************************************
1916 * rt_raster_to_gdal_mem()
1917 ******************************************************************************/
1918 
1934 GDALDatasetH
1936  rt_raster raster,
1937  const char *srs,
1938  uint32_t *bandNums,
1939  int *excludeNodataValues,
1940  int count,
1941  GDALDriverH *rtn_drv, int *destroy_rtn_drv
1942 ) {
1943  GDALDriverH drv = NULL;
1944  GDALDatasetH ds = NULL;
1945  double gt[6] = {0.0};
1946  CPLErr cplerr;
1947  GDALDataType gdal_pt = GDT_Unknown;
1948  GDALRasterBandH band;
1949  void *pVoid;
1950  char *pszDataPointer;
1951  char szGDALOption[50];
1952  char *apszOptions[4];
1953  double nodata = 0.0;
1954  int allocBandNums = 0;
1955  int allocNodataValues = 0;
1956 
1957  int i;
1958  uint32_t numBands;
1959  uint32_t width = 0;
1960  uint32_t height = 0;
1961  rt_band rtband = NULL;
1962  rt_pixtype pt = PT_END;
1963 
1964  assert(NULL != raster);
1965  assert(NULL != rtn_drv);
1966  assert(NULL != destroy_rtn_drv);
1967 
1968  *destroy_rtn_drv = 0;
1969 
1970  /* store raster in GDAL MEM raster */
1971  if (!rt_util_gdal_driver_registered("MEM")) {
1972  RASTER_DEBUG(4, "Registering MEM driver");
1973  GDALRegister_MEM();
1974  *destroy_rtn_drv = 1;
1975  }
1976  drv = GDALGetDriverByName("MEM");
1977  if (NULL == drv) {
1978  rterror("rt_raster_to_gdal_mem: Could not load the MEM GDAL driver");
1979  return 0;
1980  }
1981  *rtn_drv = drv;
1982 
1983  /* unload driver from GDAL driver manager */
1984  if (*destroy_rtn_drv) {
1985  RASTER_DEBUG(4, "Deregistering MEM driver");
1986  GDALDeregisterDriver(drv);
1987  }
1988 
1989  width = rt_raster_get_width(raster);
1990  height = rt_raster_get_height(raster);
1991  ds = GDALCreate(
1992  drv, "",
1993  width, height,
1994  0, GDT_Byte, NULL
1995  );
1996  if (NULL == ds) {
1997  rterror("rt_raster_to_gdal_mem: Could not create a GDALDataset to convert into");
1998  return 0;
1999  }
2000 
2001  /* add geotransform */
2003  cplerr = GDALSetGeoTransform(ds, gt);
2004  if (cplerr != CE_None) {
2005  rterror("rt_raster_to_gdal_mem: Could not set geotransformation");
2006  GDALClose(ds);
2007  return 0;
2008  }
2009 
2010  /* set spatial reference */
2011  if (NULL != srs && strlen(srs)) {
2012  char *_srs = rt_util_gdal_convert_sr(srs, 0);
2013  if (_srs == NULL) {
2014  rterror("rt_raster_to_gdal_mem: Could not convert srs to GDAL accepted format");
2015  GDALClose(ds);
2016  return 0;
2017  }
2018 
2019  cplerr = GDALSetProjection(ds, _srs);
2020  CPLFree(_srs);
2021  if (cplerr != CE_None) {
2022  rterror("rt_raster_to_gdal_mem: Could not set projection");
2023  GDALClose(ds);
2024  return 0;
2025  }
2026  RASTER_DEBUGF(3, "Projection set to: %s", GDALGetProjectionRef(ds));
2027  }
2028 
2029  /* process bandNums */
2030  numBands = rt_raster_get_num_bands(raster);
2031  if (NULL != bandNums && count > 0) {
2032  for (i = 0; i < count; i++) {
2033  if (bandNums[i] >= numBands) {
2034  rterror("rt_raster_to_gdal_mem: The band index %d is invalid", bandNums[i]);
2035  GDALClose(ds);
2036  return 0;
2037  }
2038  }
2039  }
2040  else {
2041  count = numBands;
2042  bandNums = (uint32_t *) rtalloc(sizeof(uint32_t) * count);
2043  if (NULL == bandNums) {
2044  rterror("rt_raster_to_gdal_mem: Could not allocate memory for band indices");
2045  GDALClose(ds);
2046  return 0;
2047  }
2048  allocBandNums = 1;
2049  for (i = 0; i < count; i++) bandNums[i] = i;
2050  }
2051 
2052  /* process exclude_nodata_values */
2053  if (NULL == excludeNodataValues) {
2054  excludeNodataValues = (int *) rtalloc(sizeof(int) * count);
2055  if (NULL == excludeNodataValues) {
2056  rterror("rt_raster_to_gdal_mem: Could not allocate memory for NODATA flags");
2057  GDALClose(ds);
2058  return 0;
2059  }
2060  allocNodataValues = 1;
2061  for (i = 0; i < count; i++) excludeNodataValues[i] = 1;
2062  }
2063 
2064  /* add band(s) */
2065  for (i = 0; i < count; i++) {
2066  rtband = rt_raster_get_band(raster, bandNums[i]);
2067  if (NULL == rtband) {
2068  rterror("rt_raster_to_gdal_mem: Could not get requested band index %d", bandNums[i]);
2069  if (allocBandNums) rtdealloc(bandNums);
2070  if (allocNodataValues) rtdealloc(excludeNodataValues);
2071  GDALClose(ds);
2072  return 0;
2073  }
2074 
2075  pt = rt_band_get_pixtype(rtband);
2076  gdal_pt = rt_util_pixtype_to_gdal_datatype(pt);
2077  if (gdal_pt == GDT_Unknown)
2078  rtwarn("rt_raster_to_gdal_mem: Unknown pixel type for band");
2079 
2080  /*
2081  For all pixel types other than PT_8BSI, set pointer to start of data
2082  */
2083  if (pt != PT_8BSI) {
2084  pVoid = rt_band_get_data(rtband);
2085  RASTER_DEBUGF(4, "Band data is at pos %p", pVoid);
2086 
2087  pszDataPointer = (char *) rtalloc(20 * sizeof (char));
2088  sprintf(pszDataPointer, "%p", pVoid);
2089  RASTER_DEBUGF(4, "rt_raster_to_gdal_mem: szDatapointer is %p",
2090  pszDataPointer);
2091 
2092  if (strncasecmp(pszDataPointer, "0x", 2) == 0)
2093  sprintf(szGDALOption, "DATAPOINTER=%s", pszDataPointer);
2094  else
2095  sprintf(szGDALOption, "DATAPOINTER=0x%s", pszDataPointer);
2096 
2097  RASTER_DEBUG(3, "Storing info for GDAL MEM raster band");
2098 
2099  apszOptions[0] = szGDALOption;
2100  apszOptions[1] = NULL; /* pixel offset, not needed */
2101  apszOptions[2] = NULL; /* line offset, not needed */
2102  apszOptions[3] = NULL;
2103 
2104  /* free */
2105  rtdealloc(pszDataPointer);
2106 
2107  /* add band */
2108  if (GDALAddBand(ds, gdal_pt, apszOptions) == CE_Failure) {
2109  rterror("rt_raster_to_gdal_mem: Could not add GDAL raster band");
2110  if (allocBandNums) rtdealloc(bandNums);
2111  GDALClose(ds);
2112  return 0;
2113  }
2114  }
2115  /*
2116  PT_8BSI is special as GDAL has no equivalent pixel type.
2117  Must convert 8BSI to 16BSI so create basic band
2118  */
2119  else {
2120  /* add band */
2121  if (GDALAddBand(ds, gdal_pt, NULL) == CE_Failure) {
2122  rterror("rt_raster_to_gdal_mem: Could not add GDAL raster band");
2123  if (allocBandNums) rtdealloc(bandNums);
2124  if (allocNodataValues) rtdealloc(excludeNodataValues);
2125  GDALClose(ds);
2126  return 0;
2127  }
2128  }
2129 
2130  /* check band count */
2131  if (GDALGetRasterCount(ds) != i + 1) {
2132  rterror("rt_raster_to_gdal_mem: Error creating GDAL MEM raster band");
2133  if (allocBandNums) rtdealloc(bandNums);
2134  if (allocNodataValues) rtdealloc(excludeNodataValues);
2135  GDALClose(ds);
2136  return 0;
2137  }
2138 
2139  /* get new band */
2140  band = NULL;
2141  band = GDALGetRasterBand(ds, i + 1);
2142  if (NULL == band) {
2143  rterror("rt_raster_to_gdal_mem: Could not get GDAL band for additional processing");
2144  if (allocBandNums) rtdealloc(bandNums);
2145  if (allocNodataValues) rtdealloc(excludeNodataValues);
2146  GDALClose(ds);
2147  return 0;
2148  }
2149 
2150  /* PT_8BSI requires manual setting of pixels */
2151  if (pt == PT_8BSI) {
2152  uint32_t nXBlocks, nYBlocks;
2153  int nXBlockSize, nYBlockSize;
2154  uint32_t iXBlock, iYBlock;
2155  int nXValid, nYValid;
2156  int iX, iY;
2157  int iXMax, iYMax;
2158 
2159  int x, y, z;
2160  uint32_t valueslen = 0;
2161  int16_t *values = NULL;
2162  double value = 0.;
2163 
2164  /* this makes use of GDAL's "natural" blocks */
2165  GDALGetBlockSize(band, &nXBlockSize, &nYBlockSize);
2166  nXBlocks = (width + nXBlockSize - 1) / nXBlockSize;
2167  nYBlocks = (height + nYBlockSize - 1) / nYBlockSize;
2168  RASTER_DEBUGF(4, "(nXBlockSize, nYBlockSize) = (%d, %d)", nXBlockSize, nYBlockSize);
2169  RASTER_DEBUGF(4, "(nXBlocks, nYBlocks) = (%d, %d)", nXBlocks, nYBlocks);
2170 
2171  /* length is for the desired pixel type */
2172  valueslen = rt_pixtype_size(PT_16BSI) * nXBlockSize * nYBlockSize;
2173  values = rtalloc(valueslen);
2174  if (NULL == values) {
2175  rterror("rt_raster_to_gdal_mem: Could not allocate memory for GDAL band pixel values");
2176  if (allocBandNums) rtdealloc(bandNums);
2177  if (allocNodataValues) rtdealloc(excludeNodataValues);
2178  GDALClose(ds);
2179  return 0;
2180  }
2181 
2182  for (iYBlock = 0; iYBlock < nYBlocks; iYBlock++) {
2183  for (iXBlock = 0; iXBlock < nXBlocks; iXBlock++) {
2184  memset(values, 0, valueslen);
2185 
2186  x = iXBlock * nXBlockSize;
2187  y = iYBlock * nYBlockSize;
2188  RASTER_DEBUGF(4, "(iXBlock, iYBlock) = (%d, %d)", iXBlock, iYBlock);
2189  RASTER_DEBUGF(4, "(x, y) = (%d, %d)", x, y);
2190 
2191  /* valid block width */
2192  if ((iXBlock + 1) * nXBlockSize > width)
2193  nXValid = width - (iXBlock * nXBlockSize);
2194  else
2195  nXValid = nXBlockSize;
2196 
2197  /* valid block height */
2198  if ((iYBlock + 1) * nYBlockSize > height)
2199  nYValid = height - (iYBlock * nYBlockSize);
2200  else
2201  nYValid = nYBlockSize;
2202 
2203  RASTER_DEBUGF(4, "(nXValid, nYValid) = (%d, %d)", nXValid, nYValid);
2204 
2205  /* convert 8BSI values to 16BSI */
2206  z = 0;
2207  iYMax = y + nYValid;
2208  iXMax = x + nXValid;
2209  for (iY = y; iY < iYMax; iY++) {
2210  for (iX = x; iX < iXMax; iX++) {
2211  if (rt_band_get_pixel(rtband, iX, iY, &value, NULL) != ES_NONE) {
2212  rterror("rt_raster_to_gdal_mem: Could not get pixel value to convert from 8BSI to 16BSI");
2213  rtdealloc(values);
2214  if (allocBandNums) rtdealloc(bandNums);
2215  if (allocNodataValues) rtdealloc(excludeNodataValues);
2216  GDALClose(ds);
2217  return 0;
2218  }
2219 
2220  values[z++] = rt_util_clamp_to_16BSI(value);
2221  }
2222  }
2223 
2224  /* burn values */
2225  if (GDALRasterIO(
2226  band, GF_Write,
2227  x, y,
2228  nXValid, nYValid,
2229  values, nXValid, nYValid,
2230  gdal_pt,
2231  0, 0
2232  ) != CE_None) {
2233  rterror("rt_raster_to_gdal_mem: Could not write converted 8BSI to 16BSI values to GDAL band");
2234  rtdealloc(values);
2235  if (allocBandNums) rtdealloc(bandNums);
2236  if (allocNodataValues) rtdealloc(excludeNodataValues);
2237  GDALClose(ds);
2238  return 0;
2239  }
2240  }
2241  }
2242 
2243  rtdealloc(values);
2244  }
2245 
2246  /* Add nodata value for band */
2247  if (rt_band_get_hasnodata_flag(rtband) != FALSE && excludeNodataValues[i]) {
2248  rt_band_get_nodata(rtband, &nodata);
2249  if (GDALSetRasterNoDataValue(band, nodata) != CE_None)
2250  rtwarn("rt_raster_to_gdal_mem: Could not set nodata value for band");
2251  RASTER_DEBUGF(3, "nodata value set to %f", GDALGetRasterNoDataValue(band, NULL));
2252  }
2253 
2254 #if POSTGIS_DEBUG_LEVEL > 3
2255  {
2256  GDALRasterBandH _grb = NULL;
2257  double _min;
2258  double _max;
2259  double _mean;
2260  double _stddev;
2261 
2262  _grb = GDALGetRasterBand(ds, i + 1);
2263  GDALComputeRasterStatistics(_grb, FALSE, &_min, &_max, &_mean, &_stddev, NULL, NULL);
2264  RASTER_DEBUGF(4, "GDAL Band %d stats: %f, %f, %f, %f", i + 1, _min, _max, _mean, _stddev);
2265  }
2266 #endif
2267 
2268  }
2269 
2270  /* necessary??? */
2271  GDALFlushCache(ds);
2272 
2273  if (allocBandNums) rtdealloc(bandNums);
2274  if (allocNodataValues) rtdealloc(excludeNodataValues);
2275 
2276  return ds;
2277 }
2278 
2279 /******************************************************************************
2280 * rt_raster_from_gdal_dataset()
2281 ******************************************************************************/
2282 
2290 rt_raster
2292  rt_raster rast = NULL;
2293  double gt[6] = {0};
2294  CPLErr cplerr;
2295  uint32_t width = 0;
2296  uint32_t height = 0;
2297  uint32_t numBands = 0;
2298  uint32_t i = 0;
2299  char *authname = NULL;
2300  char *authcode = NULL;
2301 
2302  GDALRasterBandH gdband = NULL;
2303  GDALDataType gdpixtype = GDT_Unknown;
2304  rt_band band;
2305  int32_t idx;
2306  rt_pixtype pt = PT_END;
2307  uint32_t ptlen = 0;
2308  int hasnodata = 0;
2309  double nodataval;
2310 
2311  int x;
2312  int y;
2313 
2314  uint32_t nXBlocks, nYBlocks;
2315  int nXBlockSize, nYBlockSize;
2316  uint32_t iXBlock, iYBlock;
2317  uint32_t nXValid, nYValid;
2318  uint32_t iY;
2319 
2320  uint8_t *values = NULL;
2321  uint32_t valueslen = 0;
2322  uint8_t *ptr = NULL;
2323 
2324  assert(NULL != ds);
2325 
2326  /* raster size */
2327  width = GDALGetRasterXSize(ds);
2328  height = GDALGetRasterYSize(ds);
2329  RASTER_DEBUGF(3, "Raster dimensions (width x height): %d x %d", width, height);
2330 
2331  /* create new raster */
2332  RASTER_DEBUG(3, "Creating new raster");
2333  rast = rt_raster_new(width, height);
2334  if (NULL == rast) {
2335  rterror("rt_raster_from_gdal_dataset: Out of memory allocating new raster");
2336  return NULL;
2337  }
2338  RASTER_DEBUGF(3, "Created raster dimensions (width x height): %d x %d", rast->width, rast->height);
2339 
2340  /* get raster attributes */
2341  cplerr = GDALGetGeoTransform(ds, gt);
2342  if (GDALGetGeoTransform(ds, gt) != CE_None) {
2343  RASTER_DEBUG(4, "Using default geotransform matrix (0, 1, 0, 0, 0, -1)");
2344  gt[0] = 0;
2345  gt[1] = 1;
2346  gt[2] = 0;
2347  gt[3] = 0;
2348  gt[4] = 0;
2349  gt[5] = -1;
2350  }
2351 
2352  /* apply raster attributes */
2354 
2355  RASTER_DEBUGF(3, "Raster geotransform (%f, %f, %f, %f, %f, %f)",
2356  gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
2357 
2358  /* srid */
2359  if (rt_util_gdal_sr_auth_info(ds, &authname, &authcode) == ES_NONE) {
2360  if (
2361  authname != NULL &&
2362  strcmp(authname, "EPSG") == 0 &&
2363  authcode != NULL
2364  ) {
2365  rt_raster_set_srid(rast, atoi(authcode));
2366  RASTER_DEBUGF(3, "New raster's SRID = %d", rast->srid);
2367  }
2368 
2369  if (authname != NULL)
2370  rtdealloc(authname);
2371  if (authcode != NULL)
2372  rtdealloc(authcode);
2373  }
2374 
2375  numBands = GDALGetRasterCount(ds);
2376 
2377 #if POSTGIS_DEBUG_LEVEL > 3
2378  for (i = 1; i <= numBands; i++) {
2379  GDALRasterBandH _grb = NULL;
2380  double _min;
2381  double _max;
2382  double _mean;
2383  double _stddev;
2384 
2385  _grb = GDALGetRasterBand(ds, i);
2386  GDALComputeRasterStatistics(_grb, FALSE, &_min, &_max, &_mean, &_stddev, NULL, NULL);
2387  RASTER_DEBUGF(4, "GDAL Band %d stats: %f, %f, %f, %f", i, _min, _max, _mean, _stddev);
2388  }
2389 #endif
2390 
2391  /* copy bands */
2392  for (i = 1; i <= numBands; i++) {
2393  RASTER_DEBUGF(3, "Processing band %d of %d", i, numBands);
2394  gdband = NULL;
2395  gdband = GDALGetRasterBand(ds, i);
2396  if (NULL == gdband) {
2397  rterror("rt_raster_from_gdal_dataset: Could not get GDAL band");
2399  return NULL;
2400  }
2401  RASTER_DEBUGF(4, "gdband @ %p", gdband);
2402 
2403  /* pixtype */
2404  gdpixtype = GDALGetRasterDataType(gdband);
2405  RASTER_DEBUGF(4, "gdpixtype, size = %s, %d", GDALGetDataTypeName(gdpixtype), GDALGetDataTypeSize(gdpixtype) / 8);
2406  pt = rt_util_gdal_datatype_to_pixtype(gdpixtype);
2407  if (pt == PT_END) {
2408  rterror("rt_raster_from_gdal_dataset: Unknown pixel type for GDAL band");
2410  return NULL;
2411  }
2412  ptlen = rt_pixtype_size(pt);
2413 
2414  /* size: width and height */
2415  width = GDALGetRasterBandXSize(gdband);
2416  height = GDALGetRasterBandYSize(gdband);
2417  RASTER_DEBUGF(3, "GDAL band dimensions (width x height): %d x %d", width, height);
2418 
2419  /* nodata */
2420  nodataval = GDALGetRasterNoDataValue(gdband, &hasnodata);
2421  RASTER_DEBUGF(3, "(hasnodata, nodataval) = (%d, %f)", hasnodata, nodataval);
2422 
2423  /* create band object */
2425  rast, pt,
2426  (hasnodata ? nodataval : 0),
2427  hasnodata, nodataval, rt_raster_get_num_bands(rast)
2428  );
2429  if (idx < 0) {
2430  rterror("rt_raster_from_gdal_dataset: Could not allocate memory for raster band");
2432  return NULL;
2433  }
2434  band = rt_raster_get_band(rast, idx);
2435  RASTER_DEBUGF(3, "Created band of dimension (width x height): %d x %d", band->width, band->height);
2436 
2437  /* this makes use of GDAL's "natural" blocks */
2438  GDALGetBlockSize(gdband, &nXBlockSize, &nYBlockSize);
2439  nXBlocks = (width + nXBlockSize - 1) / nXBlockSize;
2440  nYBlocks = (height + nYBlockSize - 1) / nYBlockSize;
2441  RASTER_DEBUGF(4, "(nXBlockSize, nYBlockSize) = (%d, %d)", nXBlockSize, nYBlockSize);
2442  RASTER_DEBUGF(4, "(nXBlocks, nYBlocks) = (%d, %d)", nXBlocks, nYBlocks);
2443 
2444  /* allocate memory for values */
2445  valueslen = ptlen * nXBlockSize * nYBlockSize;
2446  values = rtalloc(valueslen);
2447  if (values == NULL) {
2448  rterror("rt_raster_from_gdal_dataset: Could not allocate memory for GDAL band pixel values");
2450  return NULL;
2451  }
2452  RASTER_DEBUGF(3, "values @ %p of length = %d", values, valueslen);
2453 
2454  for (iYBlock = 0; iYBlock < nYBlocks; iYBlock++) {
2455  for (iXBlock = 0; iXBlock < nXBlocks; iXBlock++) {
2456  x = iXBlock * nXBlockSize;
2457  y = iYBlock * nYBlockSize;
2458  RASTER_DEBUGF(4, "(iXBlock, iYBlock) = (%d, %d)", iXBlock, iYBlock);
2459  RASTER_DEBUGF(4, "(x, y) = (%d, %d)", x, y);
2460 
2461  memset(values, 0, valueslen);
2462 
2463  /* valid block width */
2464  if ((iXBlock + 1) * nXBlockSize > width)
2465  nXValid = width - (iXBlock * nXBlockSize);
2466  else
2467  nXValid = nXBlockSize;
2468 
2469  /* valid block height */
2470  if ((iYBlock + 1) * nYBlockSize > height)
2471  nYValid = height - (iYBlock * nYBlockSize);
2472  else
2473  nYValid = nYBlockSize;
2474 
2475  RASTER_DEBUGF(4, "(nXValid, nYValid) = (%d, %d)", nXValid, nYValid);
2476 
2477  cplerr = GDALRasterIO(
2478  gdband, GF_Read,
2479  x, y,
2480  nXValid, nYValid,
2481  values, nXValid, nYValid,
2482  gdpixtype,
2483  0, 0
2484  );
2485  if (cplerr != CE_None) {
2486  rterror("rt_raster_from_gdal_dataset: Could not get data from GDAL raster");
2487  rtdealloc(values);
2489  return NULL;
2490  }
2491 
2492  /* if block width is same as raster width, shortcut */
2493  if (nXBlocks == 1 && nYBlockSize > 1 && nXValid == width) {
2494  x = 0;
2495  y = nYBlockSize * iYBlock;
2496 
2497  RASTER_DEBUGF(4, "Setting set of pixel lines at (%d, %d) for %d pixels", x, y, nXValid * nYValid);
2498  rt_band_set_pixel_line(band, x, y, values, nXValid * nYValid);
2499  }
2500  else {
2501  ptr = values;
2502  x = nXBlockSize * iXBlock;
2503  for (iY = 0; iY < nYValid; iY++) {
2504  y = iY + (nYBlockSize * iYBlock);
2505 
2506  RASTER_DEBUGF(4, "Setting pixel line at (%d, %d) for %d pixels", x, y, nXValid);
2507  rt_band_set_pixel_line(band, x, y, ptr, nXValid);
2508  ptr += (nXValid * ptlen);
2509  }
2510  }
2511  }
2512  }
2513 
2514  /* free memory */
2515  rtdealloc(values);
2516  }
2517 
2518  return rast;
2519 }
2520 
2521 /******************************************************************************
2522 * rt_raster_gdal_rasterize()
2523 ******************************************************************************/
2524 
2527  uint8_t noband;
2528 
2529  uint32_t numbands;
2530 
2531  OGRSpatialReferenceH src_sr;
2532 
2534  double *init;
2535  double *nodata;
2536  uint8_t *hasnodata;
2537  double *value;
2538  int *bandlist;
2539 };
2540 
2541 static _rti_rasterize_arg
2543  _rti_rasterize_arg arg = NULL;
2544 
2545  arg = rtalloc(sizeof(struct _rti_rasterize_arg_t));
2546  if (arg == NULL) {
2547  rterror("_rti_rasterize_arg_init: Could not allocate memory for _rti_rasterize_arg");
2548  return NULL;
2549  }
2550 
2551  arg->noband = 0;
2552 
2553  arg->numbands = 0;
2554 
2555  arg->src_sr = NULL;
2556 
2557  arg->pixtype = NULL;
2558  arg->init = NULL;
2559  arg->nodata = NULL;
2560  arg->hasnodata = NULL;
2561  arg->value = NULL;
2562  arg->bandlist = NULL;
2563 
2564  return arg;
2565 }
2566 
2567 static void
2569  if (arg->noband) {
2570  if (arg->pixtype != NULL)
2571  rtdealloc(arg->pixtype);
2572  if (arg->init != NULL)
2573  rtdealloc(arg->init);
2574  if (arg->nodata != NULL)
2575  rtdealloc(arg->nodata);
2576  if (arg->hasnodata != NULL)
2577  rtdealloc(arg->hasnodata);
2578  if (arg->value != NULL)
2579  rtdealloc(arg->value);
2580  }
2581 
2582  if (arg->bandlist != NULL)
2583  rtdealloc(arg->bandlist);
2584 
2585  if (arg->src_sr != NULL)
2586  OSRDestroySpatialReference(arg->src_sr);
2587 
2588  rtdealloc(arg);
2589 }
2590 
2617 rt_raster
2619  const unsigned char *wkb, uint32_t wkb_len,
2620  const char *srs,
2621  uint32_t num_bands, rt_pixtype *pixtype,
2622  double *init, double *value,
2623  double *nodata, uint8_t *hasnodata,
2624  int *width, int *height,
2625  double *scale_x, double *scale_y,
2626  double *ul_xw, double *ul_yw,
2627  double *grid_xw, double *grid_yw,
2628  double *skew_x, double *skew_y,
2629  char **options
2630 ) {
2631  rt_raster rast = NULL;
2632  uint32_t i = 0;
2633  int err = 0;
2634 
2635  _rti_rasterize_arg arg = NULL;
2636 
2637  int _dim[2] = {0};
2638  double _scale[2] = {0};
2639  double _skew[2] = {0};
2640 
2641  OGRErr ogrerr;
2642  OGRGeometryH src_geom;
2643  OGREnvelope src_env;
2644  rt_envelope extent;
2645  OGRwkbGeometryType wkbtype = wkbUnknown;
2646 
2647  int ul_user = 0;
2648 
2649  CPLErr cplerr;
2650  double _gt[6] = {0};
2651  GDALDriverH _drv = NULL;
2652  int unload_drv = 0;
2653  GDALDatasetH _ds = NULL;
2654  GDALRasterBandH _band = NULL;
2655 
2656  uint16_t _width = 0;
2657  uint16_t _height = 0;
2658 
2659  RASTER_DEBUG(3, "starting");
2660 
2661  assert(NULL != wkb);
2662  assert(0 != wkb_len);
2663 
2664  /* internal variables */
2665  arg = _rti_rasterize_arg_init();
2666  if (arg == NULL) {
2667  rterror("rt_raster_gdal_rasterize: Could not initialize internal variables");
2668  return NULL;
2669  }
2670 
2671  /* no bands, raster is a mask */
2672  if (num_bands < 1) {
2673  arg->noband = 1;
2674  arg->numbands = 1;
2675 
2676  arg->pixtype = (rt_pixtype *) rtalloc(sizeof(rt_pixtype));
2677  arg->pixtype[0] = PT_8BUI;
2678 
2679  arg->init = (double *) rtalloc(sizeof(double));
2680  arg->init[0] = 0;
2681 
2682  arg->nodata = (double *) rtalloc(sizeof(double));
2683  arg->nodata[0] = 0;
2684 
2685  arg->hasnodata = (uint8_t *) rtalloc(sizeof(uint8_t));
2686  arg->hasnodata[0] = 1;
2687 
2688  arg->value = (double *) rtalloc(sizeof(double));
2689  arg->value[0] = 1;
2690  }
2691  else {
2692  arg->noband = 0;
2693  arg->numbands = num_bands;
2694 
2695  arg->pixtype = pixtype;
2696  arg->init = init;
2697  arg->nodata = nodata;
2698  arg->hasnodata = hasnodata;
2699  arg->value = value;
2700  }
2701 
2702  /* OGR spatial reference */
2703  if (NULL != srs && strlen(srs)) {
2704  arg->src_sr = OSRNewSpatialReference(NULL);
2705  if (OSRSetFromUserInput(arg->src_sr, srs) != OGRERR_NONE) {
2706  rterror("rt_raster_gdal_rasterize: Could not create OSR spatial reference using the provided srs: %s", srs);
2708  return NULL;
2709  }
2710  }
2711 
2712  /* convert WKB to OGR Geometry */
2713  ogrerr = OGR_G_CreateFromWkb((unsigned char *) wkb, arg->src_sr, &src_geom, wkb_len);
2714  if (ogrerr != OGRERR_NONE) {
2715  rterror("rt_raster_gdal_rasterize: Could not create OGR Geometry from WKB");
2716 
2718  /* OGRCleanupAll(); */
2719 
2720  return NULL;
2721  }
2722 
2723  /* OGR Geometry is empty */
2724  if (OGR_G_IsEmpty(src_geom)) {
2725  rtinfo("Geometry provided is empty. Returning empty raster");
2726 
2727  OGR_G_DestroyGeometry(src_geom);
2729  /* OGRCleanupAll(); */
2730 
2731  return rt_raster_new(0, 0);
2732  }
2733 
2734  /* get envelope */
2735  OGR_G_GetEnvelope(src_geom, &src_env);
2736  rt_util_from_ogr_envelope(src_env, &extent);
2737 
2738  RASTER_DEBUGF(3, "Suggested raster envelope: %f, %f, %f, %f",
2739  extent.MinX, extent.MinY, extent.MaxX, extent.MaxY);
2740 
2741  /* user-defined scale */
2742  if (
2743  (NULL != scale_x) &&
2744  (NULL != scale_y) &&
2745  (FLT_NEQ(*scale_x, 0.0)) &&
2746  (FLT_NEQ(*scale_y, 0.0))
2747  ) {
2748  /* for now, force scale to be in left-right, top-down orientation */
2749  _scale[0] = fabs(*scale_x);
2750  _scale[1] = fabs(*scale_y);
2751  }
2752  /* user-defined width/height */
2753  else if ((NULL != width) && (NULL != height) && (*width != 0) && (*height != 0))
2754  {
2755  _dim[0] = abs(*width);
2756  _dim[1] = abs(*height);
2757 
2758  if (FLT_NEQ(extent.MaxX, extent.MinX))
2759  _scale[0] = fabs((extent.MaxX - extent.MinX) / _dim[0]);
2760  else
2761  _scale[0] = 1.;
2762 
2763  if (FLT_NEQ(extent.MaxY, extent.MinY))
2764  _scale[1] = fabs((extent.MaxY - extent.MinY) / _dim[1]);
2765  else
2766  _scale[1] = 1.;
2767  }
2768  else {
2769  rterror("rt_raster_gdal_rasterize: Values must be provided for width and height or X and Y of scale");
2770 
2771  OGR_G_DestroyGeometry(src_geom);
2773  /* OGRCleanupAll(); */
2774 
2775  return NULL;
2776  }
2777  RASTER_DEBUGF(3, "scale (x, y) = %f, %f", _scale[0], -1 * _scale[1]);
2778  RASTER_DEBUGF(3, "dim (x, y) = %d, %d", _dim[0], _dim[1]);
2779 
2780  /* user-defined skew */
2781  if (NULL != skew_x) {
2782  _skew[0] = *skew_x;
2783 
2784  /*
2785  negative scale-x affects skew
2786  for now, force skew to be in left-right, top-down orientation
2787  */
2788  if (
2789  NULL != scale_x &&
2790  *scale_x < 0.
2791  ) {
2792  _skew[0] *= -1;
2793  }
2794  }
2795  if (NULL != skew_y) {
2796  _skew[1] = *skew_y;
2797 
2798  /*
2799  positive scale-y affects skew
2800  for now, force skew to be in left-right, top-down orientation
2801  */
2802  if (
2803  NULL != scale_y &&
2804  *scale_y > 0.
2805  ) {
2806  _skew[1] *= -1;
2807  }
2808  }
2809 
2810  /*
2811  if geometry is a point, a linestring or set of either and bounds not set,
2812  increase extent by a pixel to avoid missing points on border
2813 
2814  a whole pixel is used instead of half-pixel due to backward
2815  compatibility with GDAL 1.6, 1.7 and 1.8. 1.9+ works fine with half-pixel.
2816  */
2817  wkbtype = wkbFlatten(OGR_G_GetGeometryType(src_geom));
2818  if ((
2819  (wkbtype == wkbPoint) ||
2820  (wkbtype == wkbMultiPoint) ||
2821  (wkbtype == wkbLineString) ||
2822  (wkbtype == wkbMultiLineString)
2823  ) &&
2824  _dim[0] == 0 &&
2825  _dim[1] == 0
2826  ) {
2827 
2828 #if POSTGIS_GDAL_VERSION > 18
2829 
2830  RASTER_DEBUG(3, "Adjusting extent for GDAL > 1.8 by half the scale on X-axis");
2831  extent.MinX -= (_scale[0] / 2.);
2832  extent.MaxX += (_scale[0] / 2.);
2833 
2834  RASTER_DEBUG(3, "Adjusting extent for GDAL > 1.8 by half the scale on Y-axis");
2835  extent.MinY -= (_scale[1] / 2.);
2836  extent.MaxY += (_scale[1] / 2.);
2837 
2838 #else
2839 
2840  RASTER_DEBUG(3, "Adjusting extent for GDAL <= 1.8 by the scale on X-axis");
2841  extent.MinX -= _scale[0];
2842  extent.MaxX += _scale[0];
2843 
2844  RASTER_DEBUG(3, "Adjusting extent for GDAL <= 1.8 by the scale on Y-axis");
2845  extent.MinY -= _scale[1];
2846  extent.MaxY += _scale[1];
2847 
2848 #endif
2849 
2850 
2851  RASTER_DEBUGF(3, "Adjusted extent: %f, %f, %f, %f",
2852  extent.MinX, extent.MinY, extent.MaxX, extent.MaxY);
2853 
2854  extent.UpperLeftX = extent.MinX;
2855  extent.UpperLeftY = extent.MaxY;
2856  }
2857 
2858  /* reprocess extent if skewed */
2859  if (FLT_NEQ(_skew[0], 0.0) || FLT_NEQ(_skew[1], 0.0))
2860  {
2861  rt_raster skewedrast;
2862 
2863  RASTER_DEBUG(3, "Computing skewed extent's envelope");
2864 
2865  skewedrast = rt_raster_compute_skewed_raster(
2866  extent,
2867  _skew,
2868  _scale,
2869  0.01
2870  );
2871  if (skewedrast == NULL) {
2872  rterror("rt_raster_gdal_rasterize: Could not compute skewed raster");
2873 
2874  OGR_G_DestroyGeometry(src_geom);
2876  /* OGRCleanupAll(); */
2877 
2878  return NULL;
2879  }
2880 
2881  _dim[0] = skewedrast->width;
2882  _dim[1] = skewedrast->height;
2883 
2884  extent.UpperLeftX = skewedrast->ipX;
2885  extent.UpperLeftY = skewedrast->ipY;
2886 
2887  rt_raster_destroy(skewedrast);
2888  }
2889 
2890  /* raster dimensions */
2891  if (!_dim[0])
2892  _dim[0] = (int) fmax((fabs(extent.MaxX - extent.MinX) + (_scale[0] / 2.)) / _scale[0], 1);
2893  if (!_dim[1])
2894  _dim[1] = (int) fmax((fabs(extent.MaxY - extent.MinY) + (_scale[1] / 2.)) / _scale[1], 1);
2895 
2896  /* temporary raster */
2897  rast = rt_raster_new(_dim[0], _dim[1]);
2898  if (rast == NULL) {
2899  rterror("rt_raster_gdal_rasterize: Out of memory allocating temporary raster");
2900 
2901  OGR_G_DestroyGeometry(src_geom);
2903  /* OGRCleanupAll(); */
2904 
2905  return NULL;
2906  }
2907 
2908  /* set raster's spatial attributes */
2910  rt_raster_set_scale(rast, _scale[0], -1 * _scale[1]);
2911  rt_raster_set_skews(rast, _skew[0], _skew[1]);
2912 
2914  RASTER_DEBUGF(3, "Temp raster's geotransform: %f, %f, %f, %f, %f, %f",
2915  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
2916  RASTER_DEBUGF(3, "Temp raster's dimensions (width x height): %d x %d",
2917  _dim[0], _dim[1]);
2918 
2919  /* user-specified upper-left corner */
2920  if (
2921  NULL != ul_xw &&
2922  NULL != ul_yw
2923  ) {
2924  ul_user = 1;
2925 
2926  RASTER_DEBUGF(4, "Using user-specified upper-left corner: %f, %f", *ul_xw, *ul_yw);
2927 
2928  /* set upper-left corner */
2929  rt_raster_set_offsets(rast, *ul_xw, *ul_yw);
2930  extent.UpperLeftX = *ul_xw;
2931  extent.UpperLeftY = *ul_yw;
2932  }
2933  else if (
2934  ((NULL != ul_xw) && (NULL == ul_yw)) ||
2935  ((NULL == ul_xw) && (NULL != ul_yw))
2936  ) {
2937  rterror("rt_raster_gdal_rasterize: Both X and Y upper-left corner values must be provided");
2938 
2940  OGR_G_DestroyGeometry(src_geom);
2942  /* OGRCleanupAll(); */
2943 
2944  return NULL;
2945  }
2946 
2947  /* alignment only considered if upper-left corner not provided */
2948  if (
2949  !ul_user && (
2950  (NULL != grid_xw) || (NULL != grid_yw)
2951  )
2952  ) {
2953 
2954  if (
2955  ((NULL != grid_xw) && (NULL == grid_yw)) ||
2956  ((NULL == grid_xw) && (NULL != grid_yw))
2957  ) {
2958  rterror("rt_raster_gdal_rasterize: Both X and Y alignment values must be provided");
2959 
2961  OGR_G_DestroyGeometry(src_geom);
2963  /* OGRCleanupAll(); */
2964 
2965  return NULL;
2966  }
2967 
2968  RASTER_DEBUGF(4, "Aligning extent to user-specified grid: %f, %f", *grid_xw, *grid_yw);
2969 
2970  do {
2971  double _r[2] = {0};
2972  double _w[2] = {0};
2973 
2974  /* raster is already aligned */
2975  if (DBL_EQ(*grid_xw, extent.UpperLeftX) && DBL_EQ(*grid_yw, extent.UpperLeftY)) {
2976  RASTER_DEBUG(3, "Skipping raster alignment as it is already aligned to grid");
2977  break;
2978  }
2979 
2980  extent.UpperLeftX = rast->ipX;
2981  extent.UpperLeftY = rast->ipY;
2982  rt_raster_set_offsets(rast, *grid_xw, *grid_yw);
2983 
2984  /* process upper-left corner */
2986  rast,
2987  extent.UpperLeftX, extent.UpperLeftY,
2988  &(_r[0]), &(_r[1]),
2989  NULL
2990  ) != ES_NONE) {
2991  rterror("rt_raster_gdal_rasterize: Could not compute raster pixel for spatial coordinates");
2992 
2994  OGR_G_DestroyGeometry(src_geom);
2996  /* OGRCleanupAll(); */
2997 
2998  return NULL;
2999  }
3000 
3002  rast,
3003  _r[0], _r[1],
3004  &(_w[0]), &(_w[1]),
3005  NULL
3006  ) != ES_NONE) {
3007  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
3008 
3010  OGR_G_DestroyGeometry(src_geom);
3012  /* OGRCleanupAll(); */
3013 
3014  return NULL;
3015  }
3016 
3017  /* shift occurred */
3018  if (FLT_NEQ(_w[0], extent.UpperLeftX)) {
3019  if (NULL == width)
3020  rast->width++;
3021  else if (NULL == scale_x) {
3022  double _c[2] = {0};
3023 
3025 
3026  /* get upper-right corner */
3028  rast,
3029  rast->width, 0,
3030  &(_c[0]), &(_c[1]),
3031  NULL
3032  ) != ES_NONE) {
3033  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
3034 
3036  OGR_G_DestroyGeometry(src_geom);
3038  /* OGRCleanupAll(); */
3039 
3040  return NULL;
3041  }
3042 
3043  rast->scaleX = fabs((_c[0] - _w[0]) / ((double) rast->width));
3044  }
3045  }
3046  if (FLT_NEQ(_w[1], extent.UpperLeftY)) {
3047  if (NULL == height)
3048  rast->height++;
3049  else if (NULL == scale_y) {
3050  double _c[2] = {0};
3051 
3053 
3054  /* get upper-right corner */
3056  rast,
3057  0, rast->height,
3058  &(_c[0]), &(_c[1]),
3059  NULL
3060  ) != ES_NONE) {
3061  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
3062 
3064  OGR_G_DestroyGeometry(src_geom);
3066  /* OGRCleanupAll(); */
3067 
3068  return NULL;
3069  }
3070 
3071  rast->scaleY = -1 * fabs((_c[1] - _w[1]) / ((double) rast->height));
3072  }
3073  }
3074 
3075  rt_raster_set_offsets(rast, _w[0], _w[1]);
3076  }
3077  while (0);
3078  }
3079 
3080  /*
3081  after this point, rt_envelope extent is no longer used
3082  */
3083 
3084  /* get key attributes from rast */
3085  _dim[0] = rast->width;
3086  _dim[1] = rast->height;
3088 
3089  /* scale-x is negative or scale-y is positive */
3090  if ((
3091  (NULL != scale_x) && (*scale_x < 0.)
3092  ) || (
3093  (NULL != scale_y) && (*scale_y > 0)
3094  )) {
3095  double _w[2] = {0};
3096 
3097  /* negative scale-x */
3098  if (
3099  (NULL != scale_x) &&
3100  (*scale_x < 0.)
3101  ) {
3102  RASTER_DEBUG(3, "Processing negative scale-x");
3103 
3105  rast,
3106  _dim[0], 0,
3107  &(_w[0]), &(_w[1]),
3108  NULL
3109  ) != ES_NONE) {
3110  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
3111 
3113  OGR_G_DestroyGeometry(src_geom);
3115  /* OGRCleanupAll(); */
3116 
3117  return NULL;
3118  }
3119 
3120  _gt[0] = _w[0];
3121  _gt[1] = *scale_x;
3122 
3123  /* check for skew */
3124  if (NULL != skew_x && FLT_NEQ(*skew_x, 0.0))
3125  _gt[2] = *skew_x;
3126  }
3127  /* positive scale-y */
3128  if (
3129  (NULL != scale_y) &&
3130  (*scale_y > 0)
3131  ) {
3132  RASTER_DEBUG(3, "Processing positive scale-y");
3133 
3135  rast,
3136  0, _dim[1],
3137  &(_w[0]), &(_w[1]),
3138  NULL
3139  ) != ES_NONE) {
3140  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
3141 
3143  OGR_G_DestroyGeometry(src_geom);
3145  /* OGRCleanupAll(); */
3146 
3147  return NULL;
3148  }
3149 
3150  _gt[3] = _w[1];
3151  _gt[5] = *scale_y;
3152 
3153  /* check for skew */
3154  if (NULL != skew_y && FLT_NEQ(*skew_y, 0.0))
3155  _gt[4] = *skew_y;
3156  }
3157  }
3158 
3160  rast = NULL;
3161 
3162  RASTER_DEBUGF(3, "Applied geotransform: %f, %f, %f, %f, %f, %f",
3163  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
3164  RASTER_DEBUGF(3, "Raster dimensions (width x height): %d x %d",
3165  _dim[0], _dim[1]);
3166 
3167  /* load GDAL mem */
3168  if (!rt_util_gdal_driver_registered("MEM")) {
3169  RASTER_DEBUG(4, "Registering MEM driver");
3170  GDALRegister_MEM();
3171  unload_drv = 1;
3172  }
3173  _drv = GDALGetDriverByName("MEM");
3174  if (NULL == _drv) {
3175  rterror("rt_raster_gdal_rasterize: Could not load the MEM GDAL driver");
3176 
3177  OGR_G_DestroyGeometry(src_geom);
3179  /* OGRCleanupAll(); */
3180 
3181  return NULL;
3182  }
3183 
3184  /* unload driver from GDAL driver manager */
3185  if (unload_drv) {
3186  RASTER_DEBUG(4, "Deregistering MEM driver");
3187  GDALDeregisterDriver(_drv);
3188  }
3189 
3190  _ds = GDALCreate(_drv, "", _dim[0], _dim[1], 0, GDT_Byte, NULL);
3191  if (NULL == _ds) {
3192  rterror("rt_raster_gdal_rasterize: Could not create a GDALDataset to rasterize the geometry into");
3193 
3194  OGR_G_DestroyGeometry(src_geom);
3196  /* OGRCleanupAll(); */
3197  if (unload_drv) GDALDestroyDriver(_drv);
3198 
3199  return NULL;
3200  }
3201 
3202  /* set geotransform */
3203  cplerr = GDALSetGeoTransform(_ds, _gt);
3204  if (cplerr != CE_None) {
3205  rterror("rt_raster_gdal_rasterize: Could not set geotransform on GDALDataset");
3206 
3207  OGR_G_DestroyGeometry(src_geom);
3209  /* OGRCleanupAll(); */
3210 
3211  GDALClose(_ds);
3212  if (unload_drv) GDALDestroyDriver(_drv);
3213 
3214  return NULL;
3215  }
3216 
3217  /* set SRS */
3218  if (NULL != arg->src_sr) {
3219  char *_srs = NULL;
3220  OSRExportToWkt(arg->src_sr, &_srs);
3221 
3222  cplerr = GDALSetProjection(_ds, _srs);
3223  CPLFree(_srs);
3224  if (cplerr != CE_None) {
3225  rterror("rt_raster_gdal_rasterize: Could not set projection on GDALDataset");
3226 
3227  OGR_G_DestroyGeometry(src_geom);
3229  /* OGRCleanupAll(); */
3230 
3231  GDALClose(_ds);
3232  if (unload_drv) GDALDestroyDriver(_drv);
3233 
3234  return NULL;
3235  }
3236  }
3237 
3238  /* set bands */
3239  for (i = 0; i < arg->numbands; i++) {
3240  err = 0;
3241 
3242  do {
3243  /* add band */
3244  cplerr = GDALAddBand(_ds, rt_util_pixtype_to_gdal_datatype(arg->pixtype[i]), NULL);
3245  if (cplerr != CE_None) {
3246  rterror("rt_raster_gdal_rasterize: Could not add band to GDALDataset");
3247  err = 1;
3248  break;
3249  }
3250 
3251  _band = GDALGetRasterBand(_ds, i + 1);
3252  if (NULL == _band) {
3253  rterror("rt_raster_gdal_rasterize: Could not get band %d from GDALDataset", i + 1);
3254  err = 1;
3255  break;
3256  }
3257 
3258  /* nodata value */
3259  if (arg->hasnodata[i]) {
3260  RASTER_DEBUGF(4, "Setting NODATA value of band %d to %f", i, arg->nodata[i]);
3261  cplerr = GDALSetRasterNoDataValue(_band, arg->nodata[i]);
3262  if (cplerr != CE_None) {
3263  rterror("rt_raster_gdal_rasterize: Could not set nodata value");
3264  err = 1;
3265  break;
3266  }
3267  RASTER_DEBUGF(4, "NODATA value set to %f", GDALGetRasterNoDataValue(_band, NULL));
3268  }
3269 
3270  /* initial value */
3271  cplerr = GDALFillRaster(_band, arg->init[i], 0);
3272  if (cplerr != CE_None) {
3273  rterror("rt_raster_gdal_rasterize: Could not set initial value");
3274  err = 1;
3275  break;
3276  }
3277  }
3278  while (0);
3279 
3280  if (err) {
3281 
3282  OGR_G_DestroyGeometry(src_geom);
3284 
3285  /* OGRCleanupAll(); */
3286 
3287  GDALClose(_ds);
3288  if (unload_drv) GDALDestroyDriver(_drv);
3289 
3290  return NULL;
3291  }
3292  }
3293 
3294  arg->bandlist = (int *) rtalloc(sizeof(int) * arg->numbands);
3295  for (i = 0; i < arg->numbands; i++) arg->bandlist[i] = i + 1;
3296 
3297  /* burn geometry */
3298  cplerr = GDALRasterizeGeometries(
3299  _ds,
3300  arg->numbands, arg->bandlist,
3301  1, &src_geom,
3302  NULL, NULL,
3303  arg->value,
3304  options,
3305  NULL, NULL
3306  );
3307  if (cplerr != CE_None) {
3308  rterror("rt_raster_gdal_rasterize: Could not rasterize geometry");
3309 
3310  OGR_G_DestroyGeometry(src_geom);
3312  /* OGRCleanupAll(); */
3313 
3314  GDALClose(_ds);
3315  if (unload_drv) GDALDestroyDriver(_drv);
3316 
3317  return NULL;
3318  }
3319 
3320  /* convert gdal dataset to raster */
3321  GDALFlushCache(_ds);
3322  RASTER_DEBUG(3, "Converting GDAL dataset to raster");
3324 
3325  OGR_G_DestroyGeometry(src_geom);
3326  /* OGRCleanupAll(); */
3327 
3328  GDALClose(_ds);
3329  if (unload_drv) GDALDestroyDriver(_drv);
3330 
3331  if (NULL == rast) {
3332  rterror("rt_raster_gdal_rasterize: Could not rasterize geometry");
3333  return NULL;
3334  }
3335 
3336  /* width, height */
3337  _width = rt_raster_get_width(rast);
3338  _height = rt_raster_get_height(rast);
3339 
3340  /* check each band for pixtype */
3341  for (i = 0; i < arg->numbands; i++) {
3342  uint8_t *data = NULL;
3343  rt_band band = NULL;
3344  rt_band oldband = NULL;
3345 
3346  double val = 0;
3347  int nodata = 0;
3348  int hasnodata = 0;
3349  double nodataval = 0;
3350  int x = 0;
3351  int y = 0;
3352 
3353  oldband = rt_raster_get_band(rast, i);
3354  if (oldband == NULL) {
3355  rterror("rt_raster_gdal_rasterize: Could not get band %d of output raster", i);
3358  return NULL;
3359  }
3360 
3361  /* band is of user-specified type */
3362  if (rt_band_get_pixtype(oldband) == arg->pixtype[i])
3363  continue;
3364 
3365  /* hasnodata, nodataval */
3366  hasnodata = rt_band_get_hasnodata_flag(oldband);
3367  if (hasnodata)
3368  rt_band_get_nodata(oldband, &nodataval);
3369 
3370  /* allocate data */
3371  data = rtalloc(rt_pixtype_size(arg->pixtype[i]) * _width * _height);
3372  if (data == NULL) {
3373  rterror("rt_raster_gdal_rasterize: Could not allocate memory for band data");
3376  return NULL;
3377  }
3378  memset(data, 0, rt_pixtype_size(arg->pixtype[i]) * _width * _height);
3379 
3380  /* create new band of correct type */
3382  _width, _height,
3383  arg->pixtype[i],
3384  hasnodata, nodataval,
3385  data
3386  );
3387  if (band == NULL) {
3388  rterror("rt_raster_gdal_rasterize: Could not create band");
3389  rtdealloc(data);
3392  return NULL;
3393  }
3394 
3395  /* give ownership of data to band */
3397 
3398  /* copy pixel by pixel */
3399  for (x = 0; x < _width; x++) {
3400  for (y = 0; y < _height; y++) {
3401  err = rt_band_get_pixel(oldband, x, y, &val, &nodata);
3402  if (err != ES_NONE) {
3403  rterror("rt_raster_gdal_rasterize: Could not get pixel value");
3407  return NULL;
3408  }
3409 
3410  if (nodata)
3411  val = nodataval;
3412 
3413  err = rt_band_set_pixel(band, x, y, val, NULL);
3414  if (err != ES_NONE) {
3415  rterror("rt_raster_gdal_rasterize: Could not set pixel value");
3419  return NULL;
3420  }
3421  }
3422  }
3423 
3424  /* replace band */
3425  oldband = rt_raster_replace_band(rast, band, i);
3426  if (oldband == NULL) {
3427  rterror("rt_raster_gdal_rasterize: Could not replace band %d of output raster", i);
3431  return NULL;
3432  }
3433 
3434  /* free oldband */
3435  rt_band_destroy(oldband);
3436  }
3437 
3439 
3440  RASTER_DEBUG(3, "done");
3441 
3442  return rast;
3443 }
3444 
3445 /******************************************************************************
3446 * rt_raster_from_two_rasters()
3447 ******************************************************************************/
3448 
3449 /*
3450  * Return raster of computed extent specified extenttype applied
3451  * on two input rasters. The raster returned should be freed by
3452  * the caller
3453  *
3454  * @param rast1 : the first raster
3455  * @param rast2 : the second raster
3456  * @param extenttype : type of extent for the output raster
3457  * @param *rtnraster : raster of computed extent
3458  * @param *offset : 4-element array indicating the X,Y offsets
3459  * for each raster. 0,1 for rast1 X,Y. 2,3 for rast2 X,Y.
3460  *
3461  * @return ES_NONE if success, ES_ERROR if error
3462  */
3465  rt_raster rast1, rt_raster rast2,
3466  rt_extenttype extenttype,
3467  rt_raster *rtnraster, double *offset
3468 ) {
3469  int i;
3470 
3471  rt_raster _rast[2] = {rast1, rast2};
3472  double _offset[2][4] = {{0.}};
3473  uint16_t _dim[2][2] = {{0}};
3474 
3475  rt_raster raster = NULL;
3476  int aligned = 0;
3477  int dim[2] = {0};
3478  double gt[6] = {0.};
3479 
3480  assert(NULL != rast1);
3481  assert(NULL != rast2);
3482  assert(NULL != rtnraster);
3483 
3484  /* set rtnraster to NULL */
3485  *rtnraster = NULL;
3486 
3487  /* rasters must be aligned */
3488  if (rt_raster_same_alignment(rast1, rast2, &aligned, NULL) != ES_NONE) {
3489  rterror("rt_raster_from_two_rasters: Could not test for alignment on the two rasters");
3490  return ES_ERROR;
3491  }
3492  if (!aligned) {
3493  rterror("rt_raster_from_two_rasters: The two rasters provided do not have the same alignment");
3494  return ES_ERROR;
3495  }
3496 
3497  /* dimensions */
3498  _dim[0][0] = rast1->width;
3499  _dim[0][1] = rast1->height;
3500  _dim[1][0] = rast2->width;
3501  _dim[1][1] = rast2->height;
3502 
3503  /* get raster offsets */
3505  _rast[1],
3506  _rast[0]->ipX, _rast[0]->ipY,
3507  &(_offset[1][0]), &(_offset[1][1]),
3508  NULL
3509  ) != ES_NONE) {
3510  rterror("rt_raster_from_two_rasters: Could not compute offsets of the second raster relative to the first raster");
3511  return ES_ERROR;
3512  }
3513  _offset[1][0] = -1 * _offset[1][0];
3514  _offset[1][1] = -1 * _offset[1][1];
3515  _offset[1][2] = _offset[1][0] + _dim[1][0] - 1;
3516  _offset[1][3] = _offset[1][1] + _dim[1][1] - 1;
3517 
3518  i = -1;
3519  switch (extenttype) {
3520  case ET_FIRST:
3521  i = 0;
3522  _offset[0][0] = 0.;
3523  _offset[0][1] = 0.;
3524  /* FALLTHROUGH */
3525  case ET_LAST:
3526  case ET_SECOND:
3527  if (i < 0) {
3528  i = 1;
3529  _offset[0][0] = -1 * _offset[1][0];
3530  _offset[0][1] = -1 * _offset[1][1];
3531  _offset[1][0] = 0.;
3532  _offset[1][1] = 0.;
3533  }
3534 
3535  dim[0] = _dim[i][0];
3536  dim[1] = _dim[i][1];
3538  dim[0],
3539  dim[1]
3540  );
3541  if (raster == NULL) {
3542  rterror("rt_raster_from_two_rasters: Could not create output raster");
3543  return ES_ERROR;
3544  }
3545  rt_raster_set_srid(raster, _rast[i]->srid);
3548  break;
3549  case ET_UNION: {
3550  double off[4] = {0};
3551 
3553  RASTER_DEBUGF(4, "gt = (%f, %f, %f, %f, %f, %f)",
3554  gt[0],
3555  gt[1],
3556  gt[2],
3557  gt[3],
3558  gt[4],
3559  gt[5]
3560  );
3561 
3562  /* new raster upper left offset */
3563  off[0] = 0;
3564  if (_offset[1][0] < 0)
3565  off[0] = _offset[1][0];
3566  off[1] = 0;
3567  if (_offset[1][1] < 0)
3568  off[1] = _offset[1][1];
3569 
3570  /* new raster lower right offset */
3571  off[2] = _dim[0][0] - 1;
3572  if ((int) _offset[1][2] >= _dim[0][0])
3573  off[2] = _offset[1][2];
3574  off[3] = _dim[0][1] - 1;
3575  if ((int) _offset[1][3] >= _dim[0][1])
3576  off[3] = _offset[1][3];
3577 
3578  /* upper left corner */
3580  _rast[0],
3581  off[0], off[1],
3582  &(gt[0]), &(gt[3]),
3583  NULL
3584  ) != ES_NONE) {
3585  rterror("rt_raster_from_two_rasters: Could not get spatial coordinates of upper-left pixel of output raster");
3586  return ES_ERROR;
3587  }
3588 
3589  dim[0] = off[2] - off[0] + 1;
3590  dim[1] = off[3] - off[1] + 1;
3591  RASTER_DEBUGF(4, "off = (%f, %f, %f, %f)",
3592  off[0],
3593  off[1],
3594  off[2],
3595  off[3]
3596  );
3597  RASTER_DEBUGF(4, "dim = (%d, %d)", dim[0], dim[1]);
3598 
3600  dim[0],
3601  dim[1]
3602  );
3603  if (raster == NULL) {
3604  rterror("rt_raster_from_two_rasters: Could not create output raster");
3605  return ES_ERROR;
3606  }
3607  rt_raster_set_srid(raster, _rast[0]->srid);
3609  RASTER_DEBUGF(4, "gt = (%f, %f, %f, %f, %f, %f)",
3610  gt[0],
3611  gt[1],
3612  gt[2],
3613  gt[3],
3614  gt[4],
3615  gt[5]
3616  );
3617 
3618  /* get offsets */
3620  _rast[0],
3621  gt[0], gt[3],
3622  &(_offset[0][0]), &(_offset[0][1]),
3623  NULL
3624  ) != ES_NONE) {
3625  rterror("rt_raster_from_two_rasters: Could not get offsets of the FIRST raster relative to the output raster");
3627  return ES_ERROR;
3628  }
3629  _offset[0][0] *= -1;
3630  _offset[0][1] *= -1;
3631 
3633  _rast[1],
3634  gt[0], gt[3],
3635  &(_offset[1][0]), &(_offset[1][1]),
3636  NULL
3637  ) != ES_NONE) {
3638  rterror("rt_raster_from_two_rasters: Could not get offsets of the SECOND raster relative to the output raster");
3640  return ES_ERROR;
3641  }
3642  _offset[1][0] *= -1;
3643  _offset[1][1] *= -1;
3644  break;
3645  }
3646  case ET_INTERSECTION: {
3647  double off[4] = {0};
3648 
3649  /* no intersection */
3650  if (
3651  (_offset[1][2] < 0 || _offset[1][0] > (_dim[0][0] - 1)) ||
3652  (_offset[1][3] < 0 || _offset[1][1] > (_dim[0][1] - 1))
3653  ) {
3654  RASTER_DEBUG(3, "The two rasters provided have no intersection. Returning no band raster");
3655 
3656  raster = rt_raster_new(0, 0);
3657  if (raster == NULL) {
3658  rterror("rt_raster_from_two_rasters: Could not create output raster");
3659  return ES_ERROR;
3660  }
3661  rt_raster_set_srid(raster, _rast[0]->srid);
3662  rt_raster_set_scale(raster, 0, 0);
3663 
3664  /* set offsets if provided */
3665  if (NULL != offset) {
3666  for (i = 0; i < 4; i++)
3667  offset[i] = _offset[i / 2][i % 2];
3668  }
3669 
3670  *rtnraster = raster;
3671  return ES_NONE;
3672  }
3673 
3674  if (_offset[1][0] > 0)
3675  off[0] = _offset[1][0];
3676  if (_offset[1][1] > 0)
3677  off[1] = _offset[1][1];
3678 
3679  off[2] = _dim[0][0] - 1;
3680  if (_offset[1][2] < _dim[0][0])
3681  off[2] = _offset[1][2];
3682  off[3] = _dim[0][1] - 1;
3683  if (_offset[1][3] < _dim[0][1])
3684  off[3] = _offset[1][3];
3685 
3686  dim[0] = off[2] - off[0] + 1;
3687  dim[1] = off[3] - off[1] + 1;
3689  dim[0],
3690  dim[1]
3691  );
3692  if (raster == NULL) {
3693  rterror("rt_raster_from_two_rasters: Could not create output raster");
3694  return ES_ERROR;
3695  }
3696  rt_raster_set_srid(raster, _rast[0]->srid);
3697 
3698  /* get upper-left corner */
3701  _rast[0],
3702  off[0], off[1],
3703  &(gt[0]), &(gt[3]),
3704  gt
3705  ) != ES_NONE) {
3706  rterror("rt_raster_from_two_rasters: Could not get spatial coordinates of upper-left pixel of output raster");
3708  return ES_ERROR;
3709  }
3710 
3712 
3713  /* get offsets */
3715  _rast[0],
3716  gt[0], gt[3],
3717  &(_offset[0][0]), &(_offset[0][1]),
3718  NULL
3719  ) != ES_NONE) {
3720  rterror("rt_raster_from_two_rasters: Could not get pixel coordinates to compute the offsets of the FIRST raster relative to the output raster");
3722  return ES_ERROR;
3723  }
3724  _offset[0][0] *= -1;
3725  _offset[0][1] *= -1;
3726 
3728  _rast[1],
3729  gt[0], gt[3],
3730  &(_offset[1][0]), &(_offset[1][1]),
3731  NULL
3732  ) != ES_NONE) {
3733  rterror("rt_raster_from_two_rasters: Could not get pixel coordinates to compute the offsets of the SECOND raster relative to the output raster");
3735  return ES_ERROR;
3736  }
3737  _offset[1][0] *= -1;
3738  _offset[1][1] *= -1;
3739  break;
3740  }
3741  case ET_CUSTOM:
3742  rterror("rt_raster_from_two_rasters: Extent type ET_CUSTOM is not supported by this function");
3743  break;
3744  }
3745 
3746  /* set offsets if provided */
3747  if (NULL != offset) {
3748  for (i = 0; i < 4; i++)
3749  offset[i] = _offset[i / 2][i % 2];
3750  }
3751 
3752  *rtnraster = raster;
3753  return ES_NONE;
3754 }
#define TRUE
Definition: dbfopen.c:73
#define FALSE
Definition: dbfopen.c:72
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_geos_error(const char *fmt,...)
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:329
int lwpointiterator_peek(LWPOINTITERATOR *s, POINT4D *p)
Attempts to assigns the next point in the iterator to p.
Definition: lwiterator.c:193
void lwpointiterator_destroy(LWPOINTITERATOR *s)
Free all memory associated with the iterator.
Definition: lwiterator.c:267
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom, double mval)
Definition: lwgeom.c:805
LWGEOM * lwgeom_force_4d(const LWGEOM *geom, double zval, double mval)
Definition: lwgeom.c:811
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom, double zval)
Definition: lwgeom.c:799
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:934
int lwpointiterator_modify_next(LWPOINTITERATOR *s, const POINT4D *p)
Attempts to replace the next point int the iterator with p, and advances the iterator to the next poi...
Definition: lwiterator.c:224
LWPOINTITERATOR * lwpointiterator_create_rw(LWGEOM *g)
Create a new LWPOINTITERATOR over supplied LWGEOM* Supports modification of coordinates during iterat...
Definition: lwiterator.c:251
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
Definition: lwgeom.c:491
int lwpointiterator_has_next(LWPOINTITERATOR *s)
Returns LW_TRUE if there is another point available in the iterator.
Definition: lwiterator.c:202
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:175
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:941
int32_t clamp_srid(int32_t srid)
Return a valid SRID from an arbitrary integer Raises a notice if what comes out is different from wha...
Definition: lwutil.c:333
rt_band rt_band_new_inline(uint16_t width, uint16_t height, rt_pixtype pixtype, uint32_t hasnodata, double nodataval, uint8_t *data)
Create an in-db rt_band with no data.
Definition: rt_band.c:63
void rt_band_set_ownsdata_flag(rt_band band, int flag)
Definition: rt_band.c:667
void rterror(const char *fmt,...)
Wrappers used for reporting errors and info.
Definition: rt_context.c:219
void * rtalloc(size_t size)
Wrappers used for managing memory.
Definition: rt_context.c:191
rt_pixtype rt_util_gdal_datatype_to_pixtype(GDALDataType gdt)
Convert GDALDataType to rt_pixtype.
Definition: rt_util.c:159
rt_band rt_band_duplicate(rt_band band)
Create a new band duplicated from source band.
Definition: rt_band.c:287
rt_errorstate rt_band_set_isnodata_flag(rt_band band, int flag)
Set isnodata flag value.
Definition: rt_band.c:695
#define FLT_NEQ(x, y)
Definition: librtcore.h:2386
#define RASTER_DEBUG(level, msg)
Definition: librtcore.h:302
int rt_util_gdal_register_all(int force_register_all)
Definition: rt_util.c:342
#define RASTER_DEBUGF(level, msg,...)
Definition: librtcore.h:306
int8_t rt_util_clamp_to_8BSI(double value)
Definition: rt_util.c:50
uint8_t rt_util_clamp_to_1BB(double value)
Definition: rt_util.c:35
void rtinfo(const char *fmt,...)
Definition: rt_context.c:231
int32_t rt_util_clamp_to_32BSI(double value)
Definition: rt_util.c:70
char * rt_util_gdal_convert_sr(const char *srs, int proj4)
Definition: rt_util.c:218
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:674
#define ROUND(x, y)
Definition: librtcore.h:2394
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_band.c:1376
rt_pixtype
Definition: librtcore.h:187
@ PT_32BUI
Definition: librtcore.h:196
@ PT_2BUI
Definition: librtcore.h:189
@ PT_32BSI
Definition: librtcore.h:195
@ PT_END
Definition: librtcore.h:199
@ PT_4BUI
Definition: librtcore.h:190
@ PT_32BF
Definition: librtcore.h:197
@ PT_1BB
Definition: librtcore.h:188
@ PT_16BUI
Definition: librtcore.h:194
@ PT_8BSI
Definition: librtcore.h:191
@ PT_16BSI
Definition: librtcore.h:193
@ PT_64BF
Definition: librtcore.h:198
@ PT_8BUI
Definition: librtcore.h:192
int rt_util_dbl_trunc_warning(double initialvalue, int32_t checkvalint, uint32_t checkvaluint, float checkvalfloat, double checkvaldouble, rt_pixtype pixtype)
Definition: rt_util.c:676
GDALDataType rt_util_pixtype_to_gdal_datatype(rt_pixtype pt)
Convert rt_pixtype to GDALDataType.
Definition: rt_util.c:124
#define FLT_EQ(x, y)
Definition: librtcore.h:2387
rt_resample_type
Definition: librtcore.h:1450
uint8_t rt_util_clamp_to_2BUI(double value)
Definition: rt_util.c:40
void rtwarn(const char *fmt,...)
Definition: rt_context.c:244
uint8_t rt_util_clamp_to_8BUI(double value)
Definition: rt_util.c:55
rt_errorstate rt_band_set_pixel(rt_band band, int x, int y, double val, int *converted)
Set single pixel's value.
Definition: rt_band.c:974
rt_errorstate
Enum definitions.
Definition: librtcore.h:181
@ ES_NONE
Definition: librtcore.h:182
@ ES_ERROR
Definition: librtcore.h:183
rt_errorstate rt_band_set_pixel_line(rt_band band, int x, int y, void *vals, uint32_t len)
Set values of multiple pixels.
Definition: rt_band.c:853
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:340
#define DBL_EQ(x, y)
Definition: librtcore.h:2389
int16_t rt_util_clamp_to_16BSI(double value)
Definition: rt_util.c:60
void * rtrealloc(void *mem, size_t size)
Definition: rt_context.c:199
struct rt_gdaldriver_t * rt_gdaldriver
Definition: librtcore.h:156
rt_errorstate rt_raster_get_convex_hull(rt_raster raster, LWGEOM **hull)
Get raster's convex hull.
Definition: rt_geometry.c:838
int rt_util_gdal_driver_registered(const char *drv)
Definition: rt_util.c:361
rt_extenttype
Definition: librtcore.h:202
@ ET_CUSTOM
Definition: librtcore.h:208
@ ET_LAST
Definition: librtcore.h:207
@ ET_INTERSECTION
Definition: librtcore.h:203
@ ET_UNION
Definition: librtcore.h:204
@ ET_SECOND
Definition: librtcore.h:206
@ ET_FIRST
Definition: librtcore.h:205
rt_errorstate rt_band_get_pixel_resample(rt_band band, double xr, double yr, rt_resample_type resample, double *r_value, int *r_nodata)
Retrieve a point value from the raster using a world coordinate and selected resampling method.
Definition: rt_band.c:1221
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:1887
uint8_t rt_util_clamp_to_4BUI(double value)
Definition: rt_util.c:45
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:631
void rtdealloc(void *mem)
Definition: rt_context.c:206
void * rt_band_get_data(rt_band band)
Get pointer to raster band data.
Definition: rt_band.c:400
rt_errorstate rt_util_gdal_sr_auth_info(GDALDatasetH hds, char **authname, char **authcode)
Get auth name and code.
Definition: rt_util.c:276
uint16_t rt_util_clamp_to_16BUI(double value)
Definition: rt_util.c:65
uint32_t rt_util_clamp_to_32BUI(double value)
Definition: rt_util.c:75
int rt_band_is_offline(rt_band band)
Return non-zero if the given band data is on the filesystem.
Definition: rt_band.c:329
LWPOLY * rt_util_envelope_to_lwpoly(rt_envelope ext)
Definition: rt_util.c:486
struct rt_raster_t * rt_raster
Types definitions.
Definition: librtcore.h:147
float rt_util_clamp_to_32F(double value)
Definition: rt_util.c:80
rt_errorstate rt_raster_same_alignment(rt_raster rast1, rt_raster rast2, int *aligned, char **reason)
void rt_util_from_ogr_envelope(OGREnvelope env, rt_envelope *ext)
Definition: rt_util.c:457
int rt_pixtype_size(rt_pixtype pixtype)
Return size in bytes of a value in the given pixtype.
Definition: rt_pixel.c:39
This library is the generic raster handling section of PostGIS.
int value
Definition: genraster.py:62
int count
Definition: genraster.py:57
band
Definition: ovdump.py:58
src_ds
MAIN.
Definition: ovdump.py:54
data
Definition: ovdump.py:104
ds
Definition: pixval.py:67
nband
Definition: pixval.py:53
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
Datum covers(PG_FUNCTION_ARGS)
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:759
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
Definition: rt_raster.c:360
double rt_raster_get_x_skew(rt_raster raster)
Get skew about the X axis.
Definition: rt_raster.c:185
double rt_raster_get_x_offset(rt_raster raster)
Get raster x offset, in projection units.
Definition: rt_raster.c:217
int rt_raster_calc_gt_coeff(double i_mag, double j_mag, double theta_i, double theta_ij, double *xscale, double *xskew, double *yskew, double *yscale)
Calculates the coefficients of a geotransform given the physically significant parameters describing ...
Definition: rt_raster.c:318
int rt_raster_generate_new_band(rt_raster raster, rt_pixtype pixtype, double initialvalue, uint32_t hasnodata, double nodatavalue, int index)
Generate a new inline band and add it to a raster.
Definition: rt_raster.c:489
void rt_raster_set_geotransform_matrix(rt_raster raster, double *gt)
Set raster's geotransform using 6-element array.
Definition: rt_raster.c:731
void rt_raster_set_scale(rt_raster raster, double scaleX, double scaleY)
Set scale in projection units.
Definition: rt_raster.c:141
int rt_raster_add_band(rt_raster raster, rt_band band, int index)
Add band data to a raster.
Definition: rt_raster.c:409
rt_errorstate rt_raster_get_inverse_geotransform_matrix(rt_raster raster, double *gt, double *igt)
Get 6-element array of raster inverse geotransform matrix.
Definition: rt_raster.c:680
uint8_t * rt_raster_to_gdal(rt_raster raster, const char *srs, char *format, char **options, uint64_t *gdalsize)
Return formatted GDAL raster from raster.
Definition: rt_raster.c:1720
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 cell coordinate.
Definition: rt_raster.c:808
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:86
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_errorstate rt_raster_geopoint_to_rasterpoint(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:852
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
Definition: rt_raster.c:52
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
Definition: rt_raster.c:1375
rt_raster rt_raster_compute_skewed_raster(rt_envelope extent, double *skew, double *scale, double tolerance)
Definition: rt_raster.c:991
rt_gdaldriver rt_raster_gdal_drivers(uint32_t *drv_count, uint8_t can_write)
Returns a set of available GDAL drivers.
Definition: rt_raster.c:1838
rt_raster rt_raster_from_gdal_dataset(GDALDatasetH ds)
Return a raster from a GDAL dataset.
Definition: rt_raster.c:2291
static void _rti_rasterize_arg_destroy(_rti_rasterize_arg arg)
Definition: rt_raster.c:2568
double rt_raster_get_x_scale(rt_raster raster)
Get scale X in projection units.
Definition: rt_raster.c:154
rt_band rt_raster_replace_band(rt_raster raster, rt_band band, int index)
Replace band at provided index with new band.
Definition: rt_raster.c:1526
rt_raster rt_raster_gdal_rasterize(const unsigned char *wkb, uint32_t wkb_len, const char *srs, uint32_t num_bands, rt_pixtype *pixtype, double *init, double *value, double *nodata, uint8_t *hasnodata, int *width, int *height, double *scale_x, double *scale_y, double *ul_xw, double *ul_yw, double *grid_xw, double *grid_yw, double *skew_x, double *skew_y, char **options)
Return a raster of the provided geometry.
Definition: rt_raster.c:2618
void rt_raster_get_phys_params(rt_raster rast, double *i_mag, double *j_mag, double *theta_i, double *theta_ij)
Calculates and returns the physically significant descriptors embodied in the geotransform attached t...
Definition: rt_raster.c:235
#define NAN
Definition: rt_raster.c:37
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:376
rt_raster rt_raster_clone(rt_raster raster, uint8_t deep)
Clone an existing raster.
Definition: rt_raster.c:1568
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_raster.c:133
rt_band rt_raster_get_band(rt_raster raster, int n)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:385
static void _rt_raster_geotransform_warn_offline_band(rt_raster raster)
Definition: rt_raster.c:99
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
Definition: rt_raster.c:367
void rt_raster_set_phys_params(rt_raster rast, double i_mag, double j_mag, double theta_i, double theta_ij)
Calculates the geotransform coefficients and applies them to the supplied raster.
Definition: rt_raster.c:301
rt_raster rt_raster_from_band(rt_raster raster, uint32_t *bandNums, int count)
Construct a new rt_raster from an existing rt_raster and an array of band numbers.
Definition: rt_raster.c:1463
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_raster.c:125
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:1935
struct _rti_rasterize_arg_t * _rti_rasterize_arg
Definition: rt_raster.c:2525
rt_errorstate rt_raster_from_two_rasters(rt_raster rast1, rt_raster rast2, rt_extenttype extenttype, rt_raster *rtnraster, double *offset)
Definition: rt_raster.c:3464
int rt_raster_copy_band(rt_raster torast, rt_raster fromrast, int fromindex, int toindex)
Copy one band from one raster to another.
Definition: rt_raster.c:1398
double rt_raster_get_y_scale(rt_raster raster)
Get scale Y in projection units.
Definition: rt_raster.c:163
rt_errorstate rt_raster_get_envelope(rt_raster raster, rt_envelope *env)
Get raster's envelope.
Definition: rt_raster.c:904
static _rti_rasterize_arg _rti_rasterize_arg_init()
Definition: rt_raster.c:2542
double rt_raster_get_y_skew(rt_raster raster)
Get skew about the Y axis.
Definition: rt_raster.c:194
void rt_raster_get_geotransform_matrix(rt_raster raster, double *gt)
Get 6-element array of raster geotransform matrix.
Definition: rt_raster.c:710
rt_errorstate rt_raster_copy_to_geometry(rt_raster raster, uint32_t bandnum, char dim, rt_resample_type resample, const LWGEOM *lwgeom_in, LWGEOM **lwgeom_out)
Copy values from a raster to the points on a geometry using the requested interpolation type.
Definition: rt_raster.c:1614
void rt_raster_set_offsets(rt_raster raster, double x, double y)
Set insertion points in projection units.
Definition: rt_raster.c:203
void rt_raster_calc_phys_params(double xscale, double xskew, double yskew, double yscale, double *i_mag, double *j_mag, double *theta_i, double *theta_ij)
Calculates the physically significant descriptors embodied in an arbitrary geotransform.
Definition: rt_raster.c:254
double rt_raster_get_y_offset(rt_raster raster)
Get raster y offset, in projection units.
Definition: rt_raster.c:226
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition: rt_raster.c:1362
return(psObject)
double m
Definition: liblwgeom.h:414
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
rt_pixtype * pixtype
Definition: rt_raster.c:2533
OGRSpatialReferenceH src_sr
Definition: rt_raster.c:2531
rt_raster raster
Definition: librtcore.h:2477
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
uint8_t can_write
Definition: librtcore.h:2630
char * long_name
Definition: librtcore.h:2627
char * create_options
Definition: librtcore.h:2628
char * short_name
Definition: librtcore.h:2626
uint8_t can_read
Definition: librtcore.h:2629
double scaleX
Definition: librtcore.h:2446
rt_band * bands
Definition: librtcore.h:2456
uint16_t width
Definition: librtcore.h:2454
double skewY
Definition: librtcore.h:2451
uint16_t numBands
Definition: librtcore.h:2443
int32_t srid
Definition: librtcore.h:2453
double ipX
Definition: librtcore.h:2448
uint16_t height
Definition: librtcore.h:2455
double scaleY
Definition: librtcore.h:2447
double ipY
Definition: librtcore.h:2449
double skewX
Definition: librtcore.h:2450