33 #include <utils/builtins.h>
34 #include <access/htup_details.h>
35 #include <utils/lsyscache.h>
36 #include <utils/array.h>
37 #include <utils/guc.h>
38 #include <catalog/pg_type.h>
39 #include <utils/memutils.h>
41 #include "../../postgis_config.h"
67 VSILFILE *vsifp = NULL;
79 bytea_data = (bytea *) PG_GETARG_BYTEA_P(0);
80 data = (uint8_t *) VARDATA(bytea_data);
81 data_len = VARSIZE_ANY_EXHDR(bytea_data);
89 vsifp = VSIFileFromMemBuffer(
"/vsimem/in.dat",
data, data_len,
FALSE);
91 PG_FREE_IF_COPY(bytea_data, 0);
92 elog(ERROR,
"RASTER_fromGDALRaster: Could not load bytea into memory file for use by GDAL");
101 if (hdsSrc == NULL) {
103 PG_FREE_IF_COPY(bytea_data, 0);
104 elog(ERROR,
"RASTER_fromGDALRaster: Could not open bytea with GDAL. Check that the bytea is of a GDAL supported format");
108 #if POSTGIS_DEBUG_LEVEL > 3
110 GDALDriverH hdrv = GDALGetDatasetDriver(hdsSrc);
113 GDALGetDriverShortName(hdrv),
114 GDALGetRasterXSize(hdsSrc),
115 GDALGetRasterYSize(hdsSrc)
125 PG_FREE_IF_COPY(bytea_data, 0);
128 elog(ERROR,
"RASTER_fromGDALRaster: Could not convert GDAL raster to raster");
141 SET_VARSIZE(pgraster, pgraster->
size);
142 PG_RETURN_POINTER(pgraster);
154 text *formattext = NULL;
156 char **options = NULL;
157 text *optiontext = NULL;
173 uint8_t *gdal = NULL;
174 uint64_t gdal_size = 0;
176 uint64_t result_size = 0;
181 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
182 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
186 PG_FREE_IF_COPY(pgraster, 0);
187 elog(ERROR,
"RASTER_asGDALRaster: Could not deserialize raster");
192 if (PG_ARGISNULL(1)) {
193 elog(NOTICE,
"Format must be provided");
195 PG_FREE_IF_COPY(pgraster, 0);
199 formattext = PG_GETARG_TEXT_P(1);
200 format = text_to_cstring(formattext);
206 if (!PG_ARGISNULL(2)) {
208 array = PG_GETARG_ARRAYTYPE_P(2);
209 etype = ARR_ELEMTYPE(array);
210 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
217 PG_FREE_IF_COPY(pgraster, 0);
218 elog(ERROR,
"RASTER_asGDALRaster: Invalid data type for options");
223 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
227 options = (
char **) palloc(
sizeof(
char *) * (n + 1));
228 if (options == NULL) {
230 PG_FREE_IF_COPY(pgraster, 0);
231 elog(ERROR,
"RASTER_asGDALRaster: Could not allocate memory for options");
236 for (i = 0, j = 0; i < n; i++) {
237 if (nulls[i])
continue;
242 optiontext = (text *) DatumGetPointer(e[i]);
243 if (NULL == optiontext)
break;
244 option = text_to_cstring(optiontext);
252 if (strlen(option)) {
253 options[j] = (
char *) palloc(
sizeof(
char) * (strlen(option) + 1));
254 strcpy(options[j], option);
261 options = repalloc(options, (j + 1) *
sizeof(
char *));
279 srid = PG_GETARG_INT32(3);
285 if (NULL != options) {
286 for (i = j - 1; i >= 0; i--) pfree(options[i]);
290 PG_FREE_IF_COPY(pgraster, 0);
291 elog(ERROR,
"RASTER_asGDALRaster: Could not find srtext for SRID (%d)", srid);
303 if (NULL != options) {
304 for (i = j - 1; i >= 0; i--) pfree(options[i]);
307 if (NULL != srs) pfree(srs);
309 PG_FREE_IF_COPY(pgraster, 0);
312 elog(ERROR,
"RASTER_asGDALRaster: Could not allocate and generate GDAL raster");
315 POSTGIS_RT_DEBUGF(3,
"RASTER_asGDALRaster: GDAL raster generated with %d bytes", (
int) gdal_size);
318 result_size = gdal_size + VARHDRSZ;
319 result = (bytea *) palloc(result_size);
321 elog(ERROR,
"RASTER_asGDALRaster: Insufficient virtual memory for GDAL raster");
324 SET_VARSIZE(
result, result_size);
325 memcpy(VARDATA(
result), gdal, VARSIZE_ANY_EXHDR(
result));
330 POSTGIS_RT_DEBUG(3,
"RASTER_asGDALRaster: Returning pointer to GDAL raster");
331 PG_RETURN_POINTER(
result);
334 #define VALUES_LENGTH 6
342 FuncCallContext *funcctx;
352 if (SRF_IS_FIRSTCALL()) {
353 MemoryContext oldcontext;
356 funcctx = SRF_FIRSTCALL_INIT();
359 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
362 if (NULL == drv_set || !drv_count) {
363 elog(NOTICE,
"No GDAL drivers found");
364 MemoryContextSwitchTo(oldcontext);
365 SRF_RETURN_DONE(funcctx);
371 funcctx->user_fctx = drv_set;
374 funcctx->max_calls = drv_count;
377 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
379 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
381 "function returning record called in context "
382 "that cannot accept type record"
387 BlessTupleDesc(tupdesc);
388 funcctx->tuple_desc = tupdesc;
389 MemoryContextSwitchTo(oldcontext);
393 funcctx = SRF_PERCALL_SETUP();
395 call_cntr = funcctx->call_cntr;
396 max_calls = funcctx->max_calls;
397 tupdesc = funcctx->tuple_desc;
398 drv_set2 = funcctx->user_fctx;
401 if (call_cntr < max_calls) {
411 values[0] = Int32GetDatum(drv_set2[call_cntr].idx);
412 values[1] = CStringGetTextDatum(drv_set2[call_cntr].short_name);
413 values[2] = CStringGetTextDatum(drv_set2[call_cntr].long_name);
414 values[3] = BoolGetDatum(drv_set2[call_cntr].can_read);
415 values[4] = BoolGetDatum(drv_set2[call_cntr].can_write);
416 values[5] = CStringGetTextDatum(drv_set2[call_cntr].create_options);
419 POSTGIS_RT_DEBUGF(4,
"Result %d, Short Name %s", call_cntr, drv_set2[call_cntr].short_name);
420 POSTGIS_RT_DEBUGF(4,
"Result %d, Full Name %s", call_cntr, drv_set2[call_cntr].long_name);
421 POSTGIS_RT_DEBUGF(4,
"Result %d, Can Read %u", call_cntr, drv_set2[call_cntr].can_read);
422 POSTGIS_RT_DEBUGF(4,
"Result %d, Can Write %u", call_cntr, drv_set2[call_cntr].can_write);
423 POSTGIS_RT_DEBUGF(5,
"Result %d, Create Options %s", call_cntr, drv_set2[call_cntr].create_options);
426 tuple = heap_form_tuple(tupdesc, values, nulls);
429 result = HeapTupleGetDatum(tuple);
432 pfree(drv_set2[call_cntr].short_name);
433 pfree(drv_set2[call_cntr].long_name);
434 pfree(drv_set2[call_cntr].create_options);
436 SRF_RETURN_NEXT(funcctx,
result);
441 SRF_RETURN_DONE(funcctx);
461 typedef struct gdal_contour_result_t {
464 } gdal_contour_result_t;
466 FuncCallContext *funcctx;
468 if (SRF_IS_FIRSTCALL())
470 MemoryContext oldcontext;
472 gdal_contour_result_t *
result;
477 char *src_srs = NULL;
484 size_t array_size = 0;
487 double level_base = 0.0;
488 double level_interval = 100.0;
489 double *fixed_levels = NULL;
490 size_t fixed_levels_count = 0;
493 bool polygonize =
false;
496 funcctx = SRF_FIRSTCALL_INIT();
499 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
502 result = palloc0(
sizeof(gdal_contour_result_t));
505 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
506 MemoryContextSwitchTo(oldcontext);
508 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
510 "function returning record called in context "
511 "that cannot accept type record"
515 BlessTupleDesc(tupdesc);
516 funcctx->tuple_desc = tupdesc;
519 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
526 band = PG_GETARG_INT32(1);
527 if (band < 1 || band > num_bands) {
528 elog(ERROR,
"%s: band number must be between 1 and %u inclusive", __func__, num_bands);
532 level_interval = PG_GETARG_FLOAT8(2);
535 level_base = PG_GETARG_FLOAT8(3);
537 if (level_interval <= 0.0) {
538 elog(ERROR,
"%s: level interval must be greater than zero", __func__);
542 polygonize = PG_GETARG_BOOL(5);
545 array = PG_GETARG_ARRAYTYPE_P(4);
546 array_size = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
547 if (array_size > 0) {
550 ArrayIterator iterator = array_create_iterator(array, 0, NULL);
551 fixed_levels = palloc0(array_size *
sizeof(
double));
552 while (array_iterate(iterator, &
value, &isnull))
559 if (fixed_levels_count >= array_size)
562 fixed_levels[fixed_levels_count++] = DatumGetFloat8(
value);
588 funcctx->user_fctx =
result;
589 funcctx->max_calls =
result->ncontours;
590 MemoryContextSwitchTo(oldcontext);
594 funcctx = SRF_PERCALL_SETUP();
597 if (funcctx->call_cntr < funcctx->max_calls) {
601 Datum values[3] = {0, 0, 0};
602 bool nulls[3] = {0, 0, 0};
604 gdal_contour_result_t *
result = funcctx->user_fctx;
608 values[0] = PointerGetDatum(c.
geom);
609 values[1] = Int32GetDatum(c.
id);
619 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
620 srf_result = HeapTupleGetDatum(tuple);
621 SRF_RETURN_NEXT(funcctx, srf_result);
624 SRF_RETURN_DONE(funcctx);
648 uint32_t out_rast_bands[1] = {0};
652 uint16_t in_band_width, in_band_height;
655 GDALDataType in_band_gdaltype;
656 size_t in_band_gdaltype_size;
660 GDALGridAlgorithm algorithm;
661 text *options_txt = NULL;
662 void *options_struct = NULL;
670 size_t coord_count = 0;
672 double *xcoords, *ycoords, *zcoords;
678 elog(ERROR,
"%s: input geometry does not have Z values", __func__);
684 in_pgrast = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
687 elog(ERROR,
"%s: Could not deserialize raster", __func__);
692 elog(ERROR,
"%s: Cannot generate a grid into a skewed raster",__func__);
696 options_txt = PG_GETARG_TEXT_P(1);
698 band_number = PG_GETARG_INT32(3);
700 elog(ERROR,
"%s: Invalid band number %d", __func__, band_number);
706 elog(ERROR,
"%s: Geometry has no points", __func__);
710 elog(ERROR,
"%s: Cannot access raster band %d", __func__, band_number);
715 elog(ERROR,
"%s: Unable to calculate envelope", __func__);
722 in_band_gdaltype_size = GDALGetDataTypeSize(in_band_gdaltype) / 8;
756 out_data = palloc(in_band_gdaltype_size * in_band_width * in_band_height);
759 xcoords = palloc(
sizeof(
double) * npoints);
760 ycoords = palloc(
sizeof(
double) * npoints);
761 zcoords = palloc(
sizeof(
double) * npoints);
766 if (coord_count >= npoints)
767 elog(ERROR,
"%s: More points from iterator than expected", __func__);
768 xcoords[coord_count] = pt.
x;
769 ycoords[coord_count] = pt.
y;
770 zcoords[coord_count] = pt.
z;
777 err = ParseAlgorithmAndOptions(
778 text_to_cstring(options_txt),
781 if (err != CE_None) {
782 if (options_struct)
free(options_struct);
783 elog(ERROR,
"%s: Unable to parse options string: %s", __func__, CPLGetLastErrorMsg());
787 err = GDALGridCreate(
788 algorithm, options_struct,
789 npoints, xcoords, ycoords, zcoords,
791 in_band_width, in_band_height,
792 in_band_gdaltype, out_data,
799 free(options_struct);
801 if (err != CE_None) {
802 elog(ERROR,
"%s: GDALGridCreate failed: %s", __func__, CPLGetLastErrorMsg());
805 out_rast_bands[0] = band_number-1;
809 elog(ERROR,
"%s: Cannot access output raster band", __func__);
812 for (uint32_t
y = 0;
y < in_band_height;
y++) {
813 size_t offset = (in_band_height-
y-1) * (in_band_gdaltype_size * in_band_width);
821 if (NULL == out_pgrast) PG_RETURN_NULL();
823 SET_VARSIZE(out_pgrast, out_pgrast->
size);
824 PG_RETURN_POINTER(out_pgrast);
840 text *algtext = NULL;
841 char *algchar = NULL;
842 GDALResampleAlg alg = GRA_NearestNeighbour;
843 double max_err = 0.125;
846 char *src_srs = NULL;
848 char *dst_srs = NULL;
851 double scale[2] = {0};
852 double *scale_x = NULL;
853 double *scale_y = NULL;
855 double gridw[2] = {0};
856 double *grid_xw = NULL;
857 double *grid_yw = NULL;
859 double skew[2] = {0};
860 double *skew_x = NULL;
861 double *skew_y = NULL;
872 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
877 PG_FREE_IF_COPY(pgraster, 0);
878 elog(ERROR,
"RASTER_GDALWarp: Could not deserialize raster");
883 if (!PG_ARGISNULL(1)) {
884 algtext = PG_GETARG_TEXT_P(1);
891 if (!PG_ARGISNULL(2)) {
892 max_err = PG_GETARG_FLOAT8(2);
893 if (max_err < 0.) max_err = 0.;
902 if (!PG_ARGISNULL(3)) {
906 PG_FREE_IF_COPY(pgraster, 0);
907 elog(ERROR,
"RASTER_GDALWarp: %d is an invalid target SRID", dst_srid);
918 PG_FREE_IF_COPY(pgraster, 0);
919 elog(ERROR,
"RASTER_GDALWarp: Input raster has unknown (%d) SRID", src_srid);
923 else if (dst_srid == src_srid) {
928 if (!PG_ARGISNULL(4)) {
929 scale[0] = PG_GETARG_FLOAT8(4);
935 if (!PG_ARGISNULL(5)) {
936 scale[1] = PG_GETARG_FLOAT8(5);
942 if (!PG_ARGISNULL(6)) {
943 gridw[0] = PG_GETARG_FLOAT8(6);
948 if (!PG_ARGISNULL(7)) {
949 gridw[1] = PG_GETARG_FLOAT8(7);
954 if (!PG_ARGISNULL(8)) {
955 skew[0] = PG_GETARG_FLOAT8(8);
961 if (!PG_ARGISNULL(9)) {
962 skew[1] = PG_GETARG_FLOAT8(9);
968 if (!PG_ARGISNULL(10)) {
969 dim[0] = PG_GETARG_INT32(10);
970 if (dim[0] < 0) dim[0] = 0;
971 if (dim[0] > 0) dim_x = &dim[0];
975 if (!PG_ARGISNULL(11)) {
976 dim[1] = PG_GETARG_INT32(11);
977 if (dim[1] < 0) dim[1] = 0;
978 if (dim[1] > 0) dim_y = &dim[1];
984 (scale_x == NULL) && (scale_y == NULL) &&
985 (grid_xw == NULL) && (grid_yw == NULL) &&
986 (skew_x == NULL) && (skew_y == NULL) &&
987 (dim_x == NULL) && (dim_y == NULL)
989 elog(NOTICE,
"No resampling parameters provided. Returning original raster");
991 PG_RETURN_POINTER(pgraster);
995 (grid_xw != NULL && grid_yw == NULL) ||
996 (grid_xw == NULL && grid_yw != NULL)
998 elog(NOTICE,
"Values must be provided for both X and Y when specifying the alignment. Returning original raster");
1000 PG_RETURN_POINTER(pgraster);
1004 (scale_x != NULL && scale_y == NULL) ||
1005 (scale_x == NULL && scale_y != NULL)
1007 elog(NOTICE,
"Values must be provided for both X and Y when specifying the scale. Returning original raster");
1009 PG_RETURN_POINTER(pgraster);
1013 (scale_x != NULL || scale_y != NULL) &&
1014 (dim_x != NULL || dim_y != NULL)
1016 elog(NOTICE,
"Scale X/Y and width/height are mutually exclusive. Only provide one. Returning original raster");
1018 PG_RETURN_POINTER(pgraster);
1025 if (NULL == src_srs) {
1027 PG_FREE_IF_COPY(pgraster, 0);
1028 elog(ERROR,
"RASTER_GDALWarp: Input raster has unknown SRID (%d)", src_srid);
1034 if (NULL == dst_srs) {
1037 PG_FREE_IF_COPY(pgraster, 0);
1038 elog(ERROR,
"RASTER_GDALWarp: Target SRID (%d) is unknown", dst_srid);
1054 PG_FREE_IF_COPY(pgraster, 0);
1060 elog(ERROR,
"RASTER_band: Could not create transformed raster");
1070 if (NULL == pgrast) PG_RETURN_NULL();
1074 SET_VARSIZE(pgrast, pgrast->
size);
1075 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,...)