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

◆ RASTER_setPixelValuesArray()

Datum RASTER_setPixelValuesArray ( PG_FUNCTION_ARGS  )

Definition at line 665 of file rtpg_pixel.c.

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 */
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}
#define TRUE
Definition dbfopen.c:169
#define FALSE
Definition dbfopen.c:168
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:1221
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition rt_raster.c:82
#define FLT_EQ(x, y)
Definition librtcore.h:2235
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:1745
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:180
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition rt_raster.c:372
uint16_t rt_raster_get_height(rt_raster raster)
Definition rt_raster.c:129
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition rt_band.c:1730
uint16_t rt_raster_get_width(rt_raster raster)
Definition rt_raster.c:121
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:381
int value
Definition genraster.py:62
nband
Definition pixval.py:53
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
Struct definitions.
Definition librtcore.h:2251

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: