PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ RASTER_dumpValues()

Datum RASTER_dumpValues ( PG_FUNCTION_ARGS  )

Definition at line 203 of file rtpg_pixel.c.

204{
205 FuncCallContext *funcctx;
206 TupleDesc tupdesc;
207 int call_cntr;
208 int max_calls;
209 int i = 0;
210 int x = 0;
211 int y = 0;
212 int z = 0;
213
214 int16 typlen;
215 bool typbyval;
216 char typalign;
217
218 rtpg_dumpvalues_arg arg1 = NULL;
219 rtpg_dumpvalues_arg arg2 = NULL;
220
221 /* stuff done only on the first call of the function */
222 if (SRF_IS_FIRSTCALL()) {
223 MemoryContext oldcontext;
224 rt_pgraster *pgraster = NULL;
225 rt_raster raster = NULL;
226 rt_band band = NULL;
227 int numbands = 0;
228 int j = 0;
229 bool exclude_nodata_value = TRUE;
230
231 ArrayType *array;
232 Oid etype;
233 Datum *e;
234 bool *nulls;
235
236 double val = 0;
237 int isnodata = 0;
238
239 POSTGIS_RT_DEBUG(2, "RASTER_dumpValues first call");
240
241 /* create a function context for cross-call persistence */
242 funcctx = SRF_FIRSTCALL_INIT();
243
244 /* switch to memory context appropriate for multiple function calls */
245 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
246
247 /* Get input arguments */
248 if (PG_ARGISNULL(0)) {
249 MemoryContextSwitchTo(oldcontext);
250 SRF_RETURN_DONE(funcctx);
251 }
252 pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
253
255 if (!raster) {
256 PG_FREE_IF_COPY(pgraster, 0);
257 ereport(ERROR, (
258 errcode(ERRCODE_OUT_OF_MEMORY),
259 errmsg("Could not deserialize raster")
260 ));
261 MemoryContextSwitchTo(oldcontext);
262 SRF_RETURN_DONE(funcctx);
263 }
264
265 /* check that raster is not empty */
266 /*
267 if (rt_raster_is_empty(raster)) {
268 elog(NOTICE, "Raster provided is empty");
269 rt_raster_destroy(raster);
270 PG_FREE_IF_COPY(pgraster, 0);
271 MemoryContextSwitchTo(oldcontext);
272 SRF_RETURN_DONE(funcctx);
273 }
274 */
275
276 /* raster has bands */
277 numbands = rt_raster_get_num_bands(raster);
278 if (!numbands) {
279 elog(NOTICE, "Raster provided has no bands");
280 rt_raster_destroy(raster);
281 PG_FREE_IF_COPY(pgraster, 0);
282 MemoryContextSwitchTo(oldcontext);
283 SRF_RETURN_DONE(funcctx);
284 }
285
286 /* initialize arg1 */
288 if (arg1 == NULL) {
289 rt_raster_destroy(raster);
290 PG_FREE_IF_COPY(pgraster, 0);
291 MemoryContextSwitchTo(oldcontext);
292 elog(ERROR, "RASTER_dumpValues: Could not initialize argument structure");
293 SRF_RETURN_DONE(funcctx);
294 }
295
296 /* nband, array */
297 if (!PG_ARGISNULL(1)) {
298 array = PG_GETARG_ARRAYTYPE_P(1);
299 etype = ARR_ELEMTYPE(array);
300 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
301
302 switch (etype) {
303 case INT2OID:
304 case INT4OID:
305 break;
306 default:
308 rt_raster_destroy(raster);
309 PG_FREE_IF_COPY(pgraster, 0);
310 MemoryContextSwitchTo(oldcontext);
311 elog(ERROR, "RASTER_dumpValues: Invalid data type for band indexes");
312 SRF_RETURN_DONE(funcctx);
313 break;
314 }
315
316 deconstruct_array(array, etype, typlen, typbyval, typalign, &e, &nulls, &(arg1->numbands));
317
318 arg1->nbands = palloc(sizeof(int) * arg1->numbands);
319 if (arg1->nbands == NULL) {
321 rt_raster_destroy(raster);
322 PG_FREE_IF_COPY(pgraster, 0);
323 MemoryContextSwitchTo(oldcontext);
324 elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
325 SRF_RETURN_DONE(funcctx);
326 }
327
328 for (i = 0, j = 0; i < arg1->numbands; i++) {
329 if (nulls[i]) continue;
330
331 switch (etype) {
332 case INT2OID:
333 arg1->nbands[j] = DatumGetInt16(e[i]) - 1;
334 break;
335 case INT4OID:
336 arg1->nbands[j] = DatumGetInt32(e[i]) - 1;
337 break;
338 }
339
340 j++;
341 }
342
343 if (j < arg1->numbands) {
344 arg1->nbands = repalloc(arg1->nbands, sizeof(int) * j);
345 if (arg1->nbands == NULL) {
347 rt_raster_destroy(raster);
348 PG_FREE_IF_COPY(pgraster, 0);
349 MemoryContextSwitchTo(oldcontext);
350 elog(ERROR, "RASTER_dumpValues: Could not reallocate memory for band indexes");
351 SRF_RETURN_DONE(funcctx);
352 }
353
354 arg1->numbands = j;
355 }
356
357 /* validate nbands */
358 for (i = 0; i < arg1->numbands; i++) {
359 if (!rt_raster_has_band(raster, arg1->nbands[i])) {
360 elog(NOTICE, "Band at index %d not found in raster", arg1->nbands[i] + 1);
362 rt_raster_destroy(raster);
363 PG_FREE_IF_COPY(pgraster, 0);
364 MemoryContextSwitchTo(oldcontext);
365 SRF_RETURN_DONE(funcctx);
366 }
367 }
368
369 }
370 /* no bands specified, return all bands */
371 else {
372 arg1->numbands = numbands;
373 arg1->nbands = palloc(sizeof(int) * arg1->numbands);
374
375 if (arg1->nbands == NULL) {
377 rt_raster_destroy(raster);
378 PG_FREE_IF_COPY(pgraster, 0);
379 MemoryContextSwitchTo(oldcontext);
380 elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
381 SRF_RETURN_DONE(funcctx);
382 }
383
384 for (i = 0; i < arg1->numbands; i++) {
385 arg1->nbands[i] = i;
386 POSTGIS_RT_DEBUGF(4, "arg1->nbands[%d] = %d", arg1->nbands[i], i);
387 }
388 }
389
390 arg1->rows = rt_raster_get_height(raster);
391 arg1->columns = rt_raster_get_width(raster);
392
393 /* exclude_nodata_value */
394 if (!PG_ARGISNULL(2))
395 exclude_nodata_value = PG_GETARG_BOOL(2);
396 POSTGIS_RT_DEBUGF(4, "exclude_nodata_value = %d", exclude_nodata_value);
397
398 /* allocate memory for each band's values and nodata flags */
399 arg1->values = palloc(sizeof(Datum *) * arg1->numbands);
400 arg1->nodata = palloc(sizeof(bool *) * arg1->numbands);
401 if (arg1->values == NULL || arg1->nodata == NULL) {
403 rt_raster_destroy(raster);
404 PG_FREE_IF_COPY(pgraster, 0);
405 MemoryContextSwitchTo(oldcontext);
406 elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
407 SRF_RETURN_DONE(funcctx);
408 }
409 memset(arg1->values, 0, sizeof(Datum *) * arg1->numbands);
410 memset(arg1->nodata, 0, sizeof(bool *) * arg1->numbands);
411
412 /* get each band and dump data */
413 for (z = 0; z < arg1->numbands; z++) {
414 /* shortcut if raster is empty */
415 if (rt_raster_is_empty(raster))
416 break;
417
418 band = rt_raster_get_band(raster, arg1->nbands[z]);
419 if (!band) {
420 int nband = arg1->nbands[z] + 1;
422 rt_raster_destroy(raster);
423 PG_FREE_IF_COPY(pgraster, 0);
424 MemoryContextSwitchTo(oldcontext);
425 elog(ERROR, "RASTER_dumpValues: Could not get band at index %d", nband);
426 SRF_RETURN_DONE(funcctx);
427 }
428
429 /* allocate memory for values and nodata flags */
430 arg1->values[z] = palloc(sizeof(Datum) * arg1->rows * arg1->columns);
431 arg1->nodata[z] = palloc(sizeof(bool) * arg1->rows * arg1->columns);
432 if (arg1->values[z] == NULL || arg1->nodata[z] == NULL) {
434 rt_raster_destroy(raster);
435 PG_FREE_IF_COPY(pgraster, 0);
436 MemoryContextSwitchTo(oldcontext);
437 elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
438 SRF_RETURN_DONE(funcctx);
439 }
440 memset(arg1->values[z], 0, sizeof(Datum) * arg1->rows * arg1->columns);
441 memset(arg1->nodata[z], 0, sizeof(bool) * arg1->rows * arg1->columns);
442
443 i = 0;
444
445 /* shortcut if band is NODATA */
446 if (rt_band_get_isnodata_flag(band)) {
447 for (i = (arg1->rows * arg1->columns) - 1; i >= 0; i--)
448 arg1->nodata[z][i] = TRUE;
449 continue;
450 }
451
452 for (y = 0; y < arg1->rows; y++) {
453 for (x = 0; x < arg1->columns; x++) {
454 /* get pixel */
455 if (rt_band_get_pixel(band, x, y, &val, &isnodata) != ES_NONE) {
456 int nband = arg1->nbands[z] + 1;
458 rt_raster_destroy(raster);
459 PG_FREE_IF_COPY(pgraster, 0);
460 MemoryContextSwitchTo(oldcontext);
461 elog(ERROR, "RASTER_dumpValues: Could not pixel (%d, %d) of band %d", x, y, nband);
462 SRF_RETURN_DONE(funcctx);
463 }
464
465 arg1->values[z][i] = Float8GetDatum(val);
466 POSTGIS_RT_DEBUGF(5, "arg1->values[z][i] = %f", DatumGetFloat8(arg1->values[z][i]));
467 POSTGIS_RT_DEBUGF(5, "clamped is?: %d", rt_band_clamped_value_is_nodata(band, val));
468
469 if (exclude_nodata_value && isnodata) {
470 arg1->nodata[z][i] = TRUE;
471 POSTGIS_RT_DEBUG(5, "nodata = 1");
472 }
473 else
474 POSTGIS_RT_DEBUG(5, "nodata = 0");
475
476 i++;
477 }
478 }
479 }
480
481 /* cleanup */
482 rt_raster_destroy(raster);
483 PG_FREE_IF_COPY(pgraster, 0);
484
485 /* Store needed information */
486 funcctx->user_fctx = arg1;
487
488 /* total number of tuples to be returned */
489 funcctx->max_calls = arg1->numbands;
490
491 /* Build a tuple descriptor for our result type */
492 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
493 MemoryContextSwitchTo(oldcontext);
494 ereport(ERROR, (
495 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
496 errmsg(
497 "function returning record called in context "
498 "that cannot accept type record"
499 )
500 ));
501 }
502
503 BlessTupleDesc(tupdesc);
504 funcctx->tuple_desc = tupdesc;
505
506 MemoryContextSwitchTo(oldcontext);
507 }
508
509 /* stuff done on every call of the function */
510 funcctx = SRF_PERCALL_SETUP();
511
512 call_cntr = funcctx->call_cntr;
513 max_calls = funcctx->max_calls;
514 tupdesc = funcctx->tuple_desc;
515 arg2 = funcctx->user_fctx;
516
517 /* do when there is more left to send */
518 if (call_cntr < max_calls) {
519 Datum values[VALUES_LENGTH];
520 bool nulls[VALUES_LENGTH];
521 HeapTuple tuple;
522 Datum result;
523 ArrayType *mdValues = NULL;
524 int ndim = 2;
525 int dim[2] = {arg2->rows, arg2->columns};
526 int lbound[2] = {1, 1};
527
528 POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
529 POSTGIS_RT_DEBUGF(4, "dim = %d, %d", dim[0], dim[1]);
530
531 memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
532
533 values[0] = Int32GetDatum(arg2->nbands[call_cntr] + 1);
534
535 /* info about the type of item in the multi-dimensional array (float8). */
536 get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
537
538 /* if values is NULL, return empty array */
539 if (arg2->values[call_cntr] == NULL)
540 ndim = 0;
541
542 /* assemble 3-dimension array of values */
543 mdValues = construct_md_array(
544 arg2->values[call_cntr], arg2->nodata[call_cntr],
545 ndim, dim, lbound,
546 FLOAT8OID,
547 typlen, typbyval, typalign
548 );
549 values[1] = PointerGetDatum(mdValues);
550
551 /* build a tuple and datum */
552 tuple = heap_form_tuple(tupdesc, values, nulls);
553 result = HeapTupleGetDatum(tuple);
554
555 SRF_RETURN_NEXT(funcctx, result);
556 }
557 /* do when there is no more left */
558 else {
560 SRF_RETURN_DONE(funcctx);
561 }
562}
#define TRUE
Definition dbfopen.c:169
#define FALSE
Definition dbfopen.c:168
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition rt_band.c:1221
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition rt_raster.c:82
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition rt_band.c:714
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
Definition rt_raster.c:1342
@ ES_NONE
Definition librtcore.h:180
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition rt_raster.c:372
uint16_t rt_raster_get_height(rt_raster raster)
Definition rt_raster.c:129
uint16_t rt_raster_get_width(rt_raster raster)
Definition rt_raster.c:121
int rt_band_clamped_value_is_nodata(rt_band band, double val)
Compare clamped value to band's clamped NODATA value.
Definition rt_band.c:1798
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
int rt_raster_is_empty(rt_raster raster)
Return TRUE if the raster is empty.
Definition rt_raster.c:1329
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition rt_raster.c:381
nband
Definition pixval.py:53
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition rtrowdump.py:121
static void rtpg_dumpvalues_arg_destroy(rtpg_dumpvalues_arg arg)
Definition rtpg_pixel.c:173
static rtpg_dumpvalues_arg rtpg_dumpvalues_arg_init()
Definition rtpg_pixel.c:153
#define VALUES_LENGTH
Definition rtpg_pixel.c:200
#define POSTGIS_RT_DEBUG(level, msg)
Definition rtpostgis.h:61
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition rtpostgis.h:65
Struct definitions.
Definition librtcore.h:2251

References rtpg_dumpvalues_arg_t::columns, ES_NONE, FALSE, rtpg_dumpvalues_arg_t::nbands, rtpg_dumpvalues_arg_t::nodata, rtpg_dumpvalues_arg_t::numbands, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtpg_dumpvalues_arg_t::rows, rt_band_clamped_value_is_nodata(), rt_band_get_isnodata_flag(), rt_band_get_pixel(), rt_raster_deserialize(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_get_height(), rt_raster_get_num_bands(), rt_raster_get_width(), rt_raster_has_band(), rt_raster_is_empty(), rtpg_dumpvalues_arg_destroy(), rtpg_dumpvalues_arg_init(), TRUE, rtpg_dumpvalues_arg_t::values, and VALUES_LENGTH.

Here is the call graph for this function: