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

◆ RASTER_nMapAlgebra()

Datum RASTER_nMapAlgebra ( PG_FUNCTION_ARGS  )

Definition at line 526 of file rtpg_mapalgebra.c.

527{
528 rtpg_nmapalgebra_arg arg = NULL;
529 rt_iterator itrset;
530 ArrayType *maskArray;
531 Oid etype;
532 Datum *maskElements;
533 bool *maskNulls;
534 int16 typlen;
535 bool typbyval;
536 char typalign;
537 int ndims = 0;
538 int num;
539 int *maskDims;
540 int x,y;
541
542
543 int i = 0;
544 int noerr = 0;
545 int allnull = 0;
546 int allempty = 0;
547 int noband = 0;
548
549 rt_raster raster = NULL;
550 rt_band band = NULL;
551 rt_pgraster *pgraster = NULL;
552
553 POSTGIS_RT_DEBUG(3, "Starting...");
554
555 if (PG_ARGISNULL(0))
556 PG_RETURN_NULL();
557
558 /* init argument struct */
560 if (arg == NULL) {
561 elog(ERROR, "RASTER_nMapAlgebra: Could not initialize argument structure");
562 PG_RETURN_NULL();
563 }
564
565 /* let helper function process rastbandarg (0) */
566 if (!rtpg_nmapalgebra_rastbandarg_process(arg, PG_GETARG_ARRAYTYPE_P(0), &allnull, &allempty, &noband)) {
568 elog(ERROR, "RASTER_nMapAlgebra: Could not process rastbandarg");
569 PG_RETURN_NULL();
570 }
571
572 POSTGIS_RT_DEBUGF(4, "allnull, allempty, noband = %d, %d, %d", allnull, allempty, noband);
573
574 /* all rasters are NULL, return NULL */
575 if (allnull == arg->numraster) {
576 elog(NOTICE, "All input rasters are NULL. Returning NULL");
578 PG_RETURN_NULL();
579 }
580
581 /* pixel type (2) */
582 if (!PG_ARGISNULL(2)) {
583 char *pixtypename = text_to_cstring(PG_GETARG_TEXT_P(2));
584
585 /* Get the pixel type index */
586 arg->pixtype = rt_pixtype_index_from_name(pixtypename);
587 if (arg->pixtype == PT_END) {
589 elog(ERROR, "RASTER_nMapAlgebra: Invalid pixel type: %s", pixtypename);
590 PG_RETURN_NULL();
591 }
592 }
593
594 /* distancex (3) */
595 if (!PG_ARGISNULL(3)){
596 arg->distance[0] = PG_GETARG_INT32(3);
597 }else{
598 arg->distance[0] = 0;
599 }
600 /* distancey (4) */
601 if (!PG_ARGISNULL(4)){
602 arg->distance[1] = PG_GETARG_INT32(4);
603 }else{
604 arg->distance[1] = 0;
605 }
606 if (arg->distance[0] < 0 || arg->distance[1] < 0) {
608 elog(ERROR, "RASTER_nMapAlgebra: Distance for X and Y axis must be greater than or equal to zero");
609 PG_RETURN_NULL();
610 }
611
612 /* extent type (5) */
613 if (!PG_ARGISNULL(5)) {
614 char *extenttypename = rtpg_strtoupper(rtpg_trim(text_to_cstring(PG_GETARG_TEXT_P(5))));
615 arg->extenttype = rt_util_extent_type(extenttypename);
616 }
617 POSTGIS_RT_DEBUGF(4, "extenttype: %d", arg->extenttype);
618
619 /* custom extent (6) */
620 if (arg->extenttype == ET_CUSTOM) {
621 if (PG_ARGISNULL(6)) {
622 elog(NOTICE, "Custom extent is NULL. Returning NULL");
624 PG_RETURN_NULL();
625 }
626
627 arg->pgcextent = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(6));
628
629 /* only need the raster header */
631 if (arg->cextent == NULL) {
633 elog(ERROR, "RASTER_nMapAlgebra: Could not deserialize custom extent");
634 PG_RETURN_NULL();
635 }
636 else if (rt_raster_is_empty(arg->cextent)) {
637 elog(NOTICE, "Custom extent is an empty raster. Returning empty raster");
639
640 raster = rt_raster_new(0, 0);
641 if (raster == NULL) {
642 elog(ERROR, "RASTER_nMapAlgebra: Could not create empty raster");
643 PG_RETURN_NULL();
644 }
645
646 pgraster = rt_raster_serialize(raster);
647 rt_raster_destroy(raster);
648 if (!pgraster) PG_RETURN_NULL();
649
650 SET_VARSIZE(pgraster, pgraster->size);
651 PG_RETURN_POINTER(pgraster);
652 }
653 }
654
655 /* mask (7) */
656
657 if( PG_ARGISNULL(7) ){
658 pfree(arg->mask);
659 arg->mask = NULL;
660 }
661 else {
662 maskArray = PG_GETARG_ARRAYTYPE_P(7);
663 etype = ARR_ELEMTYPE(maskArray);
664 get_typlenbyvalalign(etype,&typlen,&typbyval,&typalign);
665
666 switch (etype) {
667 case FLOAT4OID:
668 case FLOAT8OID:
669 break;
670 default:
672 elog(ERROR,"RASTER_nMapAlgebra: Mask data type must be FLOAT8 or FLOAT4");
673 PG_RETURN_NULL();
674 }
675
676 ndims = ARR_NDIM(maskArray);
677
678 if (ndims != 2) {
679 elog(ERROR, "RASTER_nMapAlgebra: Mask Must be a 2D array");
681 PG_RETURN_NULL();
682 }
683
684 maskDims = ARR_DIMS(maskArray);
685
686 if (maskDims[0] % 2 == 0 || maskDims[1] % 2 == 0) {
687 elog(ERROR,"RASTER_nMapAlgebra: Mask dimensions must be odd");
689 PG_RETURN_NULL();
690 }
691
692 deconstruct_array(
693 maskArray,
694 etype,
695 typlen, typbyval,typalign,
696 &maskElements,&maskNulls,&num
697 );
698
699 if (num < 1 || num != (maskDims[0] * maskDims[1])) {
700 if (num) {
701 pfree(maskElements);
702 pfree(maskNulls);
703 }
704 elog(ERROR, "RASTER_nMapAlgebra: Could not deconstruct new values array");
706 PG_RETURN_NULL();
707 }
708
709 /* allocate mem for mask array */
710 arg->mask->values = palloc(sizeof(double*)* maskDims[0]);
711 arg->mask->nodata = palloc(sizeof(int*)*maskDims[0]);
712 for (i = 0; i < maskDims[0]; i++) {
713 arg->mask->values[i] = (double*) palloc(sizeof(double) * maskDims[1]);
714 arg->mask->nodata[i] = (int*) palloc(sizeof(int) * maskDims[1]);
715 }
716
717 /* place values in to mask */
718 i = 0;
719 for (y = 0; y < maskDims[0]; y++) {
720 for (x = 0; x < maskDims[1]; x++) {
721 if (maskNulls[i]) {
722 arg->mask->values[y][x] = 0;
723 arg->mask->nodata[y][x] = 1;
724 }
725 else {
726 switch (etype) {
727 case FLOAT4OID:
728 arg->mask->values[y][x] = (double) DatumGetFloat4(maskElements[i]);
729 arg->mask->nodata[y][x] = 0;
730 break;
731 case FLOAT8OID:
732 arg->mask->values[y][x] = (double) DatumGetFloat8(maskElements[i]);
733 arg->mask->nodata[y][x] = 0;
734 }
735 }
736 i++;
737 }
738 }
739
740 /*set mask dimensions*/
741 arg->mask->dimx = maskDims[0];
742 arg->mask->dimy = maskDims[1];
743 if (maskDims[0] == 1 && maskDims[1] == 1) {
744 arg->distance[0] = 0;
745 arg->distance[1] = 0;
746 }
747 else {
748 arg->distance[0] = maskDims[0] % 2;
749 arg->distance[1] = maskDims[1] % 2;
750 }
751 }/*end if else argisnull*/
752
753 /* (8) weighted boolean */
754 if (PG_ARGISNULL(8) || !PG_GETARG_BOOL(8)) {
755 if (arg->mask != NULL)
756 arg->mask->weighted = 0;
757 }else{
758 if(arg->mask !=NULL)
759 arg->mask->weighted = 1;
760 }
761
762 noerr = 1;
763
764 /* all rasters are empty, return empty raster */
765 if (allempty == arg->numraster) {
766 elog(NOTICE, "All input rasters are empty. Returning empty raster");
767 noerr = 0;
768 }
769 /* all rasters don't have indicated band, return empty raster */
770 else if (noband == arg->numraster) {
771 elog(NOTICE, "All input rasters do not have bands at indicated indexes. Returning empty raster");
772 noerr = 0;
773 }
774 if (!noerr) {
776
777 raster = rt_raster_new(0, 0);
778 if (raster == NULL) {
779 elog(ERROR, "RASTER_nMapAlgebra: Could not create empty raster");
780 PG_RETURN_NULL();
781 }
782
783 pgraster = rt_raster_serialize(raster);
784 rt_raster_destroy(raster);
785 if (!pgraster) PG_RETURN_NULL();
786
787 SET_VARSIZE(pgraster, pgraster->size);
788 PG_RETURN_POINTER(pgraster);
789 }
790
791 /* do regprocedure last (1) */
792 if (!PG_ARGISNULL(1) || get_fn_expr_argtype(fcinfo->flinfo, 1) == REGPROCEDUREOID) {
793 POSTGIS_RT_DEBUG(4, "processing callbackfunc");
794 arg->callback.ufc_noid = PG_GETARG_OID(1);
795
796 /* get function info */
797 fmgr_info(arg->callback.ufc_noid, &(arg->callback.ufl_info));
798
799 /* function cannot return set */
800 noerr = 0;
801 if (arg->callback.ufl_info.fn_retset) {
802 noerr = 1;
803 }
804 /* function should have correct # of args */
805 else if (arg->callback.ufl_info.fn_nargs != 3) {
806 noerr = 2;
807 }
808
809 /* check that callback function return type is supported */
810 if (
811 get_func_result_type(
812 arg->callback.ufc_noid,
813 &(arg->callback.ufc_rettype),
814 NULL
815 ) != TYPEFUNC_SCALAR
816 ) {
817 noerr = 3;
818 }
819
820 if (!(
821 arg->callback.ufc_rettype == FLOAT8OID ||
822 arg->callback.ufc_rettype == FLOAT4OID ||
823 arg->callback.ufc_rettype == INT4OID ||
824 arg->callback.ufc_rettype == INT2OID
825 )) {
826 noerr = 4;
827 }
828
829 /*
830 TODO: consider adding checks of the userfunction parameters
831 should be able to use get_fn_expr_argtype() of fmgr.c
832 */
833
834 if (noerr != 0) {
836 switch (noerr) {
837 case 4:
838 elog(ERROR, "RASTER_nMapAlgebra: Function provided must return a double precision, float, int or smallint");
839 break;
840 case 3:
841 elog(ERROR, "RASTER_nMapAlgebra: Function provided must return scalar (double precision, float, int, smallint)");
842 break;
843 case 2:
844 elog(ERROR, "RASTER_nMapAlgebra: Function provided must have three input parameters");
845 break;
846 case 1:
847 elog(ERROR, "RASTER_nMapAlgebra: Function provided must return double precision, not resultset");
848 break;
849 }
850 PG_RETURN_NULL();
851 }
852
853 if (func_volatile(arg->callback.ufc_noid) == 'v')
854 elog(NOTICE, "Function provided is VOLATILE. Unless required and for best performance, function should be IMMUTABLE or STABLE");
855
856 /* prep function call data */
857 InitFunctionCallInfoData(*(arg->callback.ufc_info),
858 &(arg->callback.ufl_info),
859 arg->callback.ufl_info.fn_nargs,
860 InvalidOid,
861 NULL,
862 NULL);
863
864 arg->callback.ufc_info->args[0].isnull = FALSE;
865 arg->callback.ufc_info->args[1].isnull = FALSE;
866 arg->callback.ufc_info->args[2].isnull = FALSE;
867 /* userargs (7) */
868 if (!PG_ARGISNULL(9))
869 arg->callback.ufc_info->args[2].value = PG_GETARG_DATUM(9);
870 else {
871 if (arg->callback.ufl_info.fn_strict) {
872 /* build and assign an empty TEXT array */
873 /* TODO: manually free the empty array? */
874 arg->callback.ufc_info->args[2].value = PointerGetDatum(construct_empty_array(TEXTOID));
875 arg->callback.ufc_info->args[2].isnull = FALSE;
876 }
877 else {
878 arg->callback.ufc_info->args[2].value = (Datum)NULL;
879 arg->callback.ufc_info->args[2].isnull = TRUE;
880 }
881 }
882 }
883 else {
885 elog(ERROR, "RASTER_nMapAlgebra: callbackfunc must be provided");
886 PG_RETURN_NULL();
887 }
888
889 /* determine nodataval and possibly pixtype */
890 /* band to check */
891 switch (arg->extenttype) {
892 case ET_LAST:
893 i = arg->numraster - 1;
894 break;
895 case ET_SECOND:
896 i = (arg->numraster > 1) ? 1 : 0;
897 break;
898 default:
899 i = 0;
900 break;
901 }
902 /* find first viable band */
903 if (!arg->hasband[i]) {
904 for (i = 0; i < arg->numraster; i++) {
905 if (arg->hasband[i])
906 break;
907 }
908 if (i >= arg->numraster)
909 i = arg->numraster - 1;
910 }
911 band = rt_raster_get_band(arg->raster[i], arg->nband[i]);
912
913 /* set pixel type if PT_END */
914 if (arg->pixtype == PT_END)
915 arg->pixtype = rt_band_get_pixtype(band);
916
917 /* set hasnodata and nodataval */
918 arg->hasnodata = 1;
920 rt_band_get_nodata(band, &(arg->nodataval));
921 else
922 arg->nodataval = rt_band_get_min_value(band);
923
924 POSTGIS_RT_DEBUGF(4, "pixtype, hasnodata, nodataval: %s, %d, %f", rt_pixtype_name(arg->pixtype), arg->hasnodata, arg->nodataval);
925
926 /* init itrset */
927 itrset = palloc(sizeof(struct rt_iterator_t) * arg->numraster);
928 if (itrset == NULL) {
930 elog(ERROR, "RASTER_nMapAlgebra: Could not allocate memory for iterator arguments");
931 PG_RETURN_NULL();
932 }
933
934 /* set itrset */
935 for (i = 0; i < arg->numraster; i++) {
936 itrset[i].raster = arg->raster[i];
937 itrset[i].nband = arg->nband[i];
938 itrset[i].nbnodata = 1;
939 }
940
941 /* pass everything to iterator */
942 noerr = rt_raster_iterator(
943 itrset, arg->numraster,
944 arg->extenttype, arg->cextent,
945 arg->pixtype,
946 arg->hasnodata, arg->nodataval,
947 arg->distance[0], arg->distance[1],
948 arg->mask,
949 &(arg->callback),
951 &raster
952 );
953
954 /* cleanup */
955 pfree(itrset);
957
958 if (noerr != ES_NONE) {
959 elog(ERROR, "RASTER_nMapAlgebra: Could not run raster iterator function");
960 PG_RETURN_NULL();
961 }
962 else if (raster == NULL)
963 PG_RETURN_NULL();
964
965 pgraster = rt_raster_serialize(raster);
966 rt_raster_destroy(raster);
967
968 POSTGIS_RT_DEBUG(3, "Finished");
969
970 if (!pgraster)
971 PG_RETURN_NULL();
972
973 SET_VARSIZE(pgraster, pgraster->size);
974 PG_RETURN_POINTER(pgraster);
975}
#define TRUE
Definition dbfopen.c:73
#define FALSE
Definition dbfopen.c:72
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition rt_band.c:833
rt_pixtype rt_pixtype_index_from_name(const char *pixname)
Definition rt_pixel.c:82
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition rt_raster.c:86
@ PT_END
Definition librtcore.h:201
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
Definition rt_raster.c:52
rt_extenttype rt_util_extent_type(const char *name)
Definition rt_util.c:301
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition rt_pixel.c:114
double rt_band_get_min_value(rt_band band)
Returns the minimal possible value for the band according to the pixel type.
Definition rt_band.c:2082
@ ES_NONE
Definition librtcore.h:182
rt_errorstate rt_raster_iterator(rt_iterator itrset, uint16_t itrcount, rt_extenttype extenttype, rt_raster customextent, rt_pixtype pixtype, uint8_t hasnodata, double nodataval, uint16_t distancex, uint16_t distancey, rt_mask mask, void *userarg, int(*callback)(rt_iterator_arg arg, void *userarg, double *value, int *nodata), rt_raster *rtnraster)
n-raster iterator.
@ ET_CUSTOM
Definition librtcore.h:210
@ ET_LAST
Definition librtcore.h:209
@ ET_SECOND
Definition librtcore.h:208
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition rt_band.c:2067
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_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
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition rtrowdump.py:125
char * rtpg_trim(const char *input)
char * rtpg_strtoupper(char *str)
static void rtpg_nmapalgebra_arg_destroy(rtpg_nmapalgebra_arg arg)
static rtpg_nmapalgebra_arg rtpg_nmapalgebra_arg_init(void)
static int rtpg_nmapalgebra_rastbandarg_process(rtpg_nmapalgebra_arg arg, ArrayType *array, int *allnull, int *allempty, int *noband)
static int rtpg_nmapalgebra_callback(rt_iterator_arg arg, void *userarg, double *value, int *nodata)
#define POSTGIS_RT_DEBUG(level, msg)
Definition rtpostgis.h:65
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition rtpostgis.h:69
rt_raster raster
Definition librtcore.h:2659
uint16_t nband
Definition librtcore.h:2660
uint8_t nbnodata
Definition librtcore.h:2661
double ** values
Definition librtcore.h:2548
uint16_t dimy
Definition librtcore.h:2547
uint16_t dimx
Definition librtcore.h:2546
int ** nodata
Definition librtcore.h:2549
Struct definitions.
Definition librtcore.h:2452
rtpg_nmapalgebra_callback_arg callback

References rtpg_nmapalgebra_arg_t::callback, rtpg_nmapalgebra_arg_t::cextent, rt_mask_t::dimx, rt_mask_t::dimy, rtpg_nmapalgebra_arg_t::distance, ES_NONE, ET_CUSTOM, ET_LAST, ET_SECOND, rtpg_nmapalgebra_arg_t::extenttype, FALSE, rtpg_nmapalgebra_arg_t::hasband, rtpg_nmapalgebra_arg_t::hasnodata, rtpg_nmapalgebra_arg_t::mask, rt_iterator_t::nband, rtpg_nmapalgebra_arg_t::nband, rt_iterator_t::nbnodata, rt_mask_t::nodata, rtpg_nmapalgebra_arg_t::nodataval, rtpg_nmapalgebra_arg_t::numraster, rtpg_nmapalgebra_arg_t::pgcextent, rtpg_nmapalgebra_arg_t::pixtype, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, PT_END, rt_iterator_t::raster, rtpg_nmapalgebra_arg_t::raster, rt_band_get_hasnodata_flag(), rt_band_get_min_value(), rt_band_get_nodata(), rt_band_get_pixtype(), rt_pixtype_index_from_name(), rt_pixtype_name(), rt_raster_deserialize(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_is_empty(), rt_raster_iterator(), rt_raster_new(), rt_raster_serialize(), rt_util_extent_type(), rtpg_nmapalgebra_arg_destroy(), rtpg_nmapalgebra_arg_init(), rtpg_nmapalgebra_callback(), rtpg_nmapalgebra_rastbandarg_process(), rtpg_strtoupper(), rtpg_trim(), rt_raster_serialized_t::size, TRUE, rtpg_nmapalgebra_callback_arg::ufc_info, rtpg_nmapalgebra_callback_arg::ufc_noid, rtpg_nmapalgebra_callback_arg::ufc_rettype, rtpg_nmapalgebra_callback_arg::ufl_info, rt_mask_t::values, and rt_mask_t::weighted.

Here is the call graph for this function: