Example #1
0
/*!
   \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;
}
Example #2
0
/*!
   \brief Build area on given side of line (GV_LEFT or GV_RIGHT)

   \param Map pointer to Map_info structure
   \param iline line id
   \param side side (GV_LEFT or GV_RIGHT)

   \return > 0 area id
   \return < 0 isle id
   \return 0 not created (may also already exist)
 */
int Vect_build_line_area(struct Map_info *Map, int iline, int side)
{
    int area, isle, n_lines;

    struct Plus_head *plus;
    struct bound_box box;
    static struct line_pnts *APoints = NULL;
    plus_t *lines;
    double area_size;

    plus = &(Map->plus);

    G_debug(3, "Vect_build_line_area() line = %d, side = %d", iline, side);

    if (!APoints)
	APoints = Vect_new_line_struct();
    
    /* get area */
    area = dig_line_get_area(plus, iline, side);
    if (area != 0) {
        /* -> there is already an area on this side of the line, skip */
        G_debug(3, "  area/isle = %d -> skip", area);
        return 0;
    }
    
    /* build an area with this line */
    n_lines = dig_build_area_with_line(plus, iline, side, &lines);
    G_debug(3, "  n_lines = %d", n_lines);
    if (n_lines < 1) {
	return 0;
    }				/* area was not built */

    /* get line points which forms a boundary of an area */
    Vect__get_area_points(Map, lines, n_lines, APoints);
    dig_line_box(APoints, &box);

    Vect_line_prune(APoints);
    if (APoints->n_points < 4) {
	G_warning(_("Area of size = 0.0 (less than 4 vertices) ignored"));
	return 0;
    }

    /* Area or island ? */
    dig_find_area_poly(APoints, &area_size);

    /* area_size = dig_find_poly_orientation(APoints); */
    /* area_size is not real area size, we are only interested in the sign */

    G_debug(3, "  area/isle size = %f", area_size);

    if (area_size > 0) {	/* CW: area */
	/* add area structure to plus */
	area = dig_add_area(plus, n_lines, lines, &box);
	if (area == -1) {	/* error */
	    G_fatal_error(_("Unable to add area (map closed, topo saved)"));
	}
	G_debug(3, "  -> area %d", area);
	return area;
    }
    else if (area_size < 0) {	/* CCW: island */
	isle = dig_add_isle(plus, n_lines, lines, &box);
	if (isle == -1) {	/* error */
	    G_fatal_error(_("Unable to add isle (map closed, topo saved)"));
	}
	G_debug(3, "  -> isle %d", isle);
	return -isle;
    }
    else {
	/* TODO: What to do with such areas? Should be areas/isles of size 0 stored,
	 *        so that may be found and cleaned by some utility
	 *  Note: it would be useful for vertical closed polygons, but such would be added twice
	 *        as area */
	G_warning(_("Area of size = 0.0 ignored"));
    }
    return 0;
}
Example #3
0
/* area_outer and area_isles[i] must be closed non self-intersecting lines
   side: 0 - auto, 1 - right, -1 left
 */
static void buffer_lines(struct line_pnts *area_outer, struct line_pnts **area_isles,
			 int isles_count, int side, double da, double db,
			 double dalpha, int round, int caps, double tol,
			 struct line_pnts **oPoints, struct line_pnts ***iPoints,
			 int *inner_count)
{
    struct planar_graph *pg2;
    struct line_pnts *sPoints, *cPoints;
    struct line_pnts **arrPoints;
    int i, count = 0;
    int res, winding;
    int auto_side;
    int more = 8;
    int allocated = 0;
    double px, py;

    G_debug(3, "buffer_lines()");

    auto_side = (side == 0);

    /* initializations */
    sPoints = Vect_new_line_struct();
    cPoints = Vect_new_line_struct();
    arrPoints = NULL;

    /* outer contour */
    G_debug(3, "    processing outer contour");
    *oPoints = Vect_new_line_struct();
    if (auto_side)
	side =
	    get_polygon_orientation(area_outer->x, area_outer->y,
				    area_outer->n_points -
				    1) ? LEFT_SIDE : RIGHT_SIDE;
    convolution_line(area_outer, da, db, dalpha, side, round, caps, tol,
		     sPoints);
    pg2 = pg_create(sPoints);
    extract_outer_contour(pg2, 0, *oPoints);
    res = extract_inner_contour(pg2, &winding, cPoints);
    while (res != 0) {
	if (winding == 0) {
	    int check_poly = 1;
	    double area_size;

	    dig_find_area_poly(cPoints, &area_size);
	    if (area_size == 0) {
		G_warning(_("zero area size"));
		check_poly = 0;
	    }
	    if (cPoints->x[0] != cPoints->x[cPoints->n_points - 1] ||
		cPoints->y[0] != cPoints->y[cPoints->n_points - 1]) {

		G_warning(_("Line was not closed"));
		check_poly = 0;
	    }

	    if (check_poly && !Vect_point_in_poly(cPoints->x[0], cPoints->y[0], area_outer)) {
		if (Vect_get_point_in_poly(cPoints, &px, &py) == 0) {
		    if (!point_in_buf(area_outer, px, py, da, db, dalpha)) {
			add_line_to_array(cPoints, &arrPoints, &count, &allocated,
					  more);
			cPoints = Vect_new_line_struct();
		    }
		}
		else {
		    G_warning(_("Vect_get_point_in_poly() failed"));
		}
	    }
	}
	res = extract_inner_contour(pg2, &winding, cPoints);
    }
    pg_destroy_struct(pg2);

    /* inner contours */
    G_debug(3, "    processing inner contours");
    for (i = 0; i < isles_count; i++) {
	if (auto_side)
	    side =
		get_polygon_orientation(area_isles[i]->x, area_isles[i]->y,
					area_isles[i]->n_points -
					1) ? RIGHT_SIDE : LEFT_SIDE;
	convolution_line(area_isles[i], da, db, dalpha, side, round, caps,
			 tol, sPoints);
	pg2 = pg_create(sPoints);
	extract_outer_contour(pg2, 0, cPoints);
	res = extract_inner_contour(pg2, &winding, cPoints);
	while (res != 0) {
	    if (winding == -1) {
		int check_poly = 1;
		double area_size;

		dig_find_area_poly(cPoints, &area_size);
		if (area_size == 0) {
		    G_warning(_("zero area size"));
		    check_poly = 0;
		}
		if (cPoints->x[0] != cPoints->x[cPoints->n_points - 1] ||
		    cPoints->y[0] != cPoints->y[cPoints->n_points - 1]) {

		    G_warning(_("Line was not closed"));
		    check_poly = 0;
		}

		/* we need to check if the area is in the buffer.
		   I've simplfied convolution_line(), so that it runs faster,
		   however that leads to ocasional problems */
		if (check_poly && Vect_point_in_poly
		    (cPoints->x[0], cPoints->y[0], area_isles[i])) {
		    if (Vect_get_point_in_poly(cPoints, &px, &py) == 0) {
			if (!point_in_buf(area_isles[i], px, py, da, db, dalpha)) {
			    add_line_to_array(cPoints, &arrPoints, &count,
					      &allocated, more);
			    cPoints = Vect_new_line_struct();
			}
		    }
		    else {
			G_warning(_("Vect_get_point_in_poly() failed"));
		    }
		}
	    }
	    res = extract_inner_contour(pg2, &winding, cPoints);
	}
	pg_destroy_struct(pg2);
    }

    arrPoints = G_realloc(arrPoints, count * sizeof(struct line_pnts *));
    *inner_count = count;
    *iPoints = arrPoints;

    Vect_destroy_line_struct(sPoints);
    Vect_destroy_line_struct(cPoints);

    G_debug(3, "buffer_lines() ... done");

    return;
}