PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ 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);
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);
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)
916 
917  /* set hasnodata and nodataval */
918  arg->hasnodata = 1;
921  else
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);
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:825
rt_pixtype rt_pixtype_index_from_name(const char *pixname)
Definition: rt_pixel.c:80
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:86
@ PT_END
Definition: librtcore.h:199
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:204
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
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:2053
@ 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:208
@ ET_LAST
Definition: librtcore.h:207
@ ET_SECOND
Definition: librtcore.h:206
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:2038
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:782
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition: rt_pixel.c:110
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:725
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
band
Definition: ovdump.py:58
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
char * rtpg_strtoupper(char *str)
char * rtpg_trim(const char *input)
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:2647
uint16_t nband
Definition: librtcore.h:2648
uint8_t nbnodata
Definition: librtcore.h:2649
double ** values
Definition: librtcore.h:2536
uint16_t dimy
Definition: librtcore.h:2535
uint16_t dimx
Definition: librtcore.h:2534
int ** nodata
Definition: librtcore.h:2537
int weighted
Definition: librtcore.h:2538
Struct definitions.
Definition: librtcore.h:2440
rtpg_nmapalgebra_callback_arg callback

References ovdump::band, 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, rtrowdump::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, rt_mask_t::weighted, pixval::x, and pixval::y.

Here is the call graph for this function: