Ticket #903: st_reclass.5.patch

File st_reclass.5.patch, 38.2 KB (added by dustymugs, 5 years ago)

No changes made. Update diff due to incremental changes in patches that this one depends on

  • raster/rt_core/rt_api.c

    diff -rupN postgis-old/raster/rt_core/rt_api.c postgis-new/raster/rt_core/rt_api.c
    old new  
    2929#include <math.h>
    3030#include <stdio.h>  /* for printf (default message handler) */
    3131#include <stdarg.h> /* for va_list, va_start etc */
    32 #include <string.h> /* for memcpy */
     32#include <string.h> /* for memcpy and strlen */
    3333#include <assert.h>
    3434#include <float.h> /* for FLT_EPSILON and float type limits */
    3535#include <limits.h> /* for integer type limits */
     36#include <time.h> /* for time */
    3637#include "rt_api.h"
    3738
    3839#define POSTGIS_RASTER_WARN_ON_TRUNCATION
    rt_band_get_summary_stats(rt_context ctx 
    39223923        RASTER_DEBUG(3, "done");
    39233924        return stats;
    39243925}
     3926
     3927/**
     3928 * Replace band at provided index with new band
     3929 *
     3930 * @param ctx : context, for thread safety
     3931 * @param raster: raster of band to be replaced
     3932 * @param band : new band to add to raster
     3933 * @param index : index of band to replace (1-based)
     3934 * @return 0 on error or replaced band
     3935 *
     3936 */
     3937int
     3938rt_raster_replace_band(rt_context ctx, rt_raster raster, rt_band band, int index) {
     3939        rt_band oldband = NULL;
     3940
     3941        assert(NULL != ctx);
     3942        assert(NULL != raster);
     3943
     3944        if (band->width != raster->width || band->height != raster->height) {
     3945                ctx->err("rt_raster_replace_band: Band does not match raster's dimensions: %dx%d band to %dx%d raster",
     3946                        band->width, band->height, raster->width, raster->height);
     3947                return 0;
     3948        }
     3949
     3950        if (index > raster->numBands || index < 0) {
     3951                ctx->err("rt_raster_replace_band: Band index is not valid");
     3952                return 0;
     3953        }
     3954
     3955        oldband = rt_raster_get_band(ctx, raster, index);
     3956        RASTER_DEBUGF(3, "rt_raster_replace_band: old band at %p", oldband);
     3957        RASTER_DEBUGF(3, "rt_raster_replace_band: new band at %p", band);
     3958
     3959        raster->bands[index] = band;
     3960        RASTER_DEBUGF(3, "rt_raster_replace_band: new band at %p", raster->bands[index]);
     3961
     3962        rt_band_destroy(ctx, oldband);
     3963        return 1;
     3964}
     3965
     3966struct rt_reclassexpr_t {
     3967        struct rt_reclassrange {
     3968                double min;
     3969                double max;
     3970                int inc_min; /* include min */
     3971                int inc_max; /* include max */
     3972                int exc_min; /* exceed min */
     3973                int exc_max; /* exceed max */
     3974        } src, dst;
     3975};
     3976
     3977/**
     3978 * Returns new band with values reclassified
     3979 *
     3980 * @param ctx : context, for thread safety
     3981 * @param srcband : the band who's values will be reclassified
     3982 * @param pixtype : pixel type of the new band
     3983 * @param hasnodata : indicates if the band has a nodata value
     3984 * @param nodataval : nodata value for the new band
     3985 * @param exprset : array of rt_reclassexpr structs
     3986 * @param exprcount : number of elements in expr
     3987 * @return a new rt_band or 0 on error
     3988 *
     3989 */
     3990rt_band
     3991rt_band_reclass(rt_context ctx, rt_band srcband, rt_pixtype pixtype,
     3992        uint32_t hasnodata, double nodataval, rt_reclassexpr *exprset,
     3993        int exprcount) {
     3994        rt_band band = NULL;
     3995        int width = 0;
     3996        int height = 0;
     3997        int numval = 0;
     3998        int memsize = 0;
     3999        void *mem = NULL;
     4000        uint32_t src_hasnodata = 0;
     4001        double src_nodataval = 0.0;
     4002
     4003        int rtn;
     4004        int x;
     4005        int y;
     4006        int i;
     4007        double or = 0;
     4008        double ov = 0;
     4009        double nr = 0;
     4010        double nv = 0;
     4011        int do_nv = 0;
     4012        rt_reclassexpr expr = NULL;
     4013
     4014        assert(NULL != ctx);
     4015        assert(NULL != srcband);
     4016        assert(NULL != exprset);
     4017
     4018        /* source nodata */
     4019        src_hasnodata = rt_band_get_hasnodata_flag(ctx, srcband);
     4020        src_nodataval = rt_band_get_nodata(ctx, srcband);
     4021
     4022        /* size of memory block to allocate */
     4023        width = rt_band_get_width(ctx, srcband);
     4024        height = rt_band_get_height(ctx, srcband);
     4025        numval = width * height;
     4026        memsize = rt_pixtype_size(ctx, pixtype) * numval;
     4027        mem = (int *) ctx->alloc(memsize);
     4028        if (!mem) {
     4029                ctx->err("rt_band_reclass: Could not allocate memory for band");
     4030                return 0;
     4031        }
     4032
     4033        /* initialize to zero */
     4034        if (!hasnodata) {
     4035                memset(mem, 0, memsize);
     4036        }
     4037        /* initialize to nodataval */
     4038        else {
     4039                int32_t checkvalint = 0;
     4040                uint32_t checkvaluint = 0;
     4041                double checkvaldouble = 0;
     4042                float checkvalfloat = 0;
     4043
     4044                switch (pixtype) {
     4045                        case PT_1BB:
     4046                        {
     4047                                uint8_t *ptr = mem;
     4048                                uint8_t clamped_initval = rt_util_clamp_to_1BB(nodataval);
     4049                                for (i = 0; i < numval; i++)
     4050                                        ptr[i] = clamped_initval;
     4051                                checkvalint = ptr[0];
     4052                                break;
     4053                        }
     4054                        case PT_2BUI:
     4055                        {
     4056                                uint8_t *ptr = mem;
     4057                                uint8_t clamped_initval = rt_util_clamp_to_2BUI(nodataval);
     4058                                for (i = 0; i < numval; i++)
     4059                                        ptr[i] = clamped_initval;
     4060                                checkvalint = ptr[0];
     4061                                break;
     4062                        }
     4063                        case PT_4BUI:
     4064                        {
     4065                                uint8_t *ptr = mem;
     4066                                uint8_t clamped_initval = rt_util_clamp_to_4BUI(nodataval);
     4067                                for (i = 0; i < numval; i++)
     4068                                        ptr[i] = clamped_initval;
     4069                                checkvalint = ptr[0];
     4070                                break;
     4071                        }
     4072                        case PT_8BSI:
     4073                        {
     4074                                int8_t *ptr = mem;
     4075                                int8_t clamped_initval = rt_util_clamp_to_8BSI(nodataval);
     4076                                for (i = 0; i < numval; i++)
     4077                                        ptr[i] = clamped_initval;
     4078                                checkvalint = ptr[0];
     4079                                break;
     4080                        }
     4081                        case PT_8BUI:
     4082                        {
     4083                                uint8_t *ptr = mem;
     4084                                uint8_t clamped_initval = rt_util_clamp_to_8BUI(nodataval);
     4085                                for (i = 0; i < numval; i++)
     4086                                        ptr[i] = clamped_initval;
     4087                                checkvalint = ptr[0];
     4088                                break;
     4089                        }
     4090                        case PT_16BSI:
     4091                        {
     4092                                int16_t *ptr = mem;
     4093                                int16_t clamped_initval = rt_util_clamp_to_16BSI(nodataval);
     4094                                for (i = 0; i < numval; i++)
     4095                                        ptr[i] = clamped_initval;
     4096                                checkvalint = ptr[0];
     4097                                break;
     4098                        }
     4099                        case PT_16BUI:
     4100                        {
     4101                                uint16_t *ptr = mem;
     4102                                uint16_t clamped_initval = rt_util_clamp_to_16BUI(nodataval);
     4103                                for (i = 0; i < numval; i++)
     4104                                        ptr[i] = clamped_initval;
     4105                                checkvalint = ptr[0];
     4106                                break;
     4107                        }
     4108                        case PT_32BSI:
     4109                        {
     4110                                int32_t *ptr = mem;
     4111                                int32_t clamped_initval = rt_util_clamp_to_32BSI(nodataval);
     4112                                for (i = 0; i < numval; i++)
     4113                                        ptr[i] = clamped_initval;
     4114                                checkvalint = ptr[0];
     4115                                break;
     4116                        }
     4117                        case PT_32BUI:
     4118                        {
     4119                                uint32_t *ptr = mem;
     4120                                uint32_t clamped_initval = rt_util_clamp_to_32BUI(nodataval);
     4121                                for (i = 0; i < numval; i++)
     4122                                        ptr[i] = clamped_initval;
     4123                                checkvaluint = ptr[0];
     4124                                break;
     4125                        }
     4126                        case PT_32BF:
     4127                        {
     4128                                float *ptr = mem;
     4129                                float clamped_initval = rt_util_clamp_to_32F(nodataval);
     4130                                for (i = 0; i < numval; i++)
     4131                                        ptr[i] = clamped_initval;
     4132                                checkvalfloat = ptr[0];
     4133                                break;
     4134                        }
     4135                        case PT_64BF:
     4136                        {
     4137                                double *ptr = mem;
     4138                                for (i = 0; i < numval; i++)
     4139                                        ptr[i] = nodataval;
     4140                                checkvaldouble = ptr[0];
     4141                                break;
     4142                        }
     4143                        default:
     4144                        {
     4145                                ctx->err("rt_band_reclass: Unknown pixeltype %d", pixtype);
     4146                                ctx->dealloc(mem);
     4147                                return 0;
     4148                        }
     4149                }
     4150
     4151#ifdef POSTGIS_RASTER_WARN_ON_TRUNCATION
     4152                /* Overflow checking */
     4153                rt_util_display_dbl_trunc_warning(ctx, nodataval, checkvalint, checkvaluint, checkvalfloat,
     4154                        checkvaldouble, pixtype);
     4155#endif /* POSTGIS_RASTER_WARN_ON_TRUNCATION */
     4156        }
     4157        RASTER_DEBUGF(3, "rt_band_reclass: width = %d height = %d", width, height);
     4158
     4159        band = rt_band_new_inline(ctx, width, height, pixtype, hasnodata, nodataval, mem);
     4160        if (!band) {
     4161                ctx->err("rt_band_reclass: Could not create new band");
     4162                ctx->dealloc(mem);
     4163                return 0;
     4164        }
     4165        RASTER_DEBUGF(3, "rt_band_reclass: new band @ %p", band);
     4166
     4167        for (x = 0; x < width; x++) {
     4168                for (y = 0; y < height; y++) {
     4169                        rtn = rt_band_get_pixel(ctx, srcband, x, y, &ov);
     4170
     4171                        /* error getting value, skip */
     4172                        if (rtn == -1) continue;
     4173
     4174                        do {
     4175                                do_nv = 0;
     4176
     4177                                /* no data*/
     4178                                if (src_hasnodata && hasnodata && ov == src_nodataval) {
     4179                                        do_nv = 1;
     4180                                        break;
     4181                                }
     4182
     4183                                for (i = 0; i < exprcount; i++) {
     4184                                        expr = exprset[i];
     4185
     4186                                        /* ov matches min and max*/
     4187                                        if (expr->src.min == ov && ov == expr->src.max) {
     4188                                                do_nv = 1;
     4189                                                break;
     4190                                        }
     4191
     4192                                        /* process min */
     4193                                        if (
     4194                                                (expr->src.exc_min && expr->src.min >= ov) ||
     4195                                                (expr->src.inc_min && expr->src.min <= ov) ||
     4196                                                (expr->src.min < ov)
     4197                                        ) {
     4198                                                /* process max */
     4199                                                if (
     4200                                                        (expr->src.exc_max && ov >= expr->src.max) ||
     4201                                                        (expr->src.inc_max && ov <= expr->src.max) ||
     4202                                                        (ov < expr->src.max)
     4203                                                ) {
     4204                                                        do_nv = 1;
     4205                                                        break;
     4206                                                }
     4207                                        }
     4208                                }
     4209                        }
     4210                        while (0);
     4211
     4212                        /* no expression matched, do not continue */
     4213                        if (!do_nv) continue;
     4214
     4215                        /* converting a value from one range to another range
     4216                        OldRange = (OldMax - OldMin)
     4217                        NewRange = (NewMax - NewMin)
     4218                        NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
     4219                        */
     4220
     4221                        /* nodata */
     4222                        if (src_hasnodata && hasnodata && ov == src_nodataval) {
     4223                                nv = nodataval;
     4224                        }
     4225                        /*
     4226                                "src" min and max is the same, prevent division by zero
     4227                                set nv to "dst" min, which should be the same as "dst" max
     4228                        */
     4229                        else if (expr->src.min == expr->src.max) {
     4230                                nv = expr->dst.min;
     4231                        }
     4232                        else {
     4233                                or = expr->src.max - expr->src.min;
     4234                                nr = expr->dst.max - expr->dst.min;
     4235                                nv = (((ov - expr->src.min) * nr) / or) + expr->dst.min;
     4236
     4237                                if (nv < expr->dst.min)
     4238                                        nv = expr->dst.min;
     4239                                else if (nv > expr->dst.max)
     4240                                        nv = expr->dst.max;
     4241                        }
     4242
     4243                        /* round the value for integers */
     4244                        switch (pixtype) {
     4245                                case PT_1BB:
     4246                                case PT_2BUI:
     4247                                case PT_4BUI:
     4248                                case PT_8BSI:
     4249                                case PT_8BUI:
     4250                                case PT_16BSI:
     4251                                case PT_16BUI:
     4252                                case PT_32BSI:
     4253                                case PT_32BUI:
     4254                                        nv = round(nv);
     4255                                        break;
     4256                                default:
     4257                                        break;
     4258                        }
     4259
     4260                        RASTER_DEBUGF(4, "(%d, %d) ov: %f or: %f - %f nr: %f - %f nv: %f"
     4261                                , x
     4262                                , y
     4263                                , ov
     4264                                , (NULL != expr) ? expr->src.min : 0
     4265                                , (NULL != expr) ? expr->src.max : 0
     4266                                , (NULL != expr) ? expr->dst.min : 0
     4267                                , (NULL != expr) ? expr->dst.max : 0
     4268                                , nv
     4269                        );
     4270                        rtn = rt_band_set_pixel(ctx, band, x, y, nv);
     4271                        if (rtn == -1) {
     4272                                ctx->err("rt_band_reclass: Could not assign value to new band");
     4273                                rt_band_destroy(ctx, band);
     4274                                ctx->dealloc(mem);
     4275                                return 0;
     4276                        }
     4277
     4278                        expr = NULL;
     4279                }
     4280        }
     4281
     4282        return band;
     4283}
  • raster/rt_core/rt_api.h

    diff -rupN postgis-old/raster/rt_core/rt_api.h postgis-new/raster/rt_core/rt_api.h
    old new  
    8484
    8585
    8686
    87 #include <stdlib.h> /* For size_t */
     87#include <stdlib.h> /* For size_t, srand and rand */
    8888#include <stdint.h> /* For C99 int types */
    8989
    9090#include "liblwgeom.h"
    typedef struct rt_bandstats_t* rt_bandst 
    765765rt_bandstats rt_band_get_summary_stats(rt_context ctx, rt_band band,
    766766        int no_nodata, double sample, int inc_vals);
    767767
     768/**
     769 * Replace band at provided index with new band
     770 *
     771 * @param ctx : context, for thread safety
     772 * @param raster: raster of band to be replaced
     773 * @param band : new band to add to raster
     774 * @param index : index of band to replace (1-based)
     775 * @return 0 on error or 1 on success
     776 *
     777 */
     778int rt_raster_replace_band(rt_context ctx, rt_raster raster,
     779        rt_band band, int index);
     780
     781/**
     782 * Returns new band with values reclassified
     783 *
     784 * @param ctx : context, for thread safety
     785 * @param srcband : the band who's values will be reclassified
     786 * @param pixtype : pixel type of the new band
     787 * @param hasnodata : indicates if the band has a nodata value
     788 * @param nodataval : nodata value for the new band
     789 * @param exprset : array of rt_reclassexpr structs
     790 * @param exprcount : number of elements in expr
     791 * @return a new rt_band or 0 on error
     792 *
     793 */
     794typedef struct rt_reclassexpr_t* rt_reclassexpr;
     795rt_band rt_band_reclass(rt_context ctx, rt_band srcband,
     796        rt_pixtype pixtype, uint32_t hasnodata, double nodataval,
     797        rt_reclassexpr *exprset, int exprcount);
     798
    768799/*- utilities -------------------------------------------------------*/
    769800
    770801/* Set of functions to clamp double to int of different size
  • raster/rt_pg/rt_pg.c

    diff -rupN postgis-old/raster/rt_pg/rt_pg.c postgis-new/raster/rt_pg/rt_pg.c
    old new  
    3030#include <float.h>
    3131#include <string.h>
    3232#include <stdio.h>
     33#include <stdlib.h> /* for strtod in RASTER_reclass */
    3334#include <errno.h>
    3435#include <assert.h>
     36#include <ctype.h> /* for isspace */
    3537
    3638#include <postgres.h> /* for palloc */
    3739#include <access/gist.h>
     
    4042#include <utils/elog.h>
    4143#include <utils/builtins.h>
    4244#include <executor/spi.h>
     45#include <executor/executor.h> /* for GetAttributeByName in RASTER_reclass */
    4346#include <funcapi.h>
    4447
    4548/*#include "lwgeom_pg.h"*/
    static void rt_pgfree(void *mem); 
    7073static char * replace(const char *str, const char *oldstr, const char *newstr,
    7174        int *count);
    7275static char *strtoupper(char *str);
     76static char     *chartrim(char* input, char *remove); /* for RASTER_reclass */
     77static char **strsplit(const char *str, const char *delimiter, int *n); /* for RASTER_reclass */
     78static char *removespaces(char *str); /* for RASTER_reclass */
    7379
    7480/***************************************************************
    7581 * Some rules for returning NOTICE or ERROR...
    Datum RASTER_band(PG_FUNCTION_ARGS); 
    168174/* Get minimum and maximum pixel values */
    169175Datum RASTER_getMinMaxPixelValues(PG_FUNCTION_ARGS);
    170176
     177/* reclassify specified bands of a raster */
     178Datum RASTER_reclass(PG_FUNCTION_ARGS);
    171179
    172180/* Replace function taken from http://ubuntuforums.org/showthread.php?s=aa6f015109fd7e4c7e30d2fd8b717497&t=141670&page=3 */
    173181/* ---------------------------------------------------------------------------
    strtoupper(char * str) 
    251259
    252260}
    253261
     262static char*
     263chartrim(char *input, char *remove) {
     264        char *start;
     265        char *ptr;
     266
     267        if (!input) {
     268                return NULL;
     269        }
     270        else if (!*input) {
     271                return input;
     272        }
     273
     274        start = (char *) palloc(sizeof(char) * strlen(input) + 1);
     275        if (NULL == start) {
     276                fprintf(stderr, "Not enough memory\n");
     277                return NULL;
     278        }
     279        strcpy(start, input);
     280
     281        /* trim left */
     282        while (strchr(remove, *start) != NULL) {
     283                start++;
     284        }
     285
     286        /* trim right */
     287        ptr = start + strlen(start);
     288        while (strchr(remove, *--ptr) != NULL);
     289        *(++ptr) = '\0';
     290
     291        return start;
     292}
     293
     294/* split a string based on a delimiter */
     295static char**
     296strsplit(const char *str, const char *delimiter, int *n) {
     297        char *tmp = NULL;
     298        char **rtn = NULL;
     299        char *token = NULL;
     300
     301        if (!str)
     302                return NULL;
     303
     304        /* copy str to tmp as strtok will mangle the string */
     305        tmp = palloc(sizeof(char) * (strlen(str) + 1));
     306        if (NULL == tmp) {
     307                fprintf(stderr, "Not enough memory\n");
     308                return NULL;
     309        }
     310        strcpy(tmp, str);
     311
     312        if (!strlen(tmp) || !delimiter || !strlen(delimiter)) {
     313                *n = 1;
     314                rtn = (char **) palloc(*n * sizeof(char *));
     315                if (NULL == rtn) {
     316                        fprintf(stderr, "Not enough memory\n");
     317                        return NULL;
     318                }
     319                rtn[0] = (char *) palloc(sizeof(char) * (strlen(tmp) + 1));
     320                if (NULL == rtn[0]) {
     321                        fprintf(stderr, "Not enough memory\n");
     322                        return NULL;
     323                }
     324                strcpy(rtn[0], tmp);
     325                pfree(tmp);
     326                return rtn;
     327        }
     328
     329        *n = 0;
     330        token = strtok(tmp, delimiter);
     331        while (token != NULL) {
     332                if (*n < 1) {
     333                        rtn = (char **) palloc(sizeof(char *));
     334                }
     335                else {
     336                        rtn = (char **) repalloc(rtn, (*n + 1) * sizeof(char *));
     337                }
     338                if (NULL == rtn) {
     339                        fprintf(stderr, "Not enough memory\n");
     340                        return NULL;
     341                }
     342
     343                rtn[*n] = NULL;
     344                rtn[*n] = (char *) palloc(sizeof(char) * (strlen(token) + 1));
     345                if (NULL == rtn[*n]) {
     346                        fprintf(stderr, "Not enough memory\n");
     347                        return NULL;
     348                }
     349
     350                strcpy(rtn[*n], token);
     351                *n = *n + 1;
     352
     353                token = strtok(NULL, delimiter);
     354        }
     355
     356        pfree(tmp);
     357        return rtn;
     358}
     359
     360static char *
     361removespaces(char *str) {
     362        char *rtn;
     363
     364        rtn = replace(str, " ", "", NULL);
     365        rtn = replace(rtn, "\n", "", NULL);
     366        rtn = replace(rtn, "\t", "", NULL);
     367        rtn = replace(rtn, "\f", "", NULL);
     368        rtn = replace(rtn, "\r", "", NULL);
     369
     370        return rtn;
     371}
    254372
    255373static void *
    256374rt_pgalloc(size_t size)
    Datum RASTER_getMinMaxPixelValues(PG_FUN 
    29943112        }
    29953113}
    29963114
     3115struct rt_reclassexpr_t {
     3116        struct rt_reclassrange {
     3117                double min;
     3118                double max;
     3119                int inc_min;
     3120                int inc_max;
     3121                int exc_min;
     3122                int exc_max;
     3123        } src, dst;
     3124};
     3125
     3126/**
     3127 * Reclassify the specified bands of the raster
     3128 */
     3129PG_FUNCTION_INFO_V1(RASTER_reclass);
     3130Datum RASTER_reclass(PG_FUNCTION_ARGS) {
     3131        rt_context ctx = get_rt_context(fcinfo);
     3132        rt_pgraster *pgrast = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
     3133        rt_raster raster = NULL;
     3134        rt_band band = NULL;
     3135        rt_band newband = NULL;
     3136        uint32_t numBands = 0;
     3137
     3138        ArrayType *array;
     3139        Oid etype;
     3140        Datum *e;
     3141        bool *nulls;
     3142        int16 typlen;
     3143        bool typbyval;
     3144        char typalign;
     3145        int ndims = 1;
     3146        int *dims;
     3147        int *lbs;
     3148        int n = 0;
     3149
     3150        int i = 0;
     3151        int j = 0;
     3152        int k = 0;
     3153
     3154        int a = 0;
     3155        int b = 0;
     3156        int c = 0;
     3157
     3158        rt_reclassexpr *exprset = NULL;
     3159        HeapTupleHeader tup;
     3160        bool isnull;
     3161        Datum tupv;
     3162        uint32_t nband = 0;
     3163        char *expr = NULL;
     3164        text *exprtext = NULL;
     3165        double val = 0;
     3166        char *junk = NULL;
     3167        int inc_val = 0;
     3168        int exc_val = 0;
     3169        char *pixeltype = NULL;
     3170        text *pixeltypetext = NULL;
     3171        rt_pixtype pixtype = PT_END;
     3172        double nodataval = 0;
     3173        bool hasnodata = FALSE;
     3174
     3175        char **comma_set = NULL;
     3176        int comma_n = 0;
     3177        char **colon_set = NULL;
     3178        int colon_n = 0;
     3179        char **dash_set = NULL;
     3180        int dash_n = 0;
     3181
     3182        POSTGIS_RT_DEBUG(3, "RASTER_reclass: Starting");
     3183
     3184        /* process set of reclassarg */
     3185        POSTGIS_RT_DEBUG(3, "RASTER_reclass: Processing Arg 1 (reclassargset)");
     3186        array = PG_GETARG_ARRAYTYPE_P(1);
     3187        etype = ARR_ELEMTYPE(array);
     3188        get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
     3189
     3190        ndims = ARR_NDIM(array);
     3191        dims = ARR_DIMS(array);
     3192        lbs = ARR_LBOUND(array);
     3193
     3194        deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
     3195                &nulls, &n);
     3196
     3197        if (!n) {
     3198                elog(ERROR, "RASTER_reclass: Unable to process reclassargset");
     3199                PG_RETURN_NULL();
     3200        }
     3201
     3202        /* raster */
     3203        raster = rt_raster_deserialize(ctx, pgrast);
     3204        if (!raster) {
     3205                elog(ERROR, "RASTER_reclass: Could not deserialize raster");
     3206                rt_context_destroy(ctx);
     3207                PG_RETURN_NULL();
     3208        }
     3209        numBands = rt_raster_get_num_bands(ctx, raster);
     3210
     3211        POSTGIS_RT_DEBUGF(3, "RASTER_reclass: %d possible bands to be reclassified", n);
     3212        /*
     3213                process each element of reclassarg
     3214                each element is the index of the band to process, the set
     3215                        of reclass ranges and the output band's pixeltype
     3216        */
     3217        for (i = 0; i < n; i++) {
     3218                if (nulls[i])
     3219                        continue;
     3220
     3221                /* each element is a tuple */
     3222                tup = (HeapTupleHeader) DatumGetPointer(e[i]);
     3223                if (NULL == tup) {
     3224                        elog(ERROR, "RASTER_reclass: Missing reclassarg");
     3225                        rt_raster_destroy(ctx, raster);
     3226                        rt_context_destroy(ctx);
     3227                        PG_RETURN_NULL();
     3228                }
     3229
     3230                /* band index (1-based) */
     3231                tupv = GetAttributeByName(tup, "nband", &isnull);
     3232                if (isnull) {
     3233                        elog(ERROR, "RASTER_reclass: Missing value for nband element of reclassarg");
     3234                        rt_raster_destroy(ctx, raster);
     3235                        rt_context_destroy(ctx);
     3236                        PG_RETURN_NULL();
     3237                }
     3238                nband = DatumGetInt32(tupv);
     3239                POSTGIS_RT_DEBUGF(3, "RASTER_reclass: expression for band %d", nband);
     3240
     3241                /* valid band index? */
     3242                if (nband < 1 || nband > numBands) {
     3243                        elog(ERROR, "RASTER_reclass: Invalid band index provided for nband element of reclassarg");
     3244                        rt_raster_destroy(ctx, raster);
     3245                        rt_context_destroy(ctx);
     3246                        PG_RETURN_NULL();
     3247                }
     3248
     3249                /* reclass expr */
     3250                tupv = GetAttributeByName(tup, "reclassexpr", &isnull);
     3251                if (isnull) {
     3252                        elog(ERROR, "RASTER_reclass: Missing value for reclassexpr element of reclassarg");
     3253                        rt_raster_destroy(ctx, raster);
     3254                        rt_context_destroy(ctx);
     3255                        PG_RETURN_NULL();
     3256                }
     3257                exprtext = (text *) DatumGetPointer(tupv);
     3258                if (NULL == exprtext) {
     3259                        elog(ERROR, "RASTER_reclass: Missing value for reclassexpr element of reclassarg");
     3260                        rt_raster_destroy(ctx, raster);
     3261                        rt_context_destroy(ctx);
     3262                        PG_RETURN_NULL();
     3263                }
     3264                expr = text_to_cstring(exprtext);
     3265                POSTGIS_RT_DEBUGF(3, "RASTER_reclass: expr (raw) %s", expr);
     3266                expr = removespaces(expr);
     3267                POSTGIS_RT_DEBUGF(4, "RASTER_reclass: expr (clean) %s", expr);
     3268
     3269                /* split string to its components */
     3270                /* comma (,) separating rangesets */
     3271                comma_set = strsplit(expr, ",", &comma_n);
     3272                if (comma_n < 1) {
     3273                        elog(ERROR, "RASTER_reclass: Invalid expression in reclassexpr element of reclassarg");
     3274                        rt_raster_destroy(ctx, raster);
     3275                        rt_context_destroy(ctx);
     3276                        PG_RETURN_NULL();
     3277                }
     3278
     3279                /* set of reclass expressions */
     3280                POSTGIS_RT_DEBUGF(3, "RASTER_reclass: %d possible expressions", comma_n);
     3281                exprset = palloc(comma_n * sizeof(rt_reclassexpr));
     3282
     3283                for (a = 0, j = 0; a < comma_n; a++) {
     3284                        POSTGIS_RT_DEBUGF(4, "RASTER_reclass: map %s", comma_set[a]);
     3285
     3286                        /* colon (:) separating range "src" and "dst" */
     3287                        colon_set = strsplit(comma_set[a], ":", &colon_n);
     3288                        if (colon_n != 2) {
     3289                                elog(ERROR, "RASTER_reclass: Invalid expression in reclassexpr element of reclassarg");
     3290                                for (k = 0; k < j; k++) pfree(exprset[k]);
     3291                                pfree(exprset);
     3292                                rt_raster_destroy(ctx, raster);
     3293                                rt_context_destroy(ctx);
     3294                                PG_RETURN_NULL();
     3295                        }
     3296
     3297                        /* allocate mem for reclass expression */
     3298                        exprset[j] = palloc(sizeof(struct rt_reclassexpr_t));
     3299
     3300                        for (b = 0; b < colon_n; b++) {
     3301                                POSTGIS_RT_DEBUGF(4, "RASTER_reclass: range %s", colon_set[b]);
     3302
     3303                                /* dash (-) separating "min" and "max" */
     3304                                dash_set = strsplit(colon_set[b], "-", &dash_n);
     3305                                if (dash_n < 1 || dash_n > 3) {
     3306                                        elog(ERROR, "RASTER_reclass: Invalid expression in reclassexpr element of reclassarg");
     3307                                        for (k = 0; k <= j; k++) pfree(exprset[k]);
     3308                                        pfree(exprset);
     3309                                        rt_raster_destroy(ctx, raster);
     3310                                        rt_context_destroy(ctx);
     3311                                        PG_RETURN_NULL();
     3312                                }
     3313
     3314                                for (c = 0; c < dash_n; c++) {
     3315                                        /* need to handle: (-9999-100 -> "(", "9999", "100" */
     3316                                        if (
     3317                                                c < 1 &&
     3318                                                strlen(dash_set[c]) == 1 && (
     3319                                                        strchr(dash_set[c], '(') != NULL ||
     3320                                                        strchr(dash_set[c], '[') != NULL ||
     3321                                                        strchr(dash_set[c], ')') != NULL ||
     3322                                                        strchr(dash_set[c], ']') != NULL
     3323                                                )
     3324                                        ) {
     3325                                                junk = palloc(sizeof(char) * (strlen(dash_set[c + 1]) + 2));
     3326                                                if (NULL == junk) {
     3327                                                        elog(ERROR, "RASTER_reclass: Insufficient memory");
     3328                                                        for (k = 0; k <= j; k++) pfree(exprset[k]);
     3329                                                        pfree(exprset);
     3330                                                        rt_raster_destroy(ctx, raster);
     3331                                                        rt_context_destroy(ctx);
     3332                                                        PG_RETURN_NULL();
     3333                                                }
     3334
     3335                                                sprintf(junk, "%s%s", dash_set[c], dash_set[c + 1]);
     3336                                                c++;
     3337                                                dash_set[c] = repalloc(dash_set[c], sizeof(char) * (strlen(junk) + 1));
     3338                                                strcpy(dash_set[c], junk);
     3339                                                pfree(junk);
     3340
     3341                                                /* rebuild dash_set */
     3342                                                for (k = 1; k < dash_n; k++) {
     3343                                                        dash_set[k - 1] = repalloc(dash_set[k - 1], (strlen(dash_set[k]) + 1) * sizeof(char));
     3344                                                        strcpy(dash_set[k - 1], dash_set[k]);
     3345                                                }
     3346                                                dash_n--;
     3347                                                c--;
     3348                                                pfree(dash_set[dash_n]);
     3349                                                dash_set = repalloc(dash_set, sizeof(char *) * dash_n);
     3350                                        }
     3351
     3352                                        /* there shouldn't be more than two in dash_n */
     3353                                        if (c < 1 && dash_n > 2) {
     3354                                                elog(ERROR, "RASTER_reclass: Invalid expression in reclassexpr element of reclassarg");
     3355                                                for (k = 0; k <= j; k++) pfree(exprset[k]);
     3356                                                pfree(exprset);
     3357                                                rt_raster_destroy(ctx, raster);
     3358                                                rt_context_destroy(ctx);
     3359                                                PG_RETURN_NULL();
     3360                                        }
     3361
     3362                                        /* check interval flags */
     3363                                        exc_val = 0;
     3364                                        inc_val = 1;
     3365                                        /* range */
     3366                                        if (dash_n != 1) {
     3367                                                /* min */
     3368                                                if (c < 1) {
     3369                                                        if (
     3370                                                                strchr(dash_set[c], ')') != NULL ||
     3371                                                                strchr(dash_set[c], ']') != NULL
     3372                                                        ) {
     3373                                                                exc_val = 1;
     3374                                                                inc_val = 1;
     3375                                                        }
     3376                                                        else if (strchr(dash_set[c], '(') != NULL){
     3377                                                                inc_val = 0;
     3378                                                        }
     3379                                                        else {
     3380                                                                inc_val = 1;
     3381                                                        }
     3382                                                }
     3383                                                /* max */
     3384                                                else {
     3385                                                        if (
     3386                                                                strrchr(dash_set[c], '(') != NULL ||
     3387                                                                strrchr(dash_set[c], '[') != NULL
     3388                                                        ) {
     3389                                                                exc_val = 1;
     3390                                                                inc_val = 0;
     3391                                                        }
     3392                                                        else if (strrchr(dash_set[c], ']') != NULL) {
     3393                                                                inc_val = 1;
     3394                                                        }
     3395                                                        else {
     3396                                                                inc_val = 0;
     3397                                                        }
     3398                                                }
     3399                                        }
     3400                                        POSTGIS_RT_DEBUGF(4, "RASTER_reclass: exc_val %d inc_val %d", exc_val, inc_val);
     3401
     3402                                        /* remove interval flags */
     3403                                        dash_set[c] = chartrim(dash_set[c], "()[]");
     3404                                        POSTGIS_RT_DEBUGF(4, "RASTER_reclass: min/max (char) %s", dash_set[c]);
     3405
     3406                                        /* value from string to double */
     3407                                        errno = 0;
     3408                                        val = strtod(dash_set[c], &junk);
     3409                                        if (errno != 0 || dash_set[c] == junk) {
     3410                                                elog(ERROR, "RASTER_reclass: Invalid expression in reclassexpr element of reclassarg");
     3411                                                for (k = 0; k <= j; k++) pfree(exprset[k]);
     3412                                                pfree(exprset);
     3413                                                rt_raster_destroy(ctx, raster);
     3414                                                rt_context_destroy(ctx);
     3415                                                PG_RETURN_NULL();
     3416                                        }
     3417                                        POSTGIS_RT_DEBUGF(4, "RASTER_reclass: min/max (double) %f", val);
     3418
     3419                                        /* strsplit removes dash (a.k.a. negative sign), compare now to restore */
     3420                                        junk = strstr(colon_set[b], dash_set[c]);
     3421                                        /* not beginning of string */
     3422                                        if (junk != colon_set[b]) {
     3423                                                /* prior is a dash */
     3424                                                if (*(junk - 1) == '-') {
     3425                                                        /* prior is beginning of string or prior - 1 char is dash, negative number */
     3426                                                        if (
     3427                                                                ((junk - 1) == colon_set[b]) ||
     3428                                                                (*(junk - 2) == '-') ||
     3429                                                                (*(junk - 2) == '[') ||
     3430                                                                (*(junk - 2) == '(')
     3431                                                        ) {
     3432                                                                val *= -1.;
     3433                                                        }
     3434                                                }
     3435                                        }
     3436                                        POSTGIS_RT_DEBUGF(4, "RASTER_reclass: min/max (double) %f", val);
     3437
     3438                                        /* src */
     3439                                        if (b < 1) {
     3440                                                /* singular value */
     3441                                                if (dash_n == 1) {
     3442                                                        exprset[j]->src.exc_min = exprset[j]->src.exc_max = exc_val;
     3443                                                        exprset[j]->src.inc_min = exprset[j]->src.inc_max = inc_val;
     3444                                                        exprset[j]->src.min = exprset[j]->src.max = val;
     3445                                                }
     3446                                                /* min */
     3447                                                else if (c < 1) {
     3448                                                        exprset[j]->src.exc_min = exc_val;
     3449                                                        exprset[j]->src.inc_min = inc_val;
     3450                                                        exprset[j]->src.min = val;
     3451                                                }
     3452                                                /* max */
     3453                                                else {
     3454                                                        exprset[j]->src.exc_max = exc_val;
     3455                                                        exprset[j]->src.inc_max = inc_val;
     3456                                                        exprset[j]->src.max = val;
     3457                                                }
     3458                                        }
     3459                                        /* dst */
     3460                                        else {
     3461                                                /* singular value */
     3462                                                if (dash_n == 1)
     3463                                                        exprset[j]->dst.min = exprset[j]->dst.max = val;
     3464                                                /* min */
     3465                                                else if (c < 1)
     3466                                                        exprset[j]->dst.min = val;
     3467                                                /* max */
     3468                                                else
     3469                                                        exprset[j]->dst.max = val;
     3470                                        }
     3471                                }
     3472                        }
     3473
     3474                        POSTGIS_RT_DEBUGF(3, "RASTER_reclass: or: %f - %f nr: %f - %f"
     3475                                , exprset[j]->src.min
     3476                                , exprset[j]->src.max
     3477                                , exprset[j]->dst.min
     3478                                , exprset[j]->dst.max
     3479                        );
     3480                        j++;
     3481                }
     3482
     3483                /* pixel type */
     3484                tupv = GetAttributeByName(tup, "pixeltype", &isnull);
     3485                if (isnull) {
     3486                        elog(ERROR, "RASTER_reclass: Missing value for pixeltype element of reclassarg");
     3487                        rt_raster_destroy(ctx, raster);
     3488                        rt_context_destroy(ctx);
     3489                        PG_RETURN_NULL();
     3490                }
     3491                pixeltypetext = (text *) DatumGetPointer(tupv);
     3492                if (NULL == pixeltypetext) {
     3493                        elog(ERROR, "RASTER_reclass: Missing value for pixeltype element of reclassarg");
     3494                        rt_raster_destroy(ctx, raster);
     3495                        rt_context_destroy(ctx);
     3496                        PG_RETURN_NULL();
     3497                }
     3498                pixeltype = text_to_cstring(pixeltypetext);
     3499                POSTGIS_RT_DEBUGF(3, "RASTER_reclass: pixeltype %s", pixeltype);
     3500                pixtype = rt_pixtype_index_from_name(ctx, pixeltype);
     3501
     3502                /* nodata */
     3503                tupv = GetAttributeByName(tup, "nodataval", &isnull);
     3504                if (isnull) {
     3505                        nodataval = 0;
     3506                        hasnodata = FALSE;
     3507                }
     3508                else {
     3509                        nodataval = DatumGetFloat8(tupv);
     3510                        hasnodata = TRUE;
     3511                }
     3512                POSTGIS_RT_DEBUGF(3, "RASTER_reclass: nodataval %f", nodataval);
     3513                POSTGIS_RT_DEBUGF(3, "RASTER_reclass: hasnodata %d", hasnodata);
     3514
     3515                /* do reclass */
     3516                band = rt_raster_get_band(ctx, raster, nband - 1);
     3517                if (!band) {
     3518                        elog(ERROR, "RASTER_reclass: Error getting source band for reclassification");
     3519                        rt_raster_destroy(ctx, raster);
     3520                        rt_context_destroy(ctx);
     3521                        for (k = 0; k < j; k++) pfree(exprset[k]);
     3522                        pfree(exprset);
     3523                        PG_RETURN_NULL();
     3524                }
     3525                newband = rt_band_reclass(ctx, band, pixtype,
     3526                        hasnodata, nodataval, exprset, j);
     3527                if (!newband) {
     3528                        elog(ERROR, "RASTER_reclass: Error reclassifying band");
     3529                        rt_raster_destroy(ctx, raster);
     3530                        rt_context_destroy(ctx);
     3531                        for (k = 0; k < j; k++) pfree(exprset[k]);
     3532                        pfree(exprset);
     3533                        PG_RETURN_NULL();
     3534                }
     3535
     3536                /* replace old band with new band */
     3537                if (rt_raster_replace_band(ctx, raster, newband, nband - 1) == 0) {
     3538                        elog(ERROR, "RASTER_reclass: Error reclassifying band");
     3539                        rt_band_destroy(ctx, newband);
     3540                        rt_raster_destroy(ctx, raster);
     3541                        rt_context_destroy(ctx);
     3542                        for (k = 0; k < j; k++) pfree(exprset[k]);
     3543                        pfree(exprset);
     3544                        PG_RETURN_NULL();
     3545                }
     3546
     3547                /* free exprset */
     3548                for (k = 0; k < j; k++) pfree(exprset[k]);
     3549                pfree(exprset);
     3550        }
     3551
     3552        pgrast = rt_raster_serialize(ctx, raster);
     3553        rt_raster_destroy(ctx, raster);
     3554        rt_context_destroy(ctx);
     3555
     3556        if (!pgrast)
     3557                PG_RETURN_NULL();
     3558
     3559        SET_VARSIZE(pgrast, pgrast->size);
     3560
     3561        POSTGIS_RT_DEBUG(3, "RASTER_reclass: Finished");
     3562        PG_RETURN_POINTER(pgrast);
     3563}
     3564
    29973565/* ---------------------------------------------------------------- */
    29983566/*  Memory allocation / error reporting hooks                       */
    29993567/* ---------------------------------------------------------------- */
  • raster/rt_pg/rtpostgis.sql.in.c

    diff -rupN postgis-old/raster/rt_pg/rtpostgis.sql.in.c postgis-new/raster/rt_pg/rtpostgis.sql.in.c
    old new CREATE OR REPLACE FUNCTION st_approxminm 
    310310        LANGUAGE 'SQL' IMMUTABLE STRICT;
    311311
    312312-----------------------------------------------------------------------
     313-- ST_Reclass
     314-----------------------------------------------------------------------
     315CREATE TYPE reclassarg AS (
     316        nband int,
     317        reclassexpr text,
     318        pixeltype text,
     319        nodataval double precision
     320);
     321
     322CREATE OR REPLACE FUNCTION _st_reclass(rast raster, VARIADIC reclassargset reclassarg[])
     323        RETURNS raster
     324        AS 'MODULE_PATHNAME', 'RASTER_reclass'
     325        LANGUAGE 'C' IMMUTABLE STRICT;
     326
     327CREATE OR REPLACE FUNCTION st_reclass(rast raster, VARIADIC reclassargset reclassarg[])
     328        RETURNS raster
     329        AS $$
     330        DECLARE
     331                i int;
     332                expr text;
     333        BEGIN
     334                -- for each reclassarg, validate elements as all except nodataval cannot be NULL
     335                FOR i IN SELECT * FROM generate_subscripts($2, 1) LOOP
     336                        IF $2[i].nband IS NULL OR $2[i].reclassexpr IS NULL OR $2[i].pixeltype IS NULL THEN
     337                                RAISE EXCEPTION 'Values are required for the nband, reclassexpr and pixeltype attributes.';
     338                        END IF;
     339                END LOOP;
     340
     341                RETURN _st_reclass($1, VARIADIC $2);
     342        END;
     343        $$ LANGUAGE 'plpgsql' IMMUTABLE STRICT;
     344
     345CREATE OR REPLACE FUNCTION st_reclass(rast raster, nband int, reclassexpr text, pixeltype text, nodataval double precision)
     346        RETURNS raster
     347        AS $$ SELECT st_reclass($1, ROW($2, $3, $4, $5)) $$
     348        LANGUAGE 'SQL' IMMUTABLE STRICT;
     349
     350CREATE OR REPLACE FUNCTION st_reclass(rast raster, nband int, reclassexpr text, pixeltype text)
     351        RETURNS raster
     352        AS $$ SELECT st_reclass($1, ROW($2, $3, $4, NULL)) $$
     353        LANGUAGE 'SQL' IMMUTABLE STRICT;
     354
     355CREATE OR REPLACE FUNCTION st_reclass(rast raster, reclassexpr text, pixeltype text)
     356        RETURNS raster
     357        AS $$ SELECT st_reclass($1, ROW(1, $2, $3, NULL)) $$
     358        LANGUAGE 'SQL' IMMUTABLE STRICT;
     359
     360-----------------------------------------------------------------------
    313361-- MapAlgebra
    314362-----------------------------------------------------------------------
    315363-- This function can not be STRICT, because nodatavalueexpr can be NULL (could be just '' though)
  • raster/test/core/testapi.c

    diff -rupN postgis-old/raster/test/core/testapi.c postgis-new/raster/test/core/testapi.c
    old new static void testBandSummaryStats(rt_cont 
    10651065        rt_raster_destroy(ctx, raster);
    10661066}
    10671067
     1068static void testRasterReplaceBand(rt_context ctx) {
     1069        rt_raster raster;
     1070        rt_band band;
     1071        void* mem;
     1072        size_t datasize;
     1073        uint16_t width;
     1074        uint16_t height;
     1075        double nodata;
     1076        int rtn;
     1077
     1078        raster = rt_raster_new(ctx, 10, 10);
     1079        assert(raster); /* or we're out of virtual memory */
     1080        band = addBand(ctx, raster, PT_8BUI, 0, 0);
     1081        CHECK(band);
     1082        band = addBand(ctx, raster, PT_8BUI, 1, 255);
     1083        CHECK(band);
     1084
     1085        width = rt_raster_get_width(ctx, raster);
     1086        height = rt_raster_get_height(ctx, raster);
     1087
     1088        datasize = rt_pixtype_size(ctx, PT_8BUI) * width * height;
     1089        mem = malloc(datasize);
     1090        band = rt_band_new_inline(ctx, width, height, PT_8BUI, 1, 1, mem);
     1091        assert(band);
     1092
     1093        rtn = rt_raster_replace_band(ctx, raster, band, 0);
     1094        CHECK(rtn);
     1095        nodata = rt_band_get_nodata(ctx, rt_raster_get_band(ctx, raster, 0));
     1096        CHECK((nodata == 1));
     1097
     1098        rt_band_destroy(ctx, band);
     1099        rt_raster_destroy(ctx, raster);
     1100        free(mem);
     1101}
     1102
     1103struct rt_reclassexpr_t {
     1104        struct rt_reclassrange {
     1105                double min;
     1106                double max;
     1107                int inc_min; /* include min */
     1108                int inc_max; /* include max */
     1109                int exc_min; /* exceed min */
     1110                int exc_max; /* exceed max */
     1111        } src, dst;
     1112};
     1113static void testBandReclass(rt_context ctx) {
     1114        rt_reclassexpr *exprset;
     1115
     1116        rt_raster raster;
     1117        rt_band band;
     1118        uint16_t x;
     1119        uint16_t y;
     1120        double nodata;
     1121        int cnt = 2;
     1122        int i = 0;
     1123        int rtn;
     1124        rt_band newband;
     1125        double val;
     1126
     1127        raster = rt_raster_new(ctx, 100, 10);
     1128        assert(raster); /* or we're out of virtual memory */
     1129        band = addBand(ctx, raster, PT_16BUI, 0, 0);
     1130        CHECK(band);
     1131        rt_band_set_nodata(ctx, band, 0);
     1132
     1133        for (x = 0; x < 100; x++) {
     1134                for (y = 0; y < 10; y++) {
     1135                        rtn = rt_band_set_pixel(ctx, band, x, y, x * y + (x + y));
     1136                        CHECK((rtn != -1));
     1137                }
     1138        }
     1139
     1140        nodata = rt_band_get_nodata(ctx, band);
     1141        CHECK_EQUALS(nodata, 0);
     1142
     1143        exprset = malloc(cnt * sizeof(rt_reclassexpr));
     1144        assert(exprset);
     1145
     1146        for (i = 0; i < cnt; i++) {
     1147                exprset[i] = malloc(sizeof(struct rt_reclassexpr_t));
     1148                assert(exprset[i]);
     1149
     1150                if (i == 0) {
     1151                        /* nodata */
     1152                        exprset[i]->src.min = 0;
     1153                        exprset[i]->src.inc_min = 0;
     1154                        exprset[i]->src.exc_min = 0;
     1155
     1156                        exprset[i]->src.max = 0;
     1157                        exprset[i]->src.inc_max = 0;
     1158                        exprset[i]->src.exc_max = 0;
     1159
     1160                        exprset[i]->dst.min = 0;
     1161                        exprset[i]->dst.max = 0;
     1162                }
     1163                else {
     1164                        /* range */
     1165                        exprset[i]->src.min = 0;
     1166                        exprset[i]->src.inc_min = 0;
     1167                        exprset[i]->src.exc_min = 0;
     1168
     1169                        exprset[i]->src.max = 1000;
     1170                        exprset[i]->src.inc_max = 1;
     1171                        exprset[i]->src.exc_max = 0;
     1172
     1173                        exprset[i]->dst.min = 1;
     1174                        exprset[i]->dst.max = 255;
     1175                }
     1176        }
     1177
     1178        newband = rt_band_reclass(ctx, band, PT_8BUI, 0, 0, exprset, cnt);
     1179        CHECK(newband);
     1180
     1181        rtn = rt_band_get_pixel(ctx, newband, 0, 0, &val);
     1182        CHECK((rtn != -1));
     1183        CHECK_EQUALS(val, 0);
     1184
     1185        rtn = rt_band_get_pixel(ctx, newband, 49, 5, &val);
     1186        CHECK((rtn != -1));
     1187        CHECK_EQUALS(val, 77);
     1188
     1189        rtn = rt_band_get_pixel(ctx, newband, 99, 9, &val);
     1190        CHECK((rtn != -1));
     1191        CHECK_EQUALS(val, 255);
     1192
     1193
     1194        for (i = cnt - 1; i >= 0; i--)
     1195                free(exprset[i]);
     1196        free(exprset);
     1197        rt_band_destroy(ctx, band);
     1198        rt_band_destroy(ctx, newband);
     1199        rt_raster_destroy(ctx, raster);
     1200}
     1201
    10681202int
    10691203main()
    10701204{
    main() 
    13831517                testBandSummaryStats(ctx);
    13841518                printf("Successfully tested rt_band_get_summary_stats\n");
    13851519
     1520                printf("Testing rt_raster_replace_band\n");
     1521                testRasterReplaceBand(ctx);
     1522                printf("Successfully tested rt_raster_replace_band\n");
     1523
     1524                printf("Testing rt_band_reclass\n");
     1525                testBandReclass(ctx);
     1526                printf("Successfully tested rt_band_reclass\n");
     1527
    13861528    deepRelease(ctx, raster);
    13871529    rt_context_destroy(ctx);
    13881530
  • raster/test/regress/Makefile.in

    diff -rupN postgis-old/raster/test/regress/Makefile.in postgis-new/raster/test/regress/Makefile.in
    old new TEST_FUNC = \ 
    4242        rt_box2d.sql \
    4343        rt_addband.sql \
    4444        rt_band.sql \
     45        rt_reclass.sql \
    4546        $(NULL)
    4647
    4748TEST_PROPS = \
  • raster/test/regress/rt_reclass.sql

    diff -rupN postgis-old/raster/test/regress/rt_reclass.sql postgis-new/raster/test/regress/rt_reclass.sql
    old new  
     1SELECT
     2        ST_Value(t.rast, 1, 1, 1),
     3        ST_Value(t.rast, 1, 10, 10),
     4        ST_Value(t.rast, 1, 2, 10),
     5        ST_BandNoDataValue(rast, 1)
     6FROM (
     7        SELECT ST_Reclass(
     8                ST_SetValue(
     9                        ST_SetValue(
     10                                ST_AddBand(
     11                                        ST_MakeEmptyRaster(10, 10, 10, 10, 2, 2, 0, 0, -1),
     12                                        1, '32BUI', 0, 0
     13                                ),
     14                                1, 1, 499
     15                        ),
     16                        10, 10, 12
     17                ),
     18                ROW(1, '0-100:1-10, 101-500:11-150,501 - 10000: 151-254', '8BUI', 255)
     19        ) AS rast
     20) AS t;
     21SELECT
     22        ST_Value(t.rast, 1, 1, 1),
     23        ST_Value(t.rast, 1, 10, 10),
     24        ST_Value(t.rast, 1, 2, 10),
     25        ST_BandNoDataValue(rast, 1),
     26        ST_Value(t.rast, 2, 1, 1),
     27        ST_Value(t.rast, 2, 10, 10),
     28        ST_Value(t.rast, 2, 2, 10),
     29        ST_BandNoDataValue(rast, 2)
     30FROM (
     31        SELECT ST_Reclass(
     32                ST_SetValue(
     33                        ST_SetValue(
     34                                ST_AddBand(
     35                                        ST_AddBand(
     36                                                ST_MakeEmptyRaster(10, 10, 10, 10, 2, 2, 0, 0, -1),
     37                                                1, '8BUI', 0, 1
     38                                        ),
     39                                        2, '32BUI', 0, 0
     40                                ),
     41                                2, 1, 1, 499
     42                        ),
     43                        2, 10, 10, 12
     44                ),
     45                ROW(2, '0-100:1-10, 101-500:11-150,501 - 10000: 151-254', '8BUI', 255)
     46        ) AS rast
     47) AS t;
     48SELECT
     49        ST_Value(t.rast, 1, 1, 1),
     50        ST_Value(t.rast, 1, 10, 10),
     51        ST_Value(t.rast, 1, 2, 10),
     52        ST_BandNoDataValue(rast, 1),
     53        ST_Value(t.rast, 2, 1, 1),
     54        ST_Value(t.rast, 2, 10, 10),
     55        ST_Value(t.rast, 2, 2, 10),
     56        ST_BandNoDataValue(rast, 2)
     57FROM (
     58        SELECT ST_Reclass(
     59                ST_SetValue(
     60                        ST_SetValue(
     61                                ST_AddBand(
     62                                        ST_AddBand(
     63                                                ST_MakeEmptyRaster(10, 10, 10, 10, 2, 2, 0, 0, -1),
     64                                                1, '8BUI', 0, 1
     65                                        ),
     66                                        2, '32BUI', 0, 0
     67                                ),
     68                                2, 1, 1, 499
     69                        ),
     70                        2, 10, 10, 12
     71                ),
     72                ROW(1, '0:1', '8BUI', 255),
     73                ROW(2, '0-100:1-10, 101-500:11-150,501 - 10000: 151-254', '8BUI', 255)
     74        ) AS rast
     75) AS t;
     76SELECT
     77        ST_Value(t.rast, 1, 1, 1),
     78        ST_Value(t.rast, 1, 10, 10),
     79        ST_BandNoDataValue(rast, 1)
     80FROM (
     81        SELECT ST_Reclass(
     82                ST_SetValue(
     83                        ST_SetValue(
     84                                ST_AddBand(
     85                                        ST_MakeEmptyRaster(10, 10, 10, 10, 2, 2, 0, 0, -1),
     86                                        1, '8BUI', 0, 0
     87                                ),
     88                                1, 1, 1, 255
     89                        ),
     90                        1, 10, 10, 0
     91                ),
     92                ROW(1, '0-100]:200-255,(100-200]:100-200,(200-255]:0-100', '8BUI', NULL)
     93        ) AS rast
     94) AS t;
     95SELECT
     96        ST_Value(t.rast, 1, 1, 1),
     97        ST_Value(t.rast, 1, 10, 10),
     98        ST_BandNoDataValue(rast, 1)
     99FROM (
     100        SELECT ST_Reclass(
     101                ST_SetValue(
     102                        ST_SetValue(
     103                                ST_AddBand(
     104                                        ST_MakeEmptyRaster(100, 100, 10, 10, 2, 2, 0, 0, -1),
     105                                        1, '32BF', 1, 0
     106                                ),
     107                                1, 1, 1, 3.14159
     108                        ),
     109                        1, 10, 10, 2.71828
     110                ),
     111                ROW(1, '-10000--100]:1-50,(-100-1000]:50-150,(1000-10000]:150-254', '8BUI', 0)
     112        ) AS rast
     113) AS t;
  • raster/test/regress/rt_reclass_expected

    diff -rupN postgis-old/raster/test/regress/rt_reclass_expected postgis-new/raster/test/regress/rt_reclass_expected
    old new  
     1150|2||255
     20|0|0|1|150|2||255
     31|1|1|255|150|2||255
     4100|200|
     559|59|0