PostGIS  3.4.0dev-r@@SVN_REVISION@@

◆ RASTER_setPixelValuesArray()

Datum RASTER_setPixelValuesArray ( PG_FUNCTION_ARGS  )

Definition at line 864 of file rtpg_pixel.c.

865 {
866  rt_pgraster *pgraster = NULL;
867  rt_pgraster *pgrtn = NULL;
868  rt_raster raster = NULL;
869  rt_band band = NULL;
870  int numbands = 0;
871 
872  int nband = 0;
873  int width = 0;
874  int height = 0;
875 
876  ArrayType *array;
877  Oid etype;
878  Datum *elements;
879  bool *nulls;
880  int16 typlen;
881  bool typbyval;
882  char typalign;
883  int ndims = 1;
884  int *dims;
885  int num = 0;
886 
887  int ul[2] = {0};
888  struct pixelvalue {
889  int x;
890  int y;
891 
892  bool noset;
893  bool nodata;
894  double value;
895  };
896  struct pixelvalue *pixval = NULL;
897  int numpixval = 0;
898  int dimpixval[2] = {1, 1};
899  int dimnoset[2] = {1, 1};
900  int hasnodata = FALSE;
901  double nodataval = 0;
902  bool keepnodata = FALSE;
903  bool hasnosetval = FALSE;
904  bool nosetvalisnull = FALSE;
905  double nosetval = 0;
906 
907  int rtn = 0;
908  double val = 0;
909  int isnodata = 0;
910 
911  int i = 0;
912  int j = 0;
913  int x = 0;
914  int y = 0;
915 
916  /* pgraster is null, return null */
917  if (PG_ARGISNULL(0))
918  PG_RETURN_NULL();
919  pgraster = (rt_pgraster *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
920 
921  /* raster */
922  raster = rt_raster_deserialize(pgraster, FALSE);
923  if (!raster) {
924  PG_FREE_IF_COPY(pgraster, 0);
925  elog(ERROR, "RASTER_setPixelValuesArray: Could not deserialize raster");
926  PG_RETURN_NULL();
927  }
928 
929  /* raster attributes */
930  numbands = rt_raster_get_num_bands(raster);
931  width = rt_raster_get_width(raster);
932  height = rt_raster_get_height(raster);
933 
934  /* nband */
935  if (PG_ARGISNULL(1)) {
936  elog(NOTICE, "Band index cannot be NULL. Value must be 1-based. Returning original raster");
938  PG_RETURN_POINTER(pgraster);
939  }
940 
941  nband = PG_GETARG_INT32(1);
942  if (nband < 1 || nband > numbands) {
943  elog(NOTICE, "Band index is invalid. Value must be 1-based. Returning original raster");
945  PG_RETURN_POINTER(pgraster);
946  }
947 
948  /* x, y */
949  for (i = 2, j = 0; i < 4; i++, j++) {
950  if (PG_ARGISNULL(i)) {
951  elog(NOTICE, "%s cannot be NULL. Value must be 1-based. Returning original raster", j < 1 ? "X" : "Y");
953  PG_RETURN_POINTER(pgraster);
954  }
955 
956  ul[j] = PG_GETARG_INT32(i);
957  if (
958  (ul[j] < 1) || (
959  (j < 1 && ul[j] > width) ||
960  (j > 0 && ul[j] > height)
961  )
962  ) {
963  elog(NOTICE, "%s is invalid. Value must be 1-based. Returning original raster", j < 1 ? "X" : "Y");
965  PG_RETURN_POINTER(pgraster);
966  }
967 
968  /* force 0-based from 1-based */
969  ul[j] -= 1;
970  }
971 
972  /* new value set */
973  if (PG_ARGISNULL(4)) {
974  elog(NOTICE, "No values to set. Returning original raster");
976  PG_RETURN_POINTER(pgraster);
977  }
978 
979  array = PG_GETARG_ARRAYTYPE_P(4);
980  etype = ARR_ELEMTYPE(array);
981  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
982 
983  switch (etype) {
984  case FLOAT4OID:
985  case FLOAT8OID:
986  break;
987  default:
989  PG_FREE_IF_COPY(pgraster, 0);
990  elog(ERROR, "RASTER_setPixelValuesArray: Invalid data type for new values");
991  PG_RETURN_NULL();
992  break;
993  }
994 
995  ndims = ARR_NDIM(array);
996  dims = ARR_DIMS(array);
997  POSTGIS_RT_DEBUGF(4, "ndims = %d", ndims);
998 
999  if (ndims < 1 || ndims > 2) {
1000  elog(NOTICE, "New values array must be of 1 or 2 dimensions. Returning original raster");
1002  PG_RETURN_POINTER(pgraster);
1003  }
1004  /* outer element, then inner element */
1005  /* i = 0, y */
1006  /* i = 1, x */
1007  if (ndims != 2)
1008  dimpixval[1] = dims[0];
1009  else {
1010  dimpixval[0] = dims[0];
1011  dimpixval[1] = dims[1];
1012  }
1013  POSTGIS_RT_DEBUGF(4, "dimpixval = (%d, %d)", dimpixval[0], dimpixval[1]);
1014 
1015  deconstruct_array(
1016  array,
1017  etype,
1018  typlen, typbyval, typalign,
1019  &elements, &nulls, &num
1020  );
1021 
1022  /* # of elements doesn't match dims */
1023  if (num < 1 || num != (dimpixval[0] * dimpixval[1])) {
1024  if (num) {
1025  pfree(elements);
1026  pfree(nulls);
1027  }
1029  PG_FREE_IF_COPY(pgraster, 0);
1030  elog(ERROR, "RASTER_setPixelValuesArray: Could not deconstruct new values array");
1031  PG_RETURN_NULL();
1032  }
1033 
1034  /* allocate memory for pixval */
1035  numpixval = num;
1036  pixval = palloc(sizeof(struct pixelvalue) * numpixval);
1037  if (pixval == NULL) {
1038  pfree(elements);
1039  pfree(nulls);
1041  PG_FREE_IF_COPY(pgraster, 0);
1042  elog(ERROR, "RASTER_setPixelValuesArray: Could not allocate memory for new pixel values");
1043  PG_RETURN_NULL();
1044  }
1045 
1046  /* load new values into pixval */
1047  i = 0;
1048  for (y = 0; y < dimpixval[0]; y++) {
1049  for (x = 0; x < dimpixval[1]; x++) {
1050  /* 0-based */
1051  pixval[i].x = ul[0] + x;
1052  pixval[i].y = ul[1] + y;
1053 
1054  pixval[i].noset = FALSE;
1055  pixval[i].nodata = FALSE;
1056  pixval[i].value = 0;
1057 
1058  if (nulls[i])
1059  pixval[i].nodata = TRUE;
1060  else {
1061  switch (etype) {
1062  case FLOAT4OID:
1063  pixval[i].value = DatumGetFloat4(elements[i]);
1064  break;
1065  case FLOAT8OID:
1066  pixval[i].value = DatumGetFloat8(elements[i]);
1067  break;
1068  }
1069  }
1070 
1071  i++;
1072  }
1073  }
1074 
1075  pfree(elements);
1076  pfree(nulls);
1077 
1078  /* now load noset flags */
1079  if (!PG_ARGISNULL(5)) {
1080  array = PG_GETARG_ARRAYTYPE_P(5);
1081  etype = ARR_ELEMTYPE(array);
1082  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1083 
1084  switch (etype) {
1085  case BOOLOID:
1086  break;
1087  default:
1088  pfree(pixval);
1090  PG_FREE_IF_COPY(pgraster, 0);
1091  elog(ERROR, "RASTER_setPixelValuesArray: Invalid data type for noset flags");
1092  PG_RETURN_NULL();
1093  break;
1094  }
1095 
1096  ndims = ARR_NDIM(array);
1097  dims = ARR_DIMS(array);
1098  POSTGIS_RT_DEBUGF(4, "ndims = %d", ndims);
1099 
1100  if (ndims < 1 || ndims > 2) {
1101  elog(NOTICE, "Noset flags array must be of 1 or 2 dimensions. Returning original raster");
1102  pfree(pixval);
1104  PG_RETURN_POINTER(pgraster);
1105  }
1106  /* outer element, then inner element */
1107  /* i = 0, y */
1108  /* i = 1, x */
1109  if (ndims != 2)
1110  dimnoset[1] = dims[0];
1111  else {
1112  dimnoset[0] = dims[0];
1113  dimnoset[1] = dims[1];
1114  }
1115  POSTGIS_RT_DEBUGF(4, "dimnoset = (%d, %d)", dimnoset[0], dimnoset[1]);
1116 
1117  deconstruct_array(
1118  array,
1119  etype,
1120  typlen, typbyval, typalign,
1121  &elements, &nulls, &num
1122  );
1123 
1124  /* # of elements doesn't match dims */
1125  if (num < 1 || num != (dimnoset[0] * dimnoset[1])) {
1126  pfree(pixval);
1127  if (num) {
1128  pfree(elements);
1129  pfree(nulls);
1130  }
1132  PG_FREE_IF_COPY(pgraster, 0);
1133  elog(ERROR, "RASTER_setPixelValuesArray: Could not deconstruct noset flags array");
1134  PG_RETURN_NULL();
1135  }
1136 
1137  i = 0;
1138  j = 0;
1139  for (y = 0; y < dimnoset[0]; y++) {
1140  if (y >= dimpixval[0]) break;
1141 
1142  for (x = 0; x < dimnoset[1]; x++) {
1143  /* fast forward noset elements */
1144  if (x >= dimpixval[1]) {
1145  i += (dimnoset[1] - dimpixval[1]);
1146  break;
1147  }
1148 
1149  if (!nulls[i] && DatumGetBool(elements[i]))
1150  pixval[j].noset = TRUE;
1151 
1152  i++;
1153  j++;
1154  }
1155 
1156  /* fast forward pixval */
1157  if (x < dimpixval[1])
1158  j += (dimpixval[1] - dimnoset[1]);
1159  }
1160 
1161  pfree(elements);
1162  pfree(nulls);
1163  }
1164  /* hasnosetvalue and nosetvalue */
1165  else if (!PG_ARGISNULL(6) && PG_GETARG_BOOL(6)) {
1166  hasnosetval = TRUE;
1167  if (PG_ARGISNULL(7))
1168  nosetvalisnull = TRUE;
1169  else
1170  nosetval = PG_GETARG_FLOAT8(7);
1171  }
1172 
1173 #if POSTGIS_DEBUG_LEVEL > 0
1174  for (i = 0; i < numpixval; i++) {
1175  POSTGIS_RT_DEBUGF(4, "pixval[%d](x, y, noset, nodata, value) = (%d, %d, %d, %d, %f)",
1176  i,
1177  pixval[i].x,
1178  pixval[i].y,
1179  pixval[i].noset,
1180  pixval[i].nodata,
1181  pixval[i].value
1182  );
1183  }
1184 #endif
1185 
1186  /* keepnodata flag */
1187  if (!PG_ARGISNULL(8))
1188  keepnodata = PG_GETARG_BOOL(8);
1189 
1190  /* get band */
1192  if (!band) {
1193  elog(NOTICE, "Could not find band at index %d. Returning original raster", nband);
1194  pfree(pixval);
1196  PG_RETURN_POINTER(pgraster);
1197  }
1198 
1199  /* get band nodata info */
1200  /* has NODATA, use NODATA */
1201  hasnodata = rt_band_get_hasnodata_flag(band);
1202  if (hasnodata)
1203  rt_band_get_nodata(band, &nodataval);
1204  /* no NODATA, use min possible value */
1205  else
1206  nodataval = rt_band_get_min_value(band);
1207 
1208  /* set pixels */
1209  for (i = 0; i < numpixval; i++) {
1210  /* noset = true, skip */
1211  if (pixval[i].noset)
1212  continue;
1213  /* check against nosetval */
1214  else if (hasnosetval) {
1215  /* pixel = NULL AND nosetval = NULL */
1216  if (pixval[i].nodata && nosetvalisnull)
1217  continue;
1218  /* pixel value = nosetval */
1219  else if (!pixval[i].nodata && !nosetvalisnull && FLT_EQ(pixval[i].value, nosetval))
1220  continue;
1221  }
1222 
1223  /* if pixel is outside bounds, skip */
1224  if (
1225  (pixval[i].x < 0 || pixval[i].x >= width) ||
1226  (pixval[i].y < 0 || pixval[i].y >= height)
1227  ) {
1228  elog(NOTICE, "Cannot set value for pixel (%d, %d) outside raster bounds: %d x %d",
1229  pixval[i].x + 1, pixval[i].y + 1,
1230  width, height
1231  );
1232  continue;
1233  }
1234 
1235  /* if hasnodata = TRUE and keepnodata = TRUE, inspect pixel value */
1236  if (hasnodata && keepnodata) {
1237  rtn = rt_band_get_pixel(band, pixval[i].x, pixval[i].y, &val, &isnodata);
1238  if (rtn != ES_NONE) {
1239  pfree(pixval);
1241  PG_FREE_IF_COPY(pgraster, 0);
1242  elog(ERROR, "Cannot get value of pixel");
1243  PG_RETURN_NULL();
1244  }
1245 
1246  /* pixel value = NODATA, skip */
1247  if (isnodata) {
1248  continue;
1249  }
1250  }
1251 
1252  if (pixval[i].nodata)
1253  rt_band_set_pixel(band, pixval[i].x, pixval[i].y, nodataval, NULL);
1254  else
1255  rt_band_set_pixel(band, pixval[i].x, pixval[i].y, pixval[i].value, NULL);
1256  }
1257 
1258  pfree(pixval);
1259 
1260  /* serialize new raster */
1261  pgrtn = rt_raster_serialize(raster);
1263  PG_FREE_IF_COPY(pgraster, 0);
1264  if (!pgrtn)
1265  PG_RETURN_NULL();
1266 
1267  SET_VARSIZE(pgrtn, pgrtn->size);
1268  PG_RETURN_POINTER(pgrtn);
1269 }
#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_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition: rt_band.c:1376
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:86
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
#define FLT_EQ(x, y)
Definition: librtcore.h:2387
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
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:974
@ 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
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:1887
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_raster.c:125
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:725
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:385
int value
Definition: genraster.py:62
band
Definition: ovdump.py:58
nband
Definition: pixval.py:53
Definition: pixval.py:1
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:69
Struct definitions.
Definition: librtcore.h:2403

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.

Here is the call graph for this function: