#include #include /*********************************************************** char * G_adjust_Cell_head (cellhd, row_flag, col_flag) struct Cell_head *cellhd; This function fills in missing parts of the input cell header. It also makes projection-specific adjustments (such as lat-lon). The north, south, east, west parts of the header must be set before calling this routine. The other parts depend on row_flag and col_flag: row_flag TRUE the rows in the cell header is already set the n-s resolution is to be computed. row_flag FALSE the n-s resolution in the cell header is already set, the rows are to be computed. (the resolution may be adjusted to conform to the computed rows) col_flag TRUE the cols in the cell header is already set the e-w resolution is to be computed. col_flag FALSE the e-w resolution in the cell header is already set, the cols are to be computed. (the resolution may be adjusted to conform to the computed cols) returns an error message, or NULL if ok note: don't free this error message. ************************************************************/ /*! * \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. * * 3D values are not adjusted. * * This routine returns NULL if execution occurs without error, otherwise it returns * an error message. * * \param cellhd * \param row_flag * \param col_flag * \return char * */ char *G_adjust_Cell_head(struct Cell_head *cellhd,int row_flag,int col_flag) { if (!row_flag) { if (cellhd->ns_res <= 0) return (_("Illegal n-s resolution value")); } else { if (cellhd->rows <= 0) return (_("Illegal row value")); } if (!col_flag) { if (cellhd->ew_res <= 0) return (_("Illegal e-w resolution value")); } else { if (cellhd->cols <= 0) return (_("Illegal col value")); } /* for lat/lon, check north,south. force east larger than west */ if (cellhd->proj == PROJECTION_LL) { double epsilon_ns, epsilon_ew; /* TODO: find good thresholds */ epsilon_ns= 1. / cellhd->rows * 0.001; epsilon_ew= .000001; /* epsilon_ew calculation doesn't work due to cellhd->cols update/global wraparound below */ G_debug(3,"G_adjust_Cell_head: epsilon_ns: %g, epsilon_ew: %g", epsilon_ns, epsilon_ew); /* TODO: once working, change below G_warning to G_debug */ /* fix rounding problems if input map slightly exceeds the world definition -180 90 180 -90 */ if (cellhd->north > 90.0) { if ( ((cellhd->north - 90.0) < epsilon_ns) && ((cellhd->north - 90.0) > GRASS_EPSILON) ) { G_warning (_("Fixing subtle input data rounding error of north boundary (%g>%g)"), cellhd->north - 90.0, epsilon_ns); cellhd->north = 90.0; } else return (_("Illegal latitude for North")); } if (cellhd->south < -90.0) { if ( ((cellhd->south + 90.0) < epsilon_ns) && ((cellhd->south + 90.0) < GRASS_EPSILON) ) { G_warning (_("Fixing subtle input data rounding error of south boundary (%g>%g)"), cellhd->south + 90.0, epsilon_ns); cellhd->south = -90.0; } else return (_("Illegal latitude for South")); } /* DISABLED: this breaks global wrap-around G_debug(3,"G_adjust_Cell_head() cellhd->west: %f, devi: %g, eps: %g", cellhd->west, cellhd->west + 180.0, epsilon_ew); if ( (cellhd->west < -180.0) && ((cellhd->west + 180.0) < epsilon_ew) && ((cellhd->west + 180.0) < GRASS_EPSILON) ) { G_warning (_("Fixing subtle input data rounding error of west boundary (%g>%g)"), cellhd->west + 180.0, epsilon_ew); cellhd->west = -180.0; } G_debug(3,"G_adjust_Cell_head() cellhd->east: %f, devi: %g, eps: %g", cellhd->east, cellhd->east - 180.0, epsilon_ew); if ( (cellhd->east > 180.0) && ((cellhd->east - 180.0) > epsilon_ew) && ((cellhd->east - 180.0) > GRASS_EPSILON) ) { G_warning (_("Fixing subtle input data rounding error of east boundary (%g>%g)"), cellhd->east - 180.0, epsilon_ew); cellhd->east = 180.0; } */ while (cellhd->east <= cellhd->west) cellhd->east += 360.0; } /* check the edge values */ if (cellhd->north <= cellhd->south) { if (cellhd->proj == PROJECTION_LL) return (_("North must be north of South")); else return (_("North must be larger than South")); } if (cellhd->east <= cellhd->west) return (_("East must be larger than 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 || cellhd->rows < 0 ) { return (_("Invalid coordinates")); } /* (re)compute the resolutions */ cellhd->ns_res = (cellhd->north - cellhd->south) / cellhd->rows; cellhd->ew_res = (cellhd->east - cellhd->west) / cellhd->cols; return NULL; } /*! * \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. * * 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. * * This routine returns NULL if execution occurs without error, otherwise it returns * an error message. * * \param cellhd * \param row_flag * \param col_flag * \return char * */ char *G_adjust_Cell_head3(struct Cell_head *cellhd,int row_flag,int col_flag, int depth_flag) { if (!row_flag) { if (cellhd->ns_res <= 0) return (_("Illegal n-s resolution value")); if (cellhd->ns_res3 <= 0) return (_("Illegal n-s3 resolution value")); } else { if (cellhd->rows <= 0) return (_("Illegal row value")); if (cellhd->rows3 <= 0) return (_("Illegal row3 value")); } if (!col_flag) { if (cellhd->ew_res <= 0) return (_("Illegal e-w resolution value")); if (cellhd->ew_res3 <= 0) return (_("Illegal e-w3 resolution value")); } else { if (cellhd->cols <= 0) return (_("Illegal col value")); if (cellhd->cols3 <= 0) return (_("Illegal col3 value")); } if (!depth_flag) { if (cellhd->tb_res <= 0) return (_("Illegal t-b3 resolution value")); } else { if (cellhd->depths <= 0) return (_("Illegal depths value")); } /* for lat/lon, check north,south. force east larger than west */ if (cellhd->proj == PROJECTION_LL) { double epsilon_ns, epsilon_ew; /* TODO: find good thresholds */ epsilon_ns= 1. / cellhd->rows * 0.001; epsilon_ew= .000001; /* epsilon_ew calculation doesn't work due to cellhd->cols update/global wraparound below */ G_debug(3,"G_adjust_Cell_head: epsilon_ns: %g, epsilon_ew: %g", epsilon_ns, epsilon_ew); /* TODO: once working, change below G_warning to G_debug */ /* fix rounding problems if input map slightly exceeds the world definition -180 90 180 -90 */ if (cellhd->north > 90.0) { if ( ((cellhd->north - 90.0) < epsilon_ns) && ((cellhd->north - 90.0) > GRASS_EPSILON) ) { G_warning (_("Fixing subtle input data rounding error of north boundary (%g>%g)"), cellhd->north - 90.0, epsilon_ns); cellhd->north = 90.0; } else return (_("Illegal latitude for North")); } if (cellhd->south < -90.0) { if ( ((cellhd->south + 90.0) < epsilon_ns) && ((cellhd->south + 90.0) < GRASS_EPSILON) ) { G_warning (_("Fixing subtle input data rounding error of south boundary (%g>%g)"), cellhd->south + 90.0, epsilon_ns); cellhd->south = -90.0; } else return (_("Illegal latitude for South")); } /* DISABLED: this breaks global wrap-around G_debug(3,"G_adjust_Cell_head3() cellhd->west: %f, devi: %g, eps: %g", cellhd->west, cellhd->west + 180.0, epsilon_ew); if ( (cellhd->west < -180.0) && ((cellhd->west + 180.0) < epsilon_ew) && ((cellhd->west + 180.0) < GRASS_EPSILON) ) { G_warning (_("Fixing subtle input data rounding error of west boundary (%g>%g)"), cellhd->west + 180.0, epsilon_ew); cellhd->west = -180.0; } G_debug(3,"G_adjust_Cell_head3() cellhd->east: %f, devi: %g, eps: %g", cellhd->east, cellhd->east - 180.0, epsilon_ew); if ( (cellhd->east > 180.0) && ((cellhd->east - 180.0) > epsilon_ew) && ((cellhd->east - 180.0) > GRASS_EPSILON) ) { G_warning (_("Fixing subtle input data rounding error of east boundary (%g>%g)"), cellhd->east - 180.0, epsilon_ew); cellhd->east = 180.0; } */ while (cellhd->east <= cellhd->west) cellhd->east += 360.0; } /* check the edge values */ if (cellhd->north <= cellhd->south) { if (cellhd->proj == PROJECTION_LL) return (_("North must be north of South")); else return (_("North must be larger than South")); } if (cellhd->east <= cellhd->west) return (_("East must be larger than West")); if (cellhd->top <= cellhd->bottom) return (_("Top must be larger than 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->rows < 0 || cellhd->cols3 < 0 || cellhd->rows3 < 0 || cellhd->depths < 0 ) { return (_("Invalid coordinates")); } /* (re)compute the resolutions */ cellhd->ns_res = (cellhd->north - cellhd->south) / cellhd->rows; cellhd->ns_res3 = (cellhd->north - cellhd->south) / cellhd->rows3; cellhd->ew_res = (cellhd->east - cellhd->west) / cellhd->cols; cellhd->ew_res3 = (cellhd->east - cellhd->west) / cellhd->cols3; cellhd->tb_res = (cellhd->top - cellhd->bottom) / cellhd->depths; return NULL; }