/*! \brief Check if point is in area \param x,y point coordinates \param Map pointer to Map_info structure \param area area id \param box area bounding box \return 1 if point is in area \return 0 if not */ int Vect_point_in_area(double x, double y, const struct Map_info *Map, int area, struct bound_box *box) { int i, isle; const struct Plus_head *Plus; struct P_area *Area; struct bound_box ibox; int poly; Plus = &(Map->plus); Area = Plus->Area[area]; if (Area == NULL) return 0; poly = Vect_point_in_area_outer_ring(x, y, Map, area, box); if (poly == 0) return 0; /* includes area boundary (poly == 2), OK? */ /* check if in islands */ for (i = 0; i < Area->n_isles; i++) { isle = Area->isles[i]; Vect_get_isle_box(Map, isle, &ibox); poly = Vect_point_in_island(x, y, Map, isle, &ibox); if (poly >= 1) return 0; /* excludes island boundary (poly == 2), OK? */ } return 1; }
/*! \brief Find area outside island \param Map vector map \param isle isle id \param box isle bbox \return area id \return 0 if not found */ int Vect_isle_find_area(struct Map_info *Map, int isle, const struct bound_box *box) { int i, j, line, sel_area, area, poly; const struct Plus_head *plus; struct P_line *Line; struct P_node *Node; struct P_isle *Isle; struct P_area *Area; struct P_topo_b *topo; struct bound_box *abox, nbox; static struct boxlist *List = NULL; static BOX_SIZE *size_list; static int alloc_size_list = 0; /* see also Vect_find_area() */ /* Note: We should check all isle points (at least) because if topology is not clean * and two areas overlap, isle which is not completely within area may be attached, * but it would take long time */ G_debug(3, "Vect_isle_find_area () island = %d", isle); plus = &(Map->plus); if (plus->Isle[isle] == NULL) { G_warning(_("Request to find area outside nonexistent isle")); return 0; } if (!List) { List = Vect_new_boxlist(1); alloc_size_list = 10; size_list = G_malloc(alloc_size_list * sizeof(BOX_SIZE)); } Isle = plus->Isle[isle]; line = abs(Isle->lines[0]); Line = plus->Line[line]; topo = (struct P_topo_b *)Line->topo; Node = plus->Node[topo->N1]; /* select areas by box */ nbox.E = Node->x; nbox.W = Node->x; nbox.N = Node->y; nbox.S = Node->y; nbox.T = PORT_DOUBLE_MAX; nbox.B = -PORT_DOUBLE_MAX; Vect_select_areas_by_box(Map, &nbox, List); G_debug(3, "%d areas overlap island boundary point", List->n_values); /* sort areas by bbox size * get the smallest area that contains the isle * using the bbox size is working because if 2 areas both contain * the isle, one of these areas must be inside the other area * which means that the bbox of the outer area must be larger than * the bbox of the inner area, and equal bbox sizes are not possible */ if (alloc_size_list < List->n_values) { alloc_size_list = List->n_values; size_list = G_realloc(size_list, alloc_size_list * sizeof(BOX_SIZE)); } j = 0; for (i = 0; i < List->n_values; i++) { abox = &List->box[i]; if (box->E > abox->E || box->W < abox->W || box->N > abox->N || box->S < abox->S) { G_debug(3, " isle not completely inside area box"); continue; } List->id[j] = List->id[i]; List->box[j] = List->box[i]; size_list[j].i = List->id[j]; size_list[j].box = List->box[j]; size_list[j].size = (abox->N - abox->S) * (abox->E - abox->W); j++; } List->n_values = j; if (List->n_values > 1) { if (List->n_values == 2) { /* simple swap */ if (size_list[1].size < size_list[0].size) { size_list[0].i = List->id[1]; size_list[1].i = List->id[0]; size_list[0].box = List->box[1]; size_list[1].box = List->box[0]; } } else qsort(size_list, List->n_values, sizeof(BOX_SIZE), sort_by_size); } sel_area = 0; for (i = 0; i < List->n_values; i++) { area = size_list[i].i; G_debug(3, "area = %d", area); Area = plus->Area[area]; /* Before other tests, simply exclude those areas inside isolated isles formed by one boundary */ if (abs(Isle->lines[0]) == abs(Area->lines[0])) { G_debug(3, " area inside isolated isle"); continue; } /* Check box */ /* Note: If build is run on large files of areas imported from nontopo format (shapefile) * attaching of isles takes very long time because each area is also isle and select by * box all overlapping areas selects all areas with box overlapping first node. * Then reading coordinates for all those areas would take a long time -> check first * if isle's box is completely within area box */ abox = &size_list[i].box; if (box->E > abox->E || box->W < abox->W || box->N > abox->N || box->S < abox->S) { G_debug(3, " isle not completely inside area box"); continue; } poly = Vect_point_in_area_outer_ring(Node->x, Node->y, Map, area, abox); G_debug(3, " poly = %d", poly); if (poly == 1) { /* point in area, but node is not part of area inside isle (would be poly == 2) */ #if 1 /* new version */ /* the bounding box of the smaller area is * 1) inside the bounding box of a larger area and thus * 2) smaller than the bounding box of a larger area */ sel_area = area; break; #else /* old version */ /* In rare case island is inside more areas in that case we have to calculate area * of outer ring and take the smaller */ if (sel_area == 0) { /* first */ sel_area = area; } else { /* is not first */ G_debug(1, "slow version of Vect_isle_find_area()"); if (cur_size < 0) { /* second area */ /* This is slow, but should not be called often */ Vect_get_area_points(Map, sel_area, APoints); /* G_begin_polygon_area_calculations(); cur_size = G_area_of_polygon(APoints->x, APoints->y, APoints->n_points); */ /* this is faster, but there may be latlon problems: the poles */ dig_find_area_poly(APoints, &cur_size); G_debug(3, " first area size = %f (n points = %d)", cur_size, APoints->n_points); } Vect_get_area_points(Map, area, APoints); /* size = G_area_of_polygon(APoints->x, APoints->y, APoints->n_points); */ /* this is faster, but there may be latlon problems: the poles */ dig_find_area_poly(APoints, &size); G_debug(3, " area size = %f (n points = %d)", size, APoints->n_points); if (size > 0 && size < cur_size) { sel_area = area; cur_size = size; /* this can not happen because the first area must be * inside the second area because the node * is inside both areas */ G_warning(_("Larger bbox but smaller area!!!")); } } G_debug(3, "sel_area = %d cur_size = %f", sel_area, cur_size); #endif } } if (sel_area > 0) { G_debug(3, "Island %d in area %d", isle, sel_area); } else { G_debug(3, "Island %d is not in area", isle); } return sel_area; }