PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ RASTER_setPixelValuesArray()

Datum RASTER_setPixelValuesArray ( PG_FUNCTION_ARGS  )

Definition at line 665 of file rtpg_pixel.c.

References ovdump::band, ES_NONE, FALSE, FLT_EQ, pixval::nband, rtpg_dumpvalues_arg_t::nodata, rtpg_dumpvalues_arg_t::numbands, 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.

Referenced by RASTER_setPixelValue().

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