865{
870 int numbands = 0;
871
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 {
891
892 bool noset;
893 bool nodata;
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;
915
916
917 if (PG_ARGISNULL(0))
918 PG_RETURN_NULL();
919 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
920
921
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
933
934
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
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
969 ul[j] -= 1;
970 }
971
972
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);
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
1005
1006
1007 if (ndims != 2)
1008 dimpixval[1] = dims[0];
1009 else {
1010 dimpixval[0] = dims[0];
1011 dimpixval[1] = dims[1];
1012 }
1014
1015 deconstruct_array(
1016 array,
1017 etype,
1018 typlen, typbyval, typalign,
1019 &elements, &nulls, &num
1020 );
1021
1022
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
1035 numpixval = num;
1036 pixval = palloc(
sizeof(
struct pixelvalue) * numpixval);
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
1047 i = 0;
1048 for (y = 0;
y < dimpixval[0];
y++) {
1049 for (x = 0;
x < dimpixval[1];
x++) {
1050
1053
1057
1058 if (nulls[i])
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
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:
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);
1099
1100 if (ndims < 1 || ndims > 2) {
1101 elog(NOTICE, "Noset flags array must be of 1 or 2 dimensions. Returning original raster");
1104 PG_RETURN_POINTER(pgraster);
1105 }
1106
1107
1108
1109 if (ndims != 2)
1110 dimnoset[1] = dims[0];
1111 else {
1112 dimnoset[0] = dims[0];
1113 dimnoset[1] = dims[1];
1114 }
1116
1117 deconstruct_array(
1118 array,
1119 etype,
1120 typlen, typbyval, typalign,
1121 &elements, &nulls, &num
1122 );
1123
1124
1125 if (num < 1 || num != (dimnoset[0] * dimnoset[1])) {
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
1144 if (x >= dimpixval[1]) {
1145 i += (dimnoset[1] - dimpixval[1]);
1146 break;
1147 }
1148
1149 if (!nulls[i] && DatumGetBool(elements[i]))
1151
1152 i++;
1153 j++;
1154 }
1155
1156
1157 if (x < dimpixval[1])
1158 j += (dimpixval[1] - dimnoset[1]);
1159 }
1160
1161 pfree(elements);
1162 pfree(nulls);
1163 }
1164
1165 else if (!PG_ARGISNULL(6) && PG_GETARG_BOOL(6)) {
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,
1182 );
1183 }
1184#endif
1185
1186
1187 if (!PG_ARGISNULL(8))
1188 keepnodata = PG_GETARG_BOOL(8);
1189
1190
1192 if (!band) {
1193 elog(NOTICE, "Could not find band at index %d. Returning original raster", nband);
1196 PG_RETURN_POINTER(pgraster);
1197 }
1198
1199
1200
1202 if (hasnodata)
1204
1205 else
1207
1208
1209 for (i = 0; i < numpixval; i++) {
1210
1212 continue;
1213
1214 else if (hasnosetval) {
1215
1216 if (
pixval[i].nodata && nosetvalisnull)
1217 continue;
1218
1220 continue;
1221 }
1222
1223
1224 if (
1227 ) {
1228 elog(NOTICE, "Cannot set value for pixel (%d, %d) outside raster bounds: %d x %d",
1230 width, height
1231 );
1232 continue;
1233 }
1234
1235
1236 if (hasnodata && keepnodata) {
1241 PG_FREE_IF_COPY(pgraster, 0);
1242 elog(ERROR, "Cannot get value of pixel");
1243 PG_RETURN_NULL();
1244 }
1245
1246
1247 if (isnodata) {
1248 continue;
1249 }
1250 }
1251
1254 else
1256 }
1257
1259
1260
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}
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
double rt_band_get_min_value(rt_band band)
Returns the minimal possible value for the band according to the pixel type.
rt_errorstate rt_band_set_pixel(rt_band band, int x, int y, double val, int *converted)
Set single pixel's value.
uint16_t rt_raster_get_num_bands(rt_raster raster)
uint16_t rt_raster_get_height(rt_raster raster)
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
uint16_t rt_raster_get_width(rt_raster raster)
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.
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
#define POSTGIS_RT_DEBUGF(level, msg,...)