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

◆ 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 */
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");
937 rt_raster_destroy(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");
944 rt_raster_destroy(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");
952 rt_raster_destroy(raster);
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");
964 rt_raster_destroy(raster);
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");
975 rt_raster_destroy(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:
988 rt_raster_destroy(raster);
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");
1001 rt_raster_destroy(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 }
1028 rt_raster_destroy(raster);
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);
1040 rt_raster_destroy(raster);
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);
1089 rt_raster_destroy(raster);
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);
1103 rt_raster_destroy(raster);
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 }
1131 rt_raster_destroy(raster);
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 */
1191 band = rt_raster_get_band(raster, nband - 1);
1192 if (!band) {
1193 elog(NOTICE, "Could not find band at index %d. Returning original raster", nband);
1194 pfree(pixval);
1195 rt_raster_destroy(raster);
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);
1240 rt_raster_destroy(raster);
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);
1262 rt_raster_destroy(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:833
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition rt_band.c:1551
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition rt_raster.c:86
#define FLT_EQ(x, y)
Definition librtcore.h:2436
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
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:1140
@ 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:2067
uint16_t rt_raster_get_width(rt_raster raster)
Definition rt_raster.c:125
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.
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
nband
Definition pixval.py:56
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition rtrowdump.py:125
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition rtpostgis.h:69
Struct definitions.
Definition librtcore.h:2452

References ES_NONE, FALSE, FLT_EQ, POSTGIS_RT_DEBUGF, 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, and TRUE.

Here is the call graph for this function: