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