PostGIS  3.7.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 
503  assert(NULL != raster);
504 
505  /* Make sure index is in a valid range */
506  oldnumbands = rt_raster_get_num_bands(raster);
507  if (index < 0)
508  index = 0;
509  else if (index > oldnumbands + 1)
510  index = oldnumbands + 1;
511 
512  /* Determine size of memory block to allocate and allocate it */
513  width = rt_raster_get_width(raster);
514  height = rt_raster_get_height(raster);
515  numval = width * height;
516  datasize = rt_pixtype_size(pixtype) * numval;
517 
518  mem = (int *)rtalloc(datasize);
519  if (!mem) {
520  rterror("rt_raster_generate_new_band: Could not allocate memory for band");
521  return -1;
522  }
523 
524  band = rt_band_new_inline(width, height, pixtype, hasnodata, nodatavalue, mem);
525  if (! band) {
526  rterror("rt_raster_generate_new_band: Could not add band to raster. Aborting");
527  rtdealloc(mem);
528  return -1;
529  }
530 
531  rt_band_init_value(band, initialvalue);
532 
533  rt_band_set_ownsdata_flag(band, 1); /* we DO own this data!!! */
534  index = rt_raster_add_band(raster, band, index);
535  numbands = rt_raster_get_num_bands(raster);
536  if (numbands == oldnumbands || index == -1) {
537  rterror("rt_raster_generate_new_band: Could not add band to raster. Aborting");
539  return -1;
540  }
541 
542  /* set isnodata if hasnodata = TRUE and initial value = nodatavalue */
543  if (hasnodata && FLT_EQ(initialvalue, nodatavalue))
545 
546  return index;
547 }
548 
560  double *gt, double *igt
561 ) {
562  double _gt[6] = {0};
563 
564  assert((raster != NULL || gt != NULL));
565  assert(igt != NULL);
566 
567  if (gt == NULL)
569  else
570  memcpy(_gt, gt, sizeof(double) * 6);
571 
572  if (!GDALInvGeoTransform(_gt, igt)) {
573  rterror("rt_raster_get_inverse_geotransform_matrix: Could not compute inverse geotransform matrix");
574  return ES_ERROR;
575  }
576 
577  return ES_NONE;
578 }
579 
587 void
589  double *gt) {
590  assert(NULL != raster);
591  assert(NULL != gt);
592 
593  gt[0] = raster->ipX;
594  gt[1] = raster->scaleX;
595  gt[2] = raster->skewX;
596  gt[3] = raster->ipY;
597  gt[4] = raster->skewY;
598  gt[5] = raster->scaleY;
599 }
600 
608 void
610  double *gt) {
611  assert(NULL != raster);
612  assert(NULL != gt);
613 
614  raster->ipX = gt[0];
615  raster->scaleX = gt[1];
616  raster->skewX = gt[2];
617  raster->ipY = gt[3];
618  raster->skewY = gt[4];
619  raster->scaleY = gt[5];
620 
622 }
623 
639  double xr, double yr,
640  double *xw, double *yw,
641  double *gt
642 ) {
643  double _gt[6] = {0};
644 
645  assert(NULL != raster);
646  assert(NULL != xw && NULL != yw);
647 
648  if (NULL != gt)
649  memcpy(_gt, gt, sizeof(double) * 6);
650 
651  /* scale of matrix is not set */
652  if (FLT_EQ(_gt[1], 0.0) || FLT_EQ(_gt[5], 0.0))
653  {
655  }
656 
657  RASTER_DEBUGF(4, "gt = (%f, %f, %f, %f, %f, %f)",
658  _gt[0],
659  _gt[1],
660  _gt[2],
661  _gt[3],
662  _gt[4],
663  _gt[5]
664  );
665 
666  GDALApplyGeoTransform(_gt, xr, yr, xw, yw);
667  RASTER_DEBUGF(4, "GDALApplyGeoTransform (c -> g) for (%f, %f) = (%f, %f)",
668  xr, yr, *xw, *yw);
669 
670  return ES_NONE;
671 }
672 
688  double xw, double yw,
689  double *xr, double *yr,
690  double *igt
691 ) {
692  double rnd = 0;
693  rt_errorstate err;
694 
695  err = rt_raster_geopoint_to_rasterpoint(raster, xw, yw, xr, yr, igt);
696  if (err != ES_NONE)
697  return err;
698 
699  rnd = ROUND(*xr, 0);
700  if (FLT_EQ(rnd, *xr))
701  *xr = rnd;
702  else
703  *xr = floor(*xr);
704 
705  rnd = ROUND(*yr, 0);
706  if (FLT_EQ(rnd, *yr))
707  *yr = rnd;
708  else
709  *yr = floor(*yr);
710 
711  RASTER_DEBUGF(4, "Corrected GDALApplyGeoTransform (g -> c) for (%f, %f) = (%f, %f)",
712  xw, yw, *xr, *yr);
713 
714  return ES_NONE;
715 }
716 
732  double xw, double yw,
733  double *xr, double *yr,
734  double *igt
735 ) {
736  double _igt[6] = {0};
737 
738  assert(NULL != raster);
739  assert(NULL != xr && NULL != yr);
740 
741  if (igt != NULL)
742  memcpy(_igt, igt, sizeof(double) * 6);
743 
744  /* matrix is not set */
745  if (
746  FLT_EQ(_igt[0], 0.) &&
747  FLT_EQ(_igt[1], 0.) &&
748  FLT_EQ(_igt[2], 0.) &&
749  FLT_EQ(_igt[3], 0.) &&
750  FLT_EQ(_igt[4], 0.) &&
751  FLT_EQ(_igt[5], 0.)
752  ) {
754  rterror("rt_raster_geopoint_to_cell: Could not get inverse geotransform matrix");
755  return ES_ERROR;
756  }
757  }
758 
759  GDALApplyGeoTransform(_igt, xw, yw, xr, yr);
760  RASTER_DEBUGF(4, "GDALApplyGeoTransform (g -> c) for (%f, %f) = (%f, %f)",
761  xw, yw, *xr, *yr);
762 
763  return ES_NONE;
764 }
765 
766 
767 /******************************************************************************
768 * rt_raster_get_envelope()
769 ******************************************************************************/
770 
784  rt_envelope *env
785 ) {
786  int i;
787  int rtn;
788  int set = 0;
789  double _r[2] = {0.};
790  double _w[2] = {0.};
791  double _gt[6] = {0.};
792 
793  assert(raster != NULL);
794  assert(env != NULL);
795 
797 
798  for (i = 0; i < 4; i++) {
799  switch (i) {
800  case 0:
801  _r[0] = 0;
802  _r[1] = 0;
803  break;
804  case 1:
805  _r[0] = 0;
806  _r[1] = raster->height;
807  break;
808  case 2:
809  _r[0] = raster->width;
810  _r[1] = raster->height;
811  break;
812  case 3:
813  _r[0] = raster->width;
814  _r[1] = 0;
815  break;
816  }
817 
819  raster,
820  _r[0], _r[1],
821  &(_w[0]), &(_w[1]),
822  _gt
823  );
824  if (rtn != ES_NONE) {
825  rterror("rt_raster_get_envelope: Could not compute spatial coordinates for raster pixel");
826  return ES_ERROR;
827  }
828 
829  if (!set) {
830  set = 1;
831  env->MinX = _w[0];
832  env->MaxX = _w[0];
833  env->MinY = _w[1];
834  env->MaxY = _w[1];
835  }
836  else {
837  if (_w[0] < env->MinX)
838  env->MinX = _w[0];
839  else if (_w[0] > env->MaxX)
840  env->MaxX = _w[0];
841 
842  if (_w[1] < env->MinY)
843  env->MinY = _w[1];
844  else if (_w[1] > env->MaxY)
845  env->MaxY = _w[1];
846  }
847  }
848 
849  return ES_NONE;
850 }
851 
852 /******************************************************************************
853 * rt_raster_compute_skewed_raster()
854 ******************************************************************************/
855 
856 /*
857  * Compute skewed extent that covers unskewed extent.
858  *
859  * @param envelope : unskewed extent of type rt_envelope
860  * @param skew : pointer to 2-element array (x, y) of skew
861  * @param scale : pointer to 2-element array (x, y) of scale
862  * @param tolerance : value between 0 and 1 where the smaller the tolerance
863  * results in an extent approaching the "minimum" skewed extent.
864  * If value <= 0, tolerance = 0.1. If value > 1, tolerance = 1.
865  *
866  * @return skewed raster who's extent covers unskewed extent, NULL on error
867  */
868 rt_raster
870  rt_envelope extent,
871  double *skew,
872  double *scale,
873  double tolerance
874 ) {
875  uint32_t run = 0;
876  uint32_t max_run = 1;
877  double dbl_run = 0;
878 
879  int rtn;
880  int covers = 0;
882  double _gt[6] = {0};
883  double _igt[6] = {0};
884  int _d[2] = {1, -1};
885  int _dlast = 0;
886  int _dlastpos = 0;
887  double _w[2] = {0};
888  double _r[2] = {0};
889  double _xy[2] = {0};
890  int i;
891  int j;
892  int x;
893  int y;
894 
895  LWGEOM *geom = NULL;
896  GEOSGeometry *sgeom = NULL;
897  GEOSGeometry *ngeom = NULL;
898 
899  if (
900  (tolerance < 0.) ||
901  FLT_EQ(tolerance, 0.)
902  ) {
903  tolerance = 0.1;
904  }
905  else if (tolerance > 1.)
906  tolerance = 1;
907 
908  dbl_run = tolerance;
909  while (dbl_run < 10) {
910  dbl_run *= 10.;
911  max_run *= 10;
912  }
913 
914  /* scale must be provided */
915  if (scale == NULL)
916  return NULL;
917  for (i = 0; i < 2; i++) {
918  if (FLT_EQ(scale[i], 0.0))
919  {
920  rterror("rt_raster_compute_skewed_raster: Scale cannot be zero");
921  return 0;
922  }
923 
924  if (i < 1)
925  _gt[1] = fabs(scale[i] * tolerance);
926  else
927  _gt[5] = fabs(scale[i] * tolerance);
928  }
929  /* conform scale-y to be negative */
930  _gt[5] *= -1;
931 
932  /* skew not provided or skew is zero, return raster of correct dim and spatial attributes */
933  if ((skew == NULL) || (FLT_EQ(skew[0], 0.0) && FLT_EQ(skew[1], 0.0)))
934  {
935  int _dim[2] = {
936  (int) fmax((fabs(extent.MaxX - extent.MinX) + (fabs(scale[0]) / 2.)) / fabs(scale[0]), 1),
937  (int) fmax((fabs(extent.MaxY - extent.MinY) + (fabs(scale[1]) / 2.)) / fabs(scale[1]), 1)
938  };
939 
940  raster = rt_raster_new(_dim[0], _dim[1]);
941  if (raster == NULL) {
942  rterror("rt_raster_compute_skewed_raster: Could not create output raster");
943  return NULL;
944  }
945 
946  rt_raster_set_offsets(raster, extent.MinX, extent.MaxY);
947  rt_raster_set_scale(raster, fabs(scale[0]), -1 * fabs(scale[1]));
948  rt_raster_set_skews(raster, skew[0], skew[1]);
949 
950  return raster;
951  }
952 
953  /* direction to shift upper-left corner */
954  if (skew[0] > 0.)
955  _d[0] = -1;
956  if (skew[1] < 0.)
957  _d[1] = 1;
958 
959  /* geotransform */
960  _gt[0] = extent.UpperLeftX;
961  _gt[2] = skew[0] * tolerance;
962  _gt[3] = extent.UpperLeftY;
963  _gt[4] = skew[1] * tolerance;
964 
965  RASTER_DEBUGF(4, "Initial geotransform: %f, %f, %f, %f, %f, %f",
966  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]
967  );
968  RASTER_DEBUGF(4, "Delta: %d, %d", _d[0], _d[1]);
969 
970  /* simple raster */
971  if ((raster = rt_raster_new(1, 1)) == NULL) {
972  rterror("rt_raster_compute_skewed_raster: Out of memory allocating extent raster");
973  return NULL;
974  }
976 
977  /* get inverse geotransform matrix */
978  if (!GDALInvGeoTransform(_gt, _igt)) {
979  rterror("rt_raster_compute_skewed_raster: Could not compute inverse geotransform matrix");
981  return NULL;
982  }
983  RASTER_DEBUGF(4, "Inverse geotransform: %f, %f, %f, %f, %f, %f",
984  _igt[0], _igt[1], _igt[2], _igt[3], _igt[4], _igt[5]
985  );
986 
987  /* shift along axis */
988  for (i = 0; i < 2; i++) {
989  covers = 0;
990  run = 0;
991 
992  RASTER_DEBUGF(3, "Shifting along %s axis", i < 1 ? "X" : "Y");
993 
994  do {
995 
996  /* prevent possible infinite loop */
997  if (run > max_run) {
998  rterror("rt_raster_compute_skewed_raster: Could not compute skewed extent due to check preventing infinite loop");
1000  return NULL;
1001  }
1002 
1003  /*
1004  check the four corners that they are covered along the specific axis
1005  pixel column should be >= 0
1006  */
1007  for (j = 0; j < 4; j++) {
1008  switch (j) {
1009  /* upper-left */
1010  case 0:
1011  _xy[0] = extent.MinX;
1012  _xy[1] = extent.MaxY;
1013  break;
1014  /* lower-left */
1015  case 1:
1016  _xy[0] = extent.MinX;
1017  _xy[1] = extent.MinY;
1018  break;
1019  /* lower-right */
1020  case 2:
1021  _xy[0] = extent.MaxX;
1022  _xy[1] = extent.MinY;
1023  break;
1024  /* upper-right */
1025  case 3:
1026  _xy[0] = extent.MaxX;
1027  _xy[1] = extent.MaxY;
1028  break;
1029  }
1030 
1032  raster,
1033  _xy[0], _xy[1],
1034  &(_r[0]), &(_r[1]),
1035  _igt
1036  );
1037  if (rtn != ES_NONE) {
1038  rterror("rt_raster_compute_skewed_raster: Could not compute raster pixel for spatial coordinates");
1040  return NULL;
1041  }
1042 
1043  RASTER_DEBUGF(4, "Point %d at cell %d x %d", j, (int) _r[0], (int) _r[1]);
1044 
1045  /* raster doesn't cover point */
1046  if ((int) _r[i] < 0) {
1047  RASTER_DEBUGF(4, "Point outside of skewed extent: %d", j);
1048  covers = 0;
1049 
1050  if (_dlastpos != j) {
1051  _dlast = (int) _r[i];
1052  _dlastpos = j;
1053  }
1054  else if ((int) _r[i] < _dlast) {
1055  RASTER_DEBUG(4, "Point going in wrong direction. Reversing direction");
1056  _d[i] *= -1;
1057  _dlastpos = -1;
1058  run = 0;
1059  }
1060 
1061  break;
1062  }
1063 
1064  covers++;
1065  }
1066 
1067  if (!covers) {
1068  x = 0;
1069  y = 0;
1070  if (i < 1)
1071  x = _d[i] * fabs(_r[i]);
1072  else
1073  y = _d[i] * fabs(_r[i]);
1074 
1076  raster,
1077  x, y,
1078  &(_w[0]), &(_w[1]),
1079  _gt
1080  );
1081  if (rtn != ES_NONE) {
1082  rterror("rt_raster_compute_skewed_raster: Could not compute spatial coordinates for raster pixel");
1084  return NULL;
1085  }
1086 
1087  /* adjust ul */
1088  if (i < 1)
1089  _gt[0] = _w[i];
1090  else
1091  _gt[3] = _w[i];
1093  RASTER_DEBUGF(4, "Shifted geotransform: %f, %f, %f, %f, %f, %f",
1094  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]
1095  );
1096 
1097  /* get inverse geotransform matrix */
1098  if (!GDALInvGeoTransform(_gt, _igt)) {
1099  rterror("rt_raster_compute_skewed_raster: Could not compute inverse geotransform matrix");
1101  return NULL;
1102  }
1103  RASTER_DEBUGF(4, "Inverse geotransform: %f, %f, %f, %f, %f, %f",
1104  _igt[0], _igt[1], _igt[2], _igt[3], _igt[4], _igt[5]
1105  );
1106  }
1107 
1108  run++;
1109  }
1110  while (!covers);
1111  }
1112 
1113  /* covers test */
1115  raster,
1116  extent.MaxX, extent.MinY,
1117  &(_r[0]), &(_r[1]),
1118  _igt
1119  );
1120  if (rtn != ES_NONE) {
1121  rterror("rt_raster_compute_skewed_raster: Could not compute raster pixel for spatial coordinates");
1123  return NULL;
1124  }
1125 
1126  RASTER_DEBUGF(4, "geopoint %f x %f at cell %d x %d", extent.MaxX, extent.MinY, (int) _r[0], (int) _r[1]);
1127 
1128  raster->width = _r[0];
1129  raster->height = _r[1];
1130 
1131  /* initialize GEOS */
1132  initGEOS(rtinfo, lwgeom_geos_error);
1133 
1134  /* create reference LWPOLY */
1135  {
1136  LWPOLY *npoly = rt_util_envelope_to_lwpoly(extent);
1137  if (npoly == NULL) {
1138  rterror("rt_raster_compute_skewed_raster: Could not build extent's geometry for covers test");
1140  return NULL;
1141  }
1142 
1143  ngeom = (GEOSGeometry *) LWGEOM2GEOS(lwpoly_as_lwgeom(npoly), 0);
1144  lwpoly_free(npoly);
1145  }
1146 
1147  do {
1148  covers = 0;
1149 
1150  /* construct sgeom from raster */
1151  if ((rt_raster_get_convex_hull(raster, &geom) != ES_NONE) || geom == NULL) {
1152  rterror("rt_raster_compute_skewed_raster: Could not build skewed extent's geometry for covers test");
1153  GEOSGeom_destroy(ngeom);
1155  return NULL;
1156  }
1157 
1158  sgeom = (GEOSGeometry *) LWGEOM2GEOS(geom, 0);
1159  lwgeom_free(geom);
1160 
1161  covers = GEOSRelatePattern(sgeom, ngeom, "******FF*");
1162  GEOSGeom_destroy(sgeom);
1163 
1164  if (covers == 2) {
1165  rterror("rt_raster_compute_skewed_raster: Could not run covers test");
1166  GEOSGeom_destroy(ngeom);
1168  return NULL;
1169  }
1170 
1171  if (!covers)
1172  {
1173  raster->width++;
1174  raster->height++;
1175  }
1176  }
1177  while (!covers);
1178 
1179  RASTER_DEBUGF(4, "Skewed extent does cover normal extent with dimensions %d x %d", raster->width, raster->height);
1180 
1181  raster->width = (int) ((((double) raster->width) * fabs(_gt[1]) + fabs(scale[0] / 2.)) / fabs(scale[0]));
1182  raster->height = (int) ((((double) raster->height) * fabs(_gt[5]) + fabs(scale[1] / 2.)) / fabs(scale[1]));
1183  _gt[1] = fabs(scale[0]);
1184  _gt[5] = -1 * fabs(scale[1]);
1185  _gt[2] = skew[0];
1186  _gt[4] = skew[1];
1188 
1189  /* minimize width/height */
1190  for (i = 0; i < 2; i++) {
1191  covers = 1;
1192  do {
1193  if (i < 1)
1194  raster->width--;
1195  else
1196  raster->height--;
1197 
1198  /* construct sgeom from raster */
1199  if ((rt_raster_get_convex_hull(raster, &geom) != ES_NONE) || geom == NULL) {
1200  rterror("rt_raster_compute_skewed_raster: Could not build skewed extent's geometry for minimizing dimensions");
1201  GEOSGeom_destroy(ngeom);
1203  return NULL;
1204  }
1205 
1206  sgeom = (GEOSGeometry *) LWGEOM2GEOS(geom, 0);
1207  lwgeom_free(geom);
1208 
1209  covers = GEOSRelatePattern(sgeom, ngeom, "******FF*");
1210  GEOSGeom_destroy(sgeom);
1211 
1212  if (covers == 2) {
1213  rterror("rt_raster_compute_skewed_raster: Could not run covers test for minimizing dimensions");
1214  GEOSGeom_destroy(ngeom);
1216  return NULL;
1217  }
1218  } while (covers);
1219 
1220  if (i < 1)
1221  raster->width++;
1222  else
1223  raster->height++;
1224 
1225  }
1226 
1227  GEOSGeom_destroy(ngeom);
1228 
1229  return raster;
1230 }
1231 
1239 int
1241  return (!raster || raster->height == 0 || raster->width == 0);
1242 }
1243 
1252 int
1254  return !(NULL == raster || nband >= raster->numBands || nband < 0);
1255 }
1256 
1257 /******************************************************************************
1258 * rt_raster_copy_band()
1259 ******************************************************************************/
1260 
1275 int
1277  rt_raster torast, rt_raster fromrast,
1278  int fromindex, int toindex
1279 ) {
1280  rt_band srcband = NULL;
1281  rt_band dstband = NULL;
1282 
1283  assert(NULL != torast);
1284  assert(NULL != fromrast);
1285 
1286  /* Check raster dimensions */
1287  if (torast->height != fromrast->height || torast->width != fromrast->width) {
1288  rtwarn("rt_raster_copy_band: Attempting to add a band with different width or height");
1289  return -1;
1290  }
1291 
1292  /* Check bands limits */
1293  if (fromrast->numBands < 1) {
1294  rtwarn("rt_raster_copy_band: Second raster has no band");
1295  return -1;
1296  }
1297  else if (fromindex < 0) {
1298  rtwarn("rt_raster_copy_band: Band index for second raster < 0. Defaulted to 0");
1299  fromindex = 0;
1300  }
1301  else if (fromindex >= fromrast->numBands) {
1302  rtwarn("rt_raster_copy_band: Band index for second raster > number of bands, truncated from %u to %u", fromindex, fromrast->numBands - 1);
1303  fromindex = fromrast->numBands - 1;
1304  }
1305 
1306  if (toindex < 0) {
1307  rtwarn("rt_raster_copy_band: Band index for first raster < 0. Defaulted to 0");
1308  toindex = 0;
1309  }
1310  else if (toindex > torast->numBands) {
1311  rtwarn("rt_raster_copy_band: Band index for first raster > number of bands, truncated from %u to %u", toindex, torast->numBands);
1312  toindex = torast->numBands;
1313  }
1314 
1315  /* Get band from source raster */
1316  srcband = rt_raster_get_band(fromrast, fromindex);
1317 
1318  /* duplicate band */
1319  dstband = rt_band_duplicate(srcband);
1320 
1321  /* Add band to the second raster */
1322  return rt_raster_add_band(torast, dstband, toindex);
1323 }
1324 
1325 /******************************************************************************
1326 * rt_raster_from_band()
1327 ******************************************************************************/
1328 
1340 rt_raster
1341 rt_raster_from_band(rt_raster raster, uint32_t *bandNums, int count) {
1342  rt_raster rast = NULL;
1343  int i = 0;
1344  int j = 0;
1345  int idx;
1346  int32_t flag;
1347  double gt[6] = {0.};
1348 
1349  assert(NULL != raster);
1350  assert(NULL != bandNums);
1351 
1352  RASTER_DEBUGF(3, "rt_raster_from_band: source raster has %d bands",
1354 
1355  /* create new raster */
1356  rast = rt_raster_new(raster->width, raster->height);
1357  if (NULL == rast) {
1358  rterror("rt_raster_from_band: Out of memory allocating new raster");
1359  return NULL;
1360  }
1361 
1362  /* copy raster attributes */
1365 
1366  /* srid */
1367  rt_raster_set_srid(rast, raster->srid);
1368 
1369  /* copy bands */
1370  for (i = 0; i < count; i++) {
1371  idx = bandNums[i];
1372  flag = rt_raster_copy_band(rast, raster, idx, i);
1373 
1374  if (flag < 0) {
1375  rterror("rt_raster_from_band: Could not copy band");
1376  for (j = 0; j < i; j++) rt_band_destroy(rast->bands[j]);
1378  return NULL;
1379  }
1380 
1381  RASTER_DEBUGF(3, "rt_raster_from_band: band created at index %d",
1382  flag);
1383  }
1384 
1385  RASTER_DEBUGF(3, "rt_raster_from_band: new raster has %d bands",
1387  return rast;
1388 }
1389 
1390 /******************************************************************************
1391 * rt_raster_replace_band()
1392 ******************************************************************************/
1393 
1403 rt_band
1405  rt_band oldband = NULL;
1406  assert(NULL != raster);
1407  assert(NULL != band);
1408 
1409  if (band->width != raster->width || band->height != raster->height) {
1410  rterror("rt_raster_replace_band: Band does not match raster's dimensions: %dx%d band to %dx%d raster",
1411  band->width, band->height, raster->width, raster->height);
1412  return 0;
1413  }
1414 
1415  if (index >= raster->numBands || index < 0) {
1416  rterror("rt_raster_replace_band: Band index is not valid");
1417  return 0;
1418  }
1419 
1420  oldband = rt_raster_get_band(raster, index);
1421  RASTER_DEBUGF(3, "rt_raster_replace_band: old band at %p", oldband);
1422  RASTER_DEBUGF(3, "rt_raster_replace_band: new band at %p", band);
1423 
1424  raster->bands[index] = band;
1425  RASTER_DEBUGF(3, "rt_raster_replace_band: new band at %p", raster->bands[index]);
1426 
1427  band->raster = raster;
1428  oldband->raster = NULL;
1429 
1430  return oldband;
1431 }
1432 
1433 /******************************************************************************
1434 * rt_raster_clone()
1435 ******************************************************************************/
1436 
1445 rt_raster
1447  rt_raster rtn = NULL;
1448  double gt[6] = {0};
1449 
1450  assert(NULL != raster);
1451 
1452  if (deep) {
1453  int numband = rt_raster_get_num_bands(raster);
1454  uint32_t *nband = NULL;
1455  int i = 0;
1456 
1457  nband = rtalloc(sizeof(uint32_t) * numband);
1458  if (nband == NULL) {
1459  rterror("rt_raster_clone: Could not allocate memory for deep clone");
1460  return NULL;
1461  }
1462  for (i = 0; i < numband; i++)
1463  nband[i] = i;
1464 
1465  rtn = rt_raster_from_band(raster, nband, numband);
1466  rtdealloc(nband);
1467 
1468  return rtn;
1469  }
1470 
1471  rtn = rt_raster_new(
1474  );
1475  if (rtn == NULL) {
1476  rterror("rt_raster_clone: Could not create cloned raster");
1477  return NULL;
1478  }
1479 
1483 
1484  return rtn;
1485 }
1486 
1487 /******************************************************************************
1488 * rt_raster_copy_to_geometry()
1489 ******************************************************************************/
1490 
1493  rt_raster raster,
1494  uint32_t bandnum,
1495  char dim,
1496  rt_resample_type resample,
1497  const LWGEOM *lwgeom_in,
1498  LWGEOM **lwgeom_out
1499  )
1500 {
1501  int has_z = lwgeom_has_z(lwgeom_in);
1502  int has_m = lwgeom_has_m(lwgeom_in);
1503  LWGEOM *lwgeom;
1504  LWPOINTITERATOR* it;
1505  POINT4D p;
1506  double igt[6] = {0};
1507  rt_errorstate err;
1508  rt_band band = NULL;
1509  double nodatavalue = 0.0;
1510 
1511  /* Get the band reference and read the nodatavalue */
1512  band = rt_raster_get_band(raster, bandnum);
1513  if (!band) {
1514  rterror("unable to read requested band");
1515  return ES_ERROR;
1516  }
1517  rt_band_get_nodata(band, &nodatavalue);
1518 
1519  /* Fluff up geometry to have space for our new dimension */
1520  if (dim == 'z') {
1521  if (has_z)
1522  lwgeom = lwgeom_clone(lwgeom_in);
1523  else if (has_m)
1524  lwgeom = lwgeom_force_4d(lwgeom_in, nodatavalue, nodatavalue);
1525  else
1526  lwgeom = lwgeom_force_3dz(lwgeom_in, nodatavalue);
1527  }
1528  else if (dim == 'm') {
1529  if (has_m)
1530  lwgeom = lwgeom_clone(lwgeom_in);
1531  if (has_z)
1532  lwgeom = lwgeom_force_4d(lwgeom_in, nodatavalue, nodatavalue);
1533  else
1534  lwgeom = lwgeom_force_3dm(lwgeom_in, nodatavalue);
1535  }
1536  else {
1537  rterror("unknown value for dim");
1538  return ES_ERROR;
1539  }
1540 
1541  /* Read every point in the geometry */
1542  it = lwpointiterator_create_rw(lwgeom);
1543  while (lwpointiterator_has_next(it))
1544  {
1545  int nodata;
1546  double xr, yr, value;
1547  lwpointiterator_peek(it, &p);
1548 
1549  /* Convert X/Y world coordinates into raster coordinates */
1550  err = rt_raster_geopoint_to_rasterpoint(raster, p.x, p.y, &xr, &yr, igt);
1551  if (err != ES_NONE) continue;
1552 
1553  /* Read the raster value for this point */
1555  band,
1556  xr, yr,
1557  resample,
1558  &value, &nodata
1559  );
1560 
1561  if (err != ES_NONE) {
1562  value = NAN;
1563  }
1564 
1565  /* Copy in the raster value */
1566  if (dim == 'z')
1567  p.z = value;
1568  if (dim == 'm')
1569  p.m = value;
1570 
1572  }
1574 
1575  if (lwgeom_out)
1576  *lwgeom_out = lwgeom;
1577  return ES_NONE;
1578 }
1579 
1580 
1581 /******************************************************************************
1582 * rt_raster_to_gdal()
1583 ******************************************************************************/
1584 
1597 uint8_t*
1599  rt_raster raster, const char *srs,
1600  char *format, char **options, uint64_t *gdalsize
1601 ) {
1602  const char *cc;
1603  const char *vio;
1604 
1605  GDALDriverH src_drv = NULL;
1606  int destroy_src_drv = 0;
1607  GDALDatasetH src_ds = NULL;
1608 
1609  vsi_l_offset rtn_lenvsi;
1610  uint64_t rtn_len = 0;
1611 
1612  GDALDriverH rtn_drv = NULL;
1613  GDALDatasetH rtn_ds = NULL;
1614  uint8_t *rtn = NULL;
1615 
1616  assert(NULL != raster);
1617  assert(NULL != gdalsize);
1618 
1619  /* any supported format is possible */
1621  RASTER_DEBUG(3, "loaded all supported GDAL formats");
1622 
1623  /* output format not specified */
1624  if (format == NULL || !strlen(format))
1625  format = "GTiff";
1626  RASTER_DEBUGF(3, "output format is %s", format);
1627 
1628  /* load raster into a GDAL MEM raster */
1629  src_ds = rt_raster_to_gdal_mem(raster, srs, NULL, NULL, 0, &src_drv, &destroy_src_drv);
1630  if (NULL == src_ds) {
1631  rterror("rt_raster_to_gdal: Could not convert raster to GDAL MEM format");
1632  return 0;
1633  }
1634 
1635  /* load driver */
1636  rtn_drv = GDALGetDriverByName(format);
1637  if (NULL == rtn_drv) {
1638  rterror("rt_raster_to_gdal: Could not load the output GDAL driver");
1639  GDALClose(src_ds);
1640  if (destroy_src_drv) GDALDestroyDriver(src_drv);
1641  return 0;
1642  }
1643  RASTER_DEBUG(3, "Output driver loaded");
1644 
1645  /* CreateCopy support */
1646  cc = GDALGetMetadataItem(rtn_drv, GDAL_DCAP_CREATECOPY, NULL);
1647  /* VirtualIO support */
1648  vio = GDALGetMetadataItem(rtn_drv, GDAL_DCAP_VIRTUALIO, NULL);
1649 
1650  if (cc == NULL || vio == NULL) {
1651  rterror("rt_raster_to_gdal: Output GDAL driver does not support CreateCopy and/or VirtualIO");
1652  GDALClose(src_ds);
1653  if (destroy_src_drv) GDALDestroyDriver(src_drv);
1654  return 0;
1655  }
1656 
1657  /* convert GDAL MEM raster to output format */
1658  RASTER_DEBUG(3, "Copying GDAL MEM raster to memory file in output format");
1659  rtn_ds = GDALCreateCopy(
1660  rtn_drv,
1661  "/vsimem/out.dat", /* should be fine assuming this is in a process */
1662  src_ds,
1663  FALSE, /* should copy be strictly equivalent? */
1664  options, /* format options */
1665  NULL, /* progress function */
1666  NULL /* progress data */
1667  );
1668 
1669  /* close source dataset */
1670  GDALClose(src_ds);
1671  if (destroy_src_drv) GDALDestroyDriver(src_drv);
1672  RASTER_DEBUG(3, "Closed GDAL MEM raster");
1673 
1674  if (NULL == rtn_ds) {
1675  rterror("rt_raster_to_gdal: Could not create the output GDAL dataset");
1676  return 0;
1677  }
1678 
1679  RASTER_DEBUGF(4, "dataset SRS: %s", GDALGetProjectionRef(rtn_ds));
1680 
1681  /* close dataset, this also flushes any pending writes */
1682  GDALClose(rtn_ds);
1683  RASTER_DEBUG(3, "Closed GDAL output raster");
1684 
1685  RASTER_DEBUG(3, "Done copying GDAL MEM raster to memory file in output format");
1686 
1687  /* from memory file to buffer */
1688  RASTER_DEBUG(3, "Copying GDAL memory file to buffer");
1689  rtn = VSIGetMemFileBuffer("/vsimem/out.dat", &rtn_lenvsi, TRUE);
1690  RASTER_DEBUG(3, "Done copying GDAL memory file to buffer");
1691  if (NULL == rtn) {
1692  rterror("rt_raster_to_gdal: Could not create the output GDAL raster");
1693  return 0;
1694  }
1695 
1696  rtn_len = (uint64_t) rtn_lenvsi;
1697  *gdalsize = rtn_len;
1698 
1699  return rtn;
1700 }
1701 
1702 /******************************************************************************
1703 * rt_raster_gdal_drivers()
1704 ******************************************************************************/
1705 
1716 rt_raster_gdal_drivers(uint32_t *drv_count, uint8_t can_write)
1717 {
1718  assert(drv_count != NULL);
1719  uint32_t output_driver = 0;
1721  uint32_t count = (uint32_t)GDALGetDriverCount();
1722 
1723  rt_gdaldriver rtn = (rt_gdaldriver)rtalloc(count * sizeof(struct rt_gdaldriver_t));
1724  if (!rtn)
1725  {
1726  rterror("rt_raster_gdal_drivers: Could not allocate memory for gdaldriver structure");
1727  *drv_count = output_driver;
1728  return NULL;
1729  }
1730 
1731  for (uint32_t i = 0; i < count; i++)
1732  {
1733  GDALDriverH *drv = GDALGetDriver(i);
1734 
1735 #ifdef GDAL_DCAP_RASTER
1736  /* Starting with GDAL 2.0, vector drivers can also be returned */
1737  /* Only keep raster drivers */
1738  const char *is_raster;
1739  is_raster = GDALGetMetadataItem(drv, GDAL_DCAP_RASTER, NULL);
1740  if (!is_raster || !EQUAL(is_raster, "YES"))
1741  continue;
1742 #endif
1743 
1744  /* CreateCopy support */
1745  const char *cc = GDALGetMetadataItem(drv, GDAL_DCAP_CREATECOPY, NULL);
1746  if (can_write && !cc)
1747  continue;
1748 
1749  /* VirtualIO support */
1750  const char *vio = GDALGetMetadataItem(drv, GDAL_DCAP_VIRTUALIO, NULL);
1751  if (can_write && !vio)
1752  continue;
1753 
1754  /* we can always read what GDAL can load */
1755  rtn[output_driver].can_read = 1;
1756  /* we require CreateCopy and VirtualIO support to write to GDAL */
1757  rtn[output_driver].can_write = (cc != NULL && vio != NULL);
1758 
1759  /* index of driver */
1760  rtn[output_driver].idx = i;
1761 
1762  /* short name */
1763  const char *txt = GDALGetDriverShortName(drv);
1764  size_t txt_len = strlen(txt);
1765  txt_len = (txt_len + 1) * sizeof(char);
1766  rtn[output_driver].short_name = (char *)rtalloc(txt_len);
1767  memcpy(rtn[output_driver].short_name, txt, txt_len);
1768 
1769  /* long name */
1770  txt = GDALGetDriverLongName(drv);
1771  txt_len = strlen(txt);
1772  txt_len = (txt_len + 1) * sizeof(char);
1773  rtn[output_driver].long_name = (char *)rtalloc(txt_len);
1774  memcpy(rtn[output_driver].long_name, txt, txt_len);
1775 
1776  /* creation options */
1777  txt = GDALGetDriverCreationOptionList(drv);
1778  txt_len = strlen(txt);
1779  txt_len = (txt_len + 1) * sizeof(char);
1780  rtn[output_driver].create_options = (char *)rtalloc(txt_len);
1781  memcpy(rtn[output_driver].create_options, txt, txt_len);
1782 
1783  output_driver++;
1784  }
1785 
1786  /* free unused memory */
1787  rtn = rtrealloc(rtn, output_driver * sizeof(struct rt_gdaldriver_t));
1788  *drv_count = output_driver;
1789 
1790  return rtn;
1791 }
1792 
1793 /******************************************************************************
1794 * rt_raster_to_gdal_mem()
1795 ******************************************************************************/
1796 
1812 GDALDatasetH
1814  rt_raster raster,
1815  const char *srs,
1816  uint32_t *bandNums,
1817  int *excludeNodataValues,
1818  int count,
1819  GDALDriverH *rtn_drv, int *destroy_rtn_drv
1820 ) {
1821  GDALDriverH drv = NULL;
1822  GDALDatasetH ds = NULL;
1823  double gt[6] = {0.0};
1824  CPLErr cplerr;
1825  GDALDataType gdal_pt = GDT_Unknown;
1826  GDALRasterBandH band;
1827  void *pVoid;
1828  char *pszDataPointer;
1829  char szGDALOption[50];
1830  char *apszOptions[4];
1831  double nodata = 0.0;
1832  int allocBandNums = 0;
1833  int allocNodataValues = 0;
1834 
1835  int i;
1836  uint32_t numBands;
1837  uint32_t width = 0;
1838  uint32_t height = 0;
1839  rt_band rtband = NULL;
1840  rt_pixtype pt = PT_END;
1841 
1842  assert(NULL != raster);
1843  assert(NULL != rtn_drv);
1844  assert(NULL != destroy_rtn_drv);
1845 
1846  *destroy_rtn_drv = 0;
1847 
1848  /* store raster in GDAL MEM raster */
1849  if (!rt_util_gdal_driver_registered("MEM")) {
1850  RASTER_DEBUG(4, "Registering MEM driver");
1851  GDALRegister_MEM();
1852  *destroy_rtn_drv = 1;
1853  }
1854  drv = GDALGetDriverByName("MEM");
1855  if (NULL == drv) {
1856  rterror("rt_raster_to_gdal_mem: Could not load the MEM GDAL driver");
1857  return 0;
1858  }
1859  *rtn_drv = drv;
1860 
1861  /* unload driver from GDAL driver manager */
1862  if (*destroy_rtn_drv) {
1863  RASTER_DEBUG(4, "Deregistering MEM driver");
1864  GDALDeregisterDriver(drv);
1865  }
1866 
1867  width = rt_raster_get_width(raster);
1868  height = rt_raster_get_height(raster);
1869  ds = GDALCreate(
1870  drv, "",
1871  width, height,
1872  0, GDT_Byte, NULL
1873  );
1874  if (NULL == ds) {
1875  rterror("rt_raster_to_gdal_mem: Could not create a GDALDataset to convert into");
1876  return 0;
1877  }
1878 
1879  /* add geotransform */
1881  cplerr = GDALSetGeoTransform(ds, gt);
1882  if (cplerr != CE_None) {
1883  rterror("rt_raster_to_gdal_mem: Could not set geotransformation");
1884  GDALClose(ds);
1885  return 0;
1886  }
1887 
1888  /* set spatial reference */
1889  if (NULL != srs && strlen(srs)) {
1890  char *_srs = rt_util_gdal_convert_sr(srs, 0);
1891  if (_srs == NULL) {
1892  rterror("rt_raster_to_gdal_mem: Could not convert srs to GDAL accepted format");
1893  GDALClose(ds);
1894  return 0;
1895  }
1896 
1897  cplerr = GDALSetProjection(ds, _srs);
1898  CPLFree(_srs);
1899  if (cplerr != CE_None) {
1900  rterror("rt_raster_to_gdal_mem: Could not set projection");
1901  GDALClose(ds);
1902  return 0;
1903  }
1904  RASTER_DEBUGF(3, "Projection set to: %s", GDALGetProjectionRef(ds));
1905  }
1906 
1907  /* process bandNums */
1908  numBands = rt_raster_get_num_bands(raster);
1909  if (NULL != bandNums && count > 0) {
1910  for (i = 0; i < count; i++) {
1911  if (bandNums[i] >= numBands) {
1912  rterror("rt_raster_to_gdal_mem: The band index %d is invalid", bandNums[i]);
1913  GDALClose(ds);
1914  return 0;
1915  }
1916  }
1917  }
1918  else {
1919  count = numBands;
1920  bandNums = (uint32_t *) rtalloc(sizeof(uint32_t) * count);
1921  if (NULL == bandNums) {
1922  rterror("rt_raster_to_gdal_mem: Could not allocate memory for band indices");
1923  GDALClose(ds);
1924  return 0;
1925  }
1926  allocBandNums = 1;
1927  for (i = 0; i < count; i++) bandNums[i] = i;
1928  }
1929 
1930  /* process exclude_nodata_values */
1931  if (NULL == excludeNodataValues) {
1932  excludeNodataValues = (int *) rtalloc(sizeof(int) * count);
1933  if (NULL == excludeNodataValues) {
1934  rterror("rt_raster_to_gdal_mem: Could not allocate memory for NODATA flags");
1935  GDALClose(ds);
1936  return 0;
1937  }
1938  allocNodataValues = 1;
1939  for (i = 0; i < count; i++) excludeNodataValues[i] = 1;
1940  }
1941 
1942  /* add band(s) */
1943  for (i = 0; i < count; i++) {
1944  rtband = rt_raster_get_band(raster, bandNums[i]);
1945  if (NULL == rtband) {
1946  rterror("rt_raster_to_gdal_mem: Could not get requested band index %d", bandNums[i]);
1947  if (allocBandNums) rtdealloc(bandNums);
1948  if (allocNodataValues) rtdealloc(excludeNodataValues);
1949  GDALClose(ds);
1950  return 0;
1951  }
1952 
1953  pt = rt_band_get_pixtype(rtband);
1954  gdal_pt = rt_util_pixtype_to_gdal_datatype(pt);
1955  if (gdal_pt == GDT_Unknown)
1956  rtwarn("rt_raster_to_gdal_mem: Unknown pixel type for band");
1957 
1958  /*
1959  For all pixel types other than PT_8BSI, set pointer to start of data
1960  */
1961 #if POSTGIS_GDAL_VERSION < 30700
1962  if (pt != PT_8BSI) {
1963 #endif
1964  pVoid = rt_band_get_data(rtband);
1965  RASTER_DEBUGF(4, "Band data is at pos %p", pVoid);
1966 
1967  pszDataPointer = (char *) rtalloc(20 * sizeof (char));
1968  sprintf(pszDataPointer, "%p", pVoid);
1969  RASTER_DEBUGF(4, "rt_raster_to_gdal_mem: szDatapointer is %p",
1970  pszDataPointer);
1971 
1972  if (strncasecmp(pszDataPointer, "0x", 2) == 0)
1973  sprintf(szGDALOption, "DATAPOINTER=%s", pszDataPointer);
1974  else
1975  sprintf(szGDALOption, "DATAPOINTER=0x%s", pszDataPointer);
1976 
1977  RASTER_DEBUG(3, "Storing info for GDAL MEM raster band");
1978 
1979  apszOptions[0] = szGDALOption;
1980  apszOptions[1] = NULL; /* pixel offset, not needed */
1981  apszOptions[2] = NULL; /* line offset, not needed */
1982  apszOptions[3] = NULL;
1983 
1984  /* free */
1985  rtdealloc(pszDataPointer);
1986 
1987  /* add band */
1988  if (GDALAddBand(ds, gdal_pt, apszOptions) == CE_Failure) {
1989  rterror("rt_raster_to_gdal_mem: Could not add GDAL raster band");
1990  if (allocBandNums) rtdealloc(bandNums);
1991  GDALClose(ds);
1992  return 0;
1993  }
1994 #if POSTGIS_GDAL_VERSION < 30700
1995  /*
1996  PT_8BSI is special as GDAL (prior to 3.7) has no equivalent pixel type.
1997  Must convert 8BSI to 16BSI so create basic band
1998  */
1999  } else {
2000  /* add band */
2001  if (GDALAddBand(ds, gdal_pt, NULL) == CE_Failure) {
2002  rterror("rt_raster_to_gdal_mem: Could not add GDAL raster band");
2003  if (allocBandNums) rtdealloc(bandNums);
2004  if (allocNodataValues) rtdealloc(excludeNodataValues);
2005  GDALClose(ds);
2006  return 0;
2007  }
2008  }
2009 #endif
2010 
2011  /* check band count */
2012  if (GDALGetRasterCount(ds) != i + 1) {
2013  rterror("rt_raster_to_gdal_mem: Error creating GDAL MEM raster band");
2014  if (allocBandNums) rtdealloc(bandNums);
2015  if (allocNodataValues) rtdealloc(excludeNodataValues);
2016  GDALClose(ds);
2017  return 0;
2018  }
2019 
2020  /* get new band */
2021  band = NULL;
2022  band = GDALGetRasterBand(ds, i + 1);
2023  if (NULL == band) {
2024  rterror("rt_raster_to_gdal_mem: Could not get GDAL band for additional processing");
2025  if (allocBandNums) rtdealloc(bandNums);
2026  if (allocNodataValues) rtdealloc(excludeNodataValues);
2027  GDALClose(ds);
2028  return 0;
2029  }
2030 
2031 #if POSTGIS_GDAL_VERSION < 30700
2032 
2033  /* PT_8BSI requires manual setting of pixels */
2034  if (pt == PT_8BSI) {
2035  uint32_t nXBlocks, nYBlocks;
2036  int nXBlockSize, nYBlockSize;
2037  uint32_t iXBlock, iYBlock;
2038  int nXValid, nYValid;
2039  int iX, iY;
2040  int iXMax, iYMax;
2041 
2042  int x, y, z;
2043  uint32_t valueslen = 0;
2044  int16_t *values = NULL;
2045  double value = 0.;
2046 
2047  /* this makes use of GDAL's "natural" blocks */
2048  GDALGetBlockSize(band, &nXBlockSize, &nYBlockSize);
2049  nXBlocks = (width + nXBlockSize - 1) / nXBlockSize;
2050  nYBlocks = (height + nYBlockSize - 1) / nYBlockSize;
2051  RASTER_DEBUGF(4, "(nXBlockSize, nYBlockSize) = (%d, %d)", nXBlockSize, nYBlockSize);
2052  RASTER_DEBUGF(4, "(nXBlocks, nYBlocks) = (%d, %d)", nXBlocks, nYBlocks);
2053 
2054  /* length is for the desired pixel type */
2055  valueslen = rt_pixtype_size(PT_16BSI) * nXBlockSize * nYBlockSize;
2056  values = rtalloc(valueslen);
2057  if (NULL == values) {
2058  rterror("rt_raster_to_gdal_mem: Could not allocate memory for GDAL band pixel values");
2059  if (allocBandNums) rtdealloc(bandNums);
2060  if (allocNodataValues) rtdealloc(excludeNodataValues);
2061  GDALClose(ds);
2062  return 0;
2063  }
2064 
2065  for (iYBlock = 0; iYBlock < nYBlocks; iYBlock++) {
2066  for (iXBlock = 0; iXBlock < nXBlocks; iXBlock++) {
2067  memset(values, 0, valueslen);
2068 
2069  x = iXBlock * nXBlockSize;
2070  y = iYBlock * nYBlockSize;
2071  RASTER_DEBUGF(4, "(iXBlock, iYBlock) = (%d, %d)", iXBlock, iYBlock);
2072  RASTER_DEBUGF(4, "(x, y) = (%d, %d)", x, y);
2073 
2074  /* valid block width */
2075  if ((iXBlock + 1) * nXBlockSize > width)
2076  nXValid = width - (iXBlock * nXBlockSize);
2077  else
2078  nXValid = nXBlockSize;
2079 
2080  /* valid block height */
2081  if ((iYBlock + 1) * nYBlockSize > height)
2082  nYValid = height - (iYBlock * nYBlockSize);
2083  else
2084  nYValid = nYBlockSize;
2085 
2086  RASTER_DEBUGF(4, "(nXValid, nYValid) = (%d, %d)", nXValid, nYValid);
2087 
2088  /* convert 8BSI values to 16BSI */
2089  z = 0;
2090  iYMax = y + nYValid;
2091  iXMax = x + nXValid;
2092  for (iY = y; iY < iYMax; iY++) {
2093  for (iX = x; iX < iXMax; iX++) {
2094  if (rt_band_get_pixel(rtband, iX, iY, &value, NULL) != ES_NONE) {
2095  rterror("rt_raster_to_gdal_mem: Could not get pixel value to convert from 8BSI to 16BSI");
2096  rtdealloc(values);
2097  if (allocBandNums) rtdealloc(bandNums);
2098  if (allocNodataValues) rtdealloc(excludeNodataValues);
2099  GDALClose(ds);
2100  return 0;
2101  }
2102 
2103  values[z++] = rt_util_clamp_to_16BSI(value);
2104  }
2105  }
2106 
2107  /* burn values */
2108  if (GDALRasterIO(
2109  band, GF_Write,
2110  x, y,
2111  nXValid, nYValid,
2112  values, nXValid, nYValid,
2113  gdal_pt,
2114  0, 0
2115  ) != CE_None) {
2116  rterror("rt_raster_to_gdal_mem: Could not write converted 8BSI to 16BSI values to GDAL band");
2117  rtdealloc(values);
2118  if (allocBandNums) rtdealloc(bandNums);
2119  if (allocNodataValues) rtdealloc(excludeNodataValues);
2120  GDALClose(ds);
2121  return 0;
2122  }
2123  }
2124  }
2125 
2126  rtdealloc(values);
2127  }
2128 #endif
2129 
2130  /* Add nodata value for band */
2131  if (rt_band_get_hasnodata_flag(rtband) != FALSE && excludeNodataValues[i]) {
2132  rt_band_get_nodata(rtband, &nodata);
2133  if (GDALSetRasterNoDataValue(band, nodata) != CE_None)
2134  rtwarn("rt_raster_to_gdal_mem: Could not set nodata value for band");
2135  RASTER_DEBUGF(3, "nodata value set to %f", GDALGetRasterNoDataValue(band, NULL));
2136  }
2137 
2138 #if POSTGIS_DEBUG_LEVEL > 3
2139  {
2140  GDALRasterBandH _grb = NULL;
2141  double _min;
2142  double _max;
2143  double _mean;
2144  double _stddev;
2145 
2146  _grb = GDALGetRasterBand(ds, i + 1);
2147  GDALComputeRasterStatistics(_grb, FALSE, &_min, &_max, &_mean, &_stddev, NULL, NULL);
2148  RASTER_DEBUGF(4, "GDAL Band %d stats: %f, %f, %f, %f", i + 1, _min, _max, _mean, _stddev);
2149  }
2150 #endif
2151 
2152  }
2153 
2154  /* necessary??? */
2155  GDALFlushCache(ds);
2156 
2157  if (allocBandNums) rtdealloc(bandNums);
2158  if (allocNodataValues) rtdealloc(excludeNodataValues);
2159 
2160  return ds;
2161 }
2162 
2163 /******************************************************************************
2164 * rt_raster_from_gdal_dataset()
2165 ******************************************************************************/
2166 
2174 rt_raster
2176  rt_raster rast = NULL;
2177  double gt[6] = {0};
2178  CPLErr cplerr;
2179  uint32_t width = 0;
2180  uint32_t height = 0;
2181  uint32_t numBands = 0;
2182  uint32_t i = 0;
2183  char *authname = NULL;
2184  char *authcode = NULL;
2185 
2186  GDALRasterBandH gdband = NULL;
2187  GDALDataType gdpixtype = GDT_Unknown;
2188  rt_band band;
2189  int32_t idx;
2190  rt_pixtype pt = PT_END;
2191  uint32_t ptlen = 0;
2192  int hasnodata = 0;
2193  double nodataval;
2194 
2195  int x;
2196  int y;
2197 
2198  uint32_t nXBlocks, nYBlocks;
2199  int nXBlockSize, nYBlockSize;
2200  uint32_t iXBlock, iYBlock;
2201  uint32_t nXValid, nYValid;
2202  uint32_t iY;
2203 
2204  uint8_t *values = NULL;
2205  uint32_t valueslen = 0;
2206  uint8_t *ptr = NULL;
2207 
2208  assert(NULL != ds);
2209 
2210  /* raster size */
2211  width = GDALGetRasterXSize(ds);
2212  height = GDALGetRasterYSize(ds);
2213  RASTER_DEBUGF(3, "Raster dimensions (width x height): %d x %d", width, height);
2214 
2215  /* create new raster */
2216  RASTER_DEBUG(3, "Creating new raster");
2217  rast = rt_raster_new(width, height);
2218  if (NULL == rast) {
2219  rterror("rt_raster_from_gdal_dataset: Out of memory allocating new raster");
2220  return NULL;
2221  }
2222  RASTER_DEBUGF(3, "Created raster dimensions (width x height): %d x %d", rast->width, rast->height);
2223 
2224  /* get raster attributes */
2225  cplerr = GDALGetGeoTransform(ds, gt);
2226  if (GDALGetGeoTransform(ds, gt) != CE_None) {
2227  RASTER_DEBUG(4, "Using default geotransform matrix (0, 1, 0, 0, 0, -1)");
2228  gt[0] = 0;
2229  gt[1] = 1;
2230  gt[2] = 0;
2231  gt[3] = 0;
2232  gt[4] = 0;
2233  gt[5] = -1;
2234  }
2235 
2236  /* apply raster attributes */
2238 
2239  RASTER_DEBUGF(3, "Raster geotransform (%f, %f, %f, %f, %f, %f)",
2240  gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
2241 
2242  /* srid */
2243  if (rt_util_gdal_sr_auth_info(ds, &authname, &authcode) == ES_NONE) {
2244  if (
2245  authname != NULL &&
2246  strcmp(authname, "EPSG") == 0 &&
2247  authcode != NULL
2248  ) {
2249  rt_raster_set_srid(rast, atoi(authcode));
2250  RASTER_DEBUGF(3, "New raster's SRID = %d", rast->srid);
2251  }
2252 
2253  if (authname != NULL)
2254  rtdealloc(authname);
2255  if (authcode != NULL)
2256  rtdealloc(authcode);
2257  }
2258 
2259  numBands = GDALGetRasterCount(ds);
2260 
2261 #if POSTGIS_DEBUG_LEVEL > 3
2262  for (i = 1; i <= numBands; i++) {
2263  GDALRasterBandH _grb = NULL;
2264  double _min;
2265  double _max;
2266  double _mean;
2267  double _stddev;
2268 
2269  _grb = GDALGetRasterBand(ds, i);
2270  GDALComputeRasterStatistics(_grb, FALSE, &_min, &_max, &_mean, &_stddev, NULL, NULL);
2271  RASTER_DEBUGF(4, "GDAL Band %d stats: %f, %f, %f, %f", i, _min, _max, _mean, _stddev);
2272  }
2273 #endif
2274 
2275  /* copy bands */
2276  for (i = 1; i <= numBands; i++) {
2277  RASTER_DEBUGF(3, "Processing band %d of %d", i, numBands);
2278  gdband = NULL;
2279  gdband = GDALGetRasterBand(ds, i);
2280  if (NULL == gdband) {
2281  rterror("rt_raster_from_gdal_dataset: Could not get GDAL band");
2283  return NULL;
2284  }
2285  RASTER_DEBUGF(4, "gdband @ %p", gdband);
2286 
2287  /* pixtype */
2288  gdpixtype = GDALGetRasterDataType(gdband);
2289  RASTER_DEBUGF(4, "gdpixtype, size = %s, %d", GDALGetDataTypeName(gdpixtype), GDALGetDataTypeSizeBytes(gdpixtype));
2290  pt = rt_util_gdal_datatype_to_pixtype(gdpixtype);
2291  if (pt == PT_END) {
2292  rterror("rt_raster_from_gdal_dataset: Unknown pixel type for GDAL band");
2294  return NULL;
2295  }
2296  ptlen = rt_pixtype_size(pt);
2297 
2298  /* size: width and height */
2299  width = GDALGetRasterBandXSize(gdband);
2300  height = GDALGetRasterBandYSize(gdband);
2301  RASTER_DEBUGF(3, "GDAL band dimensions (width x height): %d x %d", width, height);
2302 
2303  /* nodata */
2304  nodataval = GDALGetRasterNoDataValue(gdband, &hasnodata);
2305  RASTER_DEBUGF(3, "(hasnodata, nodataval) = (%d, %f)", hasnodata, nodataval);
2306 
2307  /* create band object */
2309  rast, pt,
2310  (hasnodata ? nodataval : 0),
2311  hasnodata, nodataval, rt_raster_get_num_bands(rast)
2312  );
2313  if (idx < 0) {
2314  rterror("rt_raster_from_gdal_dataset: Could not allocate memory for raster band");
2316  return NULL;
2317  }
2318  band = rt_raster_get_band(rast, idx);
2319  RASTER_DEBUGF(3, "Created band of dimension (width x height): %d x %d", band->width, band->height);
2320 
2321  /* this makes use of GDAL's "natural" blocks */
2322  GDALGetBlockSize(gdband, &nXBlockSize, &nYBlockSize);
2323  nXBlocks = (width + nXBlockSize - 1) / nXBlockSize;
2324  nYBlocks = (height + nYBlockSize - 1) / nYBlockSize;
2325  RASTER_DEBUGF(4, "(nXBlockSize, nYBlockSize) = (%d, %d)", nXBlockSize, nYBlockSize);
2326  RASTER_DEBUGF(4, "(nXBlocks, nYBlocks) = (%d, %d)", nXBlocks, nYBlocks);
2327 
2328  /* allocate memory for values */
2329  valueslen = ptlen * nXBlockSize * nYBlockSize;
2330  values = rtalloc(valueslen);
2331  if (values == NULL) {
2332  rterror("rt_raster_from_gdal_dataset: Could not allocate memory for GDAL band pixel values");
2334  return NULL;
2335  }
2336  RASTER_DEBUGF(3, "values @ %p of length = %d", values, valueslen);
2337 
2338  for (iYBlock = 0; iYBlock < nYBlocks; iYBlock++) {
2339  for (iXBlock = 0; iXBlock < nXBlocks; iXBlock++) {
2340  x = iXBlock * nXBlockSize;
2341  y = iYBlock * nYBlockSize;
2342  RASTER_DEBUGF(4, "(iXBlock, iYBlock) = (%d, %d)", iXBlock, iYBlock);
2343  RASTER_DEBUGF(4, "(x, y) = (%d, %d)", x, y);
2344 
2345  memset(values, 0, valueslen);
2346 
2347  /* valid block width */
2348  if ((iXBlock + 1) * nXBlockSize > width)
2349  nXValid = width - (iXBlock * nXBlockSize);
2350  else
2351  nXValid = nXBlockSize;
2352 
2353  /* valid block height */
2354  if ((iYBlock + 1) * nYBlockSize > height)
2355  nYValid = height - (iYBlock * nYBlockSize);
2356  else
2357  nYValid = nYBlockSize;
2358 
2359  RASTER_DEBUGF(4, "(nXValid, nYValid) = (%d, %d)", nXValid, nYValid);
2360 
2361  cplerr = GDALRasterIO(
2362  gdband, GF_Read,
2363  x, y,
2364  nXValid, nYValid,
2365  values, nXValid, nYValid,
2366  gdpixtype,
2367  0, 0
2368  );
2369  if (cplerr != CE_None) {
2370  rterror("rt_raster_from_gdal_dataset: Could not get data from GDAL raster");
2371  rtdealloc(values);
2373  return NULL;
2374  }
2375 
2376  /* if block width is same as raster width, shortcut */
2377  if (nXBlocks == 1 && nYBlockSize > 1 && nXValid == width) {
2378  x = 0;
2379  y = nYBlockSize * iYBlock;
2380 
2381  RASTER_DEBUGF(4, "Setting set of pixel lines at (%d, %d) for %d pixels", x, y, nXValid * nYValid);
2382  rt_band_set_pixel_line(band, x, y, values, nXValid * nYValid);
2383  }
2384  else {
2385  ptr = values;
2386  x = nXBlockSize * iXBlock;
2387  for (iY = 0; iY < nYValid; iY++) {
2388  y = iY + (nYBlockSize * iYBlock);
2389 
2390  RASTER_DEBUGF(4, "Setting pixel line at (%d, %d) for %d pixels", x, y, nXValid);
2391  rt_band_set_pixel_line(band, x, y, ptr, nXValid);
2392  ptr += (nXValid * ptlen);
2393  }
2394  }
2395  }
2396  }
2397 
2398  /* free memory */
2399  rtdealloc(values);
2400  }
2401 
2402  return rast;
2403 }
2404 
2405 /******************************************************************************
2406 * rt_raster_gdal_rasterize()
2407 ******************************************************************************/
2408 
2411  uint8_t noband;
2412 
2413  uint32_t numbands;
2414 
2415  OGRSpatialReferenceH src_sr;
2416 
2418  double *init;
2419  double *nodata;
2420  uint8_t *hasnodata;
2421  double *value;
2422  int *bandlist;
2423 };
2424 
2425 static _rti_rasterize_arg
2427  _rti_rasterize_arg arg = NULL;
2428 
2429  arg = rtalloc(sizeof(struct _rti_rasterize_arg_t));
2430  if (arg == NULL) {
2431  rterror("_rti_rasterize_arg_init: Could not allocate memory for _rti_rasterize_arg");
2432  return NULL;
2433  }
2434 
2435  arg->noband = 0;
2436 
2437  arg->numbands = 0;
2438 
2439  arg->src_sr = NULL;
2440 
2441  arg->pixtype = NULL;
2442  arg->init = NULL;
2443  arg->nodata = NULL;
2444  arg->hasnodata = NULL;
2445  arg->value = NULL;
2446  arg->bandlist = NULL;
2447 
2448  return arg;
2449 }
2450 
2451 static void
2453  if (arg->noband) {
2454  if (arg->pixtype != NULL)
2455  rtdealloc(arg->pixtype);
2456  if (arg->init != NULL)
2457  rtdealloc(arg->init);
2458  if (arg->nodata != NULL)
2459  rtdealloc(arg->nodata);
2460  if (arg->hasnodata != NULL)
2461  rtdealloc(arg->hasnodata);
2462  if (arg->value != NULL)
2463  rtdealloc(arg->value);
2464  }
2465 
2466  if (arg->bandlist != NULL)
2467  rtdealloc(arg->bandlist);
2468 
2469  if (arg->src_sr != NULL)
2470  OSRDestroySpatialReference(arg->src_sr);
2471 
2472  rtdealloc(arg);
2473 }
2474 
2501 rt_raster
2503  const unsigned char *wkb, uint32_t wkb_len,
2504  const char *srs,
2505  uint32_t num_bands, rt_pixtype *pixtype,
2506  double *init, double *value,
2507  double *nodata, uint8_t *hasnodata,
2508  int *width, int *height,
2509  double *scale_x, double *scale_y,
2510  double *ul_xw, double *ul_yw,
2511  double *grid_xw, double *grid_yw,
2512  double *skew_x, double *skew_y,
2513  char **options
2514 ) {
2515  rt_raster rast = NULL;
2516  uint32_t i = 0;
2517  int err = 0;
2518 
2519  _rti_rasterize_arg arg = NULL;
2520 
2521  int _dim[2] = {0};
2522  double _scale[2] = {0};
2523  double _skew[2] = {0};
2524 
2525  OGRErr ogrerr;
2526  OGRGeometryH src_geom;
2527  OGREnvelope src_env;
2528  rt_envelope extent;
2529  OGRwkbGeometryType wkbtype = wkbUnknown;
2530 
2531  int ul_user = 0;
2532 
2533  CPLErr cplerr;
2534  double _gt[6] = {0};
2535  GDALDriverH _drv = NULL;
2536  int unload_drv = 0;
2537  GDALDatasetH _ds = NULL;
2538  GDALRasterBandH _band = NULL;
2539 
2540  uint16_t _width = 0;
2541  uint16_t _height = 0;
2542 
2543  RASTER_DEBUG(3, "starting");
2544 
2545  assert(NULL != wkb);
2546  assert(0 != wkb_len);
2547 
2548  /* internal variables */
2549  arg = _rti_rasterize_arg_init();
2550  if (arg == NULL) {
2551  rterror("rt_raster_gdal_rasterize: Could not initialize internal variables");
2552  return NULL;
2553  }
2554 
2555  /* no bands, raster is a mask */
2556  if (num_bands < 1) {
2557  arg->noband = 1;
2558  arg->numbands = 1;
2559 
2560  arg->pixtype = (rt_pixtype *) rtalloc(sizeof(rt_pixtype));
2561  arg->pixtype[0] = PT_8BUI;
2562 
2563  arg->init = (double *) rtalloc(sizeof(double));
2564  arg->init[0] = 0;
2565 
2566  arg->nodata = (double *) rtalloc(sizeof(double));
2567  arg->nodata[0] = 0;
2568 
2569  arg->hasnodata = (uint8_t *) rtalloc(sizeof(uint8_t));
2570  arg->hasnodata[0] = 1;
2571 
2572  arg->value = (double *) rtalloc(sizeof(double));
2573  arg->value[0] = 1;
2574  }
2575  else {
2576  arg->noband = 0;
2577  arg->numbands = num_bands;
2578 
2579  arg->pixtype = pixtype;
2580  arg->init = init;
2581  arg->nodata = nodata;
2582  arg->hasnodata = hasnodata;
2583  arg->value = value;
2584  }
2585 
2586  /* OGR spatial reference */
2587  if (NULL != srs && strlen(srs)) {
2588  arg->src_sr = OSRNewSpatialReference(NULL);
2589  if (OSRSetFromUserInput(arg->src_sr, srs) != OGRERR_NONE) {
2590  rterror("rt_raster_gdal_rasterize: Could not create OSR spatial reference using the provided srs: %s", srs);
2592  return NULL;
2593  }
2594  }
2595 
2596  /* convert WKB to OGR Geometry */
2597  ogrerr = OGR_G_CreateFromWkb((unsigned char *) wkb, arg->src_sr, &src_geom, wkb_len);
2598  if (ogrerr != OGRERR_NONE) {
2599  rterror("rt_raster_gdal_rasterize: Could not create OGR Geometry from WKB");
2600 
2602  /* OGRCleanupAll(); */
2603 
2604  return NULL;
2605  }
2606 
2607  /* OGR Geometry is empty */
2608  if (OGR_G_IsEmpty(src_geom)) {
2609  rtinfo("Geometry provided is empty. Returning empty raster");
2610 
2611  OGR_G_DestroyGeometry(src_geom);
2613  /* OGRCleanupAll(); */
2614 
2615  return rt_raster_new(0, 0);
2616  }
2617 
2618  /* get envelope */
2619  OGR_G_GetEnvelope(src_geom, &src_env);
2620  rt_util_from_ogr_envelope(src_env, &extent);
2621 
2622  RASTER_DEBUGF(3, "Suggested raster envelope: %f, %f, %f, %f",
2623  extent.MinX, extent.MinY, extent.MaxX, extent.MaxY);
2624 
2625  /* user-defined scale */
2626  if (
2627  (NULL != scale_x) &&
2628  (NULL != scale_y) &&
2629  (FLT_NEQ(*scale_x, 0.0)) &&
2630  (FLT_NEQ(*scale_y, 0.0))
2631  ) {
2632  /* for now, force scale to be in left-right, top-down orientation */
2633  _scale[0] = fabs(*scale_x);
2634  _scale[1] = fabs(*scale_y);
2635  }
2636  /* user-defined width/height */
2637  else if ((NULL != width) && (NULL != height) && (*width != 0) && (*height != 0))
2638  {
2639  _dim[0] = abs(*width);
2640  _dim[1] = abs(*height);
2641 
2642  if (FLT_NEQ(extent.MaxX, extent.MinX))
2643  _scale[0] = fabs((extent.MaxX - extent.MinX) / _dim[0]);
2644  else
2645  _scale[0] = 1.;
2646 
2647  if (FLT_NEQ(extent.MaxY, extent.MinY))
2648  _scale[1] = fabs((extent.MaxY - extent.MinY) / _dim[1]);
2649  else
2650  _scale[1] = 1.;
2651  }
2652  else {
2653  rterror("rt_raster_gdal_rasterize: Values must be provided for width and height or X and Y of scale");
2654 
2655  OGR_G_DestroyGeometry(src_geom);
2657  /* OGRCleanupAll(); */
2658 
2659  return NULL;
2660  }
2661  RASTER_DEBUGF(3, "scale (x, y) = %f, %f", _scale[0], -1 * _scale[1]);
2662  RASTER_DEBUGF(3, "dim (x, y) = %d, %d", _dim[0], _dim[1]);
2663 
2664  /* user-defined skew */
2665  if (NULL != skew_x) {
2666  _skew[0] = *skew_x;
2667 
2668  /*
2669  negative scale-x affects skew
2670  for now, force skew to be in left-right, top-down orientation
2671  */
2672  if (
2673  NULL != scale_x &&
2674  *scale_x < 0.
2675  ) {
2676  _skew[0] *= -1;
2677  }
2678  }
2679  if (NULL != skew_y) {
2680  _skew[1] = *skew_y;
2681 
2682  /*
2683  positive scale-y affects skew
2684  for now, force skew to be in left-right, top-down orientation
2685  */
2686  if (
2687  NULL != scale_y &&
2688  *scale_y > 0.
2689  ) {
2690  _skew[1] *= -1;
2691  }
2692  }
2693 
2694  /*
2695  if geometry is a point, a linestring or set of either and bounds not set,
2696  increase extent by a pixel to avoid missing points on border
2697 
2698  a whole pixel is used instead of half-pixel due to backward
2699  compatibility with GDAL 1.6, 1.7 and 1.8. 1.9+ works fine with half-pixel.
2700  */
2701  wkbtype = wkbFlatten(OGR_G_GetGeometryType(src_geom));
2702  if ((
2703  (wkbtype == wkbPoint) ||
2704  (wkbtype == wkbMultiPoint) ||
2705  (wkbtype == wkbLineString) ||
2706  (wkbtype == wkbMultiLineString)
2707  ) &&
2708  _dim[0] == 0 &&
2709  _dim[1] == 0
2710  ) {
2711 
2712 #if POSTGIS_GDAL_VERSION > 10800
2713 
2714  RASTER_DEBUG(3, "Adjusting extent for GDAL > 1.8 by half the scale on X-axis");
2715  extent.MinX -= (_scale[0] / 2.);
2716  extent.MaxX += (_scale[0] / 2.);
2717 
2718  RASTER_DEBUG(3, "Adjusting extent for GDAL > 1.8 by half the scale on Y-axis");
2719  extent.MinY -= (_scale[1] / 2.);
2720  extent.MaxY += (_scale[1] / 2.);
2721 
2722 #else
2723 
2724  RASTER_DEBUG(3, "Adjusting extent for GDAL <= 1.8 by the scale on X-axis");
2725  extent.MinX -= _scale[0];
2726  extent.MaxX += _scale[0];
2727 
2728  RASTER_DEBUG(3, "Adjusting extent for GDAL <= 1.8 by the scale on Y-axis");
2729  extent.MinY -= _scale[1];
2730  extent.MaxY += _scale[1];
2731 
2732 #endif
2733 
2734 
2735  RASTER_DEBUGF(3, "Adjusted extent: %f, %f, %f, %f",
2736  extent.MinX, extent.MinY, extent.MaxX, extent.MaxY);
2737 
2738  extent.UpperLeftX = extent.MinX;
2739  extent.UpperLeftY = extent.MaxY;
2740  }
2741 
2742  /* reprocess extent if skewed */
2743  if (FLT_NEQ(_skew[0], 0.0) || FLT_NEQ(_skew[1], 0.0))
2744  {
2745  rt_raster skewedrast;
2746 
2747  RASTER_DEBUG(3, "Computing skewed extent's envelope");
2748 
2749  skewedrast = rt_raster_compute_skewed_raster(
2750  extent,
2751  _skew,
2752  _scale,
2753  0.01
2754  );
2755  if (skewedrast == NULL) {
2756  rterror("rt_raster_gdal_rasterize: Could not compute skewed raster");
2757 
2758  OGR_G_DestroyGeometry(src_geom);
2760  /* OGRCleanupAll(); */
2761 
2762  return NULL;
2763  }
2764 
2765  _dim[0] = skewedrast->width;
2766  _dim[1] = skewedrast->height;
2767 
2768  extent.UpperLeftX = skewedrast->ipX;
2769  extent.UpperLeftY = skewedrast->ipY;
2770 
2771  rt_raster_destroy(skewedrast);
2772  }
2773 
2774  /* raster dimensions */
2775  if (!_dim[0])
2776  _dim[0] = (int) fmax((fabs(extent.MaxX - extent.MinX) + (_scale[0] / 2.)) / _scale[0], 1);
2777  if (!_dim[1])
2778  _dim[1] = (int) fmax((fabs(extent.MaxY - extent.MinY) + (_scale[1] / 2.)) / _scale[1], 1);
2779 
2780  /* temporary raster */
2781  rast = rt_raster_new(_dim[0], _dim[1]);
2782  if (rast == NULL) {
2783  rterror("rt_raster_gdal_rasterize: Out of memory allocating temporary raster");
2784 
2785  OGR_G_DestroyGeometry(src_geom);
2787  /* OGRCleanupAll(); */
2788 
2789  return NULL;
2790  }
2791 
2792  /* set raster's spatial attributes */
2794  rt_raster_set_scale(rast, _scale[0], -1 * _scale[1]);
2795  rt_raster_set_skews(rast, _skew[0], _skew[1]);
2796 
2798  RASTER_DEBUGF(3, "Temp raster's geotransform: %f, %f, %f, %f, %f, %f",
2799  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
2800  RASTER_DEBUGF(3, "Temp raster's dimensions (width x height): %d x %d",
2801  _dim[0], _dim[1]);
2802 
2803  /* user-specified upper-left corner */
2804  if (
2805  NULL != ul_xw &&
2806  NULL != ul_yw
2807  ) {
2808  ul_user = 1;
2809 
2810  RASTER_DEBUGF(4, "Using user-specified upper-left corner: %f, %f", *ul_xw, *ul_yw);
2811 
2812  /* set upper-left corner */
2813  rt_raster_set_offsets(rast, *ul_xw, *ul_yw);
2814  extent.UpperLeftX = *ul_xw;
2815  extent.UpperLeftY = *ul_yw;
2816  }
2817  else if (
2818  ((NULL != ul_xw) && (NULL == ul_yw)) ||
2819  ((NULL == ul_xw) && (NULL != ul_yw))
2820  ) {
2821  rterror("rt_raster_gdal_rasterize: Both X and Y upper-left corner values must be provided");
2822 
2824  OGR_G_DestroyGeometry(src_geom);
2826  /* OGRCleanupAll(); */
2827 
2828  return NULL;
2829  }
2830 
2831  /* alignment only considered if upper-left corner not provided */
2832  if (
2833  !ul_user && (
2834  (NULL != grid_xw) || (NULL != grid_yw)
2835  )
2836  ) {
2837 
2838  if (
2839  ((NULL != grid_xw) && (NULL == grid_yw)) ||
2840  ((NULL == grid_xw) && (NULL != grid_yw))
2841  ) {
2842  rterror("rt_raster_gdal_rasterize: Both X and Y alignment values must be provided");
2843 
2845  OGR_G_DestroyGeometry(src_geom);
2847  /* OGRCleanupAll(); */
2848 
2849  return NULL;
2850  }
2851 
2852  RASTER_DEBUGF(4, "Aligning extent to user-specified grid: %f, %f", *grid_xw, *grid_yw);
2853 
2854  do {
2855  double _r[2] = {0};
2856  double _w[2] = {0};
2857 
2858  /* raster is already aligned */
2859  if (DBL_EQ(*grid_xw, extent.UpperLeftX) && DBL_EQ(*grid_yw, extent.UpperLeftY)) {
2860  RASTER_DEBUG(3, "Skipping raster alignment as it is already aligned to grid");
2861  break;
2862  }
2863 
2864  extent.UpperLeftX = rast->ipX;
2865  extent.UpperLeftY = rast->ipY;
2866  rt_raster_set_offsets(rast, *grid_xw, *grid_yw);
2867 
2868  /* process upper-left corner */
2870  rast,
2871  extent.UpperLeftX, extent.UpperLeftY,
2872  &(_r[0]), &(_r[1]),
2873  NULL
2874  ) != ES_NONE) {
2875  rterror("rt_raster_gdal_rasterize: Could not compute raster pixel for spatial coordinates");
2876 
2878  OGR_G_DestroyGeometry(src_geom);
2880  /* OGRCleanupAll(); */
2881 
2882  return NULL;
2883  }
2884 
2886  rast,
2887  _r[0], _r[1],
2888  &(_w[0]), &(_w[1]),
2889  NULL
2890  ) != ES_NONE) {
2891  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
2892 
2894  OGR_G_DestroyGeometry(src_geom);
2896  /* OGRCleanupAll(); */
2897 
2898  return NULL;
2899  }
2900 
2901  /* shift occurred */
2902  if (FLT_NEQ(_w[0], extent.UpperLeftX)) {
2903  if (NULL == width)
2904  rast->width++;
2905  else if (NULL == scale_x) {
2906  double _c[2] = {0};
2907 
2909 
2910  /* get upper-right corner */
2912  rast,
2913  rast->width, 0,
2914  &(_c[0]), &(_c[1]),
2915  NULL
2916  ) != ES_NONE) {
2917  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
2918 
2920  OGR_G_DestroyGeometry(src_geom);
2922  /* OGRCleanupAll(); */
2923 
2924  return NULL;
2925  }
2926 
2927  rast->scaleX = fabs((_c[0] - _w[0]) / ((double) rast->width));
2928  }
2929  }
2930  if (FLT_NEQ(_w[1], extent.UpperLeftY)) {
2931  if (NULL == height)
2932  rast->height++;
2933  else if (NULL == scale_y) {
2934  double _c[2] = {0};
2935 
2937 
2938  /* get upper-right corner */
2940  rast,
2941  0, rast->height,
2942  &(_c[0]), &(_c[1]),
2943  NULL
2944  ) != ES_NONE) {
2945  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
2946 
2948  OGR_G_DestroyGeometry(src_geom);
2950  /* OGRCleanupAll(); */
2951 
2952  return NULL;
2953  }
2954 
2955  rast->scaleY = -1 * fabs((_c[1] - _w[1]) / ((double) rast->height));
2956  }
2957  }
2958 
2959  rt_raster_set_offsets(rast, _w[0], _w[1]);
2960  }
2961  while (0);
2962  }
2963 
2964  /*
2965  after this point, rt_envelope extent is no longer used
2966  */
2967 
2968  /* get key attributes from rast */
2969  _dim[0] = rast->width;
2970  _dim[1] = rast->height;
2972 
2973  /* scale-x is negative or scale-y is positive */
2974  if ((
2975  (NULL != scale_x) && (*scale_x < 0.)
2976  ) || (
2977  (NULL != scale_y) && (*scale_y > 0)
2978  )) {
2979  double _w[2] = {0};
2980 
2981  /* negative scale-x */
2982  if (
2983  (NULL != scale_x) &&
2984  (*scale_x < 0.)
2985  ) {
2986  RASTER_DEBUG(3, "Processing negative scale-x");
2987 
2989  rast,
2990  _dim[0], 0,
2991  &(_w[0]), &(_w[1]),
2992  NULL
2993  ) != ES_NONE) {
2994  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
2995 
2997  OGR_G_DestroyGeometry(src_geom);
2999  /* OGRCleanupAll(); */
3000 
3001  return NULL;
3002  }
3003 
3004  _gt[0] = _w[0];
3005  _gt[1] = *scale_x;
3006 
3007  /* check for skew */
3008  if (NULL != skew_x && FLT_NEQ(*skew_x, 0.0))
3009  _gt[2] = *skew_x;
3010  }
3011  /* positive scale-y */
3012  if (
3013  (NULL != scale_y) &&
3014  (*scale_y > 0)
3015  ) {
3016  RASTER_DEBUG(3, "Processing positive scale-y");
3017 
3019  rast,
3020  0, _dim[1],
3021  &(_w[0]), &(_w[1]),
3022  NULL
3023  ) != ES_NONE) {
3024  rterror("rt_raster_gdal_rasterize: Could not compute spatial coordinates for raster pixel");
3025 
3027  OGR_G_DestroyGeometry(src_geom);
3029  /* OGRCleanupAll(); */
3030 
3031  return NULL;
3032  }
3033 
3034  _gt[3] = _w[1];
3035  _gt[5] = *scale_y;
3036 
3037  /* check for skew */
3038  if (NULL != skew_y && FLT_NEQ(*skew_y, 0.0))
3039  _gt[4] = *skew_y;
3040  }
3041  }
3042 
3044  rast = NULL;
3045 
3046  RASTER_DEBUGF(3, "Applied geotransform: %f, %f, %f, %f, %f, %f",
3047  _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
3048  RASTER_DEBUGF(3, "Raster dimensions (width x height): %d x %d",
3049  _dim[0], _dim[1]);
3050 
3051  /* load GDAL mem */
3052  if (!rt_util_gdal_driver_registered("MEM")) {
3053  RASTER_DEBUG(4, "Registering MEM driver");
3054  GDALRegister_MEM();
3055  unload_drv = 1;
3056  }
3057  _drv = GDALGetDriverByName("MEM");
3058  if (NULL == _drv) {
3059  rterror("rt_raster_gdal_rasterize: Could not load the MEM GDAL driver");
3060 
3061  OGR_G_DestroyGeometry(src_geom);
3063  /* OGRCleanupAll(); */
3064 
3065  return NULL;
3066  }
3067 
3068  /* unload driver from GDAL driver manager */
3069  if (unload_drv) {
3070  RASTER_DEBUG(4, "Deregistering MEM driver");
3071  GDALDeregisterDriver(_drv);
3072  }
3073 
3074  _ds = GDALCreate(_drv, "", _dim[0], _dim[1], 0, GDT_Byte, NULL);
3075  if (NULL == _ds) {
3076  rterror("rt_raster_gdal_rasterize: Could not create a GDALDataset to rasterize the geometry into");
3077 
3078  OGR_G_DestroyGeometry(src_geom);
3080  /* OGRCleanupAll(); */
3081  if (unload_drv) GDALDestroyDriver(_drv);
3082 
3083  return NULL;
3084  }
3085 
3086  /* set geotransform */
3087  cplerr = GDALSetGeoTransform(_ds, _gt);
3088  if (cplerr != CE_None) {
3089  rterror("rt_raster_gdal_rasterize: Could not set geotransform on GDALDataset");
3090 
3091  OGR_G_DestroyGeometry(src_geom);
3093  /* OGRCleanupAll(); */
3094 
3095  GDALClose(_ds);
3096  if (unload_drv) GDALDestroyDriver(_drv);
3097 
3098  return NULL;
3099  }
3100 
3101  /* set SRS */
3102  if (NULL != arg->src_sr) {
3103  char *_srs = NULL;
3104  OSRExportToWkt(arg->src_sr, &_srs);
3105 
3106  cplerr = GDALSetProjection(_ds, _srs);
3107  CPLFree(_srs);
3108  if (cplerr != CE_None) {
3109  rterror("rt_raster_gdal_rasterize: Could not set projection on GDALDataset");
3110 
3111  OGR_G_DestroyGeometry(src_geom);
3113  /* OGRCleanupAll(); */
3114 
3115  GDALClose(_ds);
3116  if (unload_drv) GDALDestroyDriver(_drv);
3117 
3118  return NULL;
3119  }
3120  }
3121 
3122  /* set bands */
3123  for (i = 0; i < arg->numbands; i++) {
3124  err = 0;
3125 
3126  do {
3127  /* add band */
3128  cplerr = GDALAddBand(_ds, rt_util_pixtype_to_gdal_datatype(arg->pixtype[i]), NULL);
3129  if (cplerr != CE_None) {
3130  rterror("rt_raster_gdal_rasterize: Could not add band to GDALDataset");
3131  err = 1;
3132  break;
3133  }
3134 
3135  _band = GDALGetRasterBand(_ds, i + 1);
3136  if (NULL == _band) {
3137  rterror("rt_raster_gdal_rasterize: Could not get band %d from GDALDataset", i + 1);
3138  err = 1;
3139  break;
3140  }
3141 
3142  /* nodata value */
3143  if (arg->hasnodata[i]) {
3144  RASTER_DEBUGF(4, "Setting NODATA value of band %d to %f", i, arg->nodata[i]);
3145  cplerr = GDALSetRasterNoDataValue(_band, arg->nodata[i]);
3146  if (cplerr != CE_None) {
3147  rterror("rt_raster_gdal_rasterize: Could not set nodata value");
3148  err = 1;
3149  break;
3150  }
3151  RASTER_DEBUGF(4, "NODATA value set to %f", GDALGetRasterNoDataValue(_band, NULL));
3152  }
3153 
3154  /* initial value */
3155  cplerr = GDALFillRaster(_band, arg->init[i], 0);
3156  if (cplerr != CE_None) {
3157  rterror("rt_raster_gdal_rasterize: Could not set initial value");
3158  err = 1;
3159  break;
3160  }
3161  }
3162  while (0);
3163 
3164  if (err) {
3165 
3166  OGR_G_DestroyGeometry(src_geom);
3168 
3169  /* OGRCleanupAll(); */
3170 
3171  GDALClose(_ds);
3172  if (unload_drv) GDALDestroyDriver(_drv);
3173 
3174  return NULL;
3175  }
3176  }
3177 
3178  arg->bandlist = (int *) rtalloc(sizeof(int) * arg->numbands);
3179  for (i = 0; i < arg->numbands; i++) arg->bandlist[i] = i + 1;
3180 
3181  /* burn geometry */
3182  cplerr = GDALRasterizeGeometries(
3183  _ds,
3184  arg->numbands, arg->bandlist,
3185  1, &src_geom,
3186  NULL, NULL,
3187  arg->value,
3188  options,
3189  NULL, NULL
3190  );
3191  if (cplerr != CE_None) {
3192  rterror("rt_raster_gdal_rasterize: Could not rasterize geometry");
3193 
3194  OGR_G_DestroyGeometry(src_geom);
3196  /* OGRCleanupAll(); */
3197 
3198  GDALClose(_ds);
3199  if (unload_drv) GDALDestroyDriver(_drv);
3200 
3201  return NULL;
3202  }
3203 
3204  /* convert gdal dataset to raster */
3205  GDALFlushCache(_ds);
3206  RASTER_DEBUG(3, "Converting GDAL dataset to raster");
3208 
3209  OGR_G_DestroyGeometry(src_geom);
3210  /* OGRCleanupAll(); */
3211 
3212  GDALClose(_ds);
3213  if (unload_drv) GDALDestroyDriver(_drv);
3214 
3215  if (NULL == rast) {
3216  rterror("rt_raster_gdal_rasterize: Could not rasterize geometry");
3217  return NULL;
3218  }
3219 
3220  /* width, height */
3221  _width = rt_raster_get_width(rast);
3222  _height = rt_raster_get_height(rast);
3223 
3224  /* check each band for pixtype */
3225  for (i = 0; i < arg->numbands; i++) {
3226  uint8_t *data = NULL;
3227  rt_band band = NULL;
3228  rt_band oldband = NULL;
3229 
3230  double val = 0;
3231  int nodata = 0;
3232  int hasnodata = 0;
3233  double nodataval = 0;
3234  int x = 0;
3235  int y = 0;
3236 
3237  oldband = rt_raster_get_band(rast, i);
3238  if (oldband == NULL) {
3239  rterror("rt_raster_gdal_rasterize: Could not get band %d of output raster", i);
3242  return NULL;
3243  }
3244 
3245  /* band is of user-specified type */
3246  if (rt_band_get_pixtype(oldband) == arg->pixtype[i])
3247  continue;
3248 
3249  /* hasnodata, nodataval */
3250  hasnodata = rt_band_get_hasnodata_flag(oldband);
3251  if (hasnodata)
3252  rt_band_get_nodata(oldband, &nodataval);
3253 
3254  /* allocate data */
3255  data = rtalloc((size_t)rt_pixtype_size(arg->pixtype[i]) * _width * _height);
3256  if (data == NULL) {
3257  rterror("rt_raster_gdal_rasterize: Could not allocate memory for band data");
3260  return NULL;
3261  }
3262  memset(data, 0, (size_t)rt_pixtype_size(arg->pixtype[i]) * _width * _height);
3263 
3264  /* create new band of correct type */
3266  _width, _height,
3267  arg->pixtype[i],
3268  hasnodata, nodataval,
3269  data
3270  );
3271  if (band == NULL) {
3272  rterror("rt_raster_gdal_rasterize: Could not create band");
3273  rtdealloc(data);
3276  return NULL;
3277  }
3278 
3279  /* give ownership of data to band */
3281 
3282  /* copy pixel by pixel */
3283  for (x = 0; x < _width; x++) {
3284  for (y = 0; y < _height; y++) {
3285  err = rt_band_get_pixel(oldband, x, y, &val, &nodata);
3286  if (err != ES_NONE) {
3287  rterror("rt_raster_gdal_rasterize: Could not get pixel value");
3291  return NULL;
3292  }
3293 
3294  if (nodata)
3295  val = nodataval;
3296 
3297  err = rt_band_set_pixel(band, x, y, val, NULL);
3298  if (err != ES_NONE) {
3299  rterror("rt_raster_gdal_rasterize: Could not set pixel value");
3303  return NULL;
3304  }
3305  }
3306  }
3307 
3308  /* replace band */
3309  oldband = rt_raster_replace_band(rast, band, i);
3310  if (oldband == NULL) {
3311  rterror("rt_raster_gdal_rasterize: Could not replace band %d of output raster", i);
3315  return NULL;
3316  }
3317 
3318  /* free oldband */
3319  rt_band_destroy(oldband);
3320  }
3321 
3323 
3324  RASTER_DEBUG(3, "done");
3325 
3326  return rast;
3327 }
3328 
3329 /******************************************************************************
3330 * rt_raster_from_two_rasters()
3331 ******************************************************************************/
3332 
3333 /*
3334  * Return raster of computed extent specified extenttype applied
3335  * on two input rasters. The raster returned should be freed by
3336  * the caller
3337  *
3338  * @param rast1 : the first raster
3339  * @param rast2 : the second raster
3340  * @param extenttype : type of extent for the output raster
3341  * @param *rtnraster : raster of computed extent
3342  * @param *offset : 4-element array indicating the X,Y offsets
3343  * for each raster. 0,1 for rast1 X,Y. 2,3 for rast2 X,Y.
3344  *
3345  * @return ES_NONE if success, ES_ERROR if error
3346  */
3349  rt_raster rast1, rt_raster rast2,
3350  rt_extenttype extenttype,
3351  rt_raster *rtnraster, double *offset
3352 ) {
3353  int i;
3354 
3355  rt_raster _rast[2] = {rast1, rast2};
3356  double _offset[2][4] = {{0.}};
3357  uint16_t _dim[2][2] = {{0}};
3358 
3359  rt_raster raster = NULL;
3360  int aligned = 0;
3361  int dim[2] = {0};
3362  double gt[6] = {0.};
3363 
3364  assert(NULL != rast1);
3365  assert(NULL != rast2);
3366  assert(NULL != rtnraster);
3367 
3368  /* set rtnraster to NULL */
3369  *rtnraster = NULL;
3370 
3371  /* rasters must be aligned */
3372  if (rt_raster_same_alignment(rast1, rast2, &aligned, NULL) != ES_NONE) {
3373  rterror("rt_raster_from_two_rasters: Could not test for alignment on the two rasters");
3374  return ES_ERROR;
3375  }
3376  if (!aligned) {
3377  rterror("rt_raster_from_two_rasters: The two rasters provided do not have the same alignment");
3378  return ES_ERROR;
3379  }
3380 
3381  /* dimensions */
3382  _dim[0][0] = rast1->width;
3383  _dim[0][1] = rast1->height;
3384  _dim[1][0] = rast2->width;
3385  _dim[1][1] = rast2->height;
3386 
3387  /* get raster offsets */
3389  _rast[1],
3390  _rast[0]->ipX, _rast[0]->ipY,
3391  &(_offset[1][0]), &(_offset[1][1]),
3392  NULL
3393  ) != ES_NONE) {
3394  rterror("rt_raster_from_two_rasters: Could not compute offsets of the second raster relative to the first raster");
3395  return ES_ERROR;
3396  }
3397  _offset[1][0] = -1 * _offset[1][0];
3398  _offset[1][1] = -1 * _offset[1][1];
3399  _offset[1][2] = _offset[1][0] + _dim[1][0] - 1;
3400  _offset[1][3] = _offset[1][1] + _dim[1][1] - 1;
3401 
3402  i = -1;
3403  switch (extenttype) {
3404  case ET_FIRST:
3405  i = 0;
3406  _offset[0][0] = 0.;
3407  _offset[0][1] = 0.;
3408  /* FALLTHROUGH */
3409  case ET_LAST:
3410  case ET_SECOND:
3411  if (i < 0) {
3412  i = 1;
3413  _offset[0][0] = -1 * _offset[1][0];
3414  _offset[0][1] = -1 * _offset[1][1];
3415  _offset[1][0] = 0.;
3416  _offset[1][1] = 0.;
3417  }
3418 
3419  dim[0] = _dim[i][0];
3420  dim[1] = _dim[i][1];
3422  dim[0],
3423  dim[1]
3424  );
3425  if (raster == NULL) {
3426  rterror("rt_raster_from_two_rasters: Could not create output raster");
3427  return ES_ERROR;
3428  }
3429  rt_raster_set_srid(raster, _rast[i]->srid);
3432  break;
3433  case ET_UNION: {
3434  double off[4] = {0};
3435 
3437  RASTER_DEBUGF(4, "gt = (%f, %f, %f, %f, %f, %f)",
3438  gt[0],
3439  gt[1],
3440  gt[2],
3441  gt[3],
3442  gt[4],
3443  gt[5]
3444  );
3445 
3446  /* new raster upper left offset */
3447  off[0] = 0;
3448  if (_offset[1][0] < 0)
3449  off[0] = _offset[1][0];
3450  off[1] = 0;
3451  if (_offset[1][1] < 0)
3452  off[1] = _offset[1][1];
3453 
3454  /* new raster lower right offset */
3455  off[2] = _dim[0][0] - 1;
3456  if ((int) _offset[1][2] >= _dim[0][0])
3457  off[2] = _offset[1][2];
3458  off[3] = _dim[0][1] - 1;
3459  if ((int) _offset[1][3] >= _dim[0][1])
3460  off[3] = _offset[1][3];
3461 
3462  /* upper left corner */
3464  _rast[0],
3465  off[0], off[1],
3466  &(gt[0]), &(gt[3]),
3467  NULL
3468  ) != ES_NONE) {
3469  rterror("rt_raster_from_two_rasters: Could not get spatial coordinates of upper-left pixel of output raster");
3470  return ES_ERROR;
3471  }
3472 
3473  dim[0] = off[2] - off[0] + 1;
3474  dim[1] = off[3] - off[1] + 1;
3475  RASTER_DEBUGF(4, "off = (%f, %f, %f, %f)",
3476  off[0],
3477  off[1],
3478  off[2],
3479  off[3]
3480  );
3481  RASTER_DEBUGF(4, "dim = (%d, %d)", dim[0], dim[1]);
3482 
3484  dim[0],
3485  dim[1]
3486  );
3487  if (raster == NULL) {
3488  rterror("rt_raster_from_two_rasters: Could not create output raster");
3489  return ES_ERROR;
3490  }
3491  rt_raster_set_srid(raster, _rast[0]->srid);
3493  RASTER_DEBUGF(4, "gt = (%f, %f, %f, %f, %f, %f)",
3494  gt[0],
3495  gt[1],
3496  gt[2],
3497  gt[3],
3498  gt[4],
3499  gt[5]
3500  );
3501 
3502  /* get offsets */
3504  _rast[0],
3505  gt[0], gt[3],
3506  &(_offset[0][0]), &(_offset[0][1]),
3507  NULL
3508  ) != ES_NONE) {
3509  rterror("rt_raster_from_two_rasters: Could not get offsets of the FIRST raster relative to the output raster");
3511  return ES_ERROR;
3512  }
3513  _offset[0][0] *= -1;
3514  _offset[0][1] *= -1;
3515 
3517  _rast[1],
3518  gt[0], gt[3],
3519  &(_offset[1][0]), &(_offset[1][1]),
3520  NULL
3521  ) != ES_NONE) {
3522  rterror("rt_raster_from_two_rasters: Could not get offsets of the SECOND raster relative to the output raster");
3524  return ES_ERROR;
3525  }
3526  _offset[1][0] *= -1;
3527  _offset[1][1] *= -1;
3528  break;
3529  }
3530  case ET_INTERSECTION: {
3531  double off[4] = {0};
3532 
3533  /* no intersection */
3534  if (
3535  (_offset[1][2] < 0 || _offset[1][0] > (_dim[0][0] - 1)) ||
3536  (_offset[1][3] < 0 || _offset[1][1] > (_dim[0][1] - 1))
3537  ) {
3538  RASTER_DEBUG(3, "The two rasters provided have no intersection. Returning no band raster");
3539 
3540  raster = rt_raster_new(0, 0);
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[0]->srid);
3546  rt_raster_set_scale(raster, 0, 0);
3547 
3548  /* set offsets if provided */
3549  if (NULL != offset) {
3550  for (i = 0; i < 4; i++)
3551  offset[i] = _offset[i / 2][i % 2];
3552  }
3553 
3554  *rtnraster = raster;
3555  return ES_NONE;
3556  }
3557 
3558  if (_offset[1][0] > 0)
3559  off[0] = _offset[1][0];
3560  if (_offset[1][1] > 0)
3561  off[1] = _offset[1][1];
3562 
3563  off[2] = _dim[0][0] - 1;
3564  if (_offset[1][2] < _dim[0][0])
3565  off[2] = _offset[1][2];
3566  off[3] = _dim[0][1] - 1;
3567  if (_offset[1][3] < _dim[0][1])
3568  off[3] = _offset[1][3];
3569 
3570  dim[0] = off[2] - off[0] + 1;
3571  dim[1] = off[3] - off[1] + 1;
3573  dim[0],
3574  dim[1]
3575  );
3576  if (raster == NULL) {
3577  rterror("rt_raster_from_two_rasters: Could not create output raster");
3578  return ES_ERROR;
3579  }
3580  rt_raster_set_srid(raster, _rast[0]->srid);
3581 
3582  /* get upper-left corner */
3585  _rast[0],
3586  off[0], off[1],
3587  &(gt[0]), &(gt[3]),
3588  gt
3589  ) != ES_NONE) {
3590  rterror("rt_raster_from_two_rasters: Could not get spatial coordinates of upper-left pixel of output raster");
3592  return ES_ERROR;
3593  }
3594 
3596 
3597  /* get offsets */
3599  _rast[0],
3600  gt[0], gt[3],
3601  &(_offset[0][0]), &(_offset[0][1]),
3602  NULL
3603  ) != ES_NONE) {
3604  rterror("rt_raster_from_two_rasters: Could not get pixel coordinates to compute the offsets of the FIRST raster relative to the output raster");
3606  return ES_ERROR;
3607  }
3608  _offset[0][0] *= -1;
3609  _offset[0][1] *= -1;
3610 
3612  _rast[1],
3613  gt[0], gt[3],
3614  &(_offset[1][0]), &(_offset[1][1]),
3615  NULL
3616  ) != ES_NONE) {
3617  rterror("rt_raster_from_two_rasters: Could not get pixel coordinates to compute the offsets of the SECOND raster relative to the output raster");
3619  return ES_ERROR;
3620  }
3621  _offset[1][0] *= -1;
3622  _offset[1][1] *= -1;
3623  break;
3624  }
3625  case ET_CUSTOM:
3626  rterror("rt_raster_from_two_rasters: Extent type ET_CUSTOM is not supported by this function");
3627  break;
3628  }
3629 
3630  /* set offsets if provided */
3631  if (NULL != offset) {
3632  for (i = 0; i < 4; i++)
3633  offset[i] = _offset[i / 2][i % 2];
3634  }
3635 
3636  *rtnraster = raster;
3637  return ES_NONE;
3638 }
#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:1218
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:268
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:252
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:339
void rt_band_init_value(rt_band band, double initval)
Fill in the cells of a band with a starting value frequently used to init with nodata value.
Definition: rt_band.c:112
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:818
void rterror(const char *fmt,...) __attribute__((format(printf
Wrappers used for reporting errors and info.
void * rtalloc(size_t size)
Wrappers used for managing memory.
Definition: rt_context.c:191
rt_pixtype rt_util_gdal_datatype_to_pixtype(GDALDataType gdt)
Convert GDALDataType to rt_pixtype.
Definition: rt_util.c:162
rt_band rt_band_duplicate(rt_band band)
Create a new band duplicated from source band.
Definition: rt_band.c:438
rt_errorstate rt_band_set_isnodata_flag(rt_band band, int flag)
Set isnodata flag value.
Definition: rt_band.c:846
#define FLT_NEQ(x, y)
Definition: librtcore.h:2423
#define RASTER_DEBUG(level, msg)
Definition: librtcore.h:302
int rt_util_gdal_register_all(int force_register_all)
Definition: rt_util.c:347
#define RASTER_DEBUGF(level, msg,...)
Definition: librtcore.h:306
void void rtinfo(const char *fmt,...) __attribute__((format(printf
void void void rtwarn(const char *fmt,...) __attribute__((format(printf
char * rt_util_gdal_convert_sr(const char *srs, int proj4)
Definition: rt_util.c:225
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:825
#define ROUND(x, y)
Definition: librtcore.h:2431
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_band.c:1527
rt_pixtype
Definition: librtcore.h:187
@ PT_END
Definition: librtcore.h:199
@ PT_8BSI
Definition: librtcore.h:191
@ PT_16BSI
Definition: librtcore.h:193
@ PT_8BUI
Definition: librtcore.h:192
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:2424
rt_resample_type
Definition: librtcore.h:1476
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:1125
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:1004
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:491
#define DBL_EQ(x, y)
Definition: librtcore.h:2426
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:155
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:366
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:1372
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:2038
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:782
void rtdealloc(void *mem)
Definition: rt_context.c:206
void * rt_band_get_data(rt_band band)
Get pointer to raster band data.
Definition: rt_band.c:551
rt_errorstate rt_util_gdal_sr_auth_info(GDALDatasetH hds, char **authname, char **authcode)
Get auth name and code.
Definition: rt_util.c:283
int rt_band_is_offline(rt_band band)
Return non-zero if the given band data is on the filesystem.
Definition: rt_band.c:480
LWPOLY * rt_util_envelope_to_lwpoly(rt_envelope ext)
Definition: rt_util.c:491
struct rt_raster_t * rt_raster
Types definitions.
Definition: librtcore.h:146
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:462
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.
Datum covers(PG_FUNCTION_ARGS)
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:68
nband
Definition: pixval.py:54
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
rt_errorstate rt_raster_cell_to_geopoint(rt_raster raster, double xr, double yr, double *xw, double *yw, double *gt)
Convert an xr, yr raster point to an xw, yw point on map.
Definition: rt_raster.c:637
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
Definition: rt_raster.c:360
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:609
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:558
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:1598
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:686
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:730
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:1253
rt_raster rt_raster_compute_skewed_raster(rt_envelope extent, double *skew, double *scale, double tolerance)
Definition: rt_raster.c:869
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:1716
rt_raster rt_raster_from_gdal_dataset(GDALDatasetH ds)
Return a raster from a GDAL dataset.
Definition: rt_raster.c:2175
static void _rti_rasterize_arg_destroy(_rti_rasterize_arg arg)
Definition: rt_raster.c:2452
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:1404
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:2502
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:1446
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:1341
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:1813
struct _rti_rasterize_arg_t * _rti_rasterize_arg
Definition: rt_raster.c:2409
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:3348
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:1276
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:782
static _rti_rasterize_arg _rti_rasterize_arg_init()
Definition: rt_raster.c:2426
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:588
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:1492
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:1240
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:2417
OGRSpatialReferenceH src_sr
Definition: rt_raster.c:2415
rt_raster raster
Definition: librtcore.h:2514
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:2681
char * long_name
Definition: librtcore.h:2678
char * create_options
Definition: librtcore.h:2679
char * short_name
Definition: librtcore.h:2677
uint8_t can_read
Definition: librtcore.h:2680
double scaleX
Definition: librtcore.h:2483
rt_band * bands
Definition: librtcore.h:2493
uint16_t width
Definition: librtcore.h:2491
double skewY
Definition: librtcore.h:2488
uint16_t numBands
Definition: librtcore.h:2480
int32_t srid
Definition: librtcore.h:2490
double ipX
Definition: librtcore.h:2485
uint16_t height
Definition: librtcore.h:2492
double scaleY
Definition: librtcore.h:2484
double ipY
Definition: librtcore.h:2486
double skewX
Definition: librtcore.h:2487