/*! * \file lib/gis/adj_cellhd.c * * \brief GIS Library - CELL header adjustment. * * (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 Original author CERL */ #include #include #include #include #define LL_TOLERANCE 10 /* TODO: find good thresholds */ /* deviation measured in cells */ static double llepsilon = 0.01; static double fpepsilon = 1.0e-9; static int ll_wrap(struct Cell_head *cellhd); static int ll_check_ns(struct Cell_head *cellhd); static int ll_check_ew(struct Cell_head *cellhd); /*! * \brief Adjust cell header. * * This function fills in missing parts of the input cell header (or * region). It also makes projection-specific adjustments. The * cellhd structure must have its north, south, east, * west, and proj fields set. * * If row_flag is true, then the north-south resolution is * computed from the number of rows in the cellhd * structure. Otherwise the number of rows is computed from the * north-south resolution in the structure, similarly for * col_flag and the number of columns and the east-west * resolution. * * Note: 3D values are not adjusted. * * \param[in,out] cellhd pointer to Cell_head structure * \param row_flag compute n-s resolution * \param col_flag compute e-w resolution */ void G_adjust_Cell_head(struct Cell_head *cellhd, int row_flag, int col_flag) { double old_res; if (!row_flag) { if (cellhd->ns_res <= 0) G_fatal_error(_("Illegal n-s resolution value: %g"), cellhd->ns_res); } else { if (cellhd->rows <= 0) G_fatal_error(_("Illegal number of rows: %d" " (resolution is %g)"), cellhd->rows, cellhd->ns_res); } if (!col_flag) { if (cellhd->ew_res <= 0) G_fatal_error(_("Illegal e-w resolution value: %g"), cellhd->ew_res); } else { if (cellhd->cols <= 0) G_fatal_error(_("Illegal number of columns: %d" " (resolution is %g)"), cellhd->cols, cellhd->ew_res); } /* check the edge values */ if (cellhd->north <= cellhd->south) { if (cellhd->proj == PROJECTION_LL) G_fatal_error(_("North must be north of South," " but %g (north) <= %g (south"), cellhd->north, cellhd->south); else G_fatal_error(_("North must be larger than South," " but %g (north) <= %g (south"), cellhd->north, cellhd->south); } ll_wrap(cellhd); if (cellhd->east <= cellhd->west) G_fatal_error(_("East must be larger than West," " but %g (east) <= %g (west)"), cellhd->east, cellhd->west); /* compute rows and columns, if not set */ if (!row_flag) { cellhd->rows = (cellhd->north - cellhd->south + cellhd->ns_res / 2.0) / cellhd->ns_res; if (cellhd->rows == 0) cellhd->rows = 1; } if (!col_flag) { cellhd->cols = (cellhd->east - cellhd->west + cellhd->ew_res / 2.0) / cellhd->ew_res; if (cellhd->cols == 0) cellhd->cols = 1; } if (cellhd->cols < 0) { G_fatal_error(_("Invalid coordinates: negative number of columns")); } if (cellhd->rows < 0) { G_fatal_error(_("Invalid coordinates: negative number of rows")); } /* (re)compute the resolutions */ old_res = cellhd->ns_res; cellhd->ns_res = (cellhd->north - cellhd->south) / cellhd->rows; if (old_res > 0 && fabs(old_res - cellhd->ns_res) / old_res > 0.01) G_verbose_message(_("NS resolution has been changed")); old_res = cellhd->ew_res; cellhd->ew_res = (cellhd->east - cellhd->west) / cellhd->cols; if (old_res > 0 && fabs(old_res - cellhd->ew_res) / old_res > 0.01) G_verbose_message(_("EW resolution has been changed")); if (fabs(cellhd->ns_res - cellhd->ew_res) / cellhd->ns_res > 0.01) G_verbose_message(_("NS and EW resolutions are different")); ll_check_ns(cellhd); ll_check_ew(cellhd); } /*! * \brief Adjust cell header for 3D values. * * This function fills in missing parts of the input cell header (or * region). It also makes projection-specific adjustments. The * cellhd structure must have its north, south, east, * west, and proj fields set. * * If row_flag is true, then the north-south resolution is computed * from the number of rows in the cellhd structure. * Otherwise the number of rows is computed from the north-south * resolution in the structure, similarly for col_flag and the * number of columns and the east-west resolution. * * If depth_flag is true, top-bottom resolution is calculated * from depths. * If depth_flag are false, number of depths is calculated from * top-bottom resolution. * * \warning This function can cause segmentation fault without any warning * when it is called with Cell_head top and bottom set to zero. * * \param[in,out] cellhd pointer to Cell_head structure * \param row_flag compute n-s resolution * \param col_flag compute e-w resolution * \param depth_flag compute t-b resolution */ void G_adjust_Cell_head3(struct Cell_head *cellhd, int row_flag, int col_flag, int depth_flag) { double old_res; if (!row_flag) { if (cellhd->ns_res <= 0) G_fatal_error(_("Illegal n-s resolution value: %g"), cellhd->ns_res); if (cellhd->ns_res3 <= 0) G_fatal_error(_("Illegal n-s resolution value for 3D: %g"), cellhd->ns_res3); } else { if (cellhd->rows <= 0) G_fatal_error(_("Illegal number of rows: %d" " (resolution is %g)"), cellhd->rows, cellhd->ns_res); if (cellhd->rows3 <= 0) G_fatal_error(_("Illegal number of rows for 3D: %d" " (resolution is %g)"), cellhd->rows3, cellhd->ns_res3); } if (!col_flag) { if (cellhd->ew_res <= 0) G_fatal_error(_("Illegal e-w resolution value: %g"), cellhd->ew_res); if (cellhd->ew_res3 <= 0) G_fatal_error(_("Illegal e-w resolution value for 3D: %g"), cellhd->ew_res3); } else { if (cellhd->cols <= 0) G_fatal_error(_("Illegal number of columns: %d" " (resolution is %g)"), cellhd->cols, cellhd->ew_res); if (cellhd->cols3 <= 0) G_fatal_error(_("Illegal number of columns for 3D: %d" " (resolution is %g)"), cellhd->cols3, cellhd->ew_res3); } if (!depth_flag) { if (cellhd->tb_res <= 0) G_fatal_error(_("Illegal t-b resolution value: %g"), cellhd->tb_res); } else { if (cellhd->depths <= 0) G_fatal_error(_("Illegal depths value: %d"), cellhd->depths); } /* check the edge values */ if (cellhd->north <= cellhd->south) { if (cellhd->proj == PROJECTION_LL) G_fatal_error(_("North must be north of South," " but %g (north) <= %g (south"), cellhd->north, cellhd->south); else G_fatal_error(_("North must be larger than South," " but %g (north) <= %g (south"), cellhd->north, cellhd->south); } ll_wrap(cellhd); if (cellhd->east <= cellhd->west) G_fatal_error(_("East must be larger than West," " but %g (east) <= %g (west)"), cellhd->east, cellhd->west); if (cellhd->top <= cellhd->bottom) G_fatal_error(_("Top must be larger than Bottom," " but %g (top) <= %g (bottom)"), cellhd->top, cellhd->bottom); /* compute rows and columns, if not set */ if (!row_flag) { cellhd->rows = (cellhd->north - cellhd->south + cellhd->ns_res / 2.0) / cellhd->ns_res; if (cellhd->rows == 0) cellhd->rows = 1; cellhd->rows3 = (cellhd->north - cellhd->south + cellhd->ns_res3 / 2.0) / cellhd->ns_res3; if (cellhd->rows3 == 0) cellhd->rows3 = 1; } if (!col_flag) { cellhd->cols = (cellhd->east - cellhd->west + cellhd->ew_res / 2.0) / cellhd->ew_res; if (cellhd->cols == 0) cellhd->cols = 1; cellhd->cols3 = (cellhd->east - cellhd->west + cellhd->ew_res3 / 2.0) / cellhd->ew_res3; if (cellhd->cols3 == 0) cellhd->cols3 = 1; } if (!depth_flag) { cellhd->depths = (cellhd->top - cellhd->bottom + cellhd->tb_res / 2.0) / cellhd->tb_res; if (cellhd->depths == 0) cellhd->depths = 1; } if (cellhd->cols < 0 || cellhd->cols3 < 0) { G_fatal_error(_("Invalid coordinates: negative number of columns")); } if (cellhd->rows < 0 || cellhd->rows3 < 0) { G_fatal_error(_("Invalid coordinates: negative number of rows")); } if (cellhd->depths < 0) { G_fatal_error(_("Invalid coordinates: negative number of depths")); } /* (re)compute the resolutions */ old_res = cellhd->ns_res; cellhd->ns_res = (cellhd->north - cellhd->south) / cellhd->rows; if (old_res > 0 && fabs(old_res - cellhd->ns_res) / old_res > 0.01) G_verbose_message(_("NS resolution has been changed")); old_res = cellhd->ew_res; cellhd->ew_res = (cellhd->east - cellhd->west) / cellhd->cols; if (old_res > 0 && fabs(old_res - cellhd->ew_res) / old_res > 0.01) G_verbose_message(_("EW resolution has been changed")); if (fabs(cellhd->ns_res - cellhd->ew_res) / cellhd->ns_res > 0.01) G_verbose_message(_("NS and EW resolutions are different")); ll_check_ns(cellhd); ll_check_ew(cellhd); cellhd->ns_res3 = (cellhd->north - cellhd->south) / cellhd->rows3; cellhd->ew_res3 = (cellhd->east - cellhd->west) / cellhd->cols3; cellhd->tb_res = (cellhd->top - cellhd->bottom) / cellhd->depths; } static int ll_wrap(struct Cell_head *cellhd) { double shift; /* for lat/lon, force east larger than west, try to wrap to -180, 180 */ if (cellhd->proj != PROJECTION_LL) return 0; if (cellhd->east <= cellhd->west) { G_warning(_("East (%.15g) is not larger than West (%.15g)"), cellhd->east, cellhd->west); while (cellhd->east <= cellhd->west) cellhd->east += 360.0; } /* with east larger than west, * any 360 degree W-E extent can be represented within -360, 360 * but not within -180, 180 */ /* try to shift to within -180, 180 */ shift = 0; while (cellhd->west + shift >= 180) { shift -= 360.0; } while (cellhd->east + shift <= -180) { shift += 360.0; } /* try to shift to within -360, 360 */ while (cellhd->east + shift > 360) { shift -= 360.0; } while (cellhd->west + shift <= -360) { shift += 360.0; } if (shift) { cellhd->west += shift; cellhd->east += shift; } /* very liberal thresholds */ if (cellhd->north > 90.0 + LL_TOLERANCE) G_fatal_error(_("Illegal latitude for North: %g"), cellhd->north); if (cellhd->south < -90.0 - LL_TOLERANCE) G_fatal_error(_("Illegal latitude for South: %g"), cellhd->south); #if 0 /* disabled: allow W-E extents larger than 360 degree e.g. for display */ if (cellhd->west < -360.0 - LL_TOLERANCE) { G_debug(1, "East: %g", cellhd->east); G_fatal_error(_("Illegal longitude for West: %g"), cellhd->west); } if (cellhd->east > 360.0 + LL_TOLERANCE) { G_debug(1, "West: %g", cellhd->west); G_fatal_error(_("Illegal longitude for East: %g"), cellhd->east); } #endif return 1; } static int ll_check_ns(struct Cell_head *cellhd) { int lladjust; double diff; int ncells; /* lat/lon checks */ if (cellhd->proj != PROJECTION_LL) return 0; lladjust = 0; G_debug(3, "ll_check_ns: epsilon: %g", llepsilon); /* North, South: allow a half cell spill-over */ diff = (cellhd->north - cellhd->south) / cellhd->ns_res; ncells = (int) (diff + 0.5); diff -= ncells; if ((diff < 0 && diff < -fpepsilon) || (diff > 0 && diff > fpepsilon)) { G_verbose_message(_("NS extent does not match NS resolution: %g cells difference"), diff); } /* north */ diff = (cellhd->north - 90) / cellhd->ns_res; if (diff < 0) diff = -diff; if (cellhd->north < 90.0 && diff < 1.0 ) { G_verbose_message(_("%g cells missing to reach 90 degree north"), diff); if (diff < llepsilon && diff > fpepsilon) { G_verbose_message(_("Subtle input data rounding error of north boundary (%g)"), cellhd->north - 90.0); /* check only, do not modify cellhd->north = 90.0; lladjust = 1; */ } } if (cellhd->north > 90.0) { if (diff <= 0.5 + llepsilon) { G_important_message(_("90 degree north is exceeded by %g cells"), diff); if (diff < llepsilon && diff > fpepsilon) { G_verbose_message(_("Subtle input data rounding error of north boundary (%g)"), cellhd->north - 90.0); G_debug(1, "North of north in seconds: %g", (cellhd->north - 90.0) * 3600); /* check only, do not modify cellhd->north = 90.0; lladjust = 1; */ } diff = diff - 0.5; if (diff < 0) diff = -diff; if (diff < llepsilon && diff > fpepsilon) { G_verbose_message(_("Subtle input data rounding error of north boundary (%g)"), cellhd->north - 90.0 - cellhd->ns_res / 2.0); G_debug(1, "North of north + 0.5 cells in seconds: %g", (cellhd->north - 90.0 - cellhd->ns_res / 2.0) * 3600); /* check only, do not modify cellhd->north = 90.0 + cellhd->ns_res / 2.0; lladjust = 1; */ } } else G_fatal_error(_("Illegal latitude for North: %g"), cellhd->north); } /* south */ diff = (cellhd->south + 90) / cellhd->ns_res; if (diff < 0) diff = -diff; if (cellhd->south > -90.0 && diff < 1.0 ) { G_verbose_message(_("%g cells missing to reach 90 degree south"), diff); if (diff < llepsilon && diff > fpepsilon) { G_verbose_message(_("Subtle input data rounding error of south boundary (%g)"), cellhd->south + 90.0); /* check only, do not modify cellhd->south = -90.0; lladjust = 1; */ } } if (cellhd->south < -90.0) { if (diff <= 0.5 + llepsilon) { G_important_message(_("90 degree south is exceeded by %g cells"), diff); if (diff < llepsilon && diff > fpepsilon) { G_verbose_message(_("Subtle input data rounding error of south boundary (%g)"), cellhd->south + 90); G_debug(1, "South of south in seconds: %g", (-cellhd->south - 90) * 3600); /* check only, do not modify cellhd->south = -90.0; lladjust = 1; */ } diff = diff - 0.5; if (diff < 0) diff = -diff; if (diff < llepsilon && diff > fpepsilon) { G_verbose_message(_("Subtle input data rounding error of south boundary (%g)"), cellhd->south + 90 + cellhd->ns_res / 2.0); G_debug(1, "South of south + 0.5 cells in seconds: %g", (-cellhd->south - 90 - cellhd->ns_res / 2.0) * 3600); /* check only, do not modify cellhd->south = -90.0 - cellhd->ns_res / 2.0; lladjust = 1; */ } } else G_fatal_error(_("Illegal latitude for South: %g"), cellhd->south); } if (lladjust) cellhd->ns_res = (cellhd->north - cellhd->south) / cellhd->rows; return lladjust; } static int ll_check_ew(struct Cell_head *cellhd) { int lladjust; double diff; int ncells; /* lat/lon checks */ if (cellhd->proj != PROJECTION_LL) return 0; lladjust = 0; G_debug(3, "ll_check_ew: epsilon: %g", llepsilon); /* west - east, no adjustment */ diff = (cellhd->east - cellhd->west) / cellhd->ew_res; ncells = (int) (diff + 0.5); diff -= ncells; if ((diff < 0 && diff < -fpepsilon) || (diff > 0 && diff > fpepsilon)) { G_verbose_message(_("EW extent does not match EW resolution: %g cells difference"), diff); } if (cellhd->east - cellhd->west > 360.0) { diff = (cellhd->east - cellhd->west - 360.0) / cellhd->ew_res; if (diff > fpepsilon) G_important_message(_("360 degree EW extent is exceeded by %g cells" " (East: %g, West: %g)"), diff, cellhd->east, cellhd->west); } else if (cellhd->east - cellhd->west < 360.0) { diff = (360.0 - (cellhd->east - cellhd->west)) / cellhd->ew_res; if (diff < 1.0 && diff > fpepsilon) G_verbose_message(_("%g cells missing to cover 360 degree EW extent"), diff); } return lladjust; } /*! * \brief Adjust window for lat/lon. * * This function tries to automatically fix fp precision issues and * adjust rounding errors for lat/lon. * * Note: 3D values are not adjusted. * * \param[in,out] cellhd pointer to Cell_head structure * \return 1 if window was adjusted * \return 0 if window was not adjusted */ int G_adjust_window_ll(struct Cell_head *cellhd) { int ll_adjust, res_adj; double dsec, dsec2; char buf[100], buf2[100]; double diff; double old, new; struct Cell_head cellhds; /* everything in seconds, not degrees */ /* lat/lon checks */ if (cellhd->proj != PROJECTION_LL) return 0; /* put everything through ll_format + ll_scan */ G_llres_format(cellhd->ns_res, buf); if (G_llres_scan(buf, &new) != 1) G_fatal_error(_("Invalid NS resolution")); cellhd->ns_res = new; G_llres_format(cellhd->ew_res, buf); if (G_llres_scan(buf, &new) != 1) G_fatal_error(_("Invalid EW resolution")); cellhd->ew_res = new; G_lat_format(cellhd->north, buf); if (G_lat_scan(buf, &new) != 1) G_fatal_error(_("Invalid North")); cellhd->north = new; G_lat_format(cellhd->south, buf); if (G_lat_scan(buf, &new) != 1) G_fatal_error(_("Invalid South")); cellhd->south = new; G_lon_format(cellhd->west, buf); if (G_lon_scan(buf, &new) != 1) G_fatal_error(_("Invalid West")); cellhd->west = new; G_lon_format(cellhd->east, buf); if (G_lon_scan(buf, &new) != 1) G_fatal_error(_("Invalid East")); cellhd->east = new; /* convert to seconds */ cellhds = *cellhd; old = cellhds.ns_res * 3600; sprintf(buf, "%f", old); sscanf(buf, "%lf", &new); cellhds.ns_res = new; old = cellhds.ew_res * 3600; sprintf(buf, "%f", old); sscanf(buf, "%lf", &new); cellhds.ew_res = new; old = cellhds.north * 3600; sprintf(buf, "%f", old); sscanf(buf, "%lf", &new); cellhds.north = new; old = cellhds.south * 3600; sprintf(buf, "%f", old); sscanf(buf, "%lf", &new); cellhds.south = new; old = cellhds.west * 3600; sprintf(buf, "%f", old); sscanf(buf, "%lf", &new); cellhds.west = new; old = cellhds.east * 3600; sprintf(buf, "%f", old); sscanf(buf, "%lf", &new); cellhds.east = new; ll_adjust = 0; /* N - S */ /* resolution */ res_adj = 0; old = cellhds.ns_res; if (old > 0.4) { /* round to nearest 0.1 sec */ dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = fabs(dsec2 - dsec) / dsec; if (diff > 0 && diff < llepsilon) { G_llres_format(old / 3600, buf); G_llres_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("NS resolution rounded from %s to %s"), buf, buf2); ll_adjust = 1; res_adj = 1; cellhds.ns_res = new; } } if (res_adj) { double n_off, s_off; old = cellhds.north; dsec = old * 10; dsec2 = floor(dsec + 0.5); diff = fabs(dsec2 - dsec) / (cellhds.ns_res * 10); n_off = diff; old = cellhds.south; dsec = old * 10; dsec2 = floor(dsec + 0.5); diff = fabs(dsec2 - dsec) / (cellhds.ns_res * 10); s_off = diff; if (n_off < llepsilon || n_off <= s_off) { old = cellhds.north; dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = n_off; if (diff > 0 && diff < llepsilon) { G_lat_format(old / 3600, buf); G_lat_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("North rounded from %s to %s"), buf, buf2); cellhds.north = new; } old = cellhds.south; new = cellhds.north - cellhds.ns_res * cellhds.rows; diff = fabs(new - old) / cellhds.ns_res; if (diff > 0) { G_lat_format(old / 3600, buf); G_lat_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("South adjusted from %s to %s"), buf, buf2); } cellhds.south = new; } else { old = cellhds.south; dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = s_off; if (diff > 0 && diff < llepsilon) { G_lat_format(old / 3600, buf); G_lat_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("South rounded from %s to %s"), buf, buf2); cellhds.south = new; } old = cellhds.north; new = cellhds.south + cellhds.ns_res * cellhds.rows; diff = fabs(new - old) / cellhds.ns_res; if (diff > 0) { G_lat_format(old / 3600, buf); G_lat_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("North adjusted from %s to %s"), buf, buf2); } cellhds.north = new; } } else { old = cellhds.north; dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = fabs(dsec2 - dsec) / (cellhds.ns_res * 10); if (diff > 0 && diff < llepsilon) { G_lat_format(old / 3600, buf); G_lat_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("North rounded from %s to %s"), buf, buf2); ll_adjust = 1; cellhds.north = new; } old = cellhds.south; dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = fabs(dsec2 - dsec) / (cellhds.ns_res * 10); if (diff > 0 && diff < llepsilon) { G_lat_format(old / 3600, buf); G_lat_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("South rounded from %s to %s"), buf, buf2); ll_adjust = 1; cellhds.south = new; } } cellhds.ns_res = (cellhds.north - cellhds.south) / cellhds.rows; /* E - W */ /* resolution */ res_adj = 0; old = cellhds.ew_res; if (old > 0.4) { /* round to nearest 0.1 sec */ dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = fabs(dsec2 - dsec) / dsec; if (diff > 0 && diff < llepsilon) { G_llres_format(old / 3600, buf); G_llres_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("EW resolution rounded from %s to %s"), buf, buf2); ll_adjust = 1; res_adj = 1; cellhds.ew_res = new; } } if (res_adj) { double w_off, e_off; old = cellhds.west; dsec = old * 10; dsec2 = floor(dsec + 0.5); diff = fabs(dsec2 - dsec) / (cellhds.ew_res * 10); w_off = diff; old = cellhds.east; dsec = old * 10; dsec2 = floor(dsec + 0.5); diff = fabs(dsec2 - dsec) / (cellhds.ew_res * 10); e_off = diff; if (w_off < llepsilon || w_off <= e_off) { old = cellhds.west; dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = w_off; if (diff > 0 && diff < llepsilon) { G_lon_format(old / 3600, buf); G_lon_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("West rounded from %s to %s"), buf, buf2); cellhds.west = new; } old = cellhds.east; new = cellhds.west + cellhds.ew_res * cellhds.cols; diff = fabs(new - old) / cellhds.ew_res; if (diff > 0) { G_lon_format(old / 3600, buf); G_lon_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("East adjusted from %s to %s"), buf, buf2); } cellhds.east = new; } else { old = cellhds.east; dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = e_off; if (diff > 0 && diff < llepsilon) { G_lon_format(old / 3600, buf); G_lon_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("East rounded from %s to %s"), buf, buf2); cellhds.east = new; } old = cellhds.west; new = cellhds.east - cellhds.ew_res * cellhds.cols; diff = fabs(new - cellhds.west) / cellhds.ew_res; if (diff > 0) { G_lon_format(old / 3600, buf); G_lon_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("West adjusted from %s to %s"), buf, buf2); } cellhds.west = new; } } else { old = cellhds.west; dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = fabs(dsec2 - dsec) / (cellhds.ew_res * 10); if (diff > 0 && diff < llepsilon) { G_lon_format(old / 3600, buf); G_lon_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("West rounded from %s to %s"), buf, buf2); ll_adjust = 1; cellhds.west = new; } old = cellhds.east; dsec = old * 10; dsec2 = floor(dsec + 0.5); new = dsec2 / 10; diff = fabs(dsec2 - dsec) / (cellhds.ew_res * 10); if (diff > 0 && diff < llepsilon) { G_lon_format(old / 3600, buf); G_lon_format(new / 3600, buf2); if (strcmp(buf, buf2)) G_verbose_message(_("East rounded from %s to %s"), buf, buf2); ll_adjust = 1; cellhds.east = new; } } cellhds.ew_res = (cellhds.east - cellhds.west) / cellhds.cols; cellhd->ns_res = cellhds.ns_res / 3600; cellhd->ew_res = cellhds.ew_res / 3600; cellhd->north = cellhds.north / 3600; cellhd->south = cellhds.south / 3600; cellhd->west = cellhds.west / 3600; cellhd->east = cellhds.east / 3600; return ll_adjust; }