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

◆ RASTER_dumpValues()

Datum RASTER_dumpValues ( PG_FUNCTION_ARGS  )

Definition at line 402 of file rtpg_pixel.c.

403{
404 FuncCallContext *funcctx;
405 TupleDesc tupdesc;
406 int call_cntr;
407 int max_calls;
408 int i = 0;
409 int x = 0;
410 int y = 0;
411 int z = 0;
412
413 int16 typlen;
414 bool typbyval;
415 char typalign;
416
417 rtpg_dumpvalues_arg arg1 = NULL;
418 rtpg_dumpvalues_arg arg2 = NULL;
419
420 /* stuff done only on the first call of the function */
421 if (SRF_IS_FIRSTCALL()) {
422 MemoryContext oldcontext;
423 rt_pgraster *pgraster = NULL;
424 rt_raster raster = NULL;
425 rt_band band = NULL;
426 int numbands = 0;
427 int j = 0;
428 bool exclude_nodata_value = TRUE;
429
430 ArrayType *array;
431 Oid etype;
432 Datum *e;
433 bool *nulls;
434
435 double val = 0;
436 int isnodata = 0;
437
438 POSTGIS_RT_DEBUG(2, "RASTER_dumpValues first call");
439
440 /* create a function context for cross-call persistence */
441 funcctx = SRF_FIRSTCALL_INIT();
442
443 /* switch to memory context appropriate for multiple function calls */
444 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
445
446 /* Get input arguments */
447 if (PG_ARGISNULL(0)) {
448 MemoryContextSwitchTo(oldcontext);
449 SRF_RETURN_DONE(funcctx);
450 }
451 pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
452
454 if (!raster) {
455 PG_FREE_IF_COPY(pgraster, 0);
456 ereport(ERROR, (
457 errcode(ERRCODE_OUT_OF_MEMORY),
458 errmsg("Could not deserialize raster")
459 ));
460 MemoryContextSwitchTo(oldcontext);
461 SRF_RETURN_DONE(funcctx);
462 }
463
464 /* check that raster is not empty */
465 /*
466 if (rt_raster_is_empty(raster)) {
467 elog(NOTICE, "Raster provided is empty");
468 rt_raster_destroy(raster);
469 PG_FREE_IF_COPY(pgraster, 0);
470 MemoryContextSwitchTo(oldcontext);
471 SRF_RETURN_DONE(funcctx);
472 }
473 */
474
475 /* raster has bands */
476 numbands = rt_raster_get_num_bands(raster);
477 if (!numbands) {
478 elog(NOTICE, "Raster provided has no bands");
479 rt_raster_destroy(raster);
480 PG_FREE_IF_COPY(pgraster, 0);
481 MemoryContextSwitchTo(oldcontext);
482 SRF_RETURN_DONE(funcctx);
483 }
484
485 /* initialize arg1 */
487 if (arg1 == NULL) {
488 rt_raster_destroy(raster);
489 PG_FREE_IF_COPY(pgraster, 0);
490 MemoryContextSwitchTo(oldcontext);
491 elog(ERROR, "RASTER_dumpValues: Could not initialize argument structure");
492 SRF_RETURN_DONE(funcctx);
493 }
494
495 /* nband, array */
496 if (!PG_ARGISNULL(1)) {
497 array = PG_GETARG_ARRAYTYPE_P(1);
498 etype = ARR_ELEMTYPE(array);
499 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
500
501 switch (etype) {
502 case INT2OID:
503 case INT4OID:
504 break;
505 default:
507 rt_raster_destroy(raster);
508 PG_FREE_IF_COPY(pgraster, 0);
509 MemoryContextSwitchTo(oldcontext);
510 elog(ERROR, "RASTER_dumpValues: Invalid data type for band indexes");
511 SRF_RETURN_DONE(funcctx);
512 break;
513 }
514
515 deconstruct_array(array, etype, typlen, typbyval, typalign, &e, &nulls, &(arg1->numbands));
516
517 arg1->nbands = palloc(sizeof(int) * arg1->numbands);
518 if (arg1->nbands == NULL) {
520 rt_raster_destroy(raster);
521 PG_FREE_IF_COPY(pgraster, 0);
522 MemoryContextSwitchTo(oldcontext);
523 elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
524 SRF_RETURN_DONE(funcctx);
525 }
526
527 for (i = 0, j = 0; i < arg1->numbands; i++) {
528 if (nulls[i]) continue;
529
530 switch (etype) {
531 case INT2OID:
532 arg1->nbands[j] = DatumGetInt16(e[i]) - 1;
533 break;
534 case INT4OID:
535 arg1->nbands[j] = DatumGetInt32(e[i]) - 1;
536 break;
537 }
538
539 j++;
540 }
541
542 if (j < arg1->numbands) {
543 arg1->nbands = repalloc(arg1->nbands, sizeof(int) * j);
544 if (arg1->nbands == NULL) {
546 rt_raster_destroy(raster);
547 PG_FREE_IF_COPY(pgraster, 0);
548 MemoryContextSwitchTo(oldcontext);
549 elog(ERROR, "RASTER_dumpValues: Could not reallocate memory for band indexes");
550 SRF_RETURN_DONE(funcctx);
551 }
552
553 arg1->numbands = j;
554 }
555
556 /* validate nbands */
557 for (i = 0; i < arg1->numbands; i++) {
558 if (!rt_raster_has_band(raster, arg1->nbands[i])) {
559 elog(NOTICE, "Band at index %d not found in raster", arg1->nbands[i] + 1);
561 rt_raster_destroy(raster);
562 PG_FREE_IF_COPY(pgraster, 0);
563 MemoryContextSwitchTo(oldcontext);
564 SRF_RETURN_DONE(funcctx);
565 }
566 }
567
568 }
569 /* no bands specified, return all bands */
570 else {
571 arg1->numbands = numbands;
572 arg1->nbands = palloc(sizeof(int) * arg1->numbands);
573
574 if (arg1->nbands == NULL) {
576 rt_raster_destroy(raster);
577 PG_FREE_IF_COPY(pgraster, 0);
578 MemoryContextSwitchTo(oldcontext);
579 elog(ERROR, "RASTER_dumpValues: Could not allocate memory for band indexes");
580 SRF_RETURN_DONE(funcctx);
581 }
582
583 for (i = 0; i < arg1->numbands; i++) {
584 arg1->nbands[i] = i;
585 POSTGIS_RT_DEBUGF(4, "arg1->nbands[%d] = %d", arg1->nbands[i], i);
586 }
587 }
588
589 arg1->rows = rt_raster_get_height(raster);
590 arg1->columns = rt_raster_get_width(raster);
591
592 /* exclude_nodata_value */
593 if (!PG_ARGISNULL(2))
594 exclude_nodata_value = PG_GETARG_BOOL(2);
595 POSTGIS_RT_DEBUGF(4, "exclude_nodata_value = %d", exclude_nodata_value);
596
597 /* allocate memory for each band's values and nodata flags */
598 arg1->values = palloc(sizeof(Datum *) * arg1->numbands);
599 arg1->nodata = palloc(sizeof(bool *) * arg1->numbands);
600 if (arg1->values == NULL || arg1->nodata == NULL) {
602 rt_raster_destroy(raster);
603 PG_FREE_IF_COPY(pgraster, 0);
604 MemoryContextSwitchTo(oldcontext);
605 elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
606 SRF_RETURN_DONE(funcctx);
607 }
608 memset(arg1->values, 0, sizeof(Datum *) * arg1->numbands);
609 memset(arg1->nodata, 0, sizeof(bool *) * arg1->numbands);
610
611 /* get each band and dump data */
612 for (z = 0; z < arg1->numbands; z++) {
613 /* shortcut if raster is empty */
614 if (rt_raster_is_empty(raster))
615 break;
616
617 band = rt_raster_get_band(raster, arg1->nbands[z]);
618 if (!band) {
619 int nband = arg1->nbands[z] + 1;
621 rt_raster_destroy(raster);
622 PG_FREE_IF_COPY(pgraster, 0);
623 MemoryContextSwitchTo(oldcontext);
624 elog(ERROR, "RASTER_dumpValues: Could not get band at index %d", nband);
625 SRF_RETURN_DONE(funcctx);
626 }
627
628 /* allocate memory for values and nodata flags */
629 arg1->values[z] = palloc(sizeof(Datum) * arg1->rows * arg1->columns);
630 arg1->nodata[z] = palloc(sizeof(bool) * arg1->rows * arg1->columns);
631 if (arg1->values[z] == NULL || arg1->nodata[z] == NULL) {
633 rt_raster_destroy(raster);
634 PG_FREE_IF_COPY(pgraster, 0);
635 MemoryContextSwitchTo(oldcontext);
636 elog(ERROR, "RASTER_dumpValues: Could not allocate memory for pixel values");
637 SRF_RETURN_DONE(funcctx);
638 }
639 memset(arg1->values[z], 0, sizeof(Datum) * arg1->rows * arg1->columns);
640 memset(arg1->nodata[z], 0, sizeof(bool) * arg1->rows * arg1->columns);
641
642 i = 0;
643
644 /* shortcut if band is NODATA */
645 if (rt_band_get_isnodata_flag(band)) {
646 for (i = (arg1->rows * arg1->columns) - 1; i >= 0; i--)
647 arg1->nodata[z][i] = TRUE;
648 continue;
649 }
650
651 for (y = 0; y < arg1->rows; y++) {
652 for (x = 0; x < arg1->columns; x++) {
653 /* get pixel */
654 if (rt_band_get_pixel(band, x, y, &val, &isnodata) != ES_NONE) {
655 int nband = arg1->nbands[z] + 1;
657 rt_raster_destroy(raster);
658 PG_FREE_IF_COPY(pgraster, 0);
659 MemoryContextSwitchTo(oldcontext);
660 elog(ERROR, "RASTER_dumpValues: Could not pixel (%d, %d) of band %d", x, y, nband);
661 SRF_RETURN_DONE(funcctx);
662 }
663
664 arg1->values[z][i] = Float8GetDatum(val);
665 POSTGIS_RT_DEBUGF(5, "arg1->values[z][i] = %f", DatumGetFloat8(arg1->values[z][i]));
666 POSTGIS_RT_DEBUGF(5, "clamped is?: %d", rt_band_clamped_value_is_nodata(band, val));
667
668 if (exclude_nodata_value && isnodata) {
669 arg1->nodata[z][i] = TRUE;
670 POSTGIS_RT_DEBUG(5, "nodata = 1");
671 }
672 else
673 POSTGIS_RT_DEBUG(5, "nodata = 0");
674
675 i++;
676 }
677 }
678 }
679
680 /* cleanup */
681 rt_raster_destroy(raster);
682 PG_FREE_IF_COPY(pgraster, 0);
683
684 /* Store needed information */
685 funcctx->user_fctx = arg1;
686
687 /* total number of tuples to be returned */
688 funcctx->max_calls = arg1->numbands;
689
690 /* Build a tuple descriptor for our result type */
691 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
692 MemoryContextSwitchTo(oldcontext);
693 ereport(ERROR, (
694 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
695 errmsg(
696 "function returning record called in context "
697 "that cannot accept type record"
698 )
699 ));
700 }
701
702 BlessTupleDesc(tupdesc);
703 funcctx->tuple_desc = tupdesc;
704
705 MemoryContextSwitchTo(oldcontext);
706 }
707
708 /* stuff done on every call of the function */
709 funcctx = SRF_PERCALL_SETUP();
710
711 call_cntr = funcctx->call_cntr;
712 max_calls = funcctx->max_calls;
713 tupdesc = funcctx->tuple_desc;
714 arg2 = funcctx->user_fctx;
715
716 /* do when there is more left to send */
717 if (call_cntr < max_calls) {
718 Datum values[VALUES_LENGTH];
719 bool nulls[VALUES_LENGTH];
720 HeapTuple tuple;
721 Datum result;
722 ArrayType *mdValues = NULL;
723 int ndim = 2;
724 int dim[2] = {arg2->rows, arg2->columns};
725 int lbound[2] = {1, 1};
726
727 POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
728 POSTGIS_RT_DEBUGF(4, "dim = %d, %d", dim[0], dim[1]);
729
730 memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
731
732 values[0] = Int32GetDatum(arg2->nbands[call_cntr] + 1);
733
734 /* info about the type of item in the multi-dimensional array (float8). */
735 get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
736
737 /* if values is NULL, return empty array */
738 if (arg2->values[call_cntr] == NULL)
739 ndim = 0;
740
741 /* assemble 3-dimension array of values */
742 mdValues = construct_md_array(
743 arg2->values[call_cntr], arg2->nodata[call_cntr],
744 ndim, dim, lbound,
745 FLOAT8OID,
746 typlen, typbyval, typalign
747 );
748 values[1] = PointerGetDatum(mdValues);
749
750 /* build a tuple and datum */
751 tuple = heap_form_tuple(tupdesc, values, nulls);
752 result = HeapTupleGetDatum(tuple);
753
754 SRF_RETURN_NEXT(funcctx, result);
755 }
756 /* do when there is no more left */
757 else {
759 SRF_RETURN_DONE(funcctx);
760 }
761}
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
#define TRUE
Definition dbfopen.c:73
#define FALSE
Definition dbfopen.c:72
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition rt_band.c:1551
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition rt_raster.c:86
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition rt_band.c:873
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:1253
@ ES_NONE
Definition librtcore.h:182
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition rt_raster.c:376
uint16_t rt_raster_get_height(rt_raster raster)
Definition rt_raster.c:133
uint16_t rt_raster_get_width(rt_raster raster)
Definition rt_raster.c:125
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:2135
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:1240
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition rt_raster.c:385
nband
Definition pixval.py:56
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition rtrowdump.py:125
static void rtpg_dumpvalues_arg_destroy(rtpg_dumpvalues_arg arg)
Definition rtpg_pixel.c:372
static rtpg_dumpvalues_arg rtpg_dumpvalues_arg_init()
Definition rtpg_pixel.c:352
#define VALUES_LENGTH
Definition rtpg_pixel.c:399
#define POSTGIS_RT_DEBUG(level, msg)
Definition rtpostgis.h:65
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition rtpostgis.h:69
Struct definitions.
Definition librtcore.h:2452

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, result, 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: