PostGIS  3.4.0dev-r@@SVN_REVISION@@

◆ RASTER_nMapAlgebra()

Datum RASTER_nMapAlgebra ( PG_FUNCTION_ARGS  )

Definition at line 525 of file rtpg_mapalgebra.c.

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