/* * Copyright (C) 1994. James Darrell McCauley. (darrell@mccauley-usa.com) * http://mccauley-usa.com/ * * This program is free software under the GPL (>=v2) * Read the file GPL.TXT coming with GRASS for details. * * 1/2006: moved to libgis from v.sample/v.drape for clone removal *************************************************** */ #include #include #include #include #include /* prototypes */ static double raster_sample_nearest (int fd, struct Cell_head *window, struct Categories *cats, double north, double east, int usedesc); static double raster_sample_bilinear (int fd, struct Cell_head *window, struct Categories *cats, double north, double east, int usedesc); static double raster_sample_cubic (int fd, struct Cell_head *window, struct Categories *cats, double north, double east, int usedesc); static double scancatlabel (char *); static void raster_row_error(struct Cell_head *window, double north, double east); /*! * \function double G_get_raster_sample (int fd, struct Cell_head *window, * struct Categories *cats, double north, double east, * int usedesc, INTERP_TYPE itype) * \brief extract a cell value from raster map at given northing and * easting with a sampled 3x3 window using a specified interpolation * method * * \param fd file descriptor * \param window * \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 */ double G_get_raster_sample (int fd, struct Cell_head *window, struct Categories *cats, double north, double east, int usedesc, INTERP_TYPE itype) { double retval; switch (itype) { case NEAREST: retval = raster_sample_nearest(fd, window, cats, north, east, usedesc); break; case BILINEAR: retval = raster_sample_bilinear(fd, window, cats, north, east, usedesc); break; case CUBIC: retval = raster_sample_cubic(fd, window, cats, north, east, usedesc); break; default: G_fatal_error(_("unknown interpolation type")); } return retval; } static double raster_sample_nearest (int fd, struct Cell_head *window, struct Categories *cats, double north, double east, int usedesc) { int row, col; double predicted; DCELL *maprow = G_allocate_d_raster_buf(); /* convert northing and easting to row and col, resp */ row = (int) G_northing_to_row (north, window); col = (int) G_easting_to_col (east, window); if (G_get_d_raster_row (fd, maprow, row) < 0) raster_row_error(window, north, east); if (G_is_d_null_value(&(maprow[col]))) { predicted = 0.0; } else if (usedesc) { char *buf = G_get_cat(maprow[col], cats); G_squeeze(buf); predicted = scancatlabel(buf); } else { predicted = maprow[col]; } G_free(maprow); return predicted; } static double raster_sample_bilinear (int fd, struct Cell_head *window, struct Categories *cats, double north, double east, int usedesc) { int i, row, col; double grid[2][2], tmp1, tmp2; DCELL *arow = G_allocate_d_raster_buf (); DCELL *brow = G_allocate_d_raster_buf (); /* convert northing and easting to row and col, resp */ row = (int) G_northing_to_row (north, window); col = (int) G_easting_to_col (east, window); if (G_get_d_raster_row (fd, arow, row) < 0) raster_row_error(window, north, east); /*- * we need 2x2 pixels to do the interpolation. First we decide if we * need the previous or next map row */ if (row == 0) { /* arow is at top, must get row below */ if (G_get_d_raster_row (fd, brow, row + 1) < 0) raster_row_error(window, north, east); } else if (row+1 == G_window_rows ()) { /* amaprow is at bottom, get the one above it */ /* brow = arow; */ for(i = 0; i < G_window_cols(); ++i) brow[i] = arow[i]; row--; if (G_get_d_raster_row (fd, arow, row) < 0) raster_row_error(window, north, east); } else if (north - G_row_to_northing ((double) row + 0.5, window) > 0) { /* north is above a horizontal centerline going through arow */ /* brow = arow; */ for(i = 0; i < G_window_cols(); ++i) brow[i] = arow[i]; row--; if (G_get_d_raster_row (fd, arow, row) < 0) raster_row_error(window, north, east); } else { /* north is below a horizontal centerline going through arow */ if (G_get_d_raster_row (fd, brow, row+1) < 0) raster_row_error(window, north, east); } /*- * next, we decide if we need the column to the right or left of the * current column using a procedure similar to above */ if (col+1 == G_window_cols()) col--; else if (east - G_col_to_easting((double) col + 0.5, window) < 0) col--; /*- * 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 = G_get_cat ((int)arow[col], cats)); grid[0][0] = scancatlabel (buf); G_squeeze(buf = G_get_cat ((int)arow[col+1], cats)); grid[0][1] = scancatlabel (buf); G_squeeze(buf = G_get_cat ((int)brow[col], cats)); grid[1][0] = scancatlabel (buf); G_squeeze(buf = G_get_cat ((int)brow[col+1], cats)); grid[1][1] = scancatlabel (buf); } else { grid[0][0] = (double) arow[col]; grid[0][1] = (double) arow[col + 1]; grid[1][0] = (double) brow[col]; grid[1][1] = (double) brow[col + 1]; } /* Treat NULL's as zero */ if (G_is_d_null_value(&(arow[col]))) grid[0][0] = 0.0; if (G_is_d_null_value(&(arow[col+1]))) grid[0][1] = 0.0; if (G_is_d_null_value(&(brow[col]))) grid[1][0] = 0.0; if (G_is_d_null_value(&(brow[col+1]))) grid[1][1] = 0.0; east = fabs(G_col_to_easting((double)col, window) - east); while (east > window->ew_res) east -= window->ew_res; north = fabs(G_row_to_northing((double)row, window) - north); while (north > window->ns_res) north -= window->ns_res; /* we do two linear interpolations along the rows */ tmp1 = east * grid[0][1] + (window->ew_res - east) * grid[0][0]; tmp1 /= window->ew_res; tmp2 = east * grid[1][1] + (window->ew_res - east) * grid[1][0]; tmp2 /= window->ew_res; G_debug(3, "DIAG: r=%d c=%d t1=%g t2=%g\te=%g n=%g", row, col, tmp1, tmp2, east, north); G_debug(3, "DIAG: %g %g\n %g %g", grid[0][0], grid[0][1], grid[1][0], grid[1][1]); /*- * Now we interpolate along a line parallel to columns * and passing through easting */ G_free(arow); G_free(brow); return (north * tmp2 + (window->ns_res - north) * tmp1) / window->ns_res; } static double raster_sample_cubic (int fd, struct Cell_head *window, struct Categories *cats, double north, double east, int usedesc) { int i, row, col; double grid[4][4], tmp[4]; DCELL *arow = G_allocate_d_raster_buf(); DCELL *brow = G_allocate_d_raster_buf(); DCELL *crow = G_allocate_d_raster_buf(); DCELL *drow = G_allocate_d_raster_buf(); /* convert northing and easting to row and col, resp */ row = G_northing_to_row(north, window); col = G_easting_to_col(east, window); if (G_get_d_raster_row(fd, arow, row) < 0) raster_row_error(window, north, east); /* we need 4x4 pixels to do the interpolation. */ if (row == 0) { /* row containing sample is at top, must get three rows below */ if (G_get_d_raster_row(fd, brow, row + 1) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, crow, row + 2) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, drow, row + 3) < 0) raster_row_error(window, north, east); } else if (row == 1) { /* must get row above and tow rows below */ for (i = 0; i < G_window_cols(); ++i) brow[i] = arow[i]; if (G_get_d_raster_row(fd, arow, row - 1) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, crow, row + 1) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, drow, row + 2) < 0) raster_row_error(window, north, east); row--; } else if (row + 1 == G_window_rows()) { /* arow is at bottom, get the three above it */ for (i = 0; i < G_window_cols(); ++i) drow[i] = arow[i]; if (G_get_d_raster_row(fd, arow, row - 3) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, brow, row - 2) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, crow, row - 1) < 0) raster_row_error(window, north, east); row -= 3; } else if (row + 2 == G_window_rows()) { /* arow is next to bottom, get the one below and two above it */ for (i = 0; i < G_window_cols(); ++i) crow[i] = arow[i]; if (G_get_d_raster_row(fd, arow, row - 2) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, brow, row - 1) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, drow, row + 1) < 0) raster_row_error(window, north, east); row -= 2; } else if (north - G_row_to_northing((double)row + 0.5, window) > 0) { /* * north is above a horizontal centerline going through arow. need two * above and one below */ for (i = 0; i < G_window_cols(); ++i) crow[i] = arow[i]; if (G_get_d_raster_row(fd, arow, row - 2) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, brow, row - 1) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, drow, row + 1) < 0) raster_row_error(window, north, east); row -= 2; } else { /* * north is below a horizontal centerline going through arow need one * above and two below */ for (i = 0; i < G_window_cols(); ++i) brow[i] = arow[i]; if (G_get_d_raster_row(fd, arow, row - 1) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, crow, row + 1) < 0) raster_row_error(window, north, east); if (G_get_d_raster_row(fd, drow, row + 2) < 0) raster_row_error(window, north, east); row--; } /* * Next, we decide if we need columns to the right and/or left of the * current column using a procedure similar to above */ if (col == 0 || col == 1) col = 0; else if (col + 1 == G_window_cols()) col -= 3; else if (col + 2 == G_window_cols()) col -= 2; else if (east - G_col_to_easting((double)col + 0.5, window) < 0) /* east is left of center */ col -= 2; else col--; /* * 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) { G_squeeze(buf = G_get_cat(arow[col + i], cats)); grid[0][i] = scancatlabel(buf); G_squeeze(buf = G_get_cat(brow[col + i], cats)); grid[1][i] = scancatlabel(buf); G_squeeze(buf = G_get_cat(crow[col + i], cats)); grid[2][i] = scancatlabel(buf); G_squeeze(buf = G_get_cat(drow[col + i], cats)); grid[3][i] = scancatlabel(buf); } } else { for (i = 0; i < 4; ++i) { grid[0][i] = (double)arow[col + i]; grid[1][i] = (double)brow[col + i]; grid[2][i] = (double)crow[col + i]; grid[3][i] = (double)drow[col + i]; } } /* Treat NULL cells as 0.0 */ for (i = 0; i < 4; i++) { if (G_is_d_null_value(&(arow[col + i]))) grid[0][i] = 0.0; if (G_is_d_null_value(&(brow[col + i]))) grid[1][i] = 0.0; if (G_is_d_null_value(&(crow[col + i]))) grid[2][i] = 0.0; if (G_is_d_null_value(&(drow[col + i]))) grid[3][i] = 0.0; } /* this needs work here */ east = fabs(G_col_to_easting((double)col + 1, window) - east); while (east > window->ew_res) east -= window->ew_res; east /= window->ew_res; north = fabs(G_row_to_northing((double)row + 1, window) - north); while (north > window->ns_res) north -= window->ns_res; north /= window->ns_res; /* we do four cubic convolutions along the rows */ for (i = 0; i < 4; ++i) tmp[i] = east * (east * (east * (grid[i][3] - grid[i][2] + grid[i][1] - grid[i][0]) + (grid[i][2] - grid[i][3] - 2 * grid[i][1] + 2 * grid[i][0])) + (grid[i][2] - grid[i][0])) + grid[i][1]; #ifdef DEBUG for (i = 0; i < 4; ++i) { for (j = 0; j < 4; ++j) fprintf(stderr, "%g ", grid[i][j]); fprintf(stderr, "\n"); } G_message("DIAG: (%d,%d) 1=%3.2g 2=%3.2g 3=%3.2g 4=%3.2g\te=%g n=%g", row, col, tmp[0], tmp[1], tmp[2], tmp[3], east, north); #endif G_free(arow); G_free(brow); G_free(crow); G_free(drow); /* user horner's method again for the final interpolation */ return (north * (north * (north * (tmp[3] - tmp[2] + tmp[1] - tmp[0]) + (tmp[2] - tmp[3] - 2 * tmp[1] + 2 * tmp[0])) + (tmp[2] - tmp[0])) + tmp[1]); } static double scancatlabel (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; } static void raster_row_error(struct Cell_head *window, double north, double east) { G_debug(3, "DIAG: \tRegion is: n=%g s=%g e=%g w=%g", window->north, window->south, window->east, window->west); G_debug(3, " \tData point is north=%g east=%g", north, east); G_fatal_error(_("problem reading raster cell file")); }