static void test_raster_from_band() { uint32_t bandNums[] = {1,3}; int lenBandNums = 2; rt_raster raster; rt_raster rast; rt_band band; uint32_t xmax = 100; uint32_t ymax = 100; uint32_t x; raster = rt_raster_new(xmax, ymax); CU_ASSERT(raster != NULL); for (x = 0; x < 5; x++) { band = cu_add_band(raster, PT_32BUI, 0, 0); CU_ASSERT(band != NULL); rt_band_set_nodata(band, 0, NULL); } rast = rt_raster_from_band(raster, bandNums, lenBandNums); CU_ASSERT(rast != NULL); CU_ASSERT(!rt_raster_is_empty(rast)); CU_ASSERT(rt_raster_has_band(rast, 1)); cu_free_raster(rast); cu_free_raster(raster); }
static void test_raster_empty() { rt_raster raster = NULL; /* check that raster is empty */ raster = rt_raster_new(0, 0); CU_ASSERT(raster != NULL); CU_ASSERT(rt_raster_is_empty(raster)); cu_free_raster(raster); /* create raster */ raster = rt_raster_new(1, 1); CU_ASSERT(raster != NULL); /* check that raster is not empty */ CU_ASSERT(!rt_raster_is_empty(raster)); cu_free_raster(raster); }
/** * n-raster iterator. * The raster returned should be freed by the caller * * @param itrset : set of rt_iterator objects. * @param itrcount : number of objects in itrset. * @param extenttype : type of extent for the output raster. * @param customextent : raster specifying custom extent. * is only used if extenttype is ET_CUSTOM. * @param pixtype : the desired pixel type of the output raster's band. * @param hasnodata : indicates if the band has nodata value * @param nodataval : the nodata value, will be appropriately * truncated to fit the pixtype size. * @param distancex : the number of pixels around the specified pixel * along the X axis * @param distancey : the number of pixels around the specified pixel * along the Y axis * @param mask : the object of mask * @param userarg : pointer to any argument that is passed as-is to callback. * @param callback : callback function for actual processing of pixel values. * @param *rtnraster : return one band raster from iterator process * * The callback function _must_ have the following signature. * * int FNAME(rt_iterator_arg arg, void *userarg, double *value, int *nodata) * * The callback function _must_ return zero (error) or non-zero (success) * indicating whether the function ran successfully. * The parameters passed to the callback function are as follows. * * - rt_iterator_arg arg: struct containing pixel values, NODATA flags and metadata * - void *userarg: NULL or calling function provides to rt_raster_iterator() for use by callback function * - double *value: value of pixel to be burned by rt_raster_iterator() * - int *nodata: flag (0 or 1) indicating that pixel to be burned is NODATA * * @return ES_NONE on success, ES_ERROR on error */ rt_errorstate rt_raster_iterator( rt_iterator itrset, uint16_t itrcount, rt_extenttype extenttype, rt_raster customextent, rt_pixtype pixtype, uint8_t hasnodata, double nodataval, uint16_t distancex, uint16_t distancey, rt_mask mask, void *userarg, int (*callback)( rt_iterator_arg arg, void *userarg, double *value, int *nodata ), rt_raster *rtnraster ) { /* output raster */ rt_raster rtnrast = NULL; /* output raster's band */ rt_band rtnband = NULL; /* working raster */ rt_raster rast = NULL; _rti_iterator_arg _param = NULL; int allnull = 0; int allempty = 0; int aligned = 0; double offset[4] = {0.}; rt_pixel npixels; int i = 0; int status = 0; int inextent = 0; int x = 0; int y = 0; int _x = 0; int _y = 0; int _width = 0; int _height = 0; double minval; double value; int isnodata; int nodata; RASTER_DEBUG(3, "Starting..."); assert(itrset != NULL && itrcount > 0); assert(rtnraster != NULL); /* init rtnraster to NULL */ *rtnraster = NULL; /* check that callback function is not NULL */ if (callback == NULL) { rterror("rt_raster_iterator: Callback function not provided"); return ES_ERROR; } /* check that custom extent is provided if extenttype = ET_CUSTOM */ if (extenttype == ET_CUSTOM && rt_raster_is_empty(customextent)) { rterror("rt_raster_iterator: Custom extent cannot be empty if extent type is ET_CUSTOM"); return ES_ERROR; } /* check that pixtype != PT_END */ if (pixtype == PT_END) { rterror("rt_raster_iterator: Pixel type cannot be PT_END"); return ES_ERROR; } /* initialize _param */ if ((_param = _rti_iterator_arg_init()) == NULL) { rterror("rt_raster_iterator: Could not initialize internal variables"); return ES_ERROR; } /* fill _param */ if (!_rti_iterator_arg_populate(_param, itrset, itrcount, distancex, distancey, &allnull, &allempty)) { rterror("rt_raster_iterator: Could not populate for internal variables"); _rti_iterator_arg_destroy(_param); return ES_ERROR; } /* shortcut if all null, return NULL */ if (allnull == itrcount) { RASTER_DEBUG(3, "all rasters are NULL, returning NULL"); _rti_iterator_arg_destroy(_param); return ES_NONE; } /* shortcut if all empty, return empty raster */ else if (allempty == itrcount) { RASTER_DEBUG(3, "all rasters are empty, returning empty raster"); _rti_iterator_arg_destroy(_param); rtnrast = rt_raster_new(0, 0); if (rtnrast == NULL) { rterror("rt_raster_iterator: Could not create empty raster"); return ES_ERROR; } rt_raster_set_scale(rtnrast, 0, 0); *rtnraster = rtnrast; return ES_NONE; } /* check that all rasters are aligned */ RASTER_DEBUG(3, "checking alignment of all rasters"); rast = NULL; /* find raster to use as reference */ /* use custom if provided */ if (extenttype == ET_CUSTOM) { RASTER_DEBUG(4, "using custom extent as reference raster"); rast = customextent; } /* use first valid one in _param->raster */ else { for (i = 0; i < itrcount; i++) { if (!_param->isempty[i]) { RASTER_DEBUGF(4, "using raster at index %d as reference raster", i); rast = _param->raster[i]; break; } } } /* no rasters found, SHOULD NEVER BE HERE! */ if (rast == NULL) { rterror("rt_raster_iterator: Could not find reference raster to use for alignment tests"); _rti_iterator_arg_destroy(_param); return ES_ERROR; } do { aligned = 1; /* check custom first if set. also skip if rasters are the same */ if (extenttype == ET_CUSTOM && rast != customextent) { if (rt_raster_same_alignment(rast, customextent, &aligned, NULL) != ES_NONE) { rterror("rt_raster_iterator: Could not test for alignment between reference raster and custom extent"); _rti_iterator_arg_destroy(_param); return ES_ERROR; } RASTER_DEBUGF(5, "custom extent alignment: %d", aligned); if (!aligned) break; } for (i = 0; i < itrcount; i++) { /* skip NULL rasters and if rasters are the same */ if (_param->isempty[i] || rast == _param->raster[i]) continue; if (rt_raster_same_alignment(rast, _param->raster[i], &aligned, NULL) != ES_NONE) { rterror("rt_raster_iterator: Could not test for alignment between reference raster and raster %d", i); _rti_iterator_arg_destroy(_param); return ES_ERROR; } RASTER_DEBUGF(5, "raster at index %d alignment: %d", i, aligned); /* abort checking since a raster isn't aligned */ if (!aligned) break; } } while (0); /* not aligned, error */ if (!aligned) { rterror("rt_raster_iterator: The set of rasters provided (custom extent included, if appropriate) do not have the same alignment"); _rti_iterator_arg_destroy(_param); return ES_ERROR; } /* use extenttype to build output raster (no bands though) */ i = -1; switch (extenttype) { case ET_INTERSECTION: case ET_UNION: /* make copy of first "real" raster */ rtnrast = rtalloc(sizeof(struct rt_raster_t)); if (rtnrast == NULL) { rterror("rt_raster_iterator: Could not allocate memory for output raster"); _rti_iterator_arg_destroy(_param); return ES_ERROR; } for (i = 0; i < itrcount; i++) { if (!_param->isempty[i]) { memcpy(rtnrast, _param->raster[i], sizeof(struct rt_raster_serialized_t)); break; } } rtnrast->numBands = 0; rtnrast->bands = NULL; /* get extent of output raster */ rast = NULL; for (i = i + 1; i < itrcount; i++) { if (_param->isempty[i]) continue; status = rt_raster_from_two_rasters(rtnrast, _param->raster[i], extenttype, &rast, NULL); rtdealloc(rtnrast); if (rast == NULL || status != ES_NONE) { rterror("rt_raster_iterator: Could not compute %s extent of rasters", extenttype == ET_UNION ? "union" : "intersection" ); _rti_iterator_arg_destroy(_param); return ES_ERROR; } else if (rt_raster_is_empty(rast)) { rtinfo("rt_raster_iterator: Computed raster for %s extent is empty", extenttype == ET_UNION ? "union" : "intersection" ); _rti_iterator_arg_destroy(_param); *rtnraster = rast; return ES_NONE; } rtnrast = rast; rast = NULL; } break; /* first, second and last have similar checks and continue into custom */ case ET_FIRST: i = 0; case ET_SECOND: if (i < 0) { if (itrcount < 2) i = 0; else i = 1; } case ET_LAST: if (i < 0) i = itrcount - 1; /* input raster is null, return NULL */ if (_param->raster[i] == NULL) { RASTER_DEBUGF(3, "returning NULL as %s raster is NULL and extent type is ET_%s", (i == 0 ? "first" : (i == 1 ? "second" : "last")), (i == 0 ? "FIRST" : (i == 1 ? "SECOND" : "LAST")) ); _rti_iterator_arg_destroy(_param); return ES_NONE; } /* input raster is empty, return empty raster */ else if (_param->isempty[i]) { RASTER_DEBUGF(3, "returning empty raster as %s raster is empty and extent type is ET_%s", (i == 0 ? "first" : (i == 1 ? "second" : "last")), (i == 0 ? "FIRST" : (i == 1 ? "SECOND" : "LAST")) ); _rti_iterator_arg_destroy(_param); rtnrast = rt_raster_new(0, 0); if (rtnrast == NULL) { rterror("rt_raster_iterator: Could not create empty raster"); return ES_ERROR; } rt_raster_set_scale(rtnrast, 0, 0); *rtnraster = rtnrast; return ES_NONE; } /* copy the custom extent raster */ case ET_CUSTOM: rtnrast = rtalloc(sizeof(struct rt_raster_t)); if (rtnrast == NULL) { rterror("rt_raster_iterator: Could not allocate memory for output raster"); _rti_iterator_arg_destroy(_param); return ES_ERROR; } switch (extenttype) { case ET_CUSTOM: memcpy(rtnrast, customextent, sizeof(struct rt_raster_serialized_t)); break; /* first, second, last */ default: memcpy(rtnrast, _param->raster[i], sizeof(struct rt_raster_serialized_t)); break; } rtnrast->numBands = 0; rtnrast->bands = NULL; break; } _width = rt_raster_get_width(rtnrast); _height = rt_raster_get_height(rtnrast); RASTER_DEBUGF(4, "rtnrast (width, height, ulx, uly, scalex, scaley, skewx, skewy, srid) = (%d, %d, %f, %f, %f, %f, %f, %f, %d)", _width, _height, rt_raster_get_x_offset(rtnrast), rt_raster_get_y_offset(rtnrast), rt_raster_get_x_scale(rtnrast), rt_raster_get_y_scale(rtnrast), rt_raster_get_x_skew(rtnrast), rt_raster_get_y_skew(rtnrast), rt_raster_get_srid(rtnrast) ); /* init values and NODATA for use with empty rasters */ if (!_rti_iterator_arg_empty_init(_param)) { rterror("rt_raster_iterator: Could not initialize empty values and NODATA"); _rti_iterator_arg_destroy(_param); rt_raster_destroy(rtnrast); return ES_ERROR; } /* create output band */ if (rt_raster_generate_new_band( rtnrast, pixtype, nodataval, hasnodata, nodataval, 0 ) < 0) { rterror("rt_raster_iterator: Could not add new band to output raster"); _rti_iterator_arg_destroy(_param); rt_raster_destroy(rtnrast); return ES_ERROR; } /* get output band */ rtnband = rt_raster_get_band(rtnrast, 0); if (rtnband == NULL) { rterror("rt_raster_iterator: Could not get new band from output raster"); _rti_iterator_arg_destroy(_param); rt_raster_destroy(rtnrast); return ES_ERROR; } /* output band's minimum value */ minval = rt_band_get_min_value(rtnband); /* initialize argument for callback function */ if (!_rti_iterator_arg_callback_init(_param)) { rterror("rt_raster_iterator: Could not initialize callback function argument"); _rti_iterator_arg_destroy(_param); rt_band_destroy(rtnband); rt_raster_destroy(rtnrast); return ES_ERROR; } /* fill _param->offset */ for (i = 0; i < itrcount; i++) { if (_param->isempty[i]) continue; status = rt_raster_from_two_rasters(rtnrast, _param->raster[i], ET_FIRST, &rast, offset); rtdealloc(rast); if (status != ES_NONE) { rterror("rt_raster_iterator: Could not compute raster offsets"); _rti_iterator_arg_destroy(_param); rt_band_destroy(rtnband); rt_raster_destroy(rtnrast); return ES_ERROR; } _param->offset[i][0] = offset[2]; _param->offset[i][1] = offset[3]; RASTER_DEBUGF(4, "rast %d offset: %f %f", i, offset[2], offset[3]); } /* loop over each pixel (POI) of output raster */ /* _x,_y are for output raster */ /* x,y are for input raster */ for (_y = 0; _y < _height; _y++) { for (_x = 0; _x < _width; _x++) { RASTER_DEBUGF(4, "iterating output pixel (x, y) = (%d, %d)", _x, _y); _param->arg->dst_pixel[0] = _x; _param->arg->dst_pixel[1] = _y; /* loop through each input raster */ for (i = 0; i < itrcount; i++) { RASTER_DEBUGF(4, "raster %d", i); /* empty raster OR band does not exist and flag set to use NODATA OR band is NODATA */ if ( _param->isempty[i] || (_param->band.rtband[i] == NULL && itrset[i].nbnodata) || _param->band.isnodata[i] ) { RASTER_DEBUG(4, "empty raster, band does not exist or band is NODATA. using empty values and NODATA"); x = _x; y = _y; _param->arg->values[i] = _param->empty.values; _param->arg->nodata[i] = _param->empty.nodata; continue; } /* input raster's X,Y */ x = _x - (int) _param->offset[i][0]; y = _y - (int) _param->offset[i][1]; RASTER_DEBUGF(4, "source pixel (x, y) = (%d, %d)", x, y); _param->arg->src_pixel[i][0] = x; _param->arg->src_pixel[i][1] = y; /* neighborhood */ npixels = NULL; status = 0; if (distancex > 0 && distancey > 0) { RASTER_DEBUG(4, "getting neighborhood"); status = rt_band_get_nearest_pixel( _param->band.rtband[i], x, y, distancex, distancey, 1, &npixels ); if (status < 0) { rterror("rt_raster_iterator: Could not get pixel neighborhood"); _rti_iterator_arg_destroy(_param); rt_band_destroy(rtnband); rt_raster_destroy(rtnrast); return ES_ERROR; } } /* get value of POI */ /* get pixel's value */ if ( (x >= 0 && x < _param->width[i]) && (y >= 0 && y < _param->height[i]) ) { RASTER_DEBUG(4, "getting value of POI"); if (rt_band_get_pixel( _param->band.rtband[i], x, y, &value, &isnodata ) != ES_NONE) { rterror("rt_raster_iterator: Could not get the pixel value of band"); _rti_iterator_arg_destroy(_param); rt_band_destroy(rtnband); rt_raster_destroy(rtnrast); return ES_ERROR; } inextent = 1; } /* outside band extent, set to NODATA */ else { RASTER_DEBUG(4, "Outside band extent, setting value to NODATA"); /* has NODATA, use NODATA */ if (_param->band.hasnodata[i]) value = _param->band.nodataval[i]; /* no NODATA, use min possible value */ else value = _param->band.minval[i]; inextent = 0; isnodata = 1; } /* add pixel to neighborhood */ status++; if (status > 1) npixels = (rt_pixel) rtrealloc(npixels, sizeof(struct rt_pixel_t) * status); else npixels = (rt_pixel) rtalloc(sizeof(struct rt_pixel_t)); if (npixels == NULL) { rterror("rt_raster_iterator: Could not reallocate memory for neighborhood"); _rti_iterator_arg_destroy(_param); rt_band_destroy(rtnband); rt_raster_destroy(rtnrast); return ES_ERROR; } npixels[status - 1].x = x; npixels[status - 1].y = y; npixels[status - 1].nodata = 1; npixels[status - 1].value = value; /* set nodata flag */ if ((!_param->band.hasnodata[i] && inextent) || !isnodata) { npixels[status - 1].nodata = 0; } RASTER_DEBUGF(4, "value, nodata: %f, %d", value, npixels[status - 1].nodata); /* convert set of rt_pixel to 2D array */ status = rt_pixel_set_to_array( npixels, status,mask, x, y, distancex, distancey, &(_param->arg->values[i]), &(_param->arg->nodata[i]), NULL, NULL ); rtdealloc(npixels); if (status != ES_NONE) { rterror("rt_raster_iterator: Could not create 2D array of neighborhood"); _rti_iterator_arg_destroy(_param); rt_band_destroy(rtnband); rt_raster_destroy(rtnrast); return ES_ERROR; } } /* callback */ RASTER_DEBUG(4, "calling callback function"); value = 0; nodata = 0; status = callback(_param->arg, userarg, &value, &nodata); /* free memory from callback */ _rti_iterator_arg_callback_clean(_param); /* handle callback status */ if (status == 0) { rterror("rt_raster_iterator: Callback function returned an error"); _rti_iterator_arg_destroy(_param); rt_band_destroy(rtnband); rt_raster_destroy(rtnrast); return ES_ERROR; } /* burn value to pixel */ status = 0; if (!nodata) { status = rt_band_set_pixel(rtnband, _x, _y, value, NULL); RASTER_DEBUGF(4, "burning pixel (%d, %d) with value: %f", _x, _y, value); } else if (!hasnodata) { status = rt_band_set_pixel(rtnband, _x, _y, minval, NULL); RASTER_DEBUGF(4, "burning pixel (%d, %d) with minval: %f", _x, _y, minval); } else { RASTER_DEBUGF(4, "NOT burning pixel (%d, %d)", _x, _y); } if (status != ES_NONE) { rterror("rt_raster_iterator: Could not set pixel value"); _rti_iterator_arg_destroy(_param); rt_band_destroy(rtnband); rt_raster_destroy(rtnrast); return ES_ERROR; } } } /* lots of cleanup */ _rti_iterator_arg_destroy(_param); *rtnraster = rtnrast; return ES_NONE; }
static int _rti_iterator_arg_populate( _rti_iterator_arg _param, rt_iterator itrset, uint16_t itrcount, uint16_t distancex, uint16_t distancey, int *allnull, int *allempty ) { int i = 0; int hasband = 0; _param->count = itrcount; _param->distance.x = distancex; _param->distance.y = distancey; _param->dimension.columns = distancex * 2 + 1; _param->dimension.rows = distancey * 2 + 1; /* allocate memory for children */ _param->raster = rtalloc(sizeof(rt_raster) * itrcount); _param->isempty = rtalloc(sizeof(int) * itrcount); _param->width = rtalloc(sizeof(int) * itrcount); _param->height = rtalloc(sizeof(int) * itrcount); _param->offset = rtalloc(sizeof(double *) * itrcount); _param->band.rtband = rtalloc(sizeof(rt_band) * itrcount); _param->band.hasnodata = rtalloc(sizeof(int) * itrcount); _param->band.isnodata = rtalloc(sizeof(int) * itrcount); _param->band.nodataval = rtalloc(sizeof(double) * itrcount); _param->band.minval = rtalloc(sizeof(double) * itrcount); if ( _param->raster == NULL || _param->isempty == NULL || _param->width == NULL || _param->height == NULL || _param->offset == NULL || _param->band.rtband == NULL || _param->band.hasnodata == NULL || _param->band.isnodata == NULL || _param->band.nodataval == NULL || _param->band.minval == NULL ) { rterror("_rti_iterator_arg_populate: Could not allocate memory for children of _rti_iterator_arg"); return 0; } *allnull = 0; *allempty = 0; /* check input rasters not empty, band # is valid copy raster pointers and set flags */ for (i = 0; i < itrcount; i++) { /* initialize elements */ _param->raster[i] = NULL; _param->isempty[i] = 0; _param->width[i] = 0; _param->height[i] = 0; _param->offset[i] = NULL; _param->band.rtband[i] = NULL; _param->band.hasnodata[i] = 0; _param->band.isnodata[i] = 0; _param->band.nodataval[i] = 0; _param->band.minval[i] = 0; /* set isempty */ if (itrset[i].raster == NULL) { _param->isempty[i] = 1; (*allnull)++; (*allempty)++; continue; } else if (rt_raster_is_empty(itrset[i].raster)) { _param->isempty[i] = 1; (*allempty)++; continue; } /* check band number */ hasband = rt_raster_has_band(itrset[i].raster, itrset[i].nband); if (!hasband) { if (!itrset[i].nbnodata) { rterror("_rti_iterator_arg_populate: Band %d not found for raster %d", itrset[i].nband, i); return 0; } else { RASTER_DEBUGF(4, "Band %d not found for raster %d. Using NODATA", itrset[i].nband, i); } } _param->raster[i] = itrset[i].raster; if (hasband) { _param->band.rtband[i] = rt_raster_get_band(itrset[i].raster, itrset[i].nband); if (_param->band.rtband[i] == NULL) { rterror("_rti_iterator_arg_populate: Could not get band %d for raster %d", itrset[i].nband, i); return 0; } /* hasnodata */ _param->band.hasnodata[i] = rt_band_get_hasnodata_flag(_param->band.rtband[i]); /* hasnodata = TRUE */ if (_param->band.hasnodata[i]) { /* nodataval */ rt_band_get_nodata(_param->band.rtband[i], &(_param->band.nodataval[i])); /* isnodata */ _param->band.isnodata[i] = rt_band_get_isnodata_flag(_param->band.rtband[i]); } /* hasnodata = FALSE */ else { /* minval */ _param->band.minval[i] = rt_band_get_min_value(_param->band.rtband[i]); } } /* width, height */ _param->width[i] = rt_raster_get_width(_param->raster[i]); _param->height[i] = rt_raster_get_height(_param->raster[i]); /* init offset */ _param->offset[i] = rtalloc(sizeof(double) * 2); if (_param->offset[i] == NULL) { rterror("_rti_iterator_arg_populate: Could not allocate memory for offsets"); return 0; } } return 1; }
/** * Returns a new raster with up to four 8BUI bands (RGBA) from * applying a colormap to the user-specified band of the * input raster. * * @param raster: input raster * @param nband: 0-based index of the band to process with colormap * @param colormap: rt_colormap object of colormap to apply to band * * @return new raster or NULL on error */ rt_raster rt_raster_colormap( rt_raster raster, int nband, rt_colormap colormap ) { _rti_colormap_arg arg = NULL; rt_raster rtnraster = NULL; rt_band band = NULL; int i = 0; int j = 0; int k = 0; assert(colormap != NULL); /* empty raster */ if (rt_raster_is_empty(raster)) return NULL; /* no colormap entries */ if (colormap->nentry < 1) { rterror("rt_raster_colormap: colormap must have at least one entry"); return NULL; } /* nband is valid */ if (!rt_raster_has_band(raster, nband)) { rterror("rt_raster_colormap: raster has no band at index %d", nband); return NULL; } band = rt_raster_get_band(raster, nband); if (band == NULL) { rterror("rt_raster_colormap: Could not get band at index %d", nband); return NULL; } /* init internal variables */ arg = _rti_colormap_arg_init(raster); if (arg == NULL) { rterror("rt_raster_colormap: Could not initialize internal variables"); return NULL; } /* handle NODATA */ if (rt_band_get_hasnodata_flag(band)) { arg->hasnodata = 1; rt_band_get_nodata(band, &(arg->nodataval)); } /* # of colors */ if (colormap->ncolor < 1) { rterror("rt_raster_colormap: At least one color must be provided"); _rti_colormap_arg_destroy(arg); return NULL; } else if (colormap->ncolor > 4) { rtinfo("More than four colors indicated. Using only the first four colors"); colormap->ncolor = 4; } /* find non-NODATA entries */ arg->npos = 0; arg->pos = rtalloc(sizeof(uint16_t) * colormap->nentry); if (arg->pos == NULL) { rterror("rt_raster_colormap: Could not allocate memory for valid entries"); _rti_colormap_arg_destroy(arg); return NULL; } for (i = 0, j = 0; i < colormap->nentry; i++) { /* special handling for NODATA entries */ if (colormap->entry[i].isnodata) { /* first NODATA entry found, use it */ if (arg->nodataentry == NULL) arg->nodataentry = &(colormap->entry[i]); else rtwarn("More than one colormap entry found for NODATA value. Only using first NOTDATA entry"); continue; } (arg->npos)++; arg->pos[j++] = i; } /* INTERPOLATE and only one non-NODATA entry */ if (colormap->method == CM_INTERPOLATE && arg->npos < 2) { rtinfo("Method INTERPOLATE requires at least two non-NODATA colormap entries. Using NEAREST instead"); colormap->method = CM_NEAREST; } /* NODATA entry but band has no NODATA value */ if (!arg->hasnodata && arg->nodataentry != NULL) { rtinfo("Band at index %d has no NODATA value. Ignoring NODATA entry", nband); arg->nodataentry = NULL; } /* allocate expr */ arg->nexpr = arg->npos; /* INTERPOLATE needs one less than the number of entries */ if (colormap->method == CM_INTERPOLATE) arg->nexpr -= 1; /* EXACT requires a no matching expression */ else if (colormap->method == CM_EXACT) arg->nexpr += 1; /* NODATA entry exists, add expression */ if (arg->nodataentry != NULL) arg->nexpr += 1; arg->expr = rtalloc(sizeof(rt_reclassexpr) * arg->nexpr); if (arg->expr == NULL) { rterror("rt_raster_colormap: Could not allocate memory for reclass expressions"); _rti_colormap_arg_destroy(arg); return NULL; } RASTER_DEBUGF(4, "nexpr = %d", arg->nexpr); RASTER_DEBUGF(4, "expr @ %p", arg->expr); for (i = 0; i < arg->nexpr; i++) { arg->expr[i] = rtalloc(sizeof(struct rt_reclassexpr_t)); if (arg->expr[i] == NULL) { rterror("rt_raster_colormap: Could not allocate memory for reclass expression"); _rti_colormap_arg_destroy(arg); return NULL; } } /* reclassify bands */ /* by # of colors */ for (i = 0; i < colormap->ncolor; i++) { k = 0; /* handle NODATA entry first */ if (arg->nodataentry != NULL) { arg->expr[k]->src.min = arg->nodataentry->value; arg->expr[k]->src.max = arg->nodataentry->value; arg->expr[k]->src.inc_min = 1; arg->expr[k]->src.inc_max = 1; arg->expr[k]->src.exc_min = 0; arg->expr[k]->src.exc_max = 0; arg->expr[k]->dst.min = arg->nodataentry->color[i]; arg->expr[k]->dst.max = arg->nodataentry->color[i]; arg->expr[k]->dst.inc_min = 1; arg->expr[k]->dst.inc_max = 1; arg->expr[k]->dst.exc_min = 0; arg->expr[k]->dst.exc_max = 0; RASTER_DEBUGF(4, "NODATA expr[%d]->src (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)", k, arg->expr[k]->src.min, arg->expr[k]->src.max, arg->expr[k]->src.inc_min, arg->expr[k]->src.inc_max, arg->expr[k]->src.exc_min, arg->expr[k]->src.exc_max ); RASTER_DEBUGF(4, "NODATA expr[%d]->dst (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)", k, arg->expr[k]->dst.min, arg->expr[k]->dst.max, arg->expr[k]->dst.inc_min, arg->expr[k]->dst.inc_max, arg->expr[k]->dst.exc_min, arg->expr[k]->dst.exc_max ); k++; } /* by non-NODATA entry */ for (j = 0; j < arg->npos; j++) { if (colormap->method == CM_INTERPOLATE) { if (j == arg->npos - 1) continue; arg->expr[k]->src.min = colormap->entry[arg->pos[j + 1]].value; arg->expr[k]->src.inc_min = 1; arg->expr[k]->src.exc_min = 0; arg->expr[k]->src.max = colormap->entry[arg->pos[j]].value; arg->expr[k]->src.inc_max = 1; arg->expr[k]->src.exc_max = 0; arg->expr[k]->dst.min = colormap->entry[arg->pos[j + 1]].color[i]; arg->expr[k]->dst.max = colormap->entry[arg->pos[j]].color[i]; arg->expr[k]->dst.inc_min = 1; arg->expr[k]->dst.exc_min = 0; arg->expr[k]->dst.inc_max = 1; arg->expr[k]->dst.exc_max = 0; } else if (colormap->method == CM_NEAREST) { /* NOT last entry */ if (j != arg->npos - 1) { arg->expr[k]->src.min = ((colormap->entry[arg->pos[j]].value - colormap->entry[arg->pos[j + 1]].value) / 2.) + colormap->entry[arg->pos[j + 1]].value; arg->expr[k]->src.inc_min = 0; arg->expr[k]->src.exc_min = 0; } /* last entry */ else { arg->expr[k]->src.min = colormap->entry[arg->pos[j]].value; arg->expr[k]->src.inc_min = 1; arg->expr[k]->src.exc_min = 1; } /* NOT first entry */ if (j > 0) { arg->expr[k]->src.max = arg->expr[k - 1]->src.min; arg->expr[k]->src.inc_max = 1; arg->expr[k]->src.exc_max = 0; } /* first entry */ else { arg->expr[k]->src.max = colormap->entry[arg->pos[j]].value; arg->expr[k]->src.inc_max = 1; arg->expr[k]->src.exc_max = 1; } arg->expr[k]->dst.min = colormap->entry[arg->pos[j]].color[i]; arg->expr[k]->dst.inc_min = 1; arg->expr[k]->dst.exc_min = 0; arg->expr[k]->dst.max = colormap->entry[arg->pos[j]].color[i]; arg->expr[k]->dst.inc_max = 1; arg->expr[k]->dst.exc_max = 0; } else if (colormap->method == CM_EXACT) { arg->expr[k]->src.min = colormap->entry[arg->pos[j]].value; arg->expr[k]->src.inc_min = 1; arg->expr[k]->src.exc_min = 0; arg->expr[k]->src.max = colormap->entry[arg->pos[j]].value; arg->expr[k]->src.inc_max = 1; arg->expr[k]->src.exc_max = 0; arg->expr[k]->dst.min = colormap->entry[arg->pos[j]].color[i]; arg->expr[k]->dst.inc_min = 1; arg->expr[k]->dst.exc_min = 0; arg->expr[k]->dst.max = colormap->entry[arg->pos[j]].color[i]; arg->expr[k]->dst.inc_max = 1; arg->expr[k]->dst.exc_max = 0; } RASTER_DEBUGF(4, "expr[%d]->src (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)", k, arg->expr[k]->src.min, arg->expr[k]->src.max, arg->expr[k]->src.inc_min, arg->expr[k]->src.inc_max, arg->expr[k]->src.exc_min, arg->expr[k]->src.exc_max ); RASTER_DEBUGF(4, "expr[%d]->dst (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)", k, arg->expr[k]->dst.min, arg->expr[k]->dst.max, arg->expr[k]->dst.inc_min, arg->expr[k]->dst.inc_max, arg->expr[k]->dst.exc_min, arg->expr[k]->dst.exc_max ); k++; } /* EXACT has one last expression for catching all uncaught values */ if (colormap->method == CM_EXACT) { arg->expr[k]->src.min = 0; arg->expr[k]->src.inc_min = 1; arg->expr[k]->src.exc_min = 1; arg->expr[k]->src.max = 0; arg->expr[k]->src.inc_max = 1; arg->expr[k]->src.exc_max = 1; arg->expr[k]->dst.min = 0; arg->expr[k]->dst.inc_min = 1; arg->expr[k]->dst.exc_min = 0; arg->expr[k]->dst.max = 0; arg->expr[k]->dst.inc_max = 1; arg->expr[k]->dst.exc_max = 0; RASTER_DEBUGF(4, "expr[%d]->src (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)", k, arg->expr[k]->src.min, arg->expr[k]->src.max, arg->expr[k]->src.inc_min, arg->expr[k]->src.inc_max, arg->expr[k]->src.exc_min, arg->expr[k]->src.exc_max ); RASTER_DEBUGF(4, "expr[%d]->dst (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)", k, arg->expr[k]->dst.min, arg->expr[k]->dst.max, arg->expr[k]->dst.inc_min, arg->expr[k]->dst.inc_max, arg->expr[k]->dst.exc_min, arg->expr[k]->dst.exc_max ); k++; } /* call rt_band_reclass */ arg->band = rt_band_reclass(band, PT_8BUI, 0, 0, arg->expr, arg->nexpr); if (arg->band == NULL) { rterror("rt_raster_colormap: Could not reclassify band"); _rti_colormap_arg_destroy(arg); return NULL; } /* add reclassified band to raster */ if (rt_raster_add_band(arg->raster, arg->band, rt_raster_get_num_bands(arg->raster)) < 0) { rterror("rt_raster_colormap: Could not add reclassified band to output raster"); _rti_colormap_arg_destroy(arg); return NULL; } } rtnraster = arg->raster; arg->raster = NULL; _rti_colormap_arg_destroy(arg); return rtnraster; }