/*! \file lib/raster/sample.c \brief Raster library - Sampling methods (extract a cell value from raster map) 1/2006: moved to libgis from v.sample/v.drape for clone removal (C) 2001-2009 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. \author James Darrell McCauley , http://mccauley-usa.com/ */ #include #include #include #include #include #include /* prototypes */ static double scancatlabel(const char *); /*! * \brief Extract a cell value from raster map. * * Extract a cell value from raster map at given northing and easting * with a sampled 3x3 window using a specified interpolation method. * * - NEAREST neighbor interpolation * - BILINEAR bilinear interpolation * - CUBIC cubic interpolation * * \param fd file descriptor * \param window region settings * \param cats categories * \param north northing position * \param east easting position * \param usedesc flag to scan category label * \param itype interpolation method * * \return cell value at given position */ DCELL Rast_get_sample(int fd, const struct Cell_head *window, struct Categories *cats, double north, double east, int usedesc, INTERP_TYPE itype) { double retval; switch (itype) { case INTERP_NEAREST: retval = Rast_get_sample_nearest(fd, window, cats, north, east, usedesc); break; case INTERP_BILINEAR: retval = Rast_get_sample_bilinear(fd, window, cats, north, east, usedesc); break; case INTERP_BICUBIC: retval = Rast_get_sample_cubic(fd, window, cats, north, east, usedesc); break; default: G_fatal_error("Rast_get_sample: %s", _("Unknown interpolation type")); } return retval; } /*! * \brief Extract a cell value from raster map (neighbor interpolation) * * Extract a cell value from raster map at given northing and easting * with a sampled 3x3 window using a neighbor interpolation. * * \param fd file descriptor * \param window region settings * \param cats categories * \param north northing position * \param east easting position * \param usedesc flag to scan category label * * \return cell value at given position */ DCELL Rast_get_sample_nearest(int fd, const struct Cell_head * window, struct Categories * cats, double north, double east, int usedesc) { int row, col; DCELL result; DCELL *maprow = Rast_allocate_d_buf(); /* convert northing and easting to row and col, resp */ row = (int)floor(Rast_northing_to_row(north, window)); col = (int)floor(Rast_easting_to_col(east, window)); if (row < 0 || row >= Rast_window_rows() || col < 0 || col >= Rast_window_cols()) { Rast_set_d_null_value(&result, 1); goto done; } Rast_get_d_row(fd, maprow, row); if (Rast_is_d_null_value(&maprow[col])) { Rast_set_d_null_value(&result, 1); goto done; } if (usedesc) { char *buf = Rast_get_c_cat((CELL *) & (maprow[col]), cats); G_squeeze(buf); result = scancatlabel(buf); } else result = maprow[col]; done: G_free(maprow); return result; } /*! * \brief Extract a cell value from raster map (bilinear interpolation). * * Extract a cell value from raster map at given northing and easting * with a sampled 3x3 window using a bilinear interpolation. * * \param fd file descriptor * \param window region settings * \param cats categories * \param north northing position * \param east easting position * \param usedesc flag to scan category label * * \return cell value at given position */ DCELL Rast_get_sample_bilinear(int fd, const struct Cell_head * window, struct Categories * cats, double north, double east, int usedesc) { int row, col; double grid[2][2]; DCELL *arow = Rast_allocate_d_buf(); DCELL *brow = Rast_allocate_d_buf(); double frow, fcol, trow, tcol; DCELL result; frow = Rast_northing_to_row(north, window); fcol = Rast_easting_to_col(east, window); /* convert northing and easting to row and col, resp */ row = (int)floor(frow - 0.5); col = (int)floor(fcol - 0.5); trow = frow - row - 0.5; tcol = fcol - col - 0.5; if (row < 0 || row + 1 >= Rast_window_rows() || col < 0 || col + 1 >= Rast_window_cols()) { Rast_set_d_null_value(&result, 1); goto done; } Rast_get_d_row(fd, arow, row); Rast_get_d_row(fd, brow, row + 1); if (Rast_is_d_null_value(&arow[col]) || Rast_is_d_null_value(&arow[col + 1]) || Rast_is_d_null_value(&brow[col]) || Rast_is_d_null_value(&brow[col + 1])) { Rast_set_d_null_value(&result, 1); goto done; } /*- * now were ready to do bilinear interpolation over * arow[col], arow[col+1], * brow[col], brow[col+1] */ if (usedesc) { char *buf; G_squeeze(buf = Rast_get_c_cat((int *)&(arow[col]), cats)); grid[0][0] = scancatlabel(buf); G_squeeze(buf = Rast_get_c_cat((CELL *) & (arow[col + 1]), cats)); grid[0][1] = scancatlabel(buf); G_squeeze(buf = Rast_get_c_cat((CELL *) & (brow[col]), cats)); grid[1][0] = scancatlabel(buf); G_squeeze(buf = Rast_get_c_cat((CELL *) & (brow[col + 1]), cats)); grid[1][1] = scancatlabel(buf); } else { grid[0][0] = arow[col]; grid[0][1] = arow[col + 1]; grid[1][0] = brow[col]; grid[1][1] = brow[col + 1]; } result = Rast_interp_bilinear(tcol, trow, grid[0][0], grid[0][1], grid[1][0], grid[1][1]); done: G_free(arow); G_free(brow); return result; } /*! * \brief Extract a cell value from raster map (cubic interpolation). * * Extract a cell value from raster map at given northing and easting * with a sampled 3x3 window using a cubic interpolation. * * \param fd file descriptor * \param window region settings * \param cats categories * \param north northing position * \param east easting position * \param usedesc flag to scan category label * * \return cell value at given position */ DCELL Rast_get_sample_cubic(int fd, const struct Cell_head * window, struct Categories * cats, double north, double east, int usedesc) { int i, j, row, col; double grid[4][4]; DCELL *rows[4]; double frow, fcol, trow, tcol; DCELL result; for (i = 0; i < 4; i++) rows[i] = Rast_allocate_d_buf(); frow = Rast_northing_to_row(north, window); fcol = Rast_easting_to_col(east, window); /* convert northing and easting to row and col, resp */ row = (int)floor(frow - 1.5); col = (int)floor(fcol - 1.5); trow = frow - row - 1.5; tcol = fcol - col - 1.5; if (row < 0 || row + 3 >= Rast_window_rows() || col < 0 || col + 3 >= Rast_window_cols()) { Rast_set_d_null_value(&result, 1); goto done; } for (i = 0; i < 4; i++) Rast_get_d_row(fd, rows[i], row + i); for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) if (Rast_is_d_null_value(&rows[i][col + j])) { Rast_set_d_null_value(&result, 1); goto done; } /* * now were ready to do cubic interpolation over * arow[col], arow[col+1], arow[col+2], arow[col+3], * brow[col], brow[col+1], brow[col+2], brow[col+3], * crow[col], crow[col+1], crow[col+2], crow[col+3], * drow[col], drow[col+1], drow[col+2], drow[col+3], */ if (usedesc) { char *buf; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { G_squeeze(buf = Rast_get_c_cat((CELL *) & (rows[i][col + j]), cats)); grid[i][j] = scancatlabel(buf); } } } else { for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) grid[i][j] = rows[i][col + j]; } result = Rast_interp_bicubic(tcol, trow, grid[0][0], grid[0][1], grid[0][2], grid[0][3], grid[1][0], grid[1][1], grid[1][2], grid[1][3], grid[2][0], grid[2][1], grid[2][2], grid[2][3], grid[3][0], grid[3][1], grid[3][2], grid[3][3]); done: for (i = 0; i < 4; i++) G_free(rows[i]); return result; } static double scancatlabel(const char *str) { double val; if (strcmp(str, "no data") != 0) sscanf(str, "%lf", &val); else { G_warning(_("\"no data\" label found; setting to zero")); val = 0.0; } return val; }