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