/*! \file lib/vector/Vlib/box.c \brief Vector library - bounding box Higher level functions for reading/writing/manipulating vectors. (C) 2001-2015 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 Radim Blazek */ #include #include #include /*! \brief Tests if point is in 3D box This function considers 3D point and 3D bounding box. \par Example \verbatim struct bound_box bbox; bbox.N = 135; bbox.S = 125; bbox.E = 220; bbox.W = 215; bbox.T = 340; bbox.B = 330; Vect_point_in_box(217, 130, 335, &bbox); \endverbatim \param x coordinate (W-E direction) \param y coordinate (S-N direction) \param z coordinate (B-T direction) \param Box boundary box \returns 1 if point is in box \returns 0 if point is not in box */ int Vect_point_in_box(double x, double y, double z, const struct bound_box *Box) { return (x >= Box->W && x <= Box->E && y >= Box->S && y <= Box->N && z >= Box->B && z <= Box->T); } /*! \brief Tests if point is in 2D box Only x and y are tested. Top and bottom of the bounding box are ignored. \param x coordinate (W-E direction) \param y coordinate (S-N direction) \param Box boundary box (only W, E, S, N are used) \returns 1 if point is in box \returns 0 if point is not in box */ int Vect_point_in_box_2d(double x, double y, const struct bound_box *Box) { return (x >= Box->W && x <= Box->E && y >= Box->S && y <= Box->N); } /*! \brief Tests for overlap of two boxes \param A boundary box A \param B boundary box B \return 1 boxes overlap \return 0 boxes do not overlap */ int Vect_box_overlap(const struct bound_box *A, const struct bound_box *B) { if (A->E < B->W || A->W > B->E || A->N < B->S || A->S > B->N || A->T < B->B || A->B > B->T) { return 0; } return 1; } /*! \brief Copy box B to box A \param A boundary A \param B boundary B \return 1 */ int Vect_box_copy(struct bound_box *A, const struct bound_box *B) { A->N = B->N; A->S = B->S; A->E = B->E; A->W = B->W; A->T = B->T; A->B = B->B; return 1; } /*! \brief Extend box A by box B \param A boundary A \param B boundary B \return 1 */ int Vect_box_extend(struct bound_box *A, const struct bound_box *B) { if (B->N > A->N) A->N = B->N; if (B->S < A->S) A->S = B->S; if (B->E > A->E) A->E = B->E; if (B->W < A->W) A->W = B->W; if (B->T > A->T) A->T = B->T; if (B->B < A->B) A->B = B->B; return 1; } /*! * \brief Clip coordinates to box, if necessary, lines extending outside of a box. * * A line represented by the coordinates x, y and c_x, c_y is clipped to * the window defined by s (south), n (north), w * (west), and e (east). Note that the following constraints must be * true: * w x and c_x are values to be compared to w and * e. The y and c_y are values to be compared to * s and n. * The x and c_x values returned lie between w and * e. The y and c_y values returned lie between * s and n. * * \param x, y coordinates (w, e) * \param c_x,c_y coordinates (s, n) * \param Box boundary box * * \return 1 if any clipping occurred * \return 0 otherwise */ int Vect_box_clip(double *x, double *y, double *c_x, double *c_y, const struct bound_box *Box) { int mod; mod = 0; if (*x < Box->W) { if (*c_x != *x) *y = *y + (Box->W - *x) / (*c_x - *x) * (*c_y - *y); *x = Box->W; mod = 1; } if (*x > Box->E) { if (*c_x != *x) *y = *y + (Box->E - *x) / (*c_x - *x) * (*c_y - *y); *x = Box->E; mod = 1; } if (*c_x < Box->W) { if (*c_x != *x) *c_y = *c_y + (Box->W - *c_x) / (*x - *c_x) * (*y - *c_y); *c_x = Box->W; mod = 1; } if (*c_x > Box->E) { if (*c_x != *x) *c_y = *c_y + (Box->E - *c_x) / (*x - *c_x) * (*y - *c_y); *c_x = Box->E; mod = 1; } if (*y < Box->S) { if (*c_y != *y) *x = *x + (Box->S - *y) / (*c_y - *y) * (*c_x - *x); *y = Box->S; mod = 1; } if (*y > Box->N) { if (*c_y != *y) *x = *x + (Box->N - *y) / (*c_y - *y) * (*c_x - *x); *y = Box->N; mod = 1; } if (*c_y < Box->S) { if (*c_y != *y) *c_x = *c_x + (Box->S - *c_y) / (*y - *c_y) * (*x - *c_x); *c_y = Box->S; mod = 1; } if (*c_y > Box->N) { if (*c_y != *y) *c_x = *c_x + (Box->N - *c_y) / (*y - *c_y) * (*x - *c_x); *c_y = Box->N; mod = 1; } return (mod); } /*! \brief Get bounding box of given feature Vector map must be open at topological level and built with level >= GV_BUILD_BASE. \param Map vector map \param line feature id \param[out] Box bounding box \return 1 on success \return 0 line is dead \return -1 on error */ int Vect_get_line_box(const struct Map_info *Map, int line, struct bound_box *Box) { struct Plus_head *Plus; struct P_line *Line; int type; static struct line_pnts *Points = NULL; Plus = (struct Plus_head *) &(Map->plus); if (line < 1 || line > Plus->n_lines) { G_warning(_("Attempt to access feature with invalid id (%d)"), line); return -1; } Line = Plus->Line[line]; if (Line == NULL) { /* dead */ Box->N = Box->S = Box->E = Box->W = Box->T = Box->B = 0. / 0.; return 0; } type = Line->type; /* GV_LINES: retrieve box from spatial index */ if (type & GV_LINES) { if (dig_find_line_box(Plus, line, Box) == 0) { G_warning(_("Unable to determine bbox for feature %d"), line); return -1; } if (!Vect_is_3d(Map)) { Box->T = PORT_DOUBLE_MAX; Box->B = -PORT_DOUBLE_MAX; } return 1; } /* all other: read line */ if (Points == NULL) Points = Vect_new_line_struct(); Vect_read_line(Map, Points, NULL, line); dig_line_box(Points, Box); if (!Vect_is_3d(Map)) { Box->T = PORT_DOUBLE_MAX; Box->B = -PORT_DOUBLE_MAX; } return 1; } /*! \brief Get bounding box of area Vector map must be open at topological level and built with level >= GV_BUILD_AREAS. \param Map vector map \param area area id \param[out] Box bounding box \return 1 on success \return 0 area is dead \return -1 on error */ int Vect_get_area_box(const struct Map_info *Map, int area, struct bound_box *Box) { struct Plus_head *Plus; struct P_area *Area; Plus = (struct Plus_head *) &(Map->plus); if (area < 1 || area > Plus->n_areas) { G_warning(_("Attempt to access area with invalid id (%d)"), area); return -1; } Area = Plus->Area[area]; if (Area == NULL) { /* dead */ Box->N = Box->S = Box->E = Box->W = Box->T = Box->B = 0. / 0.; return 0; } if (dig_find_area_box(Plus, area, Box) == 0) { G_warning(_("Unable to determine bbox for area %d"), area); return -1; } if (!Vect_is_3d(Map)) { Box->T = PORT_DOUBLE_MAX; Box->B = -PORT_DOUBLE_MAX; } return 1; } /*! \brief Get bounding box of isle Vector map must be open at topological level and built with level >= GV_BUILD_AREAS. \param Map vector map \param isle isle id \param[out] Box bounding box \return 1 on success \return 0 isle is dead / bounding box not found \return -1 on error */ int Vect_get_isle_box(const struct Map_info *Map, int isle, struct bound_box *Box) { struct Plus_head *Plus; struct P_isle *Isle; Plus = (struct Plus_head *) &(Map->plus); if (isle < 1 || isle > Plus->n_isles) { G_warning(_("Attempt to access area with invalid id (%d)"), isle); return -1; } Isle = Plus->Isle[isle]; if (Isle == NULL) { /* dead */ Box->N = Box->S = Box->E = Box->W = Box->T = Box->B = 0. / 0.; return 0; } if (dig_find_isle_box(Plus, isle, Box) == 0) { G_warning(_("Unable to determine bbox for isle %d"), isle); return -1; } if (!Vect_is_3d(Map)) { Box->T = PORT_DOUBLE_MAX; Box->B = -PORT_DOUBLE_MAX; } return 1; } /*! \brief Get bounding box of map (all features in the map) Requires level 2. On level 1 error code is returned. \param Map vector map \param[out] Box bounding box \return 1 on success \return 0 on error */ int Vect_get_map_box(const struct Map_info *Map, struct bound_box *Box) { const struct Plus_head *Plus; Plus = &(Map->plus); Vect_box_copy(Box, &(Plus->box)); if (Vect_level(Map) < 2) return 0; return 1; } /*! \brief Get bounding box of map on level 1 (all features in the map) This subroutine determines bounding box by reading all features sequentially. \param Map vector map \param[out] Box bounding box \return 1 on success \return 0 on error */ int Vect_get_map_box1(struct Map_info *Map, struct bound_box *Box) { int type; int first = TRUE; struct line_pnts *Points; struct bound_box line_box; Points = Vect_new_line_struct(); Vect_rewind(Map); G_verbose_message(_("Topology not available for vector map <%s>. " "Registering primitives..."), Vect_get_full_name(Map)); while (TRUE) { /* register line */ type = Vect_read_next_line(Map, Points, NULL); if (type == -1) { G_warning(_("Unable to read vector map")); return 0; } else if (type == -2) { break; } /* update box */ dig_line_box(Points, &line_box); if (first == TRUE) { Vect_box_copy(Box, &line_box); first = FALSE; } else Vect_box_extend(Box, &line_box); } Vect_destroy_line_struct(Points); return 1; } /*! \brief Copy region window to bounding box \param Window region structure (raster-based) \param[out] Box boundary box (vector-based) \return 1 on success \return 0 on error */ int Vect_region_box(const struct Cell_head *Window, struct bound_box *Box) { Box->N = Window->north; Box->S = Window->south; Box->E = Window->east; Box->W = Window->west; Box->T = PORT_DOUBLE_MAX; Box->B = -PORT_DOUBLE_MAX; return 1; }