PostGIS  3.3.9dev-r@@SVN_REVISION@@
rtpg_gdal.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) 2011-2013 Regents of the University of California
7  * <bkpark@ucdavis.edu>
8  * Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo@deimos-space.com>
9  * Copyright (C) 2010-2011 David Zwarg <dzwarg@azavea.com>
10  * Copyright (C) 2009-2011 Pierre Racine <pierre.racine@sbf.ulaval.ca>
11  * Copyright (C) 2009-2011 Mateusz Loskot <mateusz@loskot.net>
12  * Copyright (C) 2008-2009 Sandro Santilli <strk@kbt.io>
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27  *
28  */
29 
30 #include <postgres.h>
31 #include <utils/builtins.h> /* for text_to_cstring() */
32 #include <access/htup_details.h> /* for heap_form_tuple() */
33 #include <utils/lsyscache.h> /* for get_typlenbyvalalign */
34 #include <utils/array.h> /* for ArrayType */
35 #include <utils/guc.h> /* for ArrayType */
36 #include <catalog/pg_type.h> /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */
37 #include <utils/memutils.h> /* For TopMemoryContext */
38 
39 #include "../../postgis_config.h"
40 
41 #include "rtpostgis.h"
42 #include "rtpg_internal.h"
43 #include "stringbuffer.h"
44 
45 /* convert GDAL raster to raster */
46 Datum RASTER_fromGDALRaster(PG_FUNCTION_ARGS);
47 
48 /* convert raster to GDAL raster */
49 Datum RASTER_asGDALRaster(PG_FUNCTION_ARGS);
50 Datum RASTER_getGDALDrivers(PG_FUNCTION_ARGS);
51 Datum RASTER_setGDALOpenOptions(PG_FUNCTION_ARGS);
52 
53 /* warp a raster using GDAL Warp API */
54 Datum RASTER_GDALWarp(PG_FUNCTION_ARGS);
55 
56 /* ----------------------------------------------------------------
57  * Returns raster from GDAL raster
58  * ---------------------------------------------------------------- */
60 Datum RASTER_fromGDALRaster(PG_FUNCTION_ARGS)
61 {
62  bytea *bytea_data;
63  uint8_t *data;
64  int data_len = 0;
65  VSILFILE *vsifp = NULL;
66  GDALDatasetH hdsSrc;
67  int32_t srid = -1; /* -1 for NULL */
68 
69  rt_pgraster *pgraster = NULL;
71 
72  /* NULL if NULL */
73  if (PG_ARGISNULL(0))
74  PG_RETURN_NULL();
75 
76  /* get data */
77  bytea_data = (bytea *) PG_GETARG_BYTEA_P(0);
78  data = (uint8_t *) VARDATA(bytea_data);
79  data_len = VARSIZE_ANY_EXHDR(bytea_data);
80 
81  /* process srid */
82  /* NULL srid means try to determine SRID from bytea */
83  if (!PG_ARGISNULL(1))
84  srid = clamp_srid(PG_GETARG_INT32(1));
85 
86  /* create memory "file" */
87  vsifp = VSIFileFromMemBuffer("/vsimem/in.dat", data, data_len, FALSE);
88  if (vsifp == NULL) {
89  PG_FREE_IF_COPY(bytea_data, 0);
90  elog(ERROR, "RASTER_fromGDALRaster: Could not load bytea into memory file for use by GDAL");
91  PG_RETURN_NULL();
92  }
93 
94  /* register all GDAL drivers */
96 
97  /* open GDAL raster */
98  hdsSrc = rt_util_gdal_open("/vsimem/in.dat", GA_ReadOnly, 1);
99  if (hdsSrc == NULL) {
100  VSIFCloseL(vsifp);
101  PG_FREE_IF_COPY(bytea_data, 0);
102  elog(ERROR, "RASTER_fromGDALRaster: Could not open bytea with GDAL. Check that the bytea is of a GDAL supported format");
103  PG_RETURN_NULL();
104  }
105 
106 #if POSTGIS_DEBUG_LEVEL > 3
107  {
108  GDALDriverH hdrv = GDALGetDatasetDriver(hdsSrc);
109 
110  POSTGIS_RT_DEBUGF(4, "Input GDAL Raster info: %s, (%d x %d)",
111  GDALGetDriverShortName(hdrv),
112  GDALGetRasterXSize(hdsSrc),
113  GDALGetRasterYSize(hdsSrc)
114  );
115  }
116 #endif
117 
118  /* convert GDAL raster to raster */
120 
121  GDALClose(hdsSrc);
122  VSIFCloseL(vsifp);
123  PG_FREE_IF_COPY(bytea_data, 0);
124 
125  if (raster == NULL) {
126  elog(ERROR, "RASTER_fromGDALRaster: Could not convert GDAL raster to raster");
127  PG_RETURN_NULL();
128  }
129 
130  /* apply SRID if set */
131  if (srid != -1)
132  rt_raster_set_srid(raster, srid);
133 
134  pgraster = rt_raster_serialize(raster);
136  if (!pgraster)
137  PG_RETURN_NULL();
138 
139  SET_VARSIZE(pgraster, pgraster->size);
140  PG_RETURN_POINTER(pgraster);
141 }
142 
147 Datum RASTER_asGDALRaster(PG_FUNCTION_ARGS)
148 {
149  rt_pgraster *pgraster = NULL;
151 
152  text *formattext = NULL;
153  char *format = NULL;
154  char **options = NULL;
155  text *optiontext = NULL;
156  char *option = NULL;
157  int32_t srid = SRID_UNKNOWN;
158  char *srs = NULL;
159 
160  ArrayType *array;
161  Oid etype;
162  Datum *e;
163  bool *nulls;
164  int16 typlen;
165  bool typbyval;
166  char typalign;
167  int n = 0;
168  int i = 0;
169  int j = 0;
170 
171  uint8_t *gdal = NULL;
172  uint64_t gdal_size = 0;
173  bytea *result = NULL;
174  uint64_t result_size = 0;
175 
176  POSTGIS_RT_DEBUG(3, "RASTER_asGDALRaster: Starting");
177 
178  /* pgraster is null, return null */
179  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
180  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
181 
182  raster = rt_raster_deserialize(pgraster, FALSE);
183  if (!raster) {
184  PG_FREE_IF_COPY(pgraster, 0);
185  elog(ERROR, "RASTER_asGDALRaster: Could not deserialize raster");
186  PG_RETURN_NULL();
187  }
188 
189  /* format is required */
190  if (PG_ARGISNULL(1)) {
191  elog(NOTICE, "Format must be provided");
193  PG_FREE_IF_COPY(pgraster, 0);
194  PG_RETURN_NULL();
195  }
196  else {
197  formattext = PG_GETARG_TEXT_P(1);
198  format = text_to_cstring(formattext);
199  }
200 
201  POSTGIS_RT_DEBUGF(3, "RASTER_asGDALRaster: Arg 1 (format) is %s", format);
202 
203  /* process options */
204  if (!PG_ARGISNULL(2)) {
205  POSTGIS_RT_DEBUG(3, "RASTER_asGDALRaster: Processing Arg 2 (options)");
206  array = PG_GETARG_ARRAYTYPE_P(2);
207  etype = ARR_ELEMTYPE(array);
208  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
209 
210  switch (etype) {
211  case TEXTOID:
212  break;
213  default:
215  PG_FREE_IF_COPY(pgraster, 0);
216  elog(ERROR, "RASTER_asGDALRaster: Invalid data type for options");
217  PG_RETURN_NULL();
218  break;
219  }
220 
221  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
222  &nulls, &n);
223 
224  if (n) {
225  options = (char **) palloc(sizeof(char *) * (n + 1));
226  if (options == NULL) {
228  PG_FREE_IF_COPY(pgraster, 0);
229  elog(ERROR, "RASTER_asGDALRaster: Could not allocate memory for options");
230  PG_RETURN_NULL();
231  }
232 
233  /* clean each option */
234  for (i = 0, j = 0; i < n; i++) {
235  if (nulls[i]) continue;
236 
237  option = NULL;
238  switch (etype) {
239  case TEXTOID:
240  optiontext = (text *) DatumGetPointer(e[i]);
241  if (NULL == optiontext) break;
242  option = text_to_cstring(optiontext);
243 
244  /* trim string */
245  option = rtpg_trim(option);
246  POSTGIS_RT_DEBUGF(3, "RASTER_asGDALRaster: option is '%s'", option);
247  break;
248  }
249 
250  if (strlen(option)) {
251  options[j] = (char *) palloc(sizeof(char) * (strlen(option) + 1));
252  strcpy(options[j], option);
253  j++;
254  }
255  }
256 
257  if (j > 0) {
258  /* trim allocation */
259  options = repalloc(options, (j + 1) * sizeof(char *));
260 
261  /* add NULL to end */
262  options[j] = NULL;
263 
264  }
265  else {
266  pfree(options);
267  options = NULL;
268  }
269  }
270  }
271 
272  /* process srid */
273  /* NULL srid means use raster's srid */
274  if (PG_ARGISNULL(3))
275  srid = rt_raster_get_srid(raster);
276  else
277  srid = PG_GETARG_INT32(3);
278 
279  /* get srs from srid */
280  if (clamp_srid(srid) != SRID_UNKNOWN) {
281  srs = rtpg_getSR(srid);
282  if (NULL == srs) {
283  if (NULL != options) {
284  for (i = j - 1; i >= 0; i--) pfree(options[i]);
285  pfree(options);
286  }
288  PG_FREE_IF_COPY(pgraster, 0);
289  elog(ERROR, "RASTER_asGDALRaster: Could not find srtext for SRID (%d)", srid);
290  PG_RETURN_NULL();
291  }
292  POSTGIS_RT_DEBUGF(3, "RASTER_asGDALRaster: Arg 3 (srs) is %s", srs);
293  }
294  else
295  srs = NULL;
296 
297  POSTGIS_RT_DEBUG(3, "RASTER_asGDALRaster: Generating GDAL raster");
298  gdal = rt_raster_to_gdal(raster, srs, format, options, &gdal_size);
299 
300  /* free memory */
301  if (NULL != options) {
302  for (i = j - 1; i >= 0; i--) pfree(options[i]);
303  pfree(options);
304  }
305  if (NULL != srs) pfree(srs);
307  PG_FREE_IF_COPY(pgraster, 0);
308 
309  if (!gdal) {
310  elog(ERROR, "RASTER_asGDALRaster: Could not allocate and generate GDAL raster");
311  PG_RETURN_NULL();
312  }
313  POSTGIS_RT_DEBUGF(3, "RASTER_asGDALRaster: GDAL raster generated with %d bytes", (int) gdal_size);
314 
315  /* result is a varlena */
316  result_size = gdal_size + VARHDRSZ;
317  result = (bytea *) palloc(result_size);
318  if (NULL == result) {
319  elog(ERROR, "RASTER_asGDALRaster: Insufficient virtual memory for GDAL raster");
320  PG_RETURN_NULL();
321  }
322  SET_VARSIZE(result, result_size);
323  memcpy(VARDATA(result), gdal, VARSIZE_ANY_EXHDR(result));
324 
325  /* free gdal mem buffer */
326  CPLFree(gdal);
327 
328  POSTGIS_RT_DEBUG(3, "RASTER_asGDALRaster: Returning pointer to GDAL raster");
329  PG_RETURN_POINTER(result);
330 }
331 
332 #define VALUES_LENGTH 6
333 
338 Datum RASTER_getGDALDrivers(PG_FUNCTION_ARGS)
339 {
340  FuncCallContext *funcctx;
341  TupleDesc tupdesc;
342 
343  uint32_t drv_count;
344  rt_gdaldriver drv_set;
345  rt_gdaldriver drv_set2;
346  int call_cntr;
347  int max_calls;
348 
349  /* first call of function */
350  if (SRF_IS_FIRSTCALL()) {
351  MemoryContext oldcontext;
352 
353  /* create a function context for cross-call persistence */
354  funcctx = SRF_FIRSTCALL_INIT();
355 
356  /* switch to memory context appropriate for multiple function calls */
357  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
358 
359  drv_set = rt_raster_gdal_drivers(&drv_count, 0);
360  if (NULL == drv_set || !drv_count) {
361  elog(NOTICE, "No GDAL drivers found");
362  MemoryContextSwitchTo(oldcontext);
363  SRF_RETURN_DONE(funcctx);
364  }
365 
366  POSTGIS_RT_DEBUGF(3, "%d drivers returned", (int) drv_count);
367 
368  /* Store needed information */
369  funcctx->user_fctx = drv_set;
370 
371  /* total number of tuples to be returned */
372  funcctx->max_calls = drv_count;
373 
374  /* Build a tuple descriptor for our result type */
375  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
376  ereport(ERROR, (
377  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
378  errmsg(
379  "function returning record called in context "
380  "that cannot accept type record"
381  )
382  ));
383  }
384 
385  BlessTupleDesc(tupdesc);
386  funcctx->tuple_desc = tupdesc;
387  MemoryContextSwitchTo(oldcontext);
388  }
389 
390  /* stuff done on every call of the function */
391  funcctx = SRF_PERCALL_SETUP();
392 
393  call_cntr = funcctx->call_cntr;
394  max_calls = funcctx->max_calls;
395  tupdesc = funcctx->tuple_desc;
396  drv_set2 = funcctx->user_fctx;
397 
398  /* do when there is more left to send */
399  if (call_cntr < max_calls) {
400  Datum values[VALUES_LENGTH];
401  bool nulls[VALUES_LENGTH];
402  HeapTuple tuple;
403  Datum result;
404 
405  POSTGIS_RT_DEBUGF(3, "Result %d", call_cntr);
406 
407  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
408 
409  values[0] = Int32GetDatum(drv_set2[call_cntr].idx);
410  values[1] = CStringGetTextDatum(drv_set2[call_cntr].short_name);
411  values[2] = CStringGetTextDatum(drv_set2[call_cntr].long_name);
412  values[3] = BoolGetDatum(drv_set2[call_cntr].can_read);
413  values[4] = BoolGetDatum(drv_set2[call_cntr].can_write);
414  values[5] = CStringGetTextDatum(drv_set2[call_cntr].create_options);
415 
416  POSTGIS_RT_DEBUGF(4, "Result %d, Index %d", call_cntr, drv_set2[call_cntr].idx);
417  POSTGIS_RT_DEBUGF(4, "Result %d, Short Name %s", call_cntr, drv_set2[call_cntr].short_name);
418  POSTGIS_RT_DEBUGF(4, "Result %d, Full Name %s", call_cntr, drv_set2[call_cntr].long_name);
419  POSTGIS_RT_DEBUGF(4, "Result %d, Can Read %u", call_cntr, drv_set2[call_cntr].can_read);
420  POSTGIS_RT_DEBUGF(4, "Result %d, Can Write %u", call_cntr, drv_set2[call_cntr].can_write);
421  POSTGIS_RT_DEBUGF(5, "Result %d, Create Options %s", call_cntr, drv_set2[call_cntr].create_options);
422 
423  /* build a tuple */
424  tuple = heap_form_tuple(tupdesc, values, nulls);
425 
426  /* make the tuple into a datum */
427  result = HeapTupleGetDatum(tuple);
428 
429  /* clean up */
430  pfree(drv_set2[call_cntr].short_name);
431  pfree(drv_set2[call_cntr].long_name);
432  pfree(drv_set2[call_cntr].create_options);
433 
434  SRF_RETURN_NEXT(funcctx, result);
435  }
436  /* do when there is no more left */
437  else {
438  pfree(drv_set2);
439  SRF_RETURN_DONE(funcctx);
440  }
441 }
442 
443 /************************************************************************
444  * ST_Contour(
445  * rast raster,
446  * bandnumber integer DEFAULT 1,
447  * level_interval float8 DEFAULT 100.0,
448  * level_base float8 DEFAULT 0.0,
449  * fixed_levels float8[] DEFAULT ARRAY[]::float8[],
450  * polygonize boolean DEFAULT false
451  * )
452  * RETURNS table(geom geometry, value float8, id integer)
453  ************************************************************************/
454 
456 Datum RASTER_Contour(PG_FUNCTION_ARGS)
457 {
458  /* For return values */
459  typedef struct gdal_contour_result_t {
460  size_t ncontours;
461  struct rt_contour_t *contours;
462  } gdal_contour_result_t;
463 
464  FuncCallContext *funcctx;
465 
466  if (SRF_IS_FIRSTCALL())
467  {
468  MemoryContext oldcontext;
469  TupleDesc tupdesc;
470  gdal_contour_result_t *result;
471  rt_pgraster *pgraster = NULL;
472 
473  /* For reading the raster */
474  int src_srid = SRID_UNKNOWN;
475  char *src_srs = NULL;
476  rt_raster raster = NULL;
477  int num_bands;
478  int band, rv;
479 
480  /* For reading the levels[] */
481  ArrayType *array;
482  size_t array_size = 0;
483 
484  /* For the level parameters */
485  double level_base = 0.0;
486  double level_interval = 100.0;
487  double *fixed_levels = NULL;
488  size_t fixed_levels_count = 0;
489 
490  /* for the polygonize flag */
491  bool polygonize = false;
492 
493  /* create a function context for cross-call persistence */
494  funcctx = SRF_FIRSTCALL_INIT();
495 
496  /* switch to memory context appropriate for multiple function calls */
497  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
498 
499  /* To carry the output from rt_raster_gdal_contour */
500  result = palloc0(sizeof(gdal_contour_result_t));
501 
502  /* Build a tuple descriptor for our return result */
503  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
504  MemoryContextSwitchTo(oldcontext);
505  ereport(ERROR, (
506  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
507  errmsg(
508  "function returning record called in context "
509  "that cannot accept type record"
510  )
511  ));
512  }
513  BlessTupleDesc(tupdesc);
514  funcctx->tuple_desc = tupdesc;
515 
516  /* Read the raster */
517  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
518  raster = rt_raster_deserialize(pgraster, FALSE);
519  num_bands = rt_raster_get_num_bands(raster);
520  src_srid = clamp_srid(rt_raster_get_srid(raster));
521  src_srs = rtpg_getSR(src_srid);
522 
523  /* Read the band number */
524  band = PG_GETARG_INT32(1);
525  if (band < 1 || band > num_bands) {
526  elog(ERROR, "%s: band number must be between 1 and %u inclusive", __func__, num_bands);
527  }
528 
529  /* Read the level_interval */
530  level_interval = PG_GETARG_FLOAT8(2);
531 
532  /* Read the level_base */
533  level_base = PG_GETARG_FLOAT8(3);
534 
535  if (level_interval <= 0.0) {
536  elog(ERROR, "%s: level interval must be greater than zero", __func__);
537  }
538 
539  /* Read the polygonize flag */
540  polygonize = PG_GETARG_BOOL(5);
541 
542  /* Read the levels array */
543  array = PG_GETARG_ARRAYTYPE_P(4);
544  array_size = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
545  if (array_size > 0) {
546  Datum value;
547  bool isnull;
548  ArrayIterator iterator = array_create_iterator(array, 0, NULL);
549  fixed_levels = palloc0(array_size * sizeof(double));
550  while (array_iterate(iterator, &value, &isnull))
551  {
552  /* Skip nulls */
553  if (isnull)
554  continue;
555 
556  /* Can out if for some reason we are about to blow memory */
557  if (fixed_levels_count >= array_size)
558  break;
559 
560  fixed_levels[fixed_levels_count++] = DatumGetFloat8(value);
561  }
562  }
563 
564  /* Run the contouring routine */
566  /* input parameters */
567  raster,
568  band,
569  src_srid,
570  src_srs,
571  level_interval,
572  level_base,
573  fixed_levels_count,
574  fixed_levels,
575  polygonize,
576  /* output parameters */
577  &(result->ncontours),
578  &(result->contours)
579  );
580 
581  /* No-op on bad return */
582  if (rv == FALSE) {
583  funcctx = SRF_PERCALL_SETUP();
584  SRF_RETURN_DONE(funcctx);
585  }
586 
587  funcctx->user_fctx = result;
588  funcctx->max_calls = result->ncontours;
589  MemoryContextSwitchTo(oldcontext);
590  }
591 
592  /* stuff done on every call of the function */
593  funcctx = SRF_PERCALL_SETUP();
594 
595  /* do when there is more left to send */
596  if (funcctx->call_cntr < funcctx->max_calls) {
597 
598  HeapTuple tuple;
599  Datum srf_result;
600  Datum values[3] = {0, 0, 0};
601  bool nulls[3] = {0, 0, 0};
602 
603  gdal_contour_result_t *result = funcctx->user_fctx;
604  struct rt_contour_t c = result->contours[funcctx->call_cntr];
605 
606  if (c.geom) {
607  values[0] = PointerGetDatum(c.geom);
608  values[1] = Int32GetDatum(c.id);
609  values[2] = Float8GetDatum(c.elevation);
610  }
611  else {
612  nulls[0] = true;
613  nulls[1] = true;
614  nulls[2] = true;
615  }
616 
617  /* return a tuple */
618  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
619  srf_result = HeapTupleGetDatum(tuple);
620  SRF_RETURN_NEXT(funcctx, srf_result);
621  }
622  else {
623  SRF_RETURN_DONE(funcctx);
624  }
625 }
626 
627 /************************************************************************
628  * RASTER_InterpolateRaster
629  *
630  * CREATE OR REPLACE FUNCTION ST_InterpolateRaster(
631  * geom geometry,
632  * rast raster,
633  * options text,
634  * bandnumber integer DEFAULT 1
635  * ) RETURNS raster
636  *
637  * https://gdal.org/api/gdal_alg.html?highlight=contour#_CPPv414GDALGridCreate17GDALGridAlgorithmPKv7GUInt32PKdPKdPKddddd7GUInt327GUInt3212GDALDataTypePv16GDALProgressFuncPv
638  ************************************************************************/
639 
641 Datum RASTER_InterpolateRaster(PG_FUNCTION_ARGS)
642 {
643  rt_pgraster *in_pgrast = NULL;
644  rt_pgraster *out_pgrast = NULL;
645  rt_raster in_rast = NULL;
646  rt_raster out_rast = NULL;
647  uint32_t out_rast_bands[1] = {0};
648  rt_band in_band = NULL;
649  rt_band out_band = NULL;
650  int band_number;
651  uint16_t in_band_width, in_band_height;
652  uint32_t npoints;
653  rt_pixtype in_band_pixtype;
654  GDALDataType in_band_gdaltype;
655  size_t in_band_gdaltype_size;
656 
657  rt_envelope env;
658 
659  GDALGridAlgorithm algorithm;
660  text *options_txt = NULL;
661  void *options_struct = NULL;
662  CPLErr err;
663  uint8_t *out_data;
664  rt_errorstate rterr;
665 
666  /* Input points */
667  LWPOINTITERATOR *iterator;
668  POINT4D pt;
669  size_t coord_count = 0;
670  LWGEOM *lwgeom;
671  double *xcoords, *ycoords, *zcoords;
672 
673  GSERIALIZED *gser = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
674 
675  /* Z value is required to drive the grid heights */
676  if (!gserialized_has_z(gser))
677  elog(ERROR, "%s: input geometry does not have Z values", __func__);
678 
679  /* Cannot process empties */
680  if (gserialized_is_empty(gser))
681  PG_RETURN_NULL();
682 
683  in_pgrast = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
684  in_rast = rt_raster_deserialize(in_pgrast, FALSE);
685  if (!in_rast)
686  elog(ERROR, "%s: Could not deserialize raster", __func__);
687 
688  /* GDAL cannot grid a skewed raster */
689  if (rt_raster_get_x_skew(in_rast) != 0.0 ||
690  rt_raster_get_y_skew(in_rast) != 0.0) {
691  elog(ERROR, "%s: Cannot generate a grid into a skewed raster",__func__);
692  }
693 
694  /* Flat JSON map of options from user */
695  options_txt = PG_GETARG_TEXT_P(1);
696  /* 1-base band number from user */
697  band_number = PG_GETARG_INT32(3);
698  if (band_number < 1)
699  elog(ERROR, "%s: Invalid band number %d", __func__, band_number);
700 
701  lwgeom = lwgeom_from_gserialized(gser);
702  npoints = lwgeom_count_vertices(lwgeom);
703  /* This shouldn't happen, but just in case... */
704  if (npoints < 1)
705  elog(ERROR, "%s: Geometry has no points", __func__);
706 
707  in_band = rt_raster_get_band(in_rast, band_number-1);
708  if (!in_band)
709  elog(ERROR, "%s: Cannot access raster band %d", __func__, band_number);
710 
711 
712  rterr = rt_raster_get_envelope(in_rast, &env);
713  if (rterr == ES_ERROR)
714  elog(ERROR, "%s: Unable to calculate envelope", __func__);
715 
716  /* Get geometry of input raster */
717  in_band_width = rt_band_get_width(in_band);
718  in_band_height = rt_band_get_height(in_band);
719  in_band_pixtype = rt_band_get_pixtype(in_band);
720  in_band_gdaltype = rt_util_pixtype_to_gdal_datatype(in_band_pixtype);
721  in_band_gdaltype_size = GDALGetDataTypeSize(in_band_gdaltype) / 8;
722 
723  /* Quickly copy options struct into local memory context, so we */
724  /* don't have malloc'ed memory lying around */
725  // if (err == CE_None && options_struct) {
726  // void *tmp = options_struct;
727  // switch (algorithm) {
728  // case GGA_InverseDistanceToAPower:
729  // options_struct = palloc(sizeof(GDALGridInverseDistanceToAPowerOptions));
730  // memcpy(options_struct, tmp, sizeof(GDALGridInverseDistanceToAPowerOptions));
731  // break;
732  // case GGA_InverseDistanceToAPowerNearestNeighbor:
733  // options_struct = palloc(sizeof(GDALGridInverseDistanceToAPowerNearestNeighborOptions));
734  // memcpy(options_struct, tmp, sizeof(GDALGridInverseDistanceToAPowerNearestNeighborOptions));
735  // break;
736  // case GGA_MovingAverage:
737  // options_struct = palloc(sizeof(GDALGridMovingAverageOptions));
738  // memcpy(options_struct, tmp, sizeof(GDALGridMovingAverageOptions));
739  // break;
740  // case GGA_NearestNeighbor:
741  // options_struct = palloc(sizeof(GDALGridNearestNeighborOptions));
742  // memcpy(options_struct, tmp, sizeof(GDALGridNearestNeighborOptions));
743  // break;
744  // case GGA_Linear:
745  // options_struct = palloc(sizeof(GDALGridLinearOptions));
746  // memcpy(options_struct, tmp, sizeof(GDALGridLinearOptions));
747  // break;
748  // default:
749  // elog(ERROR, "%s: Unsupported gridding algorithm %d", __func__, algorithm);
750  // }
751  // free(tmp);
752  // }
753 
754  /* Prepare destination grid buffer for output */
755  out_data = palloc(in_band_gdaltype_size * in_band_width * in_band_height);
756 
757  /* Prepare input points for processing */
758  xcoords = palloc(sizeof(double) * npoints);
759  ycoords = palloc(sizeof(double) * npoints);
760  zcoords = palloc(sizeof(double) * npoints);
761 
762  /* Populate input points */
763  iterator = lwpointiterator_create(lwgeom);
764  while(lwpointiterator_next(iterator, &pt) == LW_SUCCESS) {
765  if (coord_count >= npoints)
766  elog(ERROR, "%s: More points from iterator than expected", __func__);
767  xcoords[coord_count] = pt.x;
768  ycoords[coord_count] = pt.y;
769  zcoords[coord_count] = pt.z;
770  coord_count++;
771  }
772  lwpointiterator_destroy(iterator);
773 
774  /* Extract algorithm and options from options text */
775  /* This malloc's the options struct, so clean up right away */
776  err = ParseAlgorithmAndOptions(
777  text_to_cstring(options_txt),
778  &algorithm,
779  &options_struct);
780  if (err != CE_None) {
781  if (options_struct) free(options_struct);
782  elog(ERROR, "%s: Unable to parse options string: %s", __func__, CPLGetLastErrorMsg());
783  }
784 
785  /* Run the gridding algorithm */
786  err = GDALGridCreate(
787  algorithm, options_struct,
788  npoints, xcoords, ycoords, zcoords,
789  env.MinX, env.MaxX, env.MinY, env.MaxY,
790  in_band_width, in_band_height,
791  in_band_gdaltype, out_data,
792  NULL, /* GDALProgressFunc */
793  NULL /* ProgressArgs */
794  );
795 
796  /* Quickly clean up malloc'ed memory */
797  if (options_struct)
798  free(options_struct);
799 
800  if (err != CE_None) {
801  elog(ERROR, "%s: GDALGridCreate failed: %s", __func__, CPLGetLastErrorMsg());
802  }
803 
804  out_rast_bands[0] = band_number-1;
805  out_rast = rt_raster_from_band(in_rast, out_rast_bands, 1);
806  out_band = rt_raster_get_band(out_rast, 0);
807  if (!out_band)
808  elog(ERROR, "%s: Cannot access output raster band", __func__);
809 
810  /* Copy the data from the output buffer into the destination band */
811  for (uint32_t y = 0; y < in_band_height; y++) {
812  size_t offset = (in_band_height-y-1) * (in_band_gdaltype_size * in_band_width);
813  rterr = rt_band_set_pixel_line(out_band, 0, y, out_data + offset, in_band_width);
814  }
815 
816  out_pgrast = rt_raster_serialize(out_rast);
817  rt_raster_destroy(out_rast);
818  rt_raster_destroy(in_rast);
819 
820  if (NULL == out_pgrast) PG_RETURN_NULL();
821 
822  SET_VARSIZE(out_pgrast, out_pgrast->size);
823  PG_RETURN_POINTER(out_pgrast);
824 }
825 
826 
827 /************************************************************************
828  * Warp a raster using GDAL Warp API
829  ************************************************************************/
830 
832 Datum RASTER_GDALWarp(PG_FUNCTION_ARGS)
833 {
834  rt_pgraster *pgraster = NULL;
835  rt_pgraster *pgrast = NULL;
836  rt_raster raster = NULL;
837  rt_raster rast = NULL;
838 
839  text *algtext = NULL;
840  char *algchar = NULL;
841  GDALResampleAlg alg = GRA_NearestNeighbour;
842  double max_err = 0.125;
843 
844  int src_srid = SRID_UNKNOWN;
845  char *src_srs = NULL;
846  int dst_srid = SRID_UNKNOWN;
847  char *dst_srs = NULL;
848  int no_srid = 0;
849 
850  double scale[2] = {0};
851  double *scale_x = NULL;
852  double *scale_y = NULL;
853 
854  double gridw[2] = {0};
855  double *grid_xw = NULL;
856  double *grid_yw = NULL;
857 
858  double skew[2] = {0};
859  double *skew_x = NULL;
860  double *skew_y = NULL;
861 
862  int dim[2] = {0};
863  int *dim_x = NULL;
864  int *dim_y = NULL;
865 
866  POSTGIS_RT_DEBUG(3, "RASTER_GDALWarp: Starting");
867 
868  /* pgraster is null, return null */
869  if (PG_ARGISNULL(0))
870  PG_RETURN_NULL();
871  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
872 
873  /* raster */
874  raster = rt_raster_deserialize(pgraster, FALSE);
875  if (!raster) {
876  PG_FREE_IF_COPY(pgraster, 0);
877  elog(ERROR, "RASTER_GDALWarp: Could not deserialize raster");
878  PG_RETURN_NULL();
879  }
880 
881  /* resampling algorithm */
882  if (!PG_ARGISNULL(1)) {
883  algtext = PG_GETARG_TEXT_P(1);
884  algchar = rtpg_trim(rtpg_strtoupper(text_to_cstring(algtext)));
885  alg = rt_util_gdal_resample_alg(algchar);
886  }
887  POSTGIS_RT_DEBUGF(4, "Resampling algorithm: %d", alg);
888 
889  /* max error */
890  if (!PG_ARGISNULL(2)) {
891  max_err = PG_GETARG_FLOAT8(2);
892  if (max_err < 0.) max_err = 0.;
893  }
894  POSTGIS_RT_DEBUGF(4, "max_err: %f", max_err);
895 
896  /* source SRID */
897  src_srid = clamp_srid(rt_raster_get_srid(raster));
898  POSTGIS_RT_DEBUGF(4, "source SRID: %d", src_srid);
899 
900  /* target SRID */
901  if (!PG_ARGISNULL(3)) {
902  dst_srid = clamp_srid(PG_GETARG_INT32(3));
903  if (dst_srid == SRID_UNKNOWN) {
905  PG_FREE_IF_COPY(pgraster, 0);
906  elog(ERROR, "RASTER_GDALWarp: %d is an invalid target SRID", dst_srid);
907  PG_RETURN_NULL();
908  }
909  }
910  else
911  dst_srid = src_srid;
912  POSTGIS_RT_DEBUGF(4, "destination SRID: %d", dst_srid);
913 
914  /* target SRID != src SRID, error */
915  if (src_srid == SRID_UNKNOWN && dst_srid != src_srid) {
917  PG_FREE_IF_COPY(pgraster, 0);
918  elog(ERROR, "RASTER_GDALWarp: Input raster has unknown (%d) SRID", src_srid);
919  PG_RETURN_NULL();
920  }
921  /* target SRID == src SRID, no reprojection */
922  else if (dst_srid == src_srid) {
923  no_srid = 1;
924  }
925 
926  /* scale x */
927  if (!PG_ARGISNULL(4)) {
928  scale[0] = PG_GETARG_FLOAT8(4);
929  if (FLT_NEQ(scale[0], 0.0))
930  scale_x = &scale[0];
931  }
932 
933  /* scale y */
934  if (!PG_ARGISNULL(5)) {
935  scale[1] = PG_GETARG_FLOAT8(5);
936  if (FLT_NEQ(scale[1], 0.0))
937  scale_y = &scale[1];
938  }
939 
940  /* grid alignment x */
941  if (!PG_ARGISNULL(6)) {
942  gridw[0] = PG_GETARG_FLOAT8(6);
943  grid_xw = &gridw[0];
944  }
945 
946  /* grid alignment y */
947  if (!PG_ARGISNULL(7)) {
948  gridw[1] = PG_GETARG_FLOAT8(7);
949  grid_yw = &gridw[1];
950  }
951 
952  /* skew x */
953  if (!PG_ARGISNULL(8)) {
954  skew[0] = PG_GETARG_FLOAT8(8);
955  if (FLT_NEQ(skew[0], 0.0))
956  skew_x = &skew[0];
957  }
958 
959  /* skew y */
960  if (!PG_ARGISNULL(9)) {
961  skew[1] = PG_GETARG_FLOAT8(9);
962  if (FLT_NEQ(skew[1], 0.0))
963  skew_y = &skew[1];
964  }
965 
966  /* width */
967  if (!PG_ARGISNULL(10)) {
968  dim[0] = PG_GETARG_INT32(10);
969  if (dim[0] < 0) dim[0] = 0;
970  if (dim[0] > 0) dim_x = &dim[0];
971  }
972 
973  /* height */
974  if (!PG_ARGISNULL(11)) {
975  dim[1] = PG_GETARG_INT32(11);
976  if (dim[1] < 0) dim[1] = 0;
977  if (dim[1] > 0) dim_y = &dim[1];
978  }
979 
980  /* check that at least something is to be done */
981  if (
982  (dst_srid == SRID_UNKNOWN) &&
983  (scale_x == NULL) && (scale_y == NULL) &&
984  (grid_xw == NULL) && (grid_yw == NULL) &&
985  (skew_x == NULL) && (skew_y == NULL) &&
986  (dim_x == NULL) && (dim_y == NULL)
987  ) {
988  elog(NOTICE, "No resampling parameters provided. Returning original raster");
990  PG_RETURN_POINTER(pgraster);
991  }
992  /* both values of alignment must be provided if any one is provided */
993  else if (
994  (grid_xw != NULL && grid_yw == NULL) ||
995  (grid_xw == NULL && grid_yw != NULL)
996  ) {
997  elog(NOTICE, "Values must be provided for both X and Y when specifying the alignment. Returning original raster");
999  PG_RETURN_POINTER(pgraster);
1000  }
1001  /* both values of scale must be provided if any one is provided */
1002  else if (
1003  (scale_x != NULL && scale_y == NULL) ||
1004  (scale_x == NULL && scale_y != NULL)
1005  ) {
1006  elog(NOTICE, "Values must be provided for both X and Y when specifying the scale. Returning original raster");
1008  PG_RETURN_POINTER(pgraster);
1009  }
1010  /* scale and width/height provided */
1011  else if (
1012  (scale_x != NULL || scale_y != NULL) &&
1013  (dim_x != NULL || dim_y != NULL)
1014  ) {
1015  elog(NOTICE, "Scale X/Y and width/height are mutually exclusive. Only provide one. Returning original raster");
1017  PG_RETURN_POINTER(pgraster);
1018  }
1019 
1020  /* get srses from srids */
1021  if (!no_srid) {
1022  /* source srs */
1023  src_srs = rtpg_getSR(src_srid);
1024  if (NULL == src_srs) {
1026  PG_FREE_IF_COPY(pgraster, 0);
1027  elog(ERROR, "RASTER_GDALWarp: Input raster has unknown SRID (%d)", src_srid);
1028  PG_RETURN_NULL();
1029  }
1030  POSTGIS_RT_DEBUGF(4, "src srs: %s", src_srs);
1031 
1032  dst_srs = rtpg_getSR(dst_srid);
1033  if (NULL == dst_srs) {
1034  pfree(src_srs);
1036  PG_FREE_IF_COPY(pgraster, 0);
1037  elog(ERROR, "RASTER_GDALWarp: Target SRID (%d) is unknown", dst_srid);
1038  PG_RETURN_NULL();
1039  }
1040  POSTGIS_RT_DEBUGF(4, "dst srs: %s", dst_srs);
1041  }
1042 
1044  raster,
1045  src_srs, dst_srs,
1046  scale_x, scale_y,
1047  dim_x, dim_y,
1048  NULL, NULL,
1049  grid_xw, grid_yw,
1050  skew_x, skew_y,
1051  alg, max_err);
1053  PG_FREE_IF_COPY(pgraster, 0);
1054  if (!no_srid) {
1055  pfree(src_srs);
1056  pfree(dst_srs);
1057  }
1058  if (!rast) {
1059  elog(ERROR, "RASTER_band: Could not create transformed raster");
1060  PG_RETURN_NULL();
1061  }
1062 
1063  /* add target SRID */
1064  rt_raster_set_srid(rast, dst_srid);
1065 
1066  pgrast = rt_raster_serialize(rast);
1068 
1069  if (NULL == pgrast) PG_RETURN_NULL();
1070 
1071  POSTGIS_RT_DEBUG(3, "RASTER_GDALWarp: done");
1072 
1073  SET_VARSIZE(pgrast, pgrast->size);
1074  PG_RETURN_POINTER(pgrast);
1075 }
1076 
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
#define FALSE
Definition: dbfopen.c:72
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:239
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized.c:152
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized.c:174
LWPOINTITERATOR * lwpointiterator_create(const LWGEOM *g)
Create a new LWPOINTITERATOR over supplied LWGEOM*.
Definition: lwiterator.c:242
int lwpointiterator_next(LWPOINTITERATOR *s, POINT4D *p)
Attempts to assign the next point in the iterator to p, and advances the iterator to the next point.
Definition: lwiterator.c:210
#define LW_SUCCESS
Definition: liblwgeom.h:112
void lwpointiterator_destroy(LWPOINTITERATOR *s)
Free all memory associated with the iterator.
Definition: lwiterator.c:267
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
Definition: lwgeom.c:1246
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:230
int32_t clamp_srid(int32_t srid)
Return a valid SRID from an arbitrary integer Raises a notice if what comes out is different from wha...
Definition: lwutil.c:333
uint16_t rt_band_get_width(rt_band band)
Return width of this band.
Definition: rt_band.c:640
#define FLT_NEQ(x, y)
Definition: librtcore.h:2379
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
Definition: rt_raster.c:360
int rt_util_gdal_register_all(int force_register_all)
Definition: rt_util.c:339
double rt_raster_get_x_skew(rt_raster raster)
Get skew about the X axis.
Definition: rt_raster.c:185
rt_gdaldriver rt_raster_gdal_drivers(uint32_t *drv_count, uint8_t cancc)
Returns a set of available GDAL drivers.
Definition: rt_raster.c:1838
uint8_t * rt_raster_to_gdal(rt_raster raster, const char *srs, char *format, char **options, uint64_t *gdalsize)
Return formatted GDAL raster from raster.
Definition: rt_raster.c:1720
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:86
rt_pixtype
Definition: librtcore.h:187
GDALDataType rt_util_pixtype_to_gdal_datatype(rt_pixtype pt)
Convert rt_pixtype to GDALDataType.
Definition: rt_util.c:121
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
rt_raster rt_raster_from_gdal_dataset(GDALDatasetH ds)
Return a raster from a GDAL dataset.
Definition: rt_raster.c:2291
GDALDatasetH rt_util_gdal_open(const char *fn, GDALAccess fn_access, int shared)
Definition: rt_util.c:386
rt_errorstate
Enum definitions.
Definition: librtcore.h:181
@ ES_ERROR
Definition: librtcore.h:183
rt_errorstate rt_band_set_pixel_line(rt_band band, int x, int y, void *vals, uint32_t len)
Set values of multiple pixels.
Definition: rt_band.c:853
GDALResampleAlg rt_util_gdal_resample_alg(const char *algname)
Convert cstring name to GDAL Resample Algorithm.
Definition: rt_util.c:94
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:376
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
Definition: rt_raster.c:367
rt_raster rt_raster_from_band(rt_raster raster, uint32_t *bandNums, int count)
Construct a new rt_raster from an existing rt_raster and an array of band numbers.
Definition: rt_raster.c:1463
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:631
rt_raster rt_raster_gdal_warp(rt_raster raster, const char *src_srs, const char *dst_srs, double *scale_x, double *scale_y, int *width, int *height, double *ul_xw, double *ul_yw, double *grid_xw, double *grid_yw, double *skew_x, double *skew_y, GDALResampleAlg resample_alg, double max_err)
Return a warped raster using GDAL Warp API.
Definition: rt_warp.c:178
int rt_raster_gdal_contour(rt_raster src_raster, int src_band, int src_srid, const char *src_srs, double contour_interval, double contour_base, int fixed_level_count, double *fixed_levels, int polygonize, size_t *ncontours, struct rt_contour_t **contours)
Return palloc'ed list of contours.
Definition: rt_gdal.c:89
rt_errorstate rt_raster_get_envelope(rt_raster raster, rt_envelope *env)
Get raster's envelope.
Definition: rt_raster.c:904
double rt_raster_get_y_skew(rt_raster raster)
Get skew about the Y axis.
Definition: rt_raster.c:194
uint16_t rt_band_get_height(rt_band band)
Return height of this band.
Definition: rt_band.c:649
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:725
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:385
void free(void *)
int value
Definition: genraster.py:62
band
Definition: ovdump.py:58
data
Definition: ovdump.py:104
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
Datum RASTER_setGDALOpenOptions(PG_FUNCTION_ARGS)
Datum RASTER_Contour(PG_FUNCTION_ARGS)
Definition: rtpg_gdal.c:456
Datum RASTER_fromGDALRaster(PG_FUNCTION_ARGS)
Definition: rtpg_gdal.c:60
Datum RASTER_getGDALDrivers(PG_FUNCTION_ARGS)
Definition: rtpg_gdal.c:338
Datum RASTER_asGDALRaster(PG_FUNCTION_ARGS)
Definition: rtpg_gdal.c:147
PG_FUNCTION_INFO_V1(RASTER_fromGDALRaster)
#define VALUES_LENGTH
Definition: rtpg_gdal.c:332
Datum RASTER_InterpolateRaster(PG_FUNCTION_ARGS)
Definition: rtpg_gdal.c:641
Datum RASTER_GDALWarp(PG_FUNCTION_ARGS)
Definition: rtpg_gdal.c:832
char * rtpg_getSR(int32_t srid)
char * rtpg_strtoupper(char *str)
char * rtpg_trim(const char *input)
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:69
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:73
double x
Definition: liblwgeom.h:429
double z
Definition: liblwgeom.h:429
double y
Definition: liblwgeom.h:429
GSERIALIZED * geom
Definition: librtcore.h:1749
double elevation
Definition: librtcore.h:1750
double MinX
Definition: librtcore.h:167
double MaxX
Definition: librtcore.h:168
double MinY
Definition: librtcore.h:169
double MaxY
Definition: librtcore.h:170
Struct definitions.
Definition: librtcore.h:2396