/*! \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; }
/* shortest distance between line and area * return 1 inside area * return 2 inside isle of area * return 3 outside area */ int line2area(const struct Map_info *To, struct line_pnts *Points, int type, int area, const struct bound_box *abox, double *fx, double *fy, double *fz, double *falong, double *fangle, double *tx, double *ty, double *tz, double *talong, double *tangle, double *dist, int with_z) { int i, j; double tmp_dist; int isle, nisles; int all_inside_outer, all_outside_outer, all_outside_inner; static struct line_pnts *aPoints = NULL; static struct line_pnts **iPoints = NULL; static struct bound_box *ibox = NULL; static int isle_alloc = 0; if (!aPoints) aPoints = Vect_new_line_struct(); *dist = PORT_DOUBLE_MAX; /* fangle and tangle are angles in radians, counter clockwise from x axis * initialize to invalid angle */ *fangle = *tangle = -9.; *falong = *talong = 0.; *fx = Points->x[0]; *fy = Points->y[0]; *fz = Points->z[0]; *tx = Points->x[0]; *ty = Points->y[0]; *tz = Points->z[0]; Vect_get_area_points(To, area, aPoints); nisles = Vect_get_area_num_isles(To, area); if (nisles > isle_alloc) { iPoints = G_realloc(iPoints, nisles * sizeof(struct line_pnts *)); ibox = G_realloc(ibox, nisles * sizeof(struct bound_box)); for (i = isle_alloc; i < nisles; i++) iPoints[i] = Vect_new_line_struct(); isle_alloc = nisles; } for (i = 0; i < nisles; i++) { isle = Vect_get_area_isle(To, area, i); Vect_get_isle_points(To, isle, iPoints[i]); Vect_get_isle_box(To, isle, &ibox[i]); } /* inside area ? */ all_inside_outer = all_outside_outer = 1; all_outside_inner = 1; int in_box; for (i = 0; i < Points->n_points; i++) { if (with_z) in_box = Vect_point_in_box(Points->x[i], Points->y[i], Points->z[i], abox); else in_box = Vect_point_in_box_2d(Points->x[i], Points->y[i], abox); if (in_box) { int poly; poly = Vect_point_in_poly(Points->x[i], Points->y[i], aPoints); if (poly > 0) { /* inside outer ring */ all_outside_outer = 0; } else { /* outside outer ring */ all_inside_outer = 0; } /* exactly on boundary */ if (poly == 2) { line2line(Points, type, aPoints, GV_BOUNDARY, fx, fy, fz, falong, fangle, tx, ty, tz, talong, tangle, dist, with_z); *talong = 0; *tangle = -9; return 1; } /* inside outer ring */ else if (poly == 1) { int inside_isle = 0; for (j = 0; j < nisles; j++) { if (with_z) in_box = Vect_point_in_box(Points->x[i], Points->y[i], Points->z[i], &ibox[j]); else in_box = Vect_point_in_box_2d(Points->x[i], Points->y[i], &ibox[j]); if (in_box) { poly = Vect_point_in_poly(Points->x[i], Points->y[i], iPoints[j]); /* inside or exactly on boundary */ if (poly > 0) { double tmp_fx, tmp_fy, tmp_fz, tmp_fangle, tmp_falong; double tmp_tx, tmp_ty, tmp_tz, tmp_tangle, tmp_talong; /* pass all points of the line, * this will catch an intersection */ line2line(Points, type, iPoints[j], GV_BOUNDARY, &tmp_fx, &tmp_fy, &tmp_fz, &tmp_falong, &tmp_fangle, &tmp_tx, &tmp_ty, &tmp_tz, &tmp_talong, &tmp_tangle, &tmp_dist, with_z); if (*dist > tmp_dist) { *dist = tmp_dist; *fx = tmp_fx; *fy = tmp_fy; *fz = tmp_fz; *falong = tmp_falong; *fangle = tmp_fangle; *tx = tmp_tx; *ty = tmp_ty; *tz = tmp_tz; *talong = 0; *tangle = tmp_tangle; } if (poly == 1) /* excludes isle boundary */ inside_isle = 1; } } if (*dist == 0) break; } /* inside area (inside outer ring, outside inner rings * or exactly on one of the inner rings) */ if (!inside_isle) { *fx = Points->x[i]; *fy = Points->y[i]; *fz = Points->z[i]; *tx = Points->x[i]; *ty = Points->y[i]; *tz = Points->z[i]; *fangle = *tangle = -9.; *falong = *talong = 0.; *dist = 0; return 1; } else { /* inside one of the islands */ all_outside_inner = 0; if (*dist == 0) { /* the line intersected with the isle boundary * -> line is partially inside the area */ *fangle = *tangle = -9.; *falong = *talong = 0.; return 1; } /* else continue with next point */ } } /* end inside outer ring */ } else { /* point not in box of outer ring */ all_inside_outer = 0; } /* exactly on boundary */ if (*dist == 0) return 1; } /* if all points are inside the outer ring and inside inner rings, * there could still be an intersection with one of the inner rings */ if (all_inside_outer) { if (all_outside_inner) { /* at least one point is really inside the area! * that should have been detected above */ G_fatal_error(_("At least one point is really inside the area!")); } /* else all points are inside one of the area isles * and we already have the minimum distance */ return 2; } /* if at least one point was found to be inside the outer ring, * but no point really inside the area, * and at least one point outside, * then there must be an intersection of the line with both * the outer ring and one of the isle boundaries */ /* if all line points are outside of the area, * intersection is still possible */ line2line(Points, type, aPoints, GV_BOUNDARY, fx, fy, fz, falong, fangle, tx, ty, tz, talong, tangle, dist, with_z); *talong = 0; if (*dist == 0) return 1; return 3; }