PostGIS  2.5.0dev-r@@SVN_REVISION@@
Datum RASTER_setPixelValuesArray ( PG_FUNCTION_ARGS  )

Definition at line 664 of file rtpg_pixel.c.

References ovdump::band, ES_NONE, FALSE, FLT_EQ, pixval::nband, POSTGIS_RT_DEBUGF, rtrowdump::raster, rt_band_get_hasnodata_flag(), rt_band_get_min_value(), rt_band_get_nodata(), rt_band_get_pixel(), rt_band_set_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_serialize(), rt_raster_serialized_t::size, TRUE, genraster::value, pixval::x, and pixval::y.

665 {
666  rt_pgraster *pgraster = NULL;
667  rt_pgraster *pgrtn = NULL;
668  rt_raster raster = NULL;
669  rt_band band = NULL;
670  int numbands = 0;
671 
672  int nband = 0;
673  int width = 0;
674  int height = 0;
675 
676  ArrayType *array;
677  Oid etype;
678  Datum *elements;
679  bool *nulls;
680  int16 typlen;
681  bool typbyval;
682  char typalign;
683  int ndims = 1;
684  int *dims;
685  int num = 0;
686 
687  int ul[2] = {0};
688  struct pixelvalue {
689  int x;
690  int y;
691 
692  bool noset;
693  bool nodata;
694  double value;
695  };
696  struct pixelvalue *pixval = NULL;
697  int numpixval = 0;
698  int dimpixval[2] = {1, 1};
699  int dimnoset[2] = {1, 1};
700  int hasnodata = FALSE;
701  double nodataval = 0;
702  bool keepnodata = FALSE;
703  bool hasnosetval = FALSE;
704  bool nosetvalisnull = FALSE;
705  double nosetval = 0;
706 
707  int rtn = 0;
708  double val = 0;
709  int isnodata = 0;
710 
711  int i = 0;
712  int j = 0;
713  int x = 0;
714  int y = 0;
715 
716  /* pgraster is null, return null */
717  if (PG_ARGISNULL(0))
718  PG_RETURN_NULL();
719  pgraster = (rt_pgraster *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
720 
721  /* raster */
722  raster = rt_raster_deserialize(pgraster, FALSE);
723  if (!raster) {
724  PG_FREE_IF_COPY(pgraster, 0);
725  elog(ERROR, "RASTER_setPixelValuesArray: Could not deserialize raster");
726  PG_RETURN_NULL();
727  }
728 
729  /* raster attributes */
730  numbands = rt_raster_get_num_bands(raster);
731  width = rt_raster_get_width(raster);
732  height = rt_raster_get_height(raster);
733 
734  /* nband */
735  if (PG_ARGISNULL(1)) {
736  elog(NOTICE, "Band index cannot be NULL. Value must be 1-based. Returning original raster");
737  rt_raster_destroy(raster);
738  PG_RETURN_POINTER(pgraster);
739  }
740 
741  nband = PG_GETARG_INT32(1);
742  if (nband < 1 || nband > numbands) {
743  elog(NOTICE, "Band index is invalid. Value must be 1-based. Returning original raster");
744  rt_raster_destroy(raster);
745  PG_RETURN_POINTER(pgraster);
746  }
747 
748  /* x, y */
749  for (i = 2, j = 0; i < 4; i++, j++) {
750  if (PG_ARGISNULL(i)) {
751  elog(NOTICE, "%s cannot be NULL. Value must be 1-based. Returning original raster", j < 1 ? "X" : "Y");
752  rt_raster_destroy(raster);
753  PG_RETURN_POINTER(pgraster);
754  }
755 
756  ul[j] = PG_GETARG_INT32(i);
757  if (
758  (ul[j] < 1) || (
759  (j < 1 && ul[j] > width) ||
760  (j > 0 && ul[j] > height)
761  )
762  ) {
763  elog(NOTICE, "%s is invalid. Value must be 1-based. Returning original raster", j < 1 ? "X" : "Y");
764  rt_raster_destroy(raster);
765  PG_RETURN_POINTER(pgraster);
766  }
767 
768  /* force 0-based from 1-based */
769  ul[j] -= 1;
770  }
771 
772  /* new value set */
773  if (PG_ARGISNULL(4)) {
774  elog(NOTICE, "No values to set. Returning original raster");
775  rt_raster_destroy(raster);
776  PG_RETURN_POINTER(pgraster);
777  }
778 
779  array = PG_GETARG_ARRAYTYPE_P(4);
780  etype = ARR_ELEMTYPE(array);
781  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
782 
783  switch (etype) {
784  case FLOAT4OID:
785  case FLOAT8OID:
786  break;
787  default:
788  rt_raster_destroy(raster);
789  PG_FREE_IF_COPY(pgraster, 0);
790  elog(ERROR, "RASTER_setPixelValuesArray: Invalid data type for new values");
791  PG_RETURN_NULL();
792  break;
793  }
794 
795  ndims = ARR_NDIM(array);
796  dims = ARR_DIMS(array);
797  POSTGIS_RT_DEBUGF(4, "ndims = %d", ndims);
798 
799  if (ndims < 1 || ndims > 2) {
800  elog(NOTICE, "New values array must be of 1 or 2 dimensions. Returning original raster");
801  rt_raster_destroy(raster);
802  PG_RETURN_POINTER(pgraster);
803  }
804  /* outer element, then inner element */
805  /* i = 0, y */
806  /* i = 1, x */
807  if (ndims != 2)
808  dimpixval[1] = dims[0];
809  else {
810  dimpixval[0] = dims[0];
811  dimpixval[1] = dims[1];
812  }
813  POSTGIS_RT_DEBUGF(4, "dimpixval = (%d, %d)", dimpixval[0], dimpixval[1]);
814 
815  deconstruct_array(
816  array,
817  etype,
818  typlen, typbyval, typalign,
819  &elements, &nulls, &num
820  );
821 
822  /* # of elements doesn't match dims */
823  if (num < 1 || num != (dimpixval[0] * dimpixval[1])) {
824  if (num) {
825  pfree(elements);
826  pfree(nulls);
827  }
828  rt_raster_destroy(raster);
829  PG_FREE_IF_COPY(pgraster, 0);
830  elog(ERROR, "RASTER_setPixelValuesArray: Could not deconstruct new values array");
831  PG_RETURN_NULL();
832  }
833 
834  /* allocate memory for pixval */
835  numpixval = num;
836  pixval = palloc(sizeof(struct pixelvalue) * numpixval);
837  if (pixval == NULL) {
838  pfree(elements);
839  pfree(nulls);
840  rt_raster_destroy(raster);
841  PG_FREE_IF_COPY(pgraster, 0);
842  elog(ERROR, "RASTER_setPixelValuesArray: Could not allocate memory for new pixel values");
843  PG_RETURN_NULL();
844  }
845 
846  /* load new values into pixval */
847  i = 0;
848  for (y = 0; y < dimpixval[0]; y++) {
849  for (x = 0; x < dimpixval[1]; x++) {
850  /* 0-based */
851  pixval[i].x = ul[0] + x;
852  pixval[i].y = ul[1] + y;
853 
854  pixval[i].noset = FALSE;
855  pixval[i].nodata = FALSE;
856  pixval[i].value = 0;
857 
858  if (nulls[i])
859  pixval[i].nodata = TRUE;
860  else {
861  switch (etype) {
862  case FLOAT4OID:
863  pixval[i].value = DatumGetFloat4(elements[i]);
864  break;
865  case FLOAT8OID:
866  pixval[i].value = DatumGetFloat8(elements[i]);
867  break;
868  }
869  }
870 
871  i++;
872  }
873  }
874 
875  pfree(elements);
876  pfree(nulls);
877 
878  /* now load noset flags */
879  if (!PG_ARGISNULL(5)) {
880  array = PG_GETARG_ARRAYTYPE_P(5);
881  etype = ARR_ELEMTYPE(array);
882  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
883 
884  switch (etype) {
885  case BOOLOID:
886  break;
887  default:
888  pfree(pixval);
889  rt_raster_destroy(raster);
890  PG_FREE_IF_COPY(pgraster, 0);
891  elog(ERROR, "RASTER_setPixelValuesArray: Invalid data type for noset flags");
892  PG_RETURN_NULL();
893  break;
894  }
895 
896  ndims = ARR_NDIM(array);
897  dims = ARR_DIMS(array);
898  POSTGIS_RT_DEBUGF(4, "ndims = %d", ndims);
899 
900  if (ndims < 1 || ndims > 2) {
901  elog(NOTICE, "Noset flags array must be of 1 or 2 dimensions. Returning original raster");
902  pfree(pixval);
903  rt_raster_destroy(raster);
904  PG_RETURN_POINTER(pgraster);
905  }
906  /* outer element, then inner element */
907  /* i = 0, y */
908  /* i = 1, x */
909  if (ndims != 2)
910  dimnoset[1] = dims[0];
911  else {
912  dimnoset[0] = dims[0];
913  dimnoset[1] = dims[1];
914  }
915  POSTGIS_RT_DEBUGF(4, "dimnoset = (%d, %d)", dimnoset[0], dimnoset[1]);
916 
917  deconstruct_array(
918  array,
919  etype,
920  typlen, typbyval, typalign,
921  &elements, &nulls, &num
922  );
923 
924  /* # of elements doesn't match dims */
925  if (num < 1 || num != (dimnoset[0] * dimnoset[1])) {
926  pfree(pixval);
927  if (num) {
928  pfree(elements);
929  pfree(nulls);
930  }
931  rt_raster_destroy(raster);
932  PG_FREE_IF_COPY(pgraster, 0);
933  elog(ERROR, "RASTER_setPixelValuesArray: Could not deconstruct noset flags array");
934  PG_RETURN_NULL();
935  }
936 
937  i = 0;
938  j = 0;
939  for (y = 0; y < dimnoset[0]; y++) {
940  if (y >= dimpixval[0]) break;
941 
942  for (x = 0; x < dimnoset[1]; x++) {
943  /* fast forward noset elements */
944  if (x >= dimpixval[1]) {
945  i += (dimnoset[1] - dimpixval[1]);
946  break;
947  }
948 
949  if (!nulls[i] && DatumGetBool(elements[i]))
950  pixval[j].noset = TRUE;
951 
952  i++;
953  j++;
954  }
955 
956  /* fast forward pixval */
957  if (x < dimpixval[1])
958  j += (dimpixval[1] - dimnoset[1]);
959  }
960 
961  pfree(elements);
962  pfree(nulls);
963  }
964  /* hasnosetvalue and nosetvalue */
965  else if (!PG_ARGISNULL(6) && PG_GETARG_BOOL(6)) {
966  hasnosetval = TRUE;
967  if (PG_ARGISNULL(7))
968  nosetvalisnull = TRUE;
969  else
970  nosetval = PG_GETARG_FLOAT8(7);
971  }
972 
973 #if POSTGIS_DEBUG_LEVEL > 0
974  for (i = 0; i < numpixval; i++) {
975  POSTGIS_RT_DEBUGF(4, "pixval[%d](x, y, noset, nodata, value) = (%d, %d, %d, %d, %f)",
976  i,
977  pixval[i].x,
978  pixval[i].y,
979  pixval[i].noset,
980  pixval[i].nodata,
981  pixval[i].value
982  );
983  }
984 #endif
985 
986  /* keepnodata flag */
987  if (!PG_ARGISNULL(8))
988  keepnodata = PG_GETARG_BOOL(8);
989 
990  /* get band */
991  band = rt_raster_get_band(raster, nband - 1);
992  if (!band) {
993  elog(NOTICE, "Could not find band at index %d. Returning original raster", nband);
994  pfree(pixval);
995  rt_raster_destroy(raster);
996  PG_RETURN_POINTER(pgraster);
997  }
998 
999  /* get band nodata info */
1000  /* has NODATA, use NODATA */
1001  hasnodata = rt_band_get_hasnodata_flag(band);
1002  if (hasnodata)
1003  rt_band_get_nodata(band, &nodataval);
1004  /* no NODATA, use min possible value */
1005  else
1006  nodataval = rt_band_get_min_value(band);
1007 
1008  /* set pixels */
1009  for (i = 0; i < numpixval; i++) {
1010  /* noset = true, skip */
1011  if (pixval[i].noset)
1012  continue;
1013  /* check against nosetval */
1014  else if (hasnosetval) {
1015  /* pixel = NULL AND nosetval = NULL */
1016  if (pixval[i].nodata && nosetvalisnull)
1017  continue;
1018  /* pixel value = nosetval */
1019  else if (!pixval[i].nodata && !nosetvalisnull && FLT_EQ(pixval[i].value, nosetval))
1020  continue;
1021  }
1022 
1023  /* if pixel is outside bounds, skip */
1024  if (
1025  (pixval[i].x < 0 || pixval[i].x >= width) ||
1026  (pixval[i].y < 0 || pixval[i].y >= height)
1027  ) {
1028  elog(NOTICE, "Cannot set value for pixel (%d, %d) outside raster bounds: %d x %d",
1029  pixval[i].x + 1, pixval[i].y + 1,
1030  width, height
1031  );
1032  continue;
1033  }
1034 
1035  /* if hasnodata = TRUE and keepnodata = TRUE, inspect pixel value */
1036  if (hasnodata && keepnodata) {
1037  rtn = rt_band_get_pixel(band, pixval[i].x, pixval[i].y, &val, &isnodata);
1038  if (rtn != ES_NONE) {
1039  pfree(pixval);
1040  rt_raster_destroy(raster);
1041  PG_FREE_IF_COPY(pgraster, 0);
1042  elog(ERROR, "Cannot get value of pixel");
1043  PG_RETURN_NULL();
1044  }
1045 
1046  /* pixel value = NODATA, skip */
1047  if (isnodata) {
1048  continue;
1049  }
1050  }
1051 
1052  if (pixval[i].nodata)
1053  rt_band_set_pixel(band, pixval[i].x, pixval[i].y, nodataval, NULL);
1054  else
1055  rt_band_set_pixel(band, pixval[i].x, pixval[i].y, pixval[i].value, NULL);
1056  }
1057 
1058  pfree(pixval);
1059 
1060  /* serialize new raster */
1061  pgrtn = rt_raster_serialize(raster);
1062  rt_raster_destroy(raster);
1063  PG_FREE_IF_COPY(pgraster, 0);
1064  if (!pgrtn)
1065  PG_RETURN_NULL();
1066 
1067  SET_VARSIZE(pgrtn, pgrtn->size);
1068  PG_RETURN_POINTER(pgrtn);
1069 }
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
#define FLT_EQ(x, y)
Definition: librtcore.h:2185
tuple band
Definition: ovdump.py:57
tuple raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:65
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:1597
Definition: pixval.py:1
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_band.c:1088
tuple nband
Definition: pixval.py:52
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:541
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
tuple x
Definition: pixval.py:53
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_raster.c:121
#define FALSE
Definition: dbfopen.c:168
Struct definitions.
Definition: librtcore.h:2201
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:1612
rt_errorstate rt_band_set_pixel(rt_band band, int x, int y, double val, int *converted)
Set single pixel's value.
Definition: rt_band.c:841
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_raster.c:129
#define TRUE
Definition: dbfopen.c:169
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:717
tuple y
Definition: pixval.py:54

Here is the call graph for this function: