PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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 */
49Datum RASTER_fromGDALRaster(PG_FUNCTION_ARGS);
50
51/* convert raster to GDAL raster */
52Datum RASTER_asGDALRaster(PG_FUNCTION_ARGS);
53Datum RASTER_getGDALDrivers(PG_FUNCTION_ARGS);
54Datum RASTER_setGDALOpenOptions(PG_FUNCTION_ARGS);
55
56/* warp a raster using GDAL Warp API */
57Datum RASTER_GDALWarp(PG_FUNCTION_ARGS);
58
59/* ----------------------------------------------------------------
60 * Returns raster from GDAL raster
61 * ---------------------------------------------------------------- */
63Datum 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;
73 rt_raster raster;
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 */
122 raster = rt_raster_from_gdal_dataset(hdsSrc);
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);
138 rt_raster_destroy(raster);
139 if (!pgraster)
140 PG_RETURN_NULL();
141
142 SET_VARSIZE(pgraster, pgraster->size);
143 PG_RETURN_POINTER(pgraster);
144}
145
150Datum RASTER_asGDALRaster(PG_FUNCTION_ARGS)
151{
152 rt_pgraster *pgraster = NULL;
153 rt_raster raster;
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");
195 rt_raster_destroy(raster);
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:
217 rt_raster_destroy(raster);
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) {
230 rt_raster_destroy(raster);
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 }
290 rt_raster_destroy(raster);
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);
309 rt_raster_destroy(raster);
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
341Datum 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
459Datum 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
656Datum 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
847Datum 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) {
919 rt_raster_destroy(raster);
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) {
931 rt_raster_destroy(raster);
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");
1004 rt_raster_destroy(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");
1013 rt_raster_destroy(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");
1022 rt_raster_destroy(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");
1031 rt_raster_destroy(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) {
1040 rt_raster_destroy(raster);
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);
1050 rt_raster_destroy(raster);
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
1058 rast = rt_raster_gdal_warp(
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);
1067 rt_raster_destroy(raster);
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);
1082 rt_raster_destroy(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
1097static 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
1118static void
1119ogrErrorHandler(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
1146void
1147rtpg_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.
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
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:1337
#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:799
#define FLT_NEQ(x, y)
Definition librtcore.h:2435
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:444
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:188
GDALDataType rt_util_pixtype_to_gdal_datatype(rt_pixtype pt)
Convert rt_pixtype to GDALDataType.
Definition rt_util.c:213
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:491
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:1019
GDALResampleAlg rt_util_gdal_resample_alg(const char *algname)
Convert cstring name to GDAL Resample Algorithm.
Definition rt_util.c:183
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:790
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
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:119
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:808
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
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 *)
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_trim(const char *input)
char * rtpg_strtoupper(char *str)
#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:1777
double elevation
Definition librtcore.h:1778
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:2452