static void _rti_iterator_arg_callback_clean(_rti_iterator_arg _param) { int i = 0; int y = 0; for (i = 0; i < _param->count; i++) { RASTER_DEBUGF(5, "empty at @ %p", _param->empty.values); RASTER_DEBUGF(5, "values at @ %p", _param->arg->values[i]); if (_param->arg->values[i] == _param->empty.values) { _param->arg->values[i] = NULL; _param->arg->nodata[i] = NULL; continue; } for (y = 0; y < _param->dimension.rows; y++) { rtdealloc(_param->arg->values[i][y]); rtdealloc(_param->arg->nodata[i][y]); } rtdealloc(_param->arg->values[i]); rtdealloc(_param->arg->nodata[i]); _param->arg->values[i] = NULL; _param->arg->nodata[i] = NULL; } }
static void _rti_colormap_arg_destroy(_rti_colormap_arg arg) { int i = 0; if (arg->raster != NULL) { rt_band band = NULL; for (i = rt_raster_get_num_bands(arg->raster) - 1; i >= 0; i--) { band = rt_raster_get_band(arg->raster, i); if (band != NULL) rt_band_destroy(band); } rt_raster_destroy(arg->raster); } if (arg->nexpr) { for (i = 0; i < arg->nexpr; i++) { if (arg->expr[i] != NULL) rtdealloc(arg->expr[i]); } rtdealloc(arg->expr); } if (arg->npos) rtdealloc(arg->pos); rtdealloc(arg); arg = NULL; }
static void test_gdal_drivers() { int i; uint32_t size; rt_gdaldriver drv = NULL; drv = (rt_gdaldriver) rt_raster_gdal_drivers(&size, 1); CU_ASSERT(drv != NULL); for (i = 0; i < size; i++) { CU_ASSERT(strlen(drv[i].short_name)); rtdealloc(drv[i].short_name); rtdealloc(drv[i].long_name); rtdealloc(drv[i].create_options); } rtdealloc(drv); }
/** * CUnit error handler * Log message in a global var instead of printing in stderr * * CAUTION: Not stop execution on rterror case !!! */ static void cu_error_reporter(const char *fmt, va_list ap) { char *msg; /** This is a GNU extension. * Dunno how to handle errors here. */ if (!lw_vasprintf (&msg, fmt, ap)) { va_end (ap); return; } strncpy(cu_error_msg, msg, MAX_CUNIT_MSG_LENGTH); rtdealloc(msg); }
static void test_gdal_rasterize() { rt_raster raster; char srs[] = "PROJCS[\"unnamed\",GEOGCS[\"unnamed ellipse\",DATUM[\"unknown\",SPHEROID[\"unnamed\",6370997,0]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]],PROJECTION[\"Lambert_Azimuthal_Equal_Area\"],PARAMETER[\"latitude_of_center\",45],PARAMETER[\"longitude_of_center\",-100],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],UNIT[\"Meter\",1],AUTHORITY[\"EPSG\",\"2163\"]]"; const char wkb_hex[] = "010300000001000000050000000000000080841ec100000000600122410000000080841ec100000000804f22410000000040e81dc100000000804f22410000000040e81dc100000000600122410000000080841ec10000000060012241"; const char *pos = wkb_hex; unsigned char *wkb = NULL; int wkb_len = 0; int i; double scale_x = 100; double scale_y = -100; rt_pixtype pixtype[] = {PT_8BUI}; double init[] = {0}; double value[] = {1}; double nodata[] = {0}; uint8_t nodata_mask[] = {1}; /* hex to byte */ wkb_len = (int) ceil(((double) strlen(wkb_hex)) / 2); wkb = (unsigned char *) rtalloc(sizeof(unsigned char) * wkb_len); for (i = 0; i < wkb_len; i++) { sscanf(pos, "%2hhx", &wkb[i]); pos += 2; } raster = rt_raster_gdal_rasterize( wkb, wkb_len, srs, 1, pixtype, init, value, nodata, nodata_mask, NULL, NULL, &scale_x, &scale_y, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); CU_ASSERT(raster != NULL); CU_ASSERT_EQUAL(rt_raster_get_width(raster), 100); CU_ASSERT_EQUAL(rt_raster_get_height(raster), 100); CU_ASSERT_NOT_EQUAL(rt_raster_get_num_bands(raster), 0); CU_ASSERT_DOUBLE_EQUAL(rt_raster_get_x_offset(raster), -500000, DBL_EPSILON); CU_ASSERT_DOUBLE_EQUAL(rt_raster_get_y_offset(raster), 600000, DBL_EPSILON); rtdealloc(wkb); cu_free_raster(raster); }
static void test_gdal_polygonize() { int i; rt_raster rt; int nPols = 0; rt_geomval gv = NULL; char *wkt = NULL; rt = fillRasterToPolygonize(1, -1.0); CU_ASSERT(rt_raster_has_band(rt, 0)); nPols = 0; gv = rt_raster_gdal_polygonize(rt, 0, TRUE, &nPols); #ifdef GDALFPOLYGONIZE CU_ASSERT_DOUBLE_EQUAL(gv[0].val, 1.8, FLT_EPSILON); #else CU_ASSERT_DOUBLE_EQUAL(gv[0].val, 2.0, 1.); #endif wkt = lwgeom_to_text((const LWGEOM *) gv[0].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((3 1,3 2,2 2,2 3,1 3,1 6,2 6,2 7,3 7,3 8,5 8,5 6,3 6,3 3,4 3,5 3,5 1,3 1))"); rtdealloc(wkt); CU_ASSERT_DOUBLE_EQUAL(gv[1].val, 0.0, FLT_EPSILON); wkt = lwgeom_to_text((const LWGEOM *) gv[1].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((3 3,3 6,6 6,6 3,3 3))"); rtdealloc(wkt); #ifdef GDALFPOLYGONIZE CU_ASSERT_DOUBLE_EQUAL(gv[2].val, 2.8, FLT_EPSILON); #else CU_ASSERT_DOUBLE_EQUAL(gv[2].val, 3.0, 1.); #endif wkt = lwgeom_to_text((const LWGEOM *) gv[2].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((5 1,5 3,6 3,6 6,5 6,5 8,6 8,6 7,7 7,7 6,8 6,8 3,7 3,7 2,6 2,6 1,5 1))"); rtdealloc(wkt); CU_ASSERT_DOUBLE_EQUAL(gv[3].val, 0.0, FLT_EPSILON); wkt = lwgeom_to_text((const LWGEOM *) gv[3].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((0 0,0 9,9 9,9 0,0 0),(6 7,6 8,3 8,3 7,2 7,2 6,1 6,1 3,2 3,2 2,3 2,3 1,6 1,6 2,7 2,7 3,8 3,8 6,7 6,7 7,6 7))"); rtdealloc(wkt); for (i = 0; i < nPols; i++) lwgeom_free((LWGEOM *) gv[i].geom); rtdealloc(gv); cu_free_raster(rt); /* Second test: NODATA value = 1.8 */ #ifdef GDALFPOLYGONIZE rt = fillRasterToPolygonize(1, 1.8); #else rt = fillRasterToPolygonize(1, 2.0); #endif /* We can check rt_raster_has_band here too */ CU_ASSERT(rt_raster_has_band(rt, 0)); nPols = 0; gv = rt_raster_gdal_polygonize(rt, 0, TRUE, &nPols); /* for (i = 0; i < nPols; i++) { wkt = lwgeom_to_text((const LWGEOM *) gv[i].geom); printf("(i, val, geom) = (%d, %f, %s)\n", i, gv[i].val, wkt); rtdealloc(wkt); } */ #ifdef GDALFPOLYGONIZE CU_ASSERT_DOUBLE_EQUAL(gv[1].val, 0.0, FLT_EPSILON); wkt = lwgeom_to_text((const LWGEOM *) gv[1].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((3 3,3 6,6 6,6 3,3 3))"); rtdealloc(wkt); CU_ASSERT_DOUBLE_EQUAL(gv[2].val, 2.8, FLT_EPSILON); wkt = lwgeom_to_text((const LWGEOM *) gv[2].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((5 1,5 3,6 3,6 6,5 6,5 8,6 8,6 7,7 7,7 6,8 6,8 3,7 3,7 2,6 2,6 1,5 1))"); rtdealloc(wkt); CU_ASSERT_DOUBLE_EQUAL(gv[3].val, 0.0, FLT_EPSILON); wkt = lwgeom_to_text((const LWGEOM *) gv[3].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((0 0,0 9,9 9,9 0,0 0),(6 7,6 8,3 8,3 7,2 7,2 6,1 6,1 3,2 3,2 2,3 2,3 1,6 1,6 2,7 2,7 3,8 3,8 6,7 6,7 7,6 7))"); rtdealloc(wkt); #else CU_ASSERT_DOUBLE_EQUAL(gv[0].val, 0.0, 1.); wkt = lwgeom_to_text((const LWGEOM *) gv[0].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((3 3,3 6,6 6,6 3,3 3))"); rtdealloc(wkt); CU_ASSERT_DOUBLE_EQUAL(gv[1].val, 3.0, 1.); wkt = lwgeom_to_text((const LWGEOM *) gv[1].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((5 1,5 3,6 3,6 6,5 6,5 8,6 8,6 7,7 7,7 6,8 6,8 3,7 3,7 2,6 2,6 1,5 1))"); rtdealloc(wkt); CU_ASSERT_DOUBLE_EQUAL(gv[2].val, 0.0, 1.); wkt = lwgeom_to_text((const LWGEOM *) gv[2].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((0 0,0 9,9 9,9 0,0 0),(6 7,6 8,3 8,3 7,2 7,2 6,1 6,1 3,2 3,2 2,3 2,3 1,6 1,6 2,7 2,7 3,8 3,8 6,7 6,7 7,6 7))"); rtdealloc(wkt); #endif for (i = 0; i < nPols; i++) lwgeom_free((LWGEOM *) gv[i].geom); rtdealloc(gv); cu_free_raster(rt); /* Third test: NODATA value = 2.8 */ #ifdef GDALFPOLYGONIZE rt = fillRasterToPolygonize(1, 2.8); #else rt = fillRasterToPolygonize(1, 3.0); #endif /* We can check rt_raster_has_band here too */ CU_ASSERT(rt_raster_has_band(rt, 0)); nPols = 0; gv = rt_raster_gdal_polygonize(rt, 0, TRUE, &nPols); /* for (i = 0; i < nPols; i++) { wkt = lwgeom_to_text((const LWGEOM *) gv[i].geom); printf("(i, val, geom) = (%d, %f, %s)\n", i, gv[i].val, wkt); rtdealloc(wkt); } */ #ifdef GDALFPOLYGONIZE CU_ASSERT_DOUBLE_EQUAL(gv[0].val, 1.8, FLT_EPSILON); CU_ASSERT_DOUBLE_EQUAL(gv[3].val, 0.0, FLT_EPSILON); wkt = lwgeom_to_text((const LWGEOM *) gv[3].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((0 0,0 9,9 9,9 0,0 0),(6 7,6 8,3 8,3 7,2 7,2 6,1 6,1 3,2 3,2 2,3 2,3 1,6 1,6 2,7 2,7 3,8 3,8 6,7 6,7 7,6 7))"); rtdealloc(wkt); #else CU_ASSERT_DOUBLE_EQUAL(gv[0].val, 2.0, 1.); CU_ASSERT_DOUBLE_EQUAL(gv[2].val, 0.0, 1.); wkt = lwgeom_to_text((const LWGEOM *) gv[2].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((0 0,0 9,9 9,9 0,0 0),(6 7,6 8,3 8,3 7,2 7,2 6,1 6,1 3,2 3,2 2,3 2,3 1,6 1,6 2,7 2,7 3,8 3,8 6,7 6,7 7,6 7))"); rtdealloc(wkt); #endif wkt = lwgeom_to_text((const LWGEOM *) gv[0].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((3 1,3 2,2 2,2 3,1 3,1 6,2 6,2 7,3 7,3 8,5 8,5 6,3 6,3 3,4 3,5 3,5 1,3 1))"); rtdealloc(wkt); CU_ASSERT_DOUBLE_EQUAL(gv[1].val, 0.0, FLT_EPSILON); wkt = lwgeom_to_text((const LWGEOM *) gv[1].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((3 3,3 6,6 6,6 3,3 3))"); rtdealloc(wkt); for (i = 0; i < nPols; i++) lwgeom_free((LWGEOM *) gv[i].geom); rtdealloc(gv); cu_free_raster(rt); /* Fourth test: NODATA value = 0 */ rt = fillRasterToPolygonize(1, 0.0); /* We can check rt_raster_has_band here too */ CU_ASSERT(rt_raster_has_band(rt, 0)); nPols = 0; gv = rt_raster_gdal_polygonize(rt, 0, TRUE, &nPols); /* for (i = 0; i < nPols; i++) { wkt = lwgeom_to_text((const LWGEOM *) gv[i].geom); printf("(i, val, geom) = (%d, %f, %s)\n", i, gv[i].val, wkt); rtdealloc(wkt); } */ #ifdef GDALFPOLYGONIZE CU_ASSERT_DOUBLE_EQUAL(gv[0].val, 1.8, FLT_EPSILON); #else CU_ASSERT_DOUBLE_EQUAL(gv[0].val, 2.0, 1.); #endif wkt = lwgeom_to_text((const LWGEOM *) gv[0].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((3 1,3 2,2 2,2 3,1 3,1 6,2 6,2 7,3 7,3 8,5 8,5 6,3 6,3 3,4 3,5 3,5 1,3 1))"); rtdealloc(wkt); #ifdef GDALFPOLYGONIZE CU_ASSERT_DOUBLE_EQUAL(gv[1].val, 2.8, FLT_EPSILON); #else CU_ASSERT_DOUBLE_EQUAL(gv[1].val, 3.0, 1.); #endif wkt = lwgeom_to_text((const LWGEOM *) gv[1].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((5 1,5 3,6 3,6 6,5 6,5 8,6 8,6 7,7 7,7 6,8 6,8 3,7 3,7 2,6 2,6 1,5 1))"); rtdealloc(wkt); for (i = 0; i < nPols; i++) lwgeom_free((LWGEOM *) gv[i].geom); rtdealloc(gv); cu_free_raster(rt); /* Last test: There is no NODATA value (all values are valid) */ rt = fillRasterToPolygonize(0, 0.0); /* We can check rt_raster_has_band here too */ CU_ASSERT(rt_raster_has_band(rt, 0)); nPols = 0; gv = rt_raster_gdal_polygonize(rt, 0, TRUE, &nPols); /* for (i = 0; i < nPols; i++) { wkt = lwgeom_to_text((const LWGEOM *) gv[i].geom); printf("(i, val, geom) = (%d, %f, %s)\n", i, gv[i].val, wkt); rtdealloc(wkt); } */ #ifdef GDALFPOLYGONIZE CU_ASSERT_DOUBLE_EQUAL(gv[0].val, 1.8, FLT_EPSILON); #else CU_ASSERT_DOUBLE_EQUAL(gv[0].val, 2.0, 1.); #endif wkt = lwgeom_to_text((const LWGEOM *) gv[0].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((3 1,3 2,2 2,2 3,1 3,1 6,2 6,2 7,3 7,3 8,5 8,5 6,3 6,3 3,4 3,5 3,5 1,3 1))"); rtdealloc(wkt); CU_ASSERT_DOUBLE_EQUAL(gv[1].val, 0.0, FLT_EPSILON); wkt = lwgeom_to_text((const LWGEOM *) gv[1].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((3 3,3 6,6 6,6 3,3 3))"); rtdealloc(wkt); #ifdef GDALFPOLYGONIZE CU_ASSERT_DOUBLE_EQUAL(gv[2].val, 2.8, FLT_EPSILON); #else CU_ASSERT_DOUBLE_EQUAL(gv[2].val, 3.0, 1.); #endif wkt = lwgeom_to_text((const LWGEOM *) gv[2].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((5 1,5 3,6 3,6 6,5 6,5 8,6 8,6 7,7 7,7 6,8 6,8 3,7 3,7 2,6 2,6 1,5 1))"); rtdealloc(wkt); CU_ASSERT_DOUBLE_EQUAL(gv[3].val, 0.0, FLT_EPSILON); wkt = lwgeom_to_text((const LWGEOM *) gv[3].geom); CU_ASSERT_STRING_EQUAL(wkt, "POLYGON((0 0,0 9,9 9,9 0,0 0),(6 7,6 8,3 8,3 7,2 7,2 6,1 6,1 3,2 3,2 2,3 2,3 1,6 1,6 2,7 2,7 3,8 3,8 6,7 6,7 7,6 7))"); rtdealloc(wkt); for (i = 0; i < nPols; i++) lwgeom_free((LWGEOM *) gv[i].geom); rtdealloc(gv); cu_free_raster(rt); }
/** * 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; }
/** * Returns new band with values reclassified * * @param srcband : the band who's values will be reclassified * @param pixtype : pixel type of the new band * @param hasnodata : indicates if the band has a nodata value * @param nodataval : nodata value for the new band * @param exprset : array of rt_reclassexpr structs * @param exprcount : number of elements in expr * * @return a new rt_band or NULL on error */ rt_band rt_band_reclass( rt_band srcband, rt_pixtype pixtype, uint32_t hasnodata, double nodataval, rt_reclassexpr *exprset, int exprcount ) { rt_band band = NULL; uint32_t width = 0; uint32_t height = 0; int numval = 0; int memsize = 0; void *mem = NULL; uint32_t src_hasnodata = 0; double src_nodataval = 0.0; int isnodata = 0; int rtn; uint32_t x; uint32_t y; int i; double or = 0; double ov = 0; double nr = 0; double nv = 0; int do_nv = 0; rt_reclassexpr expr = NULL; assert(NULL != srcband); assert(NULL != exprset && exprcount > 0); RASTER_DEBUGF(4, "exprcount = %d", exprcount); RASTER_DEBUGF(4, "exprset @ %p", exprset); /* source nodata */ src_hasnodata = rt_band_get_hasnodata_flag(srcband); if (src_hasnodata) rt_band_get_nodata(srcband, &src_nodataval); /* size of memory block to allocate */ width = rt_band_get_width(srcband); height = rt_band_get_height(srcband); numval = width * height; memsize = rt_pixtype_size(pixtype) * numval; mem = (int *) rtalloc(memsize); if (!mem) { rterror("rt_band_reclass: Could not allocate memory for band"); return 0; } /* initialize to zero */ if (!hasnodata) { memset(mem, 0, memsize); } /* initialize to nodataval */ else { int32_t checkvalint = 0; uint32_t checkvaluint = 0; double checkvaldouble = 0; float checkvalfloat = 0; switch (pixtype) { case PT_1BB: { uint8_t *ptr = mem; uint8_t clamped_initval = rt_util_clamp_to_1BB(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvalint = ptr[0]; break; } case PT_2BUI: { uint8_t *ptr = mem; uint8_t clamped_initval = rt_util_clamp_to_2BUI(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvalint = ptr[0]; break; } case PT_4BUI: { uint8_t *ptr = mem; uint8_t clamped_initval = rt_util_clamp_to_4BUI(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvalint = ptr[0]; break; } case PT_8BSI: { int8_t *ptr = mem; int8_t clamped_initval = rt_util_clamp_to_8BSI(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvalint = ptr[0]; break; } case PT_8BUI: { uint8_t *ptr = mem; uint8_t clamped_initval = rt_util_clamp_to_8BUI(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvalint = ptr[0]; break; } case PT_16BSI: { int16_t *ptr = mem; int16_t clamped_initval = rt_util_clamp_to_16BSI(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvalint = ptr[0]; break; } case PT_16BUI: { uint16_t *ptr = mem; uint16_t clamped_initval = rt_util_clamp_to_16BUI(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvalint = ptr[0]; break; } case PT_32BSI: { int32_t *ptr = mem; int32_t clamped_initval = rt_util_clamp_to_32BSI(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvalint = ptr[0]; break; } case PT_32BUI: { uint32_t *ptr = mem; uint32_t clamped_initval = rt_util_clamp_to_32BUI(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvaluint = ptr[0]; break; } case PT_32BF: { float *ptr = mem; float clamped_initval = rt_util_clamp_to_32F(nodataval); for (i = 0; i < numval; i++) ptr[i] = clamped_initval; checkvalfloat = ptr[0]; break; } case PT_64BF: { double *ptr = mem; for (i = 0; i < numval; i++) ptr[i] = nodataval; checkvaldouble = ptr[0]; break; } default: { rterror("rt_band_reclass: Unknown pixeltype %d", pixtype); rtdealloc(mem); return 0; } } /* Overflow checking */ rt_util_dbl_trunc_warning( nodataval, checkvalint, checkvaluint, checkvalfloat, checkvaldouble, pixtype ); } RASTER_DEBUGF(3, "rt_band_reclass: width = %d height = %d", width, height); band = rt_band_new_inline(width, height, pixtype, hasnodata, nodataval, mem); if (!band) { rterror("rt_band_reclass: Could not create new band"); rtdealloc(mem); return 0; } rt_band_set_ownsdata_flag(band, 1); /* we DO own this data!!! */ RASTER_DEBUGF(3, "rt_band_reclass: new band @ %p", band); for (x = 0; x < width; x++) { for (y = 0; y < height; y++) { rtn = rt_band_get_pixel(srcband, x, y, &ov, &isnodata); /* error getting value, skip */ if (rtn != ES_NONE) { RASTER_DEBUGF(3, "Cannot get value at %d, %d", x, y); continue; } RASTER_DEBUGF(4, "(x, y, ov, isnodata) = (%d, %d, %f, %d)", x, y, ov, isnodata); do { do_nv = 0; /* no data*/ if (hasnodata && isnodata) { do_nv = 1; break; } for (i = 0; i < exprcount; i++) { expr = exprset[i]; /* ov matches min and max*/ if ( FLT_EQ(expr->src.min, ov) && FLT_EQ(expr->src.max, ov) ) { do_nv = 1; break; } /* process min */ if (( expr->src.exc_min && ( expr->src.min > ov || FLT_EQ(expr->src.min, ov) )) || ( expr->src.inc_min && ( expr->src.min < ov || FLT_EQ(expr->src.min, ov) )) || ( expr->src.min < ov )) { /* process max */ if (( expr->src.exc_max && ( ov > expr->src.max || FLT_EQ(expr->src.max, ov) )) || ( expr->src.inc_max && ( ov < expr->src.max || FLT_EQ(expr->src.max, ov) )) || ( ov < expr->src.max )) { do_nv = 1; break; } } } } while (0); /* no expression matched, do not continue */ if (!do_nv) continue; RASTER_DEBUGF(3, "Using exprset[%d] unless NODATA", i); /* converting a value from one range to another range OldRange = (OldMax - OldMin) NewRange = (NewMax - NewMin) NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin */ /* NODATA */ if (hasnodata && isnodata) { nv = nodataval; } /* "src" min and max is the same, prevent division by zero set nv to "dst" min, which should be the same as "dst" max */ else if (FLT_EQ(expr->src.max, expr->src.min)) { nv = expr->dst.min; } else { or = expr->src.max - expr->src.min; nr = expr->dst.max - expr->dst.min; nv = (((ov - expr->src.min) * nr) / or) + expr->dst.min; /* if dst range is from high to low */ if (expr->dst.min > expr->dst.max) { if (nv > expr->dst.min) nv = expr->dst.min; else if (nv < expr->dst.max) nv = expr->dst.max; } /* if dst range is from low to high */ else { if (nv < expr->dst.min) nv = expr->dst.min; else if (nv > expr->dst.max) nv = expr->dst.max; } } /* round the value for integers */ switch (pixtype) { case PT_1BB: case PT_2BUI: case PT_4BUI: case PT_8BSI: case PT_8BUI: case PT_16BSI: case PT_16BUI: case PT_32BSI: case PT_32BUI: nv = round(nv); break; default: break; } RASTER_DEBUGF(4, "(%d, %d) ov: %f or: %f - %f nr: %f - %f nv: %f" , x , y , ov , (NULL != expr) ? expr->src.min : 0 , (NULL != expr) ? expr->src.max : 0 , (NULL != expr) ? expr->dst.min : 0 , (NULL != expr) ? expr->dst.max : 0 , nv ); if (rt_band_set_pixel(band, x, y, nv, NULL) != ES_NONE) { rterror("rt_band_reclass: Could not assign value to new band"); rt_band_destroy(band); rtdealloc(mem); return 0; } expr = NULL; } } return band; }
static void _rti_iterator_arg_destroy(_rti_iterator_arg _param) { int i = 0; if (_param->raster != NULL) rtdealloc(_param->raster); if (_param->isempty != NULL) rtdealloc(_param->isempty); if (_param->width != NULL) rtdealloc(_param->width); if (_param->height != NULL) rtdealloc(_param->height); if (_param->band.rtband != NULL) rtdealloc(_param->band.rtband); if (_param->band.hasnodata != NULL) rtdealloc(_param->band.hasnodata); if (_param->band.isnodata != NULL) rtdealloc(_param->band.isnodata); if (_param->band.nodataval != NULL) rtdealloc(_param->band.nodataval); if (_param->band.minval != NULL) rtdealloc(_param->band.minval); if (_param->offset != NULL) { for (i = 0; i < _param->count; i++) { if (_param->offset[i] == NULL) continue; rtdealloc(_param->offset[i]); } rtdealloc(_param->offset); } if (_param->empty.values != NULL) { for (i = 0; i < _param->dimension.rows; i++) { if (_param->empty.values[i] == NULL) continue; rtdealloc(_param->empty.values[i]); } rtdealloc(_param->empty.values); } if (_param->empty.nodata != NULL) { for (i = 0; i < _param->dimension.rows; i++) { if (_param->empty.nodata[i] == NULL) continue; rtdealloc(_param->empty.nodata[i]); } rtdealloc(_param->empty.nodata); } if (_param->arg != NULL) { if (_param->arg->values != NULL) rtdealloc(_param->arg->values); if (_param->arg->nodata != NULL) rtdealloc(_param->arg->nodata); if (_param->arg->src_pixel != NULL) { for (i = 0; i < _param->count; i++) { if (_param->arg->src_pixel[i] == NULL) continue; rtdealloc(_param->arg->src_pixel[i]); } rtdealloc(_param->arg->src_pixel); } rtdealloc(_param->arg); } rtdealloc(_param); }