31 #include <utils/builtins.h>
32 #include <access/htup_details.h>
33 #include <utils/lsyscache.h>
34 #include <utils/array.h>
35 #include <utils/guc.h>
36 #include <catalog/pg_type.h>
37 #include <utils/memutils.h>
39 #include "../../postgis_config.h"
65 VSILFILE *vsifp = NULL;
77 bytea_data = (bytea *) PG_GETARG_BYTEA_P(0);
78 data = (uint8_t *) VARDATA(bytea_data);
79 data_len = VARSIZE_ANY_EXHDR(bytea_data);
87 vsifp = VSIFileFromMemBuffer(
"/vsimem/in.dat",
data, data_len,
FALSE);
89 PG_FREE_IF_COPY(bytea_data, 0);
90 elog(ERROR,
"RASTER_fromGDALRaster: Could not load bytea into memory file for use by GDAL");
101 PG_FREE_IF_COPY(bytea_data, 0);
102 elog(ERROR,
"RASTER_fromGDALRaster: Could not open bytea with GDAL. Check that the bytea is of a GDAL supported format");
106 #if POSTGIS_DEBUG_LEVEL > 3
108 GDALDriverH hdrv = GDALGetDatasetDriver(hdsSrc);
111 GDALGetDriverShortName(hdrv),
112 GDALGetRasterXSize(hdsSrc),
113 GDALGetRasterYSize(hdsSrc)
123 PG_FREE_IF_COPY(bytea_data, 0);
126 elog(ERROR,
"RASTER_fromGDALRaster: Could not convert GDAL raster to raster");
139 SET_VARSIZE(pgraster, pgraster->
size);
140 PG_RETURN_POINTER(pgraster);
152 text *formattext = NULL;
154 char **options = NULL;
155 text *optiontext = NULL;
171 uint8_t *gdal = NULL;
172 uint64_t gdal_size = 0;
174 uint64_t result_size = 0;
179 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
180 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
184 PG_FREE_IF_COPY(pgraster, 0);
185 elog(ERROR,
"RASTER_asGDALRaster: Could not deserialize raster");
190 if (PG_ARGISNULL(1)) {
191 elog(NOTICE,
"Format must be provided");
193 PG_FREE_IF_COPY(pgraster, 0);
197 formattext = PG_GETARG_TEXT_P(1);
198 format = text_to_cstring(formattext);
204 if (!PG_ARGISNULL(2)) {
206 array = PG_GETARG_ARRAYTYPE_P(2);
207 etype = ARR_ELEMTYPE(array);
208 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
215 PG_FREE_IF_COPY(pgraster, 0);
216 elog(ERROR,
"RASTER_asGDALRaster: Invalid data type for options");
221 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
225 options = (
char **) palloc(
sizeof(
char *) * (n + 1));
226 if (options == NULL) {
228 PG_FREE_IF_COPY(pgraster, 0);
229 elog(ERROR,
"RASTER_asGDALRaster: Could not allocate memory for options");
234 for (i = 0, j = 0; i < n; i++) {
235 if (nulls[i])
continue;
240 optiontext = (text *) DatumGetPointer(e[i]);
241 if (NULL == optiontext)
break;
242 option = text_to_cstring(optiontext);
250 if (strlen(option)) {
251 options[j] = (
char *) palloc(
sizeof(
char) * (strlen(option) + 1));
252 strcpy(options[j], option);
259 options = repalloc(options, (j + 1) *
sizeof(
char *));
277 srid = PG_GETARG_INT32(3);
283 if (NULL != options) {
284 for (i = j - 1; i >= 0; i--) pfree(options[i]);
288 PG_FREE_IF_COPY(pgraster, 0);
289 elog(ERROR,
"RASTER_asGDALRaster: Could not find srtext for SRID (%d)", srid);
301 if (NULL != options) {
302 for (i = j - 1; i >= 0; i--) pfree(options[i]);
305 if (NULL != srs) pfree(srs);
307 PG_FREE_IF_COPY(pgraster, 0);
310 elog(ERROR,
"RASTER_asGDALRaster: Could not allocate and generate GDAL raster");
313 POSTGIS_RT_DEBUGF(3,
"RASTER_asGDALRaster: GDAL raster generated with %d bytes", (
int) gdal_size);
316 result_size = gdal_size + VARHDRSZ;
317 result = (bytea *) palloc(result_size);
319 elog(ERROR,
"RASTER_asGDALRaster: Insufficient virtual memory for GDAL raster");
322 SET_VARSIZE(
result, result_size);
323 memcpy(VARDATA(
result), gdal, VARSIZE_ANY_EXHDR(
result));
328 POSTGIS_RT_DEBUG(3,
"RASTER_asGDALRaster: Returning pointer to GDAL raster");
329 PG_RETURN_POINTER(
result);
332 #define VALUES_LENGTH 6
340 FuncCallContext *funcctx;
350 if (SRF_IS_FIRSTCALL()) {
351 MemoryContext oldcontext;
354 funcctx = SRF_FIRSTCALL_INIT();
357 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
360 if (NULL == drv_set || !drv_count) {
361 elog(NOTICE,
"No GDAL drivers found");
362 MemoryContextSwitchTo(oldcontext);
363 SRF_RETURN_DONE(funcctx);
369 funcctx->user_fctx = drv_set;
372 funcctx->max_calls = drv_count;
375 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
377 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
379 "function returning record called in context "
380 "that cannot accept type record"
385 BlessTupleDesc(tupdesc);
386 funcctx->tuple_desc = tupdesc;
387 MemoryContextSwitchTo(oldcontext);
391 funcctx = SRF_PERCALL_SETUP();
393 call_cntr = funcctx->call_cntr;
394 max_calls = funcctx->max_calls;
395 tupdesc = funcctx->tuple_desc;
396 drv_set2 = funcctx->user_fctx;
399 if (call_cntr < max_calls) {
409 values[0] = Int32GetDatum(drv_set2[call_cntr].idx);
410 values[1] = CStringGetTextDatum(drv_set2[call_cntr].short_name);
411 values[2] = CStringGetTextDatum(drv_set2[call_cntr].long_name);
412 values[3] = BoolGetDatum(drv_set2[call_cntr].can_read);
413 values[4] = BoolGetDatum(drv_set2[call_cntr].can_write);
414 values[5] = CStringGetTextDatum(drv_set2[call_cntr].create_options);
417 POSTGIS_RT_DEBUGF(4,
"Result %d, Short Name %s", call_cntr, drv_set2[call_cntr].short_name);
418 POSTGIS_RT_DEBUGF(4,
"Result %d, Full Name %s", call_cntr, drv_set2[call_cntr].long_name);
419 POSTGIS_RT_DEBUGF(4,
"Result %d, Can Read %u", call_cntr, drv_set2[call_cntr].can_read);
420 POSTGIS_RT_DEBUGF(4,
"Result %d, Can Write %u", call_cntr, drv_set2[call_cntr].can_write);
421 POSTGIS_RT_DEBUGF(5,
"Result %d, Create Options %s", call_cntr, drv_set2[call_cntr].create_options);
424 tuple = heap_form_tuple(tupdesc, values, nulls);
427 result = HeapTupleGetDatum(tuple);
430 pfree(drv_set2[call_cntr].short_name);
431 pfree(drv_set2[call_cntr].long_name);
432 pfree(drv_set2[call_cntr].create_options);
434 SRF_RETURN_NEXT(funcctx,
result);
439 SRF_RETURN_DONE(funcctx);
459 typedef struct gdal_contour_result_t {
462 } gdal_contour_result_t;
464 FuncCallContext *funcctx;
466 if (SRF_IS_FIRSTCALL())
468 MemoryContext oldcontext;
470 gdal_contour_result_t *
result;
475 char *src_srs = NULL;
482 size_t array_size = 0;
485 double level_base = 0.0;
486 double level_interval = 100.0;
487 double *fixed_levels = NULL;
488 size_t fixed_levels_count = 0;
491 bool polygonize =
false;
494 funcctx = SRF_FIRSTCALL_INIT();
497 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
500 result = palloc0(
sizeof(gdal_contour_result_t));
503 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
504 MemoryContextSwitchTo(oldcontext);
506 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
508 "function returning record called in context "
509 "that cannot accept type record"
513 BlessTupleDesc(tupdesc);
514 funcctx->tuple_desc = tupdesc;
517 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
524 band = PG_GETARG_INT32(1);
525 if (band < 1 || band > num_bands) {
526 elog(ERROR,
"%s: band number must be between 1 and %u inclusive", __func__, num_bands);
530 level_interval = PG_GETARG_FLOAT8(2);
533 level_base = PG_GETARG_FLOAT8(3);
535 if (level_interval <= 0.0) {
536 elog(ERROR,
"%s: level interval must be greater than zero", __func__);
540 polygonize = PG_GETARG_BOOL(5);
543 array = PG_GETARG_ARRAYTYPE_P(4);
544 array_size = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
545 if (array_size > 0) {
548 ArrayIterator iterator = array_create_iterator(array, 0, NULL);
549 fixed_levels = palloc0(array_size *
sizeof(
double));
550 while (array_iterate(iterator, &
value, &isnull))
557 if (fixed_levels_count >= array_size)
560 fixed_levels[fixed_levels_count++] = DatumGetFloat8(
value);
583 funcctx = SRF_PERCALL_SETUP();
584 SRF_RETURN_DONE(funcctx);
587 funcctx->user_fctx =
result;
588 funcctx->max_calls =
result->ncontours;
589 MemoryContextSwitchTo(oldcontext);
593 funcctx = SRF_PERCALL_SETUP();
596 if (funcctx->call_cntr < funcctx->max_calls) {
600 Datum values[3] = {0, 0, 0};
601 bool nulls[3] = {0, 0, 0};
603 gdal_contour_result_t *
result = funcctx->user_fctx;
607 values[0] = PointerGetDatum(c.
geom);
608 values[1] = Int32GetDatum(c.
id);
618 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
619 srf_result = HeapTupleGetDatum(tuple);
620 SRF_RETURN_NEXT(funcctx, srf_result);
623 SRF_RETURN_DONE(funcctx);
647 uint32_t out_rast_bands[1] = {0};
651 uint16_t in_band_width, in_band_height;
654 GDALDataType in_band_gdaltype;
655 size_t in_band_gdaltype_size;
659 GDALGridAlgorithm algorithm;
660 text *options_txt = NULL;
661 void *options_struct = NULL;
669 size_t coord_count = 0;
671 double *xcoords, *ycoords, *zcoords;
677 elog(ERROR,
"%s: input geometry does not have Z values", __func__);
683 in_pgrast = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
686 elog(ERROR,
"%s: Could not deserialize raster", __func__);
691 elog(ERROR,
"%s: Cannot generate a grid into a skewed raster",__func__);
695 options_txt = PG_GETARG_TEXT_P(1);
697 band_number = PG_GETARG_INT32(3);
699 elog(ERROR,
"%s: Invalid band number %d", __func__, band_number);
705 elog(ERROR,
"%s: Geometry has no points", __func__);
709 elog(ERROR,
"%s: Cannot access raster band %d", __func__, band_number);
714 elog(ERROR,
"%s: Unable to calculate envelope", __func__);
721 in_band_gdaltype_size = GDALGetDataTypeSize(in_band_gdaltype) / 8;
755 out_data = palloc(in_band_gdaltype_size * in_band_width * in_band_height);
758 xcoords = palloc(
sizeof(
double) * npoints);
759 ycoords = palloc(
sizeof(
double) * npoints);
760 zcoords = palloc(
sizeof(
double) * npoints);
765 if (coord_count >= npoints)
766 elog(ERROR,
"%s: More points from iterator than expected", __func__);
767 xcoords[coord_count] = pt.
x;
768 ycoords[coord_count] = pt.
y;
769 zcoords[coord_count] = pt.
z;
776 err = ParseAlgorithmAndOptions(
777 text_to_cstring(options_txt),
780 if (err != CE_None) {
781 if (options_struct)
free(options_struct);
782 elog(ERROR,
"%s: Unable to parse options string: %s", __func__, CPLGetLastErrorMsg());
786 err = GDALGridCreate(
787 algorithm, options_struct,
788 npoints, xcoords, ycoords, zcoords,
790 in_band_width, in_band_height,
791 in_band_gdaltype, out_data,
798 free(options_struct);
800 if (err != CE_None) {
801 elog(ERROR,
"%s: GDALGridCreate failed: %s", __func__, CPLGetLastErrorMsg());
804 out_rast_bands[0] = band_number-1;
808 elog(ERROR,
"%s: Cannot access output raster band", __func__);
811 for (uint32_t
y = 0;
y < in_band_height;
y++) {
812 size_t offset = (in_band_height-
y-1) * (in_band_gdaltype_size * in_band_width);
820 if (NULL == out_pgrast) PG_RETURN_NULL();
822 SET_VARSIZE(out_pgrast, out_pgrast->
size);
823 PG_RETURN_POINTER(out_pgrast);
839 text *algtext = NULL;
840 char *algchar = NULL;
841 GDALResampleAlg alg = GRA_NearestNeighbour;
842 double max_err = 0.125;
845 char *src_srs = NULL;
847 char *dst_srs = NULL;
850 double scale[2] = {0};
851 double *scale_x = NULL;
852 double *scale_y = NULL;
854 double gridw[2] = {0};
855 double *grid_xw = NULL;
856 double *grid_yw = NULL;
858 double skew[2] = {0};
859 double *skew_x = NULL;
860 double *skew_y = NULL;
871 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
876 PG_FREE_IF_COPY(pgraster, 0);
877 elog(ERROR,
"RASTER_GDALWarp: Could not deserialize raster");
882 if (!PG_ARGISNULL(1)) {
883 algtext = PG_GETARG_TEXT_P(1);
890 if (!PG_ARGISNULL(2)) {
891 max_err = PG_GETARG_FLOAT8(2);
892 if (max_err < 0.) max_err = 0.;
901 if (!PG_ARGISNULL(3)) {
905 PG_FREE_IF_COPY(pgraster, 0);
906 elog(ERROR,
"RASTER_GDALWarp: %d is an invalid target SRID", dst_srid);
917 PG_FREE_IF_COPY(pgraster, 0);
918 elog(ERROR,
"RASTER_GDALWarp: Input raster has unknown (%d) SRID", src_srid);
922 else if (dst_srid == src_srid) {
927 if (!PG_ARGISNULL(4)) {
928 scale[0] = PG_GETARG_FLOAT8(4);
934 if (!PG_ARGISNULL(5)) {
935 scale[1] = PG_GETARG_FLOAT8(5);
941 if (!PG_ARGISNULL(6)) {
942 gridw[0] = PG_GETARG_FLOAT8(6);
947 if (!PG_ARGISNULL(7)) {
948 gridw[1] = PG_GETARG_FLOAT8(7);
953 if (!PG_ARGISNULL(8)) {
954 skew[0] = PG_GETARG_FLOAT8(8);
960 if (!PG_ARGISNULL(9)) {
961 skew[1] = PG_GETARG_FLOAT8(9);
967 if (!PG_ARGISNULL(10)) {
968 dim[0] = PG_GETARG_INT32(10);
969 if (dim[0] < 0) dim[0] = 0;
970 if (dim[0] > 0) dim_x = &dim[0];
974 if (!PG_ARGISNULL(11)) {
975 dim[1] = PG_GETARG_INT32(11);
976 if (dim[1] < 0) dim[1] = 0;
977 if (dim[1] > 0) dim_y = &dim[1];
983 (scale_x == NULL) && (scale_y == NULL) &&
984 (grid_xw == NULL) && (grid_yw == NULL) &&
985 (skew_x == NULL) && (skew_y == NULL) &&
986 (dim_x == NULL) && (dim_y == NULL)
988 elog(NOTICE,
"No resampling parameters provided. Returning original raster");
990 PG_RETURN_POINTER(pgraster);
994 (grid_xw != NULL && grid_yw == NULL) ||
995 (grid_xw == NULL && grid_yw != NULL)
997 elog(NOTICE,
"Values must be provided for both X and Y when specifying the alignment. Returning original raster");
999 PG_RETURN_POINTER(pgraster);
1003 (scale_x != NULL && scale_y == NULL) ||
1004 (scale_x == NULL && scale_y != NULL)
1006 elog(NOTICE,
"Values must be provided for both X and Y when specifying the scale. Returning original raster");
1008 PG_RETURN_POINTER(pgraster);
1012 (scale_x != NULL || scale_y != NULL) &&
1013 (dim_x != NULL || dim_y != NULL)
1015 elog(NOTICE,
"Scale X/Y and width/height are mutually exclusive. Only provide one. Returning original raster");
1017 PG_RETURN_POINTER(pgraster);
1024 if (NULL == src_srs) {
1026 PG_FREE_IF_COPY(pgraster, 0);
1027 elog(ERROR,
"RASTER_GDALWarp: Input raster has unknown SRID (%d)", src_srid);
1033 if (NULL == dst_srs) {
1036 PG_FREE_IF_COPY(pgraster, 0);
1037 elog(ERROR,
"RASTER_GDALWarp: Target SRID (%d) is unknown", dst_srid);
1053 PG_FREE_IF_COPY(pgraster, 0);
1059 elog(ERROR,
"RASTER_band: Could not create transformed raster");
1069 if (NULL == pgrast) PG_RETURN_NULL();
1073 SET_VARSIZE(pgrast, pgrast->
size);
1074 PG_RETURN_POINTER(pgrast);
char result[OUT_DOUBLE_BUFFER_SIZE]
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*.
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.
void lwpointiterator_destroy(LWPOINTITERATOR *s)
Free all memory associated with the iterator.
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
#define SRID_UNKNOWN
Unknown SRID value.
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...
uint16_t rt_band_get_width(rt_band band)
Return width of this band.
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
int rt_util_gdal_register_all(int force_register_all)
double rt_raster_get_x_skew(rt_raster raster)
Get skew about the X axis.
rt_gdaldriver rt_raster_gdal_drivers(uint32_t *drv_count, uint8_t cancc)
Returns a set of available GDAL drivers.
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.
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
GDALDataType rt_util_pixtype_to_gdal_datatype(rt_pixtype pt)
Convert rt_pixtype to GDALDataType.
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
rt_raster rt_raster_from_gdal_dataset(GDALDatasetH ds)
Return a raster from a GDAL dataset.
GDALDatasetH rt_util_gdal_open(const char *fn, GDALAccess fn_access, int shared)
rt_errorstate
Enum definitions.
rt_errorstate rt_band_set_pixel_line(rt_band band, int x, int y, void *vals, uint32_t len)
Set values of multiple pixels.
GDALResampleAlg rt_util_gdal_resample_alg(const char *algname)
Convert cstring name to GDAL Resample Algorithm.
uint16_t rt_raster_get_num_bands(rt_raster raster)
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
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.
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
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.
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.
rt_errorstate rt_raster_get_envelope(rt_raster raster, rt_envelope *env)
Get raster's envelope.
double rt_raster_get_y_skew(rt_raster raster)
Get skew about the Y axis.
uint16_t rt_band_get_height(rt_band band)
Return height of this band.
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.
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Datum RASTER_setGDALOpenOptions(PG_FUNCTION_ARGS)
Datum RASTER_Contour(PG_FUNCTION_ARGS)
Datum RASTER_fromGDALRaster(PG_FUNCTION_ARGS)
Datum RASTER_getGDALDrivers(PG_FUNCTION_ARGS)
Datum RASTER_asGDALRaster(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(RASTER_fromGDALRaster)
Datum RASTER_InterpolateRaster(PG_FUNCTION_ARGS)
Datum RASTER_GDALWarp(PG_FUNCTION_ARGS)
char * rtpg_getSR(int32_t srid)
char * rtpg_strtoupper(char *str)
char * rtpg_trim(const char *input)
#define POSTGIS_RT_DEBUG(level, msg)
#define POSTGIS_RT_DEBUGF(level, msg,...)