예제 #1
0
/*!
   \brief Get line type

   \param map vector map
   \param line line id

   \return line type
 */
int
Vect_get_line_type(const struct Map_info *Map, int line)
{
    if (Map->level < 2)
	G_fatal_error(_("Vector map <%s> is not open on level >= 2"),
		      Vect_get_full_name(Map));

    if (!Vect_line_alive(Map, line))
	return 0;
	
    return (Map->plus.Line[line]->type);
}
예제 #2
0
int rmdac(struct Map_info *Out, struct Map_info *Err)
{
    int i, type, area, ndupl, nlines;

    struct line_pnts *Points;
    struct line_cats *Cats;

    nlines = Vect_get_num_lines(Out);

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    G_debug(1, "nlines =  %d", nlines);

    ndupl = 0;

    for (i = 1; i <= nlines; i++) {
	G_percent(i, nlines, 2);
	if (!Vect_line_alive(Out, i))
	    continue;

	type = Vect_read_line(Out, Points, Cats, i);
	if (!(type & GV_CENTROID))
	    continue;

	area = Vect_get_centroid_area(Out, i);
	G_debug(3, "  area = %d", area);

	if (area < 0) {
	    Vect_delete_line(Out, i);
	    ndupl++;

	    if (Err) {
		Vect_write_line(Err, type, Points, Cats);
	    }
	}
    }

    G_verbose_message(_("Duplicate area centroids: %d"), ndupl);

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return ndupl;
}
예제 #3
0
/* break polygons using a file-based search index */
void Vect_break_polygons_file(struct Map_info *Map, int type, struct Map_info *Err)
{
    struct line_pnts *BPoints, *Points;
    struct line_cats *Cats, *ErrCats;
    int i, j, k, ret, ltype, broken, last, nlines;
    int nbreaks;
    struct RTree *RTree;
    int npoints, nallpoints, nmarks;
    XPNT2 XPnt;
    double dx, dy, a1 = 0, a2 = 0;
    int closed, last_point;
    char cross;
    int fd, xpntfd;
    char *filename;
    static struct RTree_Rect rect;
    static int rect_init = 0;

    if (!rect_init) {
	rect.boundary = G_malloc(6 * sizeof(RectReal));
	rect_init = 6;
    }
    
    G_debug(1, "File-based version of Vect_break_polygons()");

    filename = G_tempfile();
    fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
    RTree = RTreeCreateTree(fd, 0, 2);
    remove(filename);

    filename = G_tempfile();
    xpntfd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
    remove(filename);

    BPoints = Vect_new_line_struct();
    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    ErrCats = Vect_new_cats_struct();

    nlines = Vect_get_num_lines(Map);

    G_debug(3, "nlines =  %d", nlines);
    /* Go through all lines in vector, and add each point to structure of points,
     * if such point already exists check angles of segments and if differ mark for break */

    nmarks = 0;
    npoints = 1;		/* index starts from 1 ! */
    nallpoints = 0;
    XPnt.used = 0;

    G_message(_("Breaking polygons (pass 1: select break points)..."));

    for (i = 1; i <= nlines; i++) {
	G_percent(i, nlines, 1);
	G_debug(3, "i =  %d", i);
	if (!Vect_line_alive(Map, i))
	    continue;

	ltype = Vect_read_line(Map, Points, Cats, i);
	if (!(ltype & type))
	    continue;

	/* This would be confused by duplicate coordinates (angle cannot be calculated) ->
	 * prune line first */
	Vect_line_prune(Points);

	/* If first and last point are identical it is close polygon, we don't need to register last point
	 * and we can calculate angle for first.
	 * If first and last point are not identical we have to mark for break both */
	last_point = Points->n_points - 1;
	if (Points->x[0] == Points->x[last_point] &&
	    Points->y[0] == Points->y[last_point])
	    closed = 1;
	else
	    closed = 0;

	for (j = 0; j < Points->n_points; j++) {
	    G_debug(3, "j =  %d", j);
	    nallpoints++;

	    if (j == last_point && closed)
		continue;	/* do not register last of close polygon */

	    /* Box */
	    rect.boundary[0] = Points->x[j];
	    rect.boundary[3] = Points->x[j];
	    rect.boundary[1] = Points->y[j];
	    rect.boundary[4] = Points->y[j];
	    rect.boundary[2] = 0;
	    rect.boundary[5] = 0;

	    /* Already in DB? */
	    fpoint = -1;
	    RTreeSearch(RTree, &rect, (void *)srch, NULL);
	    G_debug(3, "fpoint =  %d", fpoint);

	    if (Points->n_points <= 2 ||
		(!closed && (j == 0 || j == last_point))) {
		cross = 1;	/* mark for cross in any case */
	    }
	    else {		/* calculate angles */
		cross = 0;
		if (j == 0 && closed) {	/* closed polygon */
		    dx = Points->x[last_point] - Points->x[0];
		    dy = Points->y[last_point] - Points->y[0];
		    a1 = atan2(dy, dx);
		    dx = Points->x[1] - Points->x[0];
		    dy = Points->y[1] - Points->y[0];
		    a2 = atan2(dy, dx);
		}
		else {
		    dx = Points->x[j - 1] - Points->x[j];
		    dy = Points->y[j - 1] - Points->y[j];
		    a1 = atan2(dy, dx);
		    dx = Points->x[j + 1] - Points->x[j];
		    dy = Points->y[j + 1] - Points->y[j];
		    a2 = atan2(dy, dx);
		}
	    }

	    if (fpoint > 0) {	/* Found */
		/* read point */
		lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET);
		read(xpntfd, &XPnt, sizeof(XPNT2));
		if (XPnt.cross == 1)
		    continue;	/* already marked */

		/* Check angles */
		if (cross) {
		    XPnt.cross = 1;
		    nmarks++;
		    /* write point */
		    lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET);
		    write(xpntfd, &XPnt, sizeof(XPNT2));
		}
		else {
		    G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1,
			    XPnt.a1, a2, XPnt.a2);
		    if ((a1 == XPnt.a1 && a2 == XPnt.a2) ||
		        (a1 == XPnt.a2 && a2 == XPnt.a1)) {	/* identical */

		    }
		    else {
			XPnt.cross = 1;
			nmarks++;
			/* write point */
			lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET);
			write(xpntfd, &XPnt, sizeof(XPNT2));
		    }
		}
	    }
	    else {
		/* Add to tree and to structure */
		RTreeInsertRect(&rect, npoints, RTree);
		if (j == 0 || j == (Points->n_points - 1) ||
		    Points->n_points < 3) {
		    XPnt.a1 = 0;
		    XPnt.a2 = 0;
		    XPnt.cross = 1;
		    nmarks++;
		}
		else {
		    XPnt.a1 = a1;
		    XPnt.a2 = a2;
		    XPnt.cross = 0;
		}
		/* write point */
		lseek(xpntfd, (off_t) (npoints - 1) * sizeof(XPNT2), SEEK_SET);
		write(xpntfd, &XPnt, sizeof(XPNT2));

		npoints++;
	    }
	}
    }

    nbreaks = 0;

    /* Second loop through lines (existing when loop is started, no need to process lines written again)
     * and break at points marked for break */

    G_message(_("Breaking polygons (pass 2: break at selected points)..."));

    for (i = 1; i <= nlines; i++) {
	int n_orig_points;

	G_percent(i, nlines, 1);
	G_debug(3, "i =  %d", i);
	if (!Vect_line_alive(Map, i))
	    continue;

	ltype = Vect_read_line(Map, Points, Cats, i);
	if (!(ltype & type))
	    continue;
	if (!(ltype & GV_LINES))
	    continue;		/* Nonsense to break points */

	/* Duplicates would result in zero length lines -> prune line first */
	n_orig_points = Points->n_points;
	Vect_line_prune(Points);

	broken = 0;
	last = 0;
	G_debug(3, "n_points =  %d", Points->n_points);
	for (j = 1; j < Points->n_points; j++) {
	    G_debug(3, "j =  %d", j);
	    nallpoints++;

	    /* Box */
	    rect.boundary[0] = Points->x[j];
	    rect.boundary[3] = Points->x[j];
	    rect.boundary[1] = Points->y[j];
	    rect.boundary[4] = Points->y[j];
	    rect.boundary[2] = 0;
	    rect.boundary[5] = 0;

	    if (Points->n_points <= 1 ||
		(j == (Points->n_points - 1) && !broken))
		break;
	    /* One point only or 
	     * last point and line is not broken, do nothing */

	    RTreeSearch(RTree, &rect, (void *)srch, 0);
	    G_debug(3, "fpoint =  %d", fpoint);

	    /* read point */
	    lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET);
	    read(xpntfd, &XPnt, sizeof(XPNT2));

	    /* break or write last segment of broken line */
	    if ((j == (Points->n_points - 1) && broken) ||
		XPnt.cross) {
		Vect_reset_line(BPoints);
		for (k = last; k <= j; k++) {
		    Vect_append_point(BPoints, Points->x[k], Points->y[k],
				      Points->z[k]);
		}

		/* Result may collapse to one point */
		Vect_line_prune(BPoints);
		if (BPoints->n_points > 1) {
		    ret = Vect_write_line(Map, ltype, BPoints, Cats);
		    G_debug(3,
			    "Line %d written j = %d n_points(orig,pruned) = %d n_points(new) = %d",
			    ret, j, Points->n_points, BPoints->n_points);
		}

		if (!broken)
		    Vect_delete_line(Map, i);	/* not yet deleted */

		/* Write points on breaks */
		if (Err) {
		    if (XPnt.cross && !XPnt.used) {
			Vect_reset_line(BPoints);
			Vect_append_point(BPoints, Points->x[j], Points->y[j], 0);
			Vect_write_line(Err, GV_POINT, BPoints, ErrCats);
		    }
		    if (!XPnt.used) {
			XPnt.used = 1;
			/* write point */
			lseek(xpntfd, (off_t) (fpoint - 1) * sizeof(XPNT2), SEEK_SET);
			write(xpntfd, &XPnt, sizeof(XPNT2));
		    }
		}

		last = j;
		broken = 1;
		nbreaks++;
	    }
	}
	if (!broken && n_orig_points > Points->n_points) {	/* was pruned before -> rewrite */
	    if (Points->n_points > 1) {
		Vect_rewrite_line(Map, i, ltype, Points, Cats);
		G_debug(3, "Line %d pruned, npoints = %d", i,
			Points->n_points);
	    }
	    else {
		Vect_delete_line(Map, i);
		G_debug(3, "Line %d was deleted", i);
	    }
	}
	else {
	    G_debug(3, "Line %d was not changed", i);
	}
    }

    close(RTree->fd);
    RTreeDestroyTree(RTree);
    close(xpntfd);
    Vect_destroy_line_struct(Points);
    Vect_destroy_line_struct(BPoints);
    Vect_destroy_cats_struct(Cats);
    Vect_destroy_cats_struct(ErrCats);
    G_verbose_message(_("Breaks: %d"), nbreaks);
}
예제 #4
0
파일: map.c 프로젝트: AsherBond/MondocosmOS
/*!
   \brief Copy all alive vector features from given layer of opened
   vector map to another opened vector map

   \param In input vector map
   \param field layer number (-1 for all layers)
   \param[out] Out output vector map

   \return 0 on success
   \return 1 on error
 */
int Vect_copy_map_lines_field(struct Map_info *In, int field,
			      struct Map_info *Out)
{
    int i, type, nlines, ret, left, rite, centroid;
    struct line_pnts *Points, *CPoints;
    struct line_cats *Cats, *CCats;

    Points = Vect_new_line_struct();
    CPoints = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    CCats = Vect_new_cats_struct();

    if (Vect_level(In) < 1)
	G_fatal_error("Vect_copy_map_lines(): %s",
		      _("input vector map is not open"));

    ret = 0;
    /* Note: sometimes is important to copy on level 2 (pseudotopo centroids) 
     *       and sometimes on level 1 if build take too long time */
    if (Vect_level(In) >= 2) {
	nlines = Vect_get_num_lines(In);
	for (i = 1; i <= nlines; i++) {
	    if (!Vect_line_alive(In, i))
		continue;

	    type = Vect_read_line(In, Points, Cats, i);
	    if (type == -1) {
		G_warning(_("Unable to read vector map <%s>"),
			  Vect_get_full_name(In));
		ret = 1;
		break;
	    }
	    if (type == 0)
		continue;	/* dead line */

	    /* don't skips boundaries if field != -1 */
	    if (field != -1) {
		if (type & GV_BOUNDARY) {
		    if (Vect_cat_get(Cats, field, NULL) == 0) {
			int skip_bndry = 1;

			Vect_get_line_areas(In, i, &left, &rite);
			if (left < 0)
			    left = Vect_get_isle_area(In, abs(left));
			if (left > 0) {
			    if ((centroid =
				 Vect_get_area_centroid(In, left)) > 0) {
				Vect_read_line(In, CPoints, CCats, centroid);
				if (Vect_cat_get(CCats, field, NULL) != 0)
				    skip_bndry = 0;
			    }
			}
			if (skip_bndry) {
			    if (rite < 0)
				rite = Vect_get_isle_area(In, abs(rite));
			    if (rite > 0) {
				if ((centroid =
				     Vect_get_area_centroid(In, rite)) > 0) {
				    Vect_read_line(In, CPoints, CCats,
						   centroid);
				    if (Vect_cat_get(CCats, field, NULL) != 0)
					skip_bndry = 0;
				}
			    }
			}
			if (skip_bndry)
			    continue;
		    }
		}
		else if (Vect_cat_get(Cats, field, NULL) == 0)
		    continue;	/* different layer */
	    }

	    Vect_write_line(Out, type, Points, Cats);
	}
    }
    else {			/* Level 1 */
	Vect_rewind(In);
	while (1) {
	    type = Vect_read_next_line(In, Points, Cats);
	    if (type == -1) {
		G_warning(_("Unable to read vector map <%s>"),
			  Vect_get_full_name(In));
		ret = 1;
		break;
	    }
	    else if (type == -2) {	/* EOF */
		break;
	    }
	    else if (type == 0) {	/* dead line */
		continue;
	    }

	    /* don't skip boundaries if field != -1 */
	    if (field != -1 && !(type & GV_BOUNDARY) &&
		Vect_cat_get(Cats, field, NULL) == 0)
		continue;	/* different layer */

	    Vect_write_line(Out, type, Points, Cats);
	}
    }
    Vect_destroy_line_struct(Points);
    Vect_destroy_line_struct(CPoints);
    Vect_destroy_cats_struct(Cats);
    Vect_destroy_cats_struct(CCats);

    return ret;
}
예제 #5
0
int
Vect_break_lines_list(struct Map_info *Map, struct ilist *List_break,
		      struct ilist *List_ref, int type, struct Map_info *Err)
{
    struct line_pnts *APoints, *BPoints, *Points;
    struct line_pnts **AXLines, **BXLines;
    struct line_cats *ACats, *BCats, *Cats;
    int j, k, l, ret, atype, btype, aline, bline, found, iline, nlines;
    int naxlines, nbxlines, nx;
    double *xx = NULL, *yx = NULL, *zx = NULL;
    struct bound_box ABox, BBox;
    struct boxlist *List;
    int nbreaks;
    int touch1_n = 0, touch1_s = 0, touch1_e = 0, touch1_w = 0;	/* other vertices except node1 touching box */
    int touch2_n = 0, touch2_s = 0, touch2_e = 0, touch2_w = 0;	/* other vertices except node2 touching box */
    int is3d;
    int node, anode1, anode2, bnode1, bnode2;
    double nodex, nodey;

    APoints = Vect_new_line_struct();
    BPoints = Vect_new_line_struct();
    Points = Vect_new_line_struct();
    ACats = Vect_new_cats_struct();
    BCats = Vect_new_cats_struct();
    Cats = Vect_new_cats_struct();
    List = Vect_new_boxlist(1);

    is3d = Vect_is_3d(Map);

    if (List_break) {
	nlines = List_break->n_values;
    }
    else {
	nlines = Vect_get_num_lines(Map);
    }
    G_debug(3, "nlines =  %d", nlines);

    /* TODO: It seems that lines/boundaries are not broken at intersections
     * with points/centroids. Check if true, if yes, skip GV_POINTS
     */

    /* To find intersection of two lines (Vect_line_intersection) is quite slow.
     * Fortunately usual lines/boundaries in GIS often forms a network where lines
     * are connected by end points, and touch by MBR. This function checks and occasionaly
     * skips such cases. This is currently done for 2D only
     */

    /* Go through all lines in vector, for each select lines which overlap MBR of
     * this line exclude those connected by one endpoint (see above)
     * and try to intersect, if lines intersect write new lines at the end of 
     * the file, and process next line (remaining lines overlapping box are skipped)
     */
    nbreaks = 0;

    for (iline = 0; iline < nlines; iline++) {
	G_percent(iline, nlines, 1);
	if (List_break) {
	    aline = List_break->value[iline];
	}
	else {
	    aline = iline + 1;
	}

	if (List_ref && !Vect_val_in_list(List_ref, aline))
	    continue;

	G_debug(3, "aline =  %d", aline);
	if (!Vect_line_alive(Map, aline))
	    continue;

	atype = Vect_read_line(Map, APoints, ACats, aline);
	if (!(atype & type))
	    continue;

	Vect_line_box(APoints, &ABox);

	/* Find which sides of the box are touched by intermediate (non-end) points of line */
	if (!is3d) {
	    touch1_n = touch1_s = touch1_e = touch1_w = 0;
	    for (j = 1; j < APoints->n_points; j++) {
		if (APoints->y[j] == ABox.N)
		    touch1_n = 1;
		if (APoints->y[j] == ABox.S)
		    touch1_s = 1;
		if (APoints->x[j] == ABox.E)
		    touch1_e = 1;
		if (APoints->x[j] == ABox.W)
		    touch1_w = 1;
	    }
	    G_debug(3, "touch1: n = %d s = %d e = %d w = %d", touch1_n,
		    touch1_s, touch1_e, touch1_w);
	    touch2_n = touch2_s = touch2_e = touch2_w = 0;
	    for (j = 0; j < APoints->n_points - 1; j++) {
		if (APoints->y[j] == ABox.N)
		    touch2_n = 1;
		if (APoints->y[j] == ABox.S)
		    touch2_s = 1;
		if (APoints->x[j] == ABox.E)
		    touch2_e = 1;
		if (APoints->x[j] == ABox.W)
		    touch2_w = 1;
	    }
	    G_debug(3, "touch2: n = %d s = %d e = %d w = %d", touch2_n,
		    touch2_s, touch2_e, touch2_w);
	}

	Vect_select_lines_by_box(Map, &ABox, type, List);
	G_debug(3, "  %d lines selected by box", List->n_values);

	for (j = 0; j < List->n_values; j++) {
	    bline = List->id[j];
	    if (List_break && !Vect_val_in_list(List_break, bline)) {
		continue;
	    }
	    G_debug(3, "  j = %d bline = %d", j, bline);

	    btype = Vect_read_line(Map, BPoints, BCats, bline);

	    /* Check if thouch by end node only */
	    if (!is3d) {
		Vect_get_line_nodes(Map, aline, &anode1, &anode2);
		Vect_get_line_nodes(Map, bline, &bnode1, &bnode2);
		BBox = List->box[j];

		if (anode1 == bnode1 || anode1 == bnode2)
		    node = anode1;
		else if (anode2 == bnode1 || anode2 == bnode2)
		    node = anode2;
		else
		    node = 0;

		if (node) {
		    Vect_get_node_coor(Map, node, &nodex, &nodey, NULL);
		    if ((node == anode1 && nodey == ABox.N &&
		         !touch1_n && nodey == BBox.S) ||
		        (node == anode2 && nodey == ABox.N &&
			 !touch2_n && nodey == BBox.S) ||
			(node == anode1 && nodey == ABox.S &&
			 !touch1_s && nodey == BBox.N) ||
			(node == anode2 && nodey == ABox.S &&
			 !touch2_s && nodey == BBox.N) ||
			(node == anode1 && nodex == ABox.E &&
			 !touch1_e && nodex == BBox.W) ||
			(node == anode2 && nodex == ABox.E &&
			 !touch2_e && nodex == BBox.W) ||
			(node == anode1 && nodex == ABox.W &&
			 !touch1_w && nodex == BBox.E) ||
			(node == anode2 && nodex == ABox.W &&
			 !touch2_w && nodex == BBox.E)) {

			G_debug(3,
				"lines %d and %d touching by end nodes only -> no intersection",
				aline, bline);
			continue;
		    }
		}
	    }

	    AXLines = NULL;
	    BXLines = NULL;
	    Vect_line_intersection(APoints, BPoints, &AXLines, &BXLines,
				   &naxlines, &nbxlines, 0);
	    G_debug(3, "  naxlines = %d nbxlines = %d", naxlines, nbxlines);

	    /* This part handles a special case when aline == bline, no other intersection was found
	     * and the line is forming collapsed loop, for example  0,0;1,0;0,0 should be broken at 1,0.
	     * ---> */
	    if (aline == bline && naxlines == 0 && nbxlines == 0 &&
		APoints->n_points >= 3) {
		int centre;
		int i;

		G_debug(3, "  Check collapsed loop");
		if (APoints->n_points % 2) {	/* odd number of vertices */
		    centre = APoints->n_points / 2;	/* index of centre */
		    if (APoints->x[centre - 1] == APoints->x[centre + 1] && APoints->y[centre - 1] == APoints->y[centre + 1] && APoints->z[centre - 1] == APoints->z[centre + 1]) {	/* -> break */
			AXLines =
			    (struct line_pnts **)G_malloc(2 *
							  sizeof(struct
								 line_pnts
								 *));
			AXLines[0] = Vect_new_line_struct();
			AXLines[1] = Vect_new_line_struct();

			for (i = 0; i <= centre; i++)
			    Vect_append_point(AXLines[0], APoints->x[i],
					      APoints->y[i], APoints->z[i]);

			for (i = centre; i < APoints->n_points; i++)
			    Vect_append_point(AXLines[1], APoints->x[i],
					      APoints->y[i], APoints->z[i]);

			naxlines = 2;
		    }
		}
	    }
	    /* <--- */

	    if (Err) {		/* array for intersections (more than needed */
		xx = (double *)G_malloc((naxlines + nbxlines) *
					sizeof(double));
		yx = (double *)G_malloc((naxlines + nbxlines) *
					sizeof(double));
		zx = (double *)G_malloc((naxlines + nbxlines) *
					sizeof(double));
	    }
	    nx = 0;		/* number of intersections to be written to Err */
	    if (naxlines > 0) {	/* intersection -> write out */
		Vect_delete_line(Map, aline);
		for (k = 0; k < naxlines; k++) {
		    /* Write new line segments */
		    /* line may collapse, don't write zero length lines */
		    Vect_line_prune(AXLines[k]);
		    if ((atype & GV_POINTS) || AXLines[k]->n_points > 1) {
			ret = Vect_write_line(Map, atype, AXLines[k], ACats);
			if (List_ref) {
			    Vect_list_append(List_ref, ret);
			}
			G_debug(3, "Line %d written, npoints = %d", ret,
				AXLines[k]->n_points);
			if (List_break) {
			    Vect_list_append(List_break, ret);
			}
		    }

		    /* Write intersection points */
		    if (Err) {
			if (k > 0) {
			    xx[nx] = AXLines[k]->x[0];
			    yx[nx] = AXLines[k]->y[0];
			    zx[nx] = AXLines[k]->z[0];
			    nx++;
			}
		    }
		    Vect_destroy_line_struct(AXLines[k]);
		}
		nbreaks += naxlines - 1;
	    }
	    if (AXLines)
		G_free(AXLines);

	    if (nbxlines > 0) {
		if (aline != bline) {	/* Self intersection, do not write twice, TODO: is it OK? */
		    Vect_delete_line(Map, bline);
		    for (k = 0; k < nbxlines; k++) {
			/* Write new line segments */
			/* line may collapse, don't write zero length lines */
			Vect_line_prune(BXLines[k]);
			if ((btype & GV_POINTS) || BXLines[k]->n_points > 1) {
			    ret =
				Vect_write_line(Map, btype, BXLines[k],
						BCats);
			    G_debug(5, "Line %d written", ret);
			    if (List_break) {
				Vect_list_append(List_break, ret);
			    }
			}

			/* Write intersection points */
			if (Err) {
			    if (k > 0) {
				found = 0;
				for (l = 0; l < nx; l++) {
				    if (xx[l] == BXLines[k]->x[0] &&
					yx[l] == BXLines[k]->y[0] &&
					zx[l] == BXLines[k]->z[0]) {
					found = 1;
					break;
				    }
				}
				if (!found) {
				    xx[nx] = BXLines[k]->x[0];
				    yx[nx] = BXLines[k]->y[0];
				    zx[nx] = BXLines[k]->z[0];
				    nx++;
				}
			    }
			}
			Vect_destroy_line_struct(BXLines[k]);
		    }
		    nbreaks += nbxlines - 1;
		}
		else {
		    for (k = 0; k < nbxlines; k++)
			Vect_destroy_line_struct(BXLines[k]);
		}
	    }
	    if (BXLines)
		G_free(BXLines);
	    if (Err) {
		for (l = 0; l < nx; l++) {	/* Write out errors */
		    Vect_reset_line(Points);
		    Vect_append_point(Points, xx[l], yx[l], zx[l]);
		    ret = Vect_write_line(Err, GV_POINT, Points, Cats);
		}

		G_free(xx);
		G_free(yx);
		G_free(zx);
	    }
	    if (naxlines > 0)
		break;		/* first line was broken and deleted -> take the next one */
	}

	if (List_break) {
	    nlines = List_break->n_values;
	}
	else {
	    nlines = Vect_get_num_lines(Map);
	}
	G_debug(3, "nlines =  %d", nlines);
    }				/* for each line */
    G_percent(nlines, nlines, 1); /* finish it */

    G_verbose_message(_("Intersections: %d"), nbreaks);

    Vect_destroy_line_struct(APoints);
    Vect_destroy_line_struct(BPoints);
    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(ACats);
    Vect_destroy_cats_struct(BCats);
    Vect_destroy_cats_struct(Cats);
    Vect_destroy_boxlist(List);

    return nbreaks;
}
예제 #6
0
int line_area(struct Map_info *In, int *field, struct Map_info *Tmp,
	      struct Map_info *Out, struct field_info *Fi,
	      dbDriver * driver, int operator, int *ofield,
	      ATTRIBUTES * attr, struct ilist *BList)
{
    int line, nlines, ncat;
    struct line_pnts *Points;
    struct line_cats *Cats, *ACats, *OCats;

    char buf[1000];
    dbString stmt;

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    ACats = Vect_new_cats_struct();
    OCats = Vect_new_cats_struct();
    db_init_string(&stmt);

    G_message(_("Breaking lines..."));
    Vect_break_lines_list(Tmp, NULL, BList, GV_LINE | GV_BOUNDARY, NULL);

    /*
    G_message(_("Merging lines..."));
    Vect_merge_lines(Tmp, GV_LINE, NULL, NULL);
    */

    nlines = Vect_get_num_lines(Tmp);

    /* Warning!: cleaning process (break) creates new vertices which are usually slightly 
     * moved (RE), to compare such new vertex with original input is a problem?
     * 
     * TODO?: would it be better to copy centroids also and query output map? 
     */

    /* Check if the line is inside or outside binput area */
    G_message(_("Selecting lines..."));
    ncat = 1;
    for (line = 1; line <= nlines; line++) {
	int ltype;

	G_percent(line, nlines, 1);	/* must be before any continue */

	if (!Vect_line_alive(Tmp, line))
	    continue;

	ltype = Vect_get_line_type(Tmp, line);

	if (ltype == GV_BOUNDARY) {	/* No more needed */
	    continue;
	}

	/* Now the type should be only GV_LINE */

	/* Decide if the line is inside or outside the area. In theory:
	 * 1) All vertices outside
	 *      - easy, first vertex must be outside
	 * 2) All vertices inside 
	 * 3) All vertices on the boundary, we take it as inside (attention, 
	 *    result of Vect_point_in_area() for points on segments between vertices may be both
	 *    inside or outside, because of representation of numbers)
	 * 4) One or two end vertices on the boundary, all others outside
	 * 5) One or two end vertices on the boundary, all others inside 
	 *
	 */

	/* Note/TODO: the test done is quite simple, check the point in the middle of segment.
	 * If the line overlaps the boundary, the result may be both outside and inside
	 * this should be solved (check angles?)
	 * This should not happen if Vect_break_lines_list() works correctly
	 */

	/* merge here */
	merge_line(Tmp, line, Points, Cats);

	G_debug(3, "line = %d", line);

	point_area(&(In[1]), field[1], (Points->x[0] + Points->x[1]) / 2,
		   (Points->y[0] + Points->y[1]) / 2, ACats);

	if ((ACats->n_cats > 0 && operator == OP_AND) ||
	    (ACats->n_cats == 0 && operator == OP_NOT)) {
	    int i;

	    /* Point is inside */
	    G_debug(3, "OK, write line, line ncats = %d area ncats = %d",
		    Cats->n_cats, ACats->n_cats);

	    Vect_reset_cats(OCats);

	    if (ofield[0]  > 0) {
		/* rewrite with all combinations of acat - bcat (-1 in cycle for null) */
		for (i = -1; i < Cats->n_cats; i++) {	/* line cats */
		    int j;

		    if (i == -1 && Cats->n_cats > 0)
			continue;	/* no need to make null */

		    for (j = -1; j < ACats->n_cats; j++) {
			if (j == -1 && ACats->n_cats > 0)
			    continue;	/* no need to make null */

			if (ofield[0] > 0)
			    Vect_cat_set(OCats, ofield[0], ncat);

			/* Attributes */
			if (driver) {
			    ATTR *at;

			    sprintf(buf, "insert into %s values ( %d", Fi->table,
				    ncat);
			    db_set_string(&stmt, buf);

			    /* cata */
			    if (i >= 0) {
				if (attr[0].columns) {
				    at = find_attr(&(attr[0]), Cats->cat[i]);
				    if (!at)
					G_fatal_error(_("Attribute not found"));

				    if (at->values)
					db_append_string(&stmt, at->values);
				    else
					db_append_string(&stmt,
							 attr[0].null_values);
				}
				else {
				    sprintf(buf, ", %d", Cats->cat[i]);
				    db_append_string(&stmt, buf);
				}
			    }
			    else {
				if (attr[0].columns) {
				    db_append_string(&stmt, attr[0].null_values);
				}
				else {
				    sprintf(buf, ", null");
				    db_append_string(&stmt, buf);
				}
			    }

			    /* catb */
			    if (j >= 0) {
				if (attr[1].columns) {
				    at = find_attr(&(attr[1]), ACats->cat[j]);
				    if (!at)
					G_fatal_error(_("Attribute not found"));

				    if (at->values)
					db_append_string(&stmt, at->values);
				    else
					db_append_string(&stmt,
							 attr[1].null_values);
				}
				else {
				    sprintf(buf, ", %d", ACats->cat[j]);
				    db_append_string(&stmt, buf);
				}
			    }
			    else {
				if (attr[1].columns) {
				    db_append_string(&stmt, attr[1].null_values);
				}
				else {
				    sprintf(buf, ", null");
				    db_append_string(&stmt, buf);
				}
			    }

			    db_append_string(&stmt, " )");

			    G_debug(3, "%s", db_get_string(&stmt));

			    if (db_execute_immediate(driver, &stmt) != DB_OK)
				G_warning(_("Unable to insert new record: '%s'"),
					  db_get_string(&stmt));
			}

			ncat++;
		    }
		}
	    }

	    /* Add cats from input vectors */
	    if (ofield[1] > 0 && field[0] > 0) {
		for (i = 0; i < Cats->n_cats; i++) {
		    if (Cats->field[i] == field[0])
			Vect_cat_set(OCats, ofield[1], Cats->cat[i]);
		}
	    }

	    if (ofield[2] > 0 && field[1] > 0 && ofield[1] != ofield[2]) {
		for (i = 0; i < ACats->n_cats; i++) {
		    if (ACats->field[i] == field[1])
			Vect_cat_set(OCats, ofield[2], ACats->cat[i]);
		}
	    }

	    Vect_write_line(Out, ltype, Points, OCats);
	}
    }

    return 0;
}
예제 #7
0
/*!
   \brief Extensive tests for correct topology

   - lines or boundaries of zero length
   - intersecting boundaries, ie. overlapping areas
   - areas without centroids that are not isles

   \param Map vector map
   \param[out] Err vector map where errors will be written or NULL

   \return 1 on success
   \return 0 on error
 */
int Vect_topo_check(struct Map_info *Map, struct Map_info *Err)
{
    int line, nlines;
    int nerrors, n_zero_lines, n_zero_boundaries;
    struct line_pnts *Points;
    struct line_cats *Cats;

    /* rebuild topology if needed */
    if (Vect_get_built(Map) != GV_BUILD_ALL) {
	Vect_build_partial(Map, GV_BUILD_NONE);
	Vect_build(Map);
    }

    G_message(_("Checking for topological errors..."));

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    /* lines or boundaries of zero length */
    n_zero_lines = n_zero_boundaries = 0;
    nlines = Vect_get_num_lines(Map);
    for (line = 1; line <= nlines; line++) {
	int type;

	if (!Vect_line_alive(Map, line))
	    continue;
	    
	type = Vect_get_line_type(Map, line);

	if (type & GV_LINES) {
	    double len;
	    
	    Vect_read_line(Map, Points, Cats, line);
	    len = Vect_line_length(Points);
	    
	    if (len == 0) {
		if (type & GV_LINE)
		    n_zero_lines++;
		else if (type & GV_BOUNDARY)
		    n_zero_boundaries++;
		    
		if (Err)
		    Vect_write_line(Err, type, Points, Cats);
	    }
	}
    }
    
    if (n_zero_lines)
	G_warning(_("Number of lines of length zero: %d"), n_zero_lines);
    if (n_zero_boundaries)
	G_warning(_("Number of boundaries of length zero: %d"), n_zero_boundaries);

    /* remaining checks are for areas only */
    if (Vect_get_num_primitives(Map, GV_BOUNDARY) == 0)
	return 1;

    /* intersecting boundaries -> overlapping areas */
    nerrors = Vect_check_line_breaks(Map, GV_BOUNDARY, Err);
    if (nerrors)
	G_warning(_("Number of boundary intersections: %d"), nerrors);

    /* areas without centroids that are not isles
     * only makes sense if all boundaries are correct */
    nerrors = 0;
    for (line = 1; line <= nlines; line++) {
	int type;
	
	if (!Vect_line_alive(Map, line))
	    continue;
	    
	type = Vect_get_line_type(Map, line);

	if (type == GV_BOUNDARY) {
	    struct P_topo_b *topo = (struct P_topo_b *)Map->plus.Line[line]->topo;

	    if (topo->left == 0 || topo->right == 0) {
		G_debug(3, "line = %d left = %d right = %d", line, 
			topo->left, topo->right);
		nerrors++;
	    }
	}
    }
    if (nerrors)
	G_warning(_("Skipping further checks because of incorrect boundaries"));
    else {
	int i, area, left, right, neighbour;
	int nareas = Vect_get_num_areas(Map);
	struct ilist *List = Vect_new_list();

	nerrors = 0;
	for (area = 1; area <= nareas; area++) {
	    if (!Vect_area_alive(Map, area))
		continue;
	    line = Vect_get_area_centroid(Map, area);
	    if (line != 0)
		continue;   /* has centroid */

	    Vect_get_area_boundaries(Map, area, List);
	    for (i = 0; i < List->n_values; i++) {
		line = List->value[i];
		Vect_get_line_areas(Map, abs(line), &left, &right);
		if (line > 0)
		    neighbour = left;
		else
		    neighbour = right;
		    
		if (neighbour < 0) {
		    neighbour = Vect_get_isle_area(Map, abs(neighbour));
		    if (!neighbour) {
			/* borders outer void */
			nerrors++;
			if (Err) {
			    Vect_read_line(Map, Points, Cats, abs(line));
			    Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
			}
		    }
		    /* else neighbour is > 0, check below */
		}
		if (neighbour > 0) {
		    if (Vect_get_area_centroid(Map, neighbour) == 0) {
			/* neighbouring area does not have a centroid either */
			nerrors++;
			if (Err) {
			    Vect_read_line(Map, Points, Cats, abs(line));
			    Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
			}
		    }
		}
	    }
	}
	Vect_destroy_list(List);

	if (nerrors)
	    G_warning(_("Number of redundant holes: %d"), 
	              nerrors);
    }

    /* what else ? */

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return 1;
}
예제 #8
0
/* *************************************************************** */
int plot1(struct Map_info *Map, int type, int area, struct cat_list *Clist,
	  const struct color_rgb *color, const struct color_rgb *fcolor,
	  int chcat, SYMBOL * Symb, int size, int id_flag,
	  int table_colors_flag, int cats_color_flag, char *rgb_column,
	  int default_width, char *width_column, double width_scale)
{
    int i, ltype, nlines = 0, line, cat = -1;
    double *x, *y;
    struct line_pnts *Points, *PPoints;
    struct line_cats *Cats;
    double msize;
    int x0, y0;

    struct field_info *fi = NULL;
    dbDriver *driver = NULL;
    dbCatValArray cvarr_rgb, cvarr_width;
    dbCatVal *cv_rgb = NULL, *cv_width = NULL;
    int nrec_rgb = 0, nrec_width = 0;

    int open_db;
    int custom_rgb = FALSE;
    char colorstring[12];	/* RRR:GGG:BBB */
    int red, grn, blu;
    RGBA_Color *line_color, *fill_color, *primary_color;
    unsigned char which;
    int width;

    line_color = G_malloc(sizeof(RGBA_Color));
    fill_color = G_malloc(sizeof(RGBA_Color));
    primary_color = G_malloc(sizeof(RGBA_Color));

    primary_color->a = RGBA_COLOR_OPAQUE;

    /* change function prototype to pass RGBA_Color instead of color_rgb? */
    if (color) {
	line_color->r = color->r;
	line_color->g = color->g;
	line_color->b = color->b;
	line_color->a = RGBA_COLOR_OPAQUE;
    }
    else
	line_color->a = RGBA_COLOR_NONE;

    if (fcolor) {
	fill_color->r = fcolor->r;
	fill_color->g = fcolor->g;
	fill_color->b = fcolor->b;
	fill_color->a = RGBA_COLOR_OPAQUE;
    }
    else
	fill_color->a = RGBA_COLOR_NONE;


    msize = size * (D_d_to_u_col(2.0) - D_d_to_u_col(1.0));	/* do it better */

    Points = Vect_new_line_struct();
    PPoints = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    open_db = table_colors_flag || width_column;

    if (open_db) {
	fi = Vect_get_field(Map, (Clist->field > 0 ? Clist->field : 1));
	if (fi == NULL) {
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  (Clist->field > 0 ? Clist->field : 1));
	}

	driver = db_start_driver_open_database(fi->driver, fi->database);
	if (driver == NULL)
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  fi->database, fi->driver);
    }

    if (table_colors_flag) {
	/* for reading RRR:GGG:BBB color strings from table */

	if (rgb_column == NULL || *rgb_column == '\0')
	    G_fatal_error(_("Color definition column not specified"));

	db_CatValArray_init(&cvarr_rgb);

	nrec_rgb = db_select_CatValArray(driver, fi->table, fi->key,
					 rgb_column, NULL, &cvarr_rgb);

	G_debug(3, "nrec_rgb (%s) = %d", rgb_column, nrec_rgb);

	if (cvarr_rgb.ctype != DB_C_TYPE_STRING)
	    G_fatal_error(_("Color definition column (%s) not a string. "
			    "Column must be of form RRR:GGG:BBB where RGB values range 0-255."),
			  rgb_column);

	if (nrec_rgb < 0)
	    G_fatal_error(_("Cannot select data (%s) from table"),
			  rgb_column);

	G_debug(2, "\n%d records selected from table", nrec_rgb);

	for (i = 0; i < cvarr_rgb.n_values; i++) {
	    G_debug(4, "cat = %d  %s = %s", cvarr_rgb.value[i].cat,
		    rgb_column, db_get_string(cvarr_rgb.value[i].val.s));
	}
    }

    if (width_column) {
	if (*width_column == '\0')
	    G_fatal_error(_("Line width column not specified."));

	db_CatValArray_init(&cvarr_width);

	nrec_width = db_select_CatValArray(driver, fi->table, fi->key,
					   width_column, NULL, &cvarr_width);

	G_debug(3, "nrec_width (%s) = %d", width_column, nrec_width);

	if (cvarr_width.ctype != DB_C_TYPE_INT &&
	    cvarr_width.ctype != DB_C_TYPE_DOUBLE)
	    G_fatal_error(_("Line width column (%s) not a number."),
			  width_column);

	if (nrec_width < 0)
	    G_fatal_error(_("Cannot select data (%s) from table"),
			  width_column);

	G_debug(2, "\n%d records selected from table", nrec_width);

	for (i = 0; i < cvarr_width.n_values; i++) {
	    G_debug(4, "cat = %d  %s = %d", cvarr_width.value[i].cat,
		    width_column,
		    (cvarr_width.ctype ==
		     DB_C_TYPE_INT ? cvarr_width.value[i].val.
		     i : (int)cvarr_width.value[i].val.d));
	}
    }

    if (open_db)
	db_close_database_shutdown_driver(driver);

    Vect_rewind(Map);

    /* Is it necessary to reset line/label color in each loop ? */

    if (color && !table_colors_flag && !cats_color_flag)
	D_RGB_color(color->r, color->g, color->b);

    if (Vect_level(Map) >= 2)
	nlines = Vect_get_num_lines(Map);

    line = 0;
    while (1) {
	if (Vect_level(Map) >= 2) {
	    line++;
	    if (line > nlines)
		return 0;
	    if (!Vect_line_alive(Map, line))
		continue;
	    ltype = Vect_read_line(Map, Points, Cats, line);
	}
	else {
	    ltype = Vect_read_next_line(Map, Points, Cats);
	    switch (ltype) {
	    case -1:
		fprintf(stderr, _("\nERROR: vector map - can't read\n"));
		return -1;
	    case -2:		/* EOF */
		return 0;
	    }
	}

	if (!(type & ltype))
	    continue;

	if (chcat) {
	    int found = 0;

	    if (id_flag) {	/* use line id */
		if (!(Vect_cat_in_cat_list(line, Clist)))
		    continue;
	    }
	    else {
		for (i = 0; i < Cats->n_cats; i++) {
		    if (Cats->field[i] == Clist->field &&
			Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
			found = 1;
			break;
		    }
		}
		if (!found)
		    continue;
	    }
	}
	else if (Clist->field > 0) {
	    int found = 0;

	    for (i = 0; i < Cats->n_cats; i++) {
		if (Cats->field[i] == Clist->field) {
		    found = 1;
		    break;
		}
	    }
	    /* lines with no category will be displayed */
	    if (Cats->n_cats > 0 && !found)
		continue;
	}


	if (table_colors_flag) {

	    /* only first category */
	    cat = Vect_get_line_cat(Map, line,
				    (Clist->field > 0 ? Clist->field :
				     (Cats->n_cats >
				      0 ? Cats->field[0] : 1)));

	    if (cat >= 0) {
		G_debug(3, "display element %d, cat %d", line, cat);

		/* Read RGB colors from db for current area # */
		if (db_CatValArray_get_value(&cvarr_rgb, cat, &cv_rgb) !=
		    DB_OK) {
		    custom_rgb = FALSE;
		}
		else {
		    sprintf(colorstring, "%s", db_get_string(cv_rgb->val.s));

		    if (*colorstring != '\0') {
			G_debug(3, "element %d: colorstring: %s", line,
				colorstring);

			if (G_str_to_color(colorstring, &red, &grn, &blu) ==
			    1) {
			    custom_rgb = TRUE;
			    G_debug(3, "element:%d  cat %d r:%d g:%d b:%d",
				    line, cat, red, grn, blu);
			}
			else {
			    custom_rgb = FALSE;
			    G_warning(_("Error in color definition column (%s), element %d "
				       "with cat %d: colorstring [%s]"),
				      rgb_column, line, cat, colorstring);
			}
		    }
		    else {
			custom_rgb = FALSE;
			G_warning(_("Error in color definition column (%s), element %d with cat %d"),
				  rgb_column, line, cat);
		    }
		}
	    }			/* end if cat */
	    else {
		custom_rgb = FALSE;
	    }
	}			/* end if table_colors_flag */


	/* random colors */
	if (cats_color_flag) {
	    custom_rgb = FALSE;
	    if (Clist->field > 0) {
		cat = Vect_get_line_cat(Map, line, Clist->field);
		if (cat >= 0) {
		    G_debug(3, "display element %d, cat %d", line, cat);
		    /* fetch color number from category */
		    which = (cat % palette_ncolors);
		    G_debug(3, "cat:%d which color:%d r:%d g:%d b:%d", cat,
			    which, palette[which].R, palette[which].G,
			    palette[which].B);

		    custom_rgb = TRUE;
		    red = palette[which].R;
		    grn = palette[which].G;
		    blu = palette[which].B;
		}
	    }
	    else if (Cats->n_cats > 0) {
		/* fetch color number from layer */
		which = (Cats->field[0] % palette_ncolors);
		G_debug(3, "layer:%d which color:%d r:%d g:%d b:%d",
			Cats->field[0], which, palette[which].R,
			palette[which].G, palette[which].B);

		custom_rgb = TRUE;
		red = palette[which].R;
		grn = palette[which].G;
		blu = palette[which].B;
	    }
	}


	if (nrec_width) {

	    /* only first category */
	    cat = Vect_get_line_cat(Map, line,
				    (Clist->field > 0 ? Clist->field :
				     (Cats->n_cats >
				      0 ? Cats->field[0] : 1)));

	    if (cat >= 0) {
		G_debug(3, "display element %d, cat %d", line, cat);

		/* Read line width from db for current area # */

		if (db_CatValArray_get_value(&cvarr_width, cat, &cv_width) !=
		    DB_OK) {
		    width = default_width;
		}
		else {
		    width =
			width_scale * (cvarr_width.ctype ==
				       DB_C_TYPE_INT ? cv_width->val.
				       i : (int)cv_width->val.d);
		    if (width < 0) {
			G_warning(_("Error in line width column (%s), element %d "
				   "with cat %d: line width [%d]"),
				  width_column, line, cat, width);
			width = default_width;
		    }
		}
	    }			/* end if cat */
	    else {
		width = default_width;
	    }

	    D_line_width(width);
	}			/* end if nrec_width */


	/* enough of the prep work, lets start plotting stuff */
	x = Points->x;
	y = Points->y;

	if ((ltype & GV_POINTS) && Symb != NULL) {
	    if (!(color || fcolor || custom_rgb))
		continue;

	    x0 = D_u_to_d_col(x[0]);
	    y0 = D_u_to_d_row(y[0]);

	    /* skip if the point is outside of the display window */
	    /*      xy<0 tests make it go ever-so-slightly faster */
	    if (x0 < 0 || y0 < 0 ||
		x0 > D_get_d_east() || x0 < D_get_d_west() ||
		y0 > D_get_d_south() || y0 < D_get_d_north())
		continue;

	    /* use random or RGB column color if given, otherwise reset */
	    /* centroids always use default color to stand out from underlying area */
	    if (custom_rgb && (ltype != GV_CENTROID)) {
		primary_color->r = (unsigned char)red;
		primary_color->g = (unsigned char)grn;
		primary_color->b = (unsigned char)blu;
		D_symbol2(Symb, x0, y0, primary_color, line_color);
	    }
	    else
		D_symbol(Symb, x0, y0, line_color, fill_color);


	}
	else if (color || custom_rgb) {
	    if (!table_colors_flag && !cats_color_flag)
		D_RGB_color(color->r, color->g, color->b);
	    else {
		if (custom_rgb)
		    D_RGB_color((unsigned char)red, (unsigned char)grn,
				(unsigned char)blu);
		else
		    D_RGB_color(color->r, color->g, color->b);
	    }

	    /* Plot the lines */
	    if (Points->n_points == 1)	/* line with one coor */
		D_polydots_abs(x, y, Points->n_points);
	    else		/*use different user defined render methods */
		D_polyline_abs(x, y, Points->n_points);
	}
    }

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return 0;			/* not reached */
}
예제 #9
0
파일: connect.c 프로젝트: caomw/grass
/**
 * \brief Consolidate network arcs (edge) based on given point vector map (nodes)
 *
 * If there is no connection between network edge and point, new edge
 * is added, the line broken, and new point added to nfield layer
 *
 * \param In,Points input vector maps
 * \param Out output vector map
 * \param nfield nodes layer
 * \param thresh threshold value to find neareast line
 *
 * \return number of new arcs
 */
int connect_arcs(struct Map_info *In, struct Map_info *Pnts,
                 struct Map_info *Out, int afield, int nfield,
                 double thresh, int snap)
{
    int narcs;
    int type, line, seg, i, ltype, broken;
    double px, py, pz, spdist, dist;

    struct line_pnts *Points, *Pline, *Pout;
    struct line_cats *Cats, *Cline, *Cnew;
    int maxcat, findex, ncats;

    narcs = 0;

    Points = Vect_new_line_struct();
    Pline = Vect_new_line_struct();
    Pout = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    Cline = Vect_new_cats_struct();
    Cnew = Vect_new_cats_struct();

    /* rewrite all primitives to output file */
    Vect_copy_map_lines(In, Out);
    Vect_build_partial(Out, GV_BUILD_BASE);

    findex = Vect_cidx_get_field_index(In, afield);
    ncats = Vect_cidx_get_num_cats_by_index(In, findex);
    Vect_cidx_get_cat_by_index(In, findex, ncats - 1, &maxcat, &type, &line);


    /* go thorough all points in point map and write a new arcs if missing */
    while ((type = Vect_read_next_line(Pnts, Points, Cats)) >= 0) {
        if (type != GV_POINT)
            continue;

        /* find the nearest line in given threshold */
        line = Vect_find_line(Out,
                              Points->x[0], Points->y[0], Points->z[0],
                              GV_LINES, thresh, WITHOUT_Z, 0);

        if (line < 1 || !Vect_line_alive(Out, line))
            continue;

        ltype = Vect_read_line(Out, Pline, Cline, line);

        /* find point on the line */
        seg = Vect_line_distance(Pline,
                                 Points->x[0], Points->y[0], Points->z[0],
                                 WITHOUT_Z, &px, &py, &pz, &dist, &spdist,
                                 NULL);

        if (seg == 0)
            G_fatal_error(_("Failed to find intersection segment"));
        /* break the line */
        broken = 0;
        Vect_reset_line(Pout);
        for (i = 0; i < seg; i++) {
            Vect_append_point(Pout, Pline->x[i], Pline->y[i], Pline->z[i]);
        }
        Vect_append_point(Pout, px, py, pz);
        Vect_line_prune(Pout);
        if (Pout->n_points > 1) {
            Vect_rewrite_line(Out, line, ltype, Pout, Cline);
            broken++;
        }

        Vect_reset_line(Pout);
        Vect_append_point(Pout, px, py, pz);
        for (i = seg; i < Pline->n_points; i++) {
            Vect_append_point(Pout, Pline->x[i], Pline->y[i], Pline->z[i]);
        }
        Vect_line_prune(Pout);
        if (Pout->n_points > 1) {
            if (broken)
                Vect_write_line(Out, ltype, Pout, Cline);
            else
                Vect_rewrite_line(Out, line, ltype, Pout, Cline);
            broken++;
        }
        if (broken == 2)
            narcs++;

        if (dist > 0.0) {
            if (snap) {
                /* snap point */
                Points->x[0] = px;
                Points->y[0] = py;
                Points->z[0] = pz;
            }
            else {
                /* write new arc */
                Vect_reset_line(Pout);
                Vect_append_point(Pout, px, py, pz);
                Vect_append_point(Pout, Points->x[0], Points->y[0], Points->z[0]);
                maxcat++;
                Vect_reset_cats(Cnew);
                Vect_cat_set(Cnew, afield, maxcat);
                Vect_write_line(Out, ltype, Pout, Cnew);

                narcs++;
            }
        }

        /* add points to 'nfield' layer */
        for (i = 0; i < Cats->n_cats; i++) {
            Cats->field[i] = nfield;	/* all points to 'nfield' layer */
        }

        Vect_write_line(Out, type, Points, Cats);
    }

    Vect_destroy_line_struct(Points);
    Vect_destroy_line_struct(Pline);
    Vect_destroy_line_struct(Pout);
    Vect_destroy_cats_struct(Cats);
    Vect_destroy_cats_struct(Cline);
    Vect_destroy_cats_struct(Cnew);

    return narcs;
}
예제 #10
0
파일: render.c 프로젝트: imincik/pkg-grass
/*!
   \brief Draw one feature
 */
struct robject *draw_line(struct Map_info *Map, int line, int draw_flag)
{
    int draw;
    struct robject *obj;

    if (!state.Points)
	state.Points = Vect_new_line_struct();

    if (!Vect_line_alive(Map, line))
	return NULL;

    state.type = Vect_read_line(Map, state.Points, NULL, line);

    obj = (struct robject *)G_malloc(sizeof(struct robject));
    obj->fid = line;
    draw = FALSE;
    if (state.type & GV_LINES) {
	if (state.type == GV_LINE) {
	    obj->type = TYPE_LINE;
	    draw = draw_flag & DRAW_LINE;
	}
	else if (state.type == GV_BOUNDARY) {
	    int left, right;

	    Vect_get_line_areas(Map, line, &left, &right);
	    if (left == 0 && right == 0) {
		obj->type = TYPE_BOUNDARYNO;
		draw = draw_flag & DRAW_BOUNDARYNO;
	    }
	    else if (left > 0 && right > 0) {
		obj->type = TYPE_BOUNDARYTWO;
		draw = draw_flag & DRAW_BOUNDARYTWO;
	    }
	    else {
		obj->type = TYPE_BOUNDARYONE;
		draw = draw_flag & DRAW_BOUNDARYONE;
	    }
	}
    }
    else if (state.type & GV_POINTS) {
	if (state.type == GV_POINT) {
	    obj->type = TYPE_POINT;
	    draw = draw_flag & DRAW_POINT;
	}
	else if (state.type == GV_CENTROID) {
	    int cret = Vect_get_centroid_area(Map, line);

	    if (cret > 0) {	/* -> area */
		obj->type = TYPE_CENTROIDIN;
		draw = draw_flag & DRAW_CENTROIDIN;
	    }
	    else if (cret == 0) {
		obj->type = TYPE_CENTROIDOUT;
		draw = draw_flag & DRAW_CENTROIDOUT;
	    }
	    else {
		obj->type = TYPE_CENTROIDDUP;
		draw = draw_flag & DRAW_CENTROIDDUP;
	    }
	}
    }
    G_debug(3, "  draw_line(): type=%d rtype=%d npoints=%d draw=%d",
	    state.type, obj->type, state.Points->n_points, draw);

    if (!draw)
	return NULL;

    obj->npoints = state.Points->n_points;
    obj->point =
	(struct rpoint *)G_malloc(obj->npoints * sizeof(struct rpoint));
    robj_points(obj, state.Points);

    return obj;
}
예제 #11
0
/* 
   Called by Vect_remove_bridges() and Vect_chtype_bridges():
   chtype = 0 -> works like Vect_remove_bridges()
   chtype = 1 -> works like Vect_chtype_bridges()

   Algorithm: Go thorough all lines, 
   if both sides of the line have left and side 0 (candidate) do this check:
   follow adjacent lines in one direction (nearest to the right at the end node),
   if we reach this line again without dangle in the way, but with this line 
   traversed from other side it is a bridge.

   List of all lines in chain is created during the cycle.
 */
void
remove_bridges(struct Map_info *Map, int chtype, struct Map_info *Err)
{
    int i, type, nlines, line;
    int left, right, node1, node2, current_line, next_line;
    int bridges_removed = 0;	/* number of removed bridges */
    int lines_removed = 0;	/* number of lines removed */
    char *lmsg;
    struct Plus_head *Plus;
    struct line_pnts *Points;
    struct line_cats *Cats;
    struct ilist *CycleList;
    struct ilist *BridgeList;

    int dangle, other_side;

    if (chtype)
	lmsg = "changed lines";
    else
	lmsg = "removed lines";

    Plus = &(Map->plus);

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    CycleList = Vect_new_list();
    BridgeList = Vect_new_list();

    nlines = Vect_get_num_lines(Map);

    G_debug(1, "nlines =  %d", nlines);

    for (line = 1; line <= nlines; line++) {
	G_percent(line, nlines, 1);
	if (!Vect_line_alive(Map, line))
	    continue;

	type = Vect_read_line(Map, NULL, NULL, line);
	if (!(type & GV_BOUNDARY))
	    continue;

	Vect_get_line_areas(Map, line, &left, &right);

	if (left != 0 || right != 0)
	    continue;		/* Cannot be bridge */

	G_debug(2, "line %d - bridge candidate", line);

	Vect_get_line_nodes(Map, line, &node1, &node2);

	if (abs(node1) == abs(node2))
	    continue;		/* either zero length or loop -> cannot be a bridge */

	current_line = -line;	/* we start with negative (go forward, node2 ) */

	dangle = 0;
	other_side = 0;
	Vect_reset_list(CycleList);
	Vect_reset_list(BridgeList);
	while (1) {
	    next_line =
		dig_angle_next_line(Plus, current_line, GV_RIGHT,
				    GV_BOUNDARY);

	    /* Add this line to the list */
	    /* TODO: Vect_val_in_list() and Vect_list_append() behave O(n)
	     * change to O(log n) */
	    if (Vect_val_in_list(CycleList, abs(next_line)))	/* other side -> bridge chain */
		Vect_list_append(BridgeList, abs(next_line));
	    else
		dig_list_add(CycleList, abs(next_line)); /* not in list, can add new line fast */

	    if (abs(next_line) == abs(current_line)) {
		G_debug(4, "  dangle -> no bridge");
		dangle = 1;
		break;
	    }
	    if (abs(next_line) == line) {	/* start line reached */
		/* which side */
		if (next_line < 0) {	/* other side (connected by node 2) */
		    G_debug(5, "  other side reached");
		    other_side = 1;
		}
		else {		/* start side */
		    break;
		}
	    }

	    current_line = -next_line;	/* change the sign to look at the next node in following cycle */
	}

	if (!dangle && other_side) {
	    G_debug(3, " line %d is part of bridge chain", line);

	    for (i = 0; i < BridgeList->n_values; i++) {
		Vect_read_line(Map, Points, Cats, BridgeList->value[i]);

		if (Err) {
		    Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
		}

		if (!chtype)
		    Vect_delete_line(Map, BridgeList->value[i]);
		else
		    Vect_rewrite_line(Map, BridgeList->value[i], GV_LINE,
				      Points, Cats);

		lines_removed++;
	    }
	    bridges_removed++;
	}
    }
    G_verbose_message("Removed lines: %d", lines_removed);
    G_verbose_message("Removed bridges: %d", bridges_removed);
}
예제 #12
0
/*!
   \brief Remove duplicate features from vector map.

   Remove duplicate lines of given types from vector map. Duplicate
   lines may be optionally written to error map. Input map must be
   opened on level 2 for update. Categories are merged.
   GV_BUILD_BASE is sufficient.

   \param[in,out] Map vector map where duplicate lines will be deleted
   \param type type of line to be delete
   \param[out] Err vector map where duplicate lines will be written or NULL

   \return void
 */
void
Vect_remove_duplicates(struct Map_info *Map, int type, struct Map_info *Err)
{
    struct line_pnts *APoints, *BPoints;
    struct line_cats *ACats, *BCats, *Cats;
    int i, j, c, atype, btype, bline;
    int nlines, nbcats_orig;
    struct bound_box ABox;
    struct boxlist *List;
    int ndupl;


    APoints = Vect_new_line_struct();
    BPoints = Vect_new_line_struct();
    ACats = Vect_new_cats_struct();
    BCats = Vect_new_cats_struct();
    Cats = Vect_new_cats_struct();
    List = Vect_new_boxlist(0);

    nlines = Vect_get_num_lines(Map);

    G_debug(1, "nlines =  %d", nlines);
    /* Go through all lines in vector, for each select lines which overlap MBR of
     *  this line and check if some of them is identical. If someone is identical
     *  remove current line. (In each step just one line is deleted)
     */

    ndupl = 0;

    for (i = 1; i <= nlines; i++) {
	G_percent(i, nlines, 1);
	if (!Vect_line_alive(Map, i))
	    continue;

	atype = Vect_read_line(Map, APoints, ACats, i);
	if (!(atype & type))
	    continue;

	Vect_line_box(APoints, &ABox);
	Vect_select_lines_by_box(Map, &ABox, type, List);
	G_debug(3, "  %d lines selected by box", List->n_values);

	for (j = 0; j < List->n_values; j++) {
	    bline = List->id[j];
	    G_debug(3, "  j = %d bline = %d", j, bline);
	    if (i == bline)
		continue;

	    btype = Vect_read_line(Map, BPoints, BCats, bline);

	    /* check for duplicates */
	    if (!Vect_line_check_duplicate(APoints, BPoints, Vect_is_3d(Map)))
		continue;

	    /* Lines area identical -> remove current */
	    if (Err) {
		Vect_write_line(Err, atype, APoints, ACats);
	    }

	    Vect_delete_line(Map, i);

	    /* Merge categories */
	    nbcats_orig = BCats->n_cats;

	    for (c = 0; c < ACats->n_cats; c++)
		Vect_cat_set(BCats, ACats->field[c], ACats->cat[c]);

	    if (BCats->n_cats > nbcats_orig) {
		G_debug(4, "cats merged: n_cats %d -> %d", nbcats_orig,
			BCats->n_cats);
		Vect_rewrite_line(Map, bline, btype, BPoints, BCats);
	    }

	    ndupl++;

	    break;		/* line was deleted -> take the next one */
	}
	nlines = Vect_get_num_lines(Map);	/* For future when lines with cats will be rewritten */
	G_debug(3, "nlines =  %d\n", nlines);
    }
    G_verbose_message("Removed duplicates: %d", ndupl);
}
예제 #13
0
int main(int argc, char **argv)
{
    int i;
    int **cats, *ncats, nfields, *fields;
    struct Flag *line_flag;

    /* struct Flag *all_flag; */
    struct Option *in_opt, *out_opt;
    struct Flag *table_flag;
    struct GModule *module;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int node, nnodes;
    COOR *coor;
    int ncoor, acoor;
    int line, nlines, type, ctype, area, nareas;
    int err_boundaries, err_centr_out, err_centr_dupl, err_nocentr;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("geometry"));
    G_add_keyword(_("triangulation"));
    module->description = _("Creates a Voronoi diagram from an input vector "
			    "map containing points or centroids.");

    in_opt = G_define_standard_option(G_OPT_V_INPUT);
    out_opt = G_define_standard_option(G_OPT_V_OUTPUT);

    /*
       all_flag = G_define_flag ();
       all_flag->key = 'a';
       all_flag->description = _("Use all points (do not limit to current region)");
     */

    line_flag = G_define_flag();
    line_flag->key = 'l';
    line_flag->description =
	_("Output tessellation as a graph (lines), not areas");

    table_flag = G_define_flag();
    table_flag->key = 't';
    table_flag->description = _("Do not create attribute table");

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);


    if (line_flag->answer)
	Type = GV_LINE;
    else
	Type = GV_BOUNDARY;

    All = 0;

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    /* open files */
    Vect_set_open_level(2);
    Vect_open_old(&In, in_opt->answer, "");

    if (Vect_open_new(&Out, out_opt->answer, 0) < 0)
	G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);

    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);

    /* initialize working region */
    G_get_window(&Window);
    Vect_region_box(&Window, &Box);
    Box.T = 0.5;
    Box.B = -0.5;

    freeinit(&sfl, sizeof(struct Site));

    G_message(_("Reading sites..."));
    readsites();

    siteidx = 0;
    geominit();

    triangulate = 0;
    plot = 0;
    debug = 0;

    G_message(_("Voronoi triangulation..."));
    voronoi(triangulate, nextone);

    /* Close free ends by current region */
    Vect_build_partial(&Out, GV_BUILD_BASE);

    ncoor = 0;
    acoor = 100;
    coor = (COOR *) G_malloc(sizeof(COOR) * acoor);

    nnodes = Vect_get_num_nodes(&Out);
    for (node = 1; node <= nnodes; node++) {
	double x, y;

	if (Vect_get_node_n_lines(&Out, node) < 2) {	/* add coordinates */
	    Vect_get_node_coor(&Out, node, &x, &y, NULL);

	    if (ncoor == acoor - 5) {	/* always space for 5 region corners */
		acoor += 100;
		coor = (COOR *) G_realloc(coor, sizeof(COOR) * acoor);
	    }

	    coor[ncoor].x = x;
	    coor[ncoor].y = y;
	    ncoor++;
	}
    }

    /* Add region corners */
    coor[ncoor].x = Box.W;
    coor[ncoor].y = Box.S;
    ncoor++;
    coor[ncoor].x = Box.E;
    coor[ncoor].y = Box.S;
    ncoor++;
    coor[ncoor].x = Box.E;
    coor[ncoor].y = Box.N;
    ncoor++;
    coor[ncoor].x = Box.W;
    coor[ncoor].y = Box.N;
    ncoor++;

    /* Sort */
    qsort(coor, ncoor, sizeof(COOR), (void *)cmp);

    /* add last (first corner) */
    coor[ncoor].x = Box.W;
    coor[ncoor].y = Box.S;
    ncoor++;

    for (i = 1; i < ncoor; i++) {
	if (coor[i].x == coor[i - 1].x && coor[i].y == coor[i - 1].y)
	    continue;		/* duplicate */

	Vect_reset_line(Points);
	Vect_append_point(Points, coor[i].x, coor[i].y, 0.0);
	Vect_append_point(Points, coor[i - 1].x, coor[i - 1].y, 0.0);
	Vect_write_line(&Out, Type, Points, Cats);
    }

    G_free(coor);

    /* Copy input points as centroids */
    nfields = Vect_cidx_get_num_fields(&In);
    cats = (int **)G_malloc(nfields * sizeof(int *));
    ncats = (int *)G_malloc(nfields * sizeof(int));
    fields = (int *)G_malloc(nfields * sizeof(int));
    for (i = 0; i < nfields; i++) {
	ncats[i] = 0;
	cats[i] =
	    (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&In, i) *
			    sizeof(int));
	fields[i] = Vect_cidx_get_field_number(&In, i);
    }

    if (line_flag->answer)
	ctype = GV_POINT;
    else
	ctype = GV_CENTROID;

    nlines = Vect_get_num_lines(&In);

    G_message(_("Writing sites to output..."));

    for (line = 1; line <= nlines; line++) {

	G_percent(line, nlines, 2);

	type = Vect_read_line(&In, Points, Cats, line);
	if (!(type & GV_POINTS))
	    continue;

	if (!Vect_point_in_box(Points->x[0], Points->y[0], 0.0, &Box))
	    continue;

	Vect_write_line(&Out, ctype, Points, Cats);


	for (i = 0; i < Cats->n_cats; i++) {
	    int f, j;

	    f = -1;
	    for (j = 0; j < nfields; j++) {	/* find field */
		if (fields[j] == Cats->field[i]) {
		    f = j;
		    break;
		}
	    }
	    if (f > -1) {
		cats[f][ncats[f]] = Cats->cat[i];
		ncats[f]++;
	    }
	}
    }

    /* Copy tables */
    if (!(table_flag->answer)) {
	int ttype, ntabs = 0;
	struct field_info *IFi, *OFi;

	/* Number of output tabs */
	for (i = 0; i < Vect_get_num_dblinks(&In); i++) {
	    int f, j;

	    IFi = Vect_get_dblink(&In, i);

	    f = -1;
	    for (j = 0; j < nfields; j++) {	/* find field */
		if (fields[j] == IFi->number) {
		    f = j;
		    break;
		}
	    }
	    if (f > -1) {
		if (ncats[f] > 0)
		    ntabs++;
	    }
	}

	if (ntabs > 1)
	    ttype = GV_MTABLE;
	else
	    ttype = GV_1TABLE;

	for (i = 0; i < nfields; i++) {
	    int ret;

	    if (fields[i] == 0)
		continue;

	    G_message(_("Layer %d"), fields[i]);

	    /* Make a list of categories */
	    IFi = Vect_get_field(&In, fields[i]);
	    if (!IFi) {		/* no table */
		G_message(_("No table"));
		continue;
	    }

	    OFi =
		Vect_default_field_info(&Out, IFi->number, IFi->name, ttype);

	    ret =
		db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table,
				      OFi->driver,
				      Vect_subst_var(OFi->database, &Out),
				      OFi->table, IFi->key, cats[i],
				      ncats[i]);

	    if (ret == DB_FAILED) {
		G_warning(_("Cannot copy table"));
	    }
	    else {
		Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table,
				    IFi->key, OFi->database, OFi->driver);
	    }
	}
    }


    Vect_close(&In);

    /* cleaning part 1: count errors */
    Vect_build_partial(&Out, GV_BUILD_CENTROIDS);
    err_boundaries = err_centr_out = err_centr_dupl = err_nocentr = 0;
    nlines = Vect_get_num_lines(&Out);
    for (line = 1; line <= nlines; line++) {

	if (!Vect_line_alive(&Out, line))
	    continue;

	type = Vect_get_line_type(&Out, line);
	if (type == GV_BOUNDARY) {
	    int left, right;

	    Vect_get_line_areas(&Out, line, &left, &right);

	    if (left == 0 || right == 0) {
		G_debug(3, "line = %d left = %d right = %d", line, 
			left, right);
		err_boundaries++;
	    }
	}
	if (type == GV_CENTROID) {
	    area = Vect_get_centroid_area(&Out, line);
	    if (area == 0)
		err_centr_out++;
	    else if (area < 0)
		err_centr_dupl++;
	}
    }

    err_nocentr = 0;
    nareas = Vect_get_num_areas(&Out);
    for (area = 1; area <= nareas; area++) {
	if (!Vect_area_alive(&Out, area))
	    continue;
	line = Vect_get_area_centroid(&Out, area);
	if (line == 0)
	    err_nocentr++;
    }

    /* cleaning part 2: snap */
    if (err_nocentr || err_centr_dupl || err_centr_out) {
	int nmod;

	G_important_message(_("Output needs topological cleaning"));
	Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL);
	do {
	    Vect_break_lines(&Out, GV_BOUNDARY, NULL);
	    Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);
	    nmod =
		Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL);
	} while (nmod > 0);

	err_boundaries = 0;
	nlines = Vect_get_num_lines(&Out);
	for (line = 1; line <= nlines; line++) {

	    if (!Vect_line_alive(&Out, line))
		continue;

	    type = Vect_get_line_type(&Out, line);
	    if (type == GV_BOUNDARY) {
		int left, right;

		Vect_get_line_areas(&Out, line, &left, &right);

		if (left == 0 || right == 0) {
		    G_debug(3, "line = %d left = %d right = %d", line, 
			    left, right);
		    err_boundaries++;
		}
	    }
	}
    }
    /* cleaning part 3: remove remaining incorrect boundaries */
    if (err_boundaries) {
	G_important_message(_("Removing incorrect boundaries from output"));
	nlines = Vect_get_num_lines(&Out);
	for (line = 1; line <= nlines; line++) {

	    if (!Vect_line_alive(&Out, line))
		continue;

	    type = Vect_get_line_type(&Out, line);
	    if (type == GV_BOUNDARY) {
		int left, right;

		Vect_get_line_areas(&Out, line, &left, &right);

		/* &&, not ||, no typo */
		if (left == 0 && right == 0) {
		    G_debug(3, "line = %d left = %d right = %d", line, 
			    left, right);
		    Vect_delete_line(&Out, line);
		}
	    }
	}
    }

    /* build clean topology */
    Vect_build_partial(&Out, GV_BUILD_NONE);
    Vect_build(&Out);
    Vect_close(&Out);

    G_done_msg(" ");
    exit(EXIT_SUCCESS);
}
예제 #14
0
/*!
  \brief Merge lines/boundaries
  
  At least two lines need to be given.
  
  \param Map pointer to Map_info
  \param List list of selected lines
  
   \return number of merged lines
   \return -1 on error
*/
int Vedit_merge_lines(struct Map_info *Map, struct ilist *List)
{
    struct ilist *List_in_box;

    struct line_pnts *Points1, *Points2, *Points;
    struct line_cats *Cats1, *Cats2;

    int line_i, i, j;
    int line, line1, type1, line2;
    int do_merge;

    /* number of lines (original, selected, merged) */
    int nlines, nlines_merged;

    nlines_merged = 0;

    if (List->n_values < 2) {
	return 0;
    }

    Points1 = Vect_new_line_struct();
    Cats1 = Vect_new_cats_struct();
    Points2 = Vect_new_line_struct();
    Cats2 = Vect_new_cats_struct();
    Points = Vect_new_line_struct();

    List_in_box = Vect_new_list();

    nlines = Vect_get_num_lines(Map);
    
    /* merge lines */
    for (line_i = 0; line_i < List->n_values; line_i++) {
	line1 = List->value[line_i];

	if (!Vect_line_alive(Map, line1))
	    continue;

	type1 = Vect_read_line(Map, Points1, Cats1, line1);

	if (!(type1 & GV_LINES))
	    continue;

	Vect_reset_line(Points);

	for (i = 0; i < Points1->n_points; i += Points1->n_points - 1) {
	    Vect_reset_list(List_in_box);

	    /* define searching region */
	    Vect_reset_line(Points2);
	    /*
	       Vect_append_point (Points2, Points1 -> x[i] - thresh,
	       Points1 -> y[i] + thresh, Points1 -> z[i]);
	       Vect_append_point (Points2, Points1 -> x[i] + thresh,
	       Points1 -> y[i] + thresh, Points1 -> z[i]);
	       Vect_append_point (Points2, Points1 -> x[i] + thresh,
	       Points1 -> y[i] - thresh, Points1 -> z[i]);
	       Vect_append_point (Points2, Points1 -> x[i] - thresh,
	       Points1 -> y[i] - thresh, Points1 -> z[i]);
	     */
	    Vect_append_point(Points2, Points1->x[i],
			      Points1->y[i], Points1->z[i]);

	    /* 
	     * merge lines only if two lines found in the region
	     * i.e. the current line and an adjacent line
	     */
	    if (1 < Vect_select_lines_by_polygon(Map, Points2, 0, NULL,
						 GV_LINES, List_in_box)) {
		do_merge = 1;
		line2 = -1;
		for (j = 0; do_merge && j < List->n_values; j++) {
		    if (List->value[j] == line1 ||
			!Vect_line_alive(Map, List->value[j]))
			continue;

		    if (Vect_val_in_list(List_in_box, List->value[j])) {
			if (line2 > 0) {
			    /* three lines found
			     * selected lines will be not merged
			     */
			    do_merge = 0;
			}
			else {
			    line2 = List->value[j];
			}
		    }
		}

		if (!do_merge || line2 < 0)
		    continue;

		Vect_read_line(Map, Points2, Cats2, line2);

		merge_lines(Points1, Cats1, Points2, Cats2, -1.0, &Points);	/* do not use threshold value */

		G_debug(3, "Vedit_merge_lines(): lines=%d,%d", line1, line2);

		if (Points->n_points > 0) {
		    if (Vect_delete_line(Map, line2) == -1) {
			return -1;
		    }

		    if (line2 <= nlines)
			nlines_merged++;
		}
	    }
	}			/* for each node */

	if (Points->n_points > 0) {
	    line = Vect_rewrite_line(Map, line1, type1, Points, Cats1);
	    if (line < 0) {
		return -1;
	    }

	    if (line1 <= nlines)
		nlines_merged++;

	    /* update number of lines */
	    Vect_list_append(List, line);
	}
    }				/* for each line */

    /* destroy stuctures */
    Vect_destroy_line_struct(Points1);
    Vect_destroy_line_struct(Points2);
    Vect_destroy_line_struct(Points);

    Vect_destroy_cats_struct(Cats1);
    Vect_destroy_cats_struct(Cats2);

    return nlines_merged;
}
예제 #15
0
/* break polygons using a memory-based search index */
void Vect_break_polygons_mem(struct Map_info *Map, int type, struct Map_info *Err)
{
    struct line_pnts *BPoints, *Points;
    struct line_cats *Cats, *ErrCats;
    int i, j, k, ret, ltype, broken, last, nlines;
    int nbreaks;
    struct RB_TREE *RBTree;
    int npoints, nallpoints, nmarks;
    XPNT *XPnt_found, XPnt_search;
    double dx, dy, a1 = 0, a2 = 0;
    int closed, last_point, cross;

    G_debug(1, "Memory-based version of Vect_break_polygons()");

    RBTree = rbtree_create(compare_xpnts, sizeof(XPNT));

    BPoints = Vect_new_line_struct();
    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    ErrCats = Vect_new_cats_struct();

    nlines = Vect_get_num_lines(Map);

    G_debug(3, "nlines =  %d", nlines);
    /* Go through all lines in vector, and add each point to structure of points,
     * if such point already exists check angles of segments and if differ mark for break */

    nmarks = 0;
    npoints = 0;
    nallpoints = 0;
    XPnt_search.used = 0;

    G_message(_("Breaking polygons (pass 1: select break points)..."));

    for (i = 1; i <= nlines; i++) {
	G_percent(i, nlines, 1);
	G_debug(3, "i =  %d", i);
	if (!Vect_line_alive(Map, i))
	    continue;

	ltype = Vect_read_line(Map, Points, Cats, i);
	if (!(ltype & type))
	    continue;

	/* This would be confused by duplicate coordinates (angle cannot be calculated) ->
	 * prune line first */
	Vect_line_prune(Points);

	/* If first and last point are identical it is close polygon, we don't need to register last point
	 * and we can calculate angle for first.
	 * If first and last point are not identical we have to mark for break both */
	last_point = Points->n_points - 1;
	if (Points->x[0] == Points->x[last_point] &&
	    Points->y[0] == Points->y[last_point])
	    closed = 1;
	else
	    closed = 0;

	for (j = 0; j < Points->n_points; j++) {
	    G_debug(3, "j =  %d", j);
	    nallpoints++;

	    if (j == last_point && closed)
		continue;	/* do not register last of close polygon */

	    XPnt_search.x = Points->x[j];
	    XPnt_search.y = Points->y[j];

	    /* Already in DB? */
	    XPnt_found = rbtree_find(RBTree, &XPnt_search);

	    if (Points->n_points <= 2 ||
		(!closed && (j == 0 || j == last_point))) {
		cross = 1;	/* mark for cross in any case */
	    }
	    else {		/* calculate angles */
		cross = 0;
		if (j == 0 && closed) {	/* closed polygon */
		    dx = Points->x[last_point] - Points->x[0];
		    dy = Points->y[last_point] - Points->y[0];
		    a1 = atan2(dy, dx);
		    dx = Points->x[1] - Points->x[0];
		    dy = Points->y[1] - Points->y[0];
		    a2 = atan2(dy, dx);
		}
		else {
		    dx = Points->x[j - 1] - Points->x[j];
		    dy = Points->y[j - 1] - Points->y[j];
		    a1 = atan2(dy, dx);
		    dx = Points->x[j + 1] - Points->x[j];
		    dy = Points->y[j + 1] - Points->y[j];
		    a2 = atan2(dy, dx);
		}
	    }

	    if (XPnt_found) {	/* found */
		if (XPnt_found->cross == 1)
		    continue;	/* already marked */

		/* check angles */
		if (cross) {
		    XPnt_found->cross = 1;
		    nmarks++;
		}
		else {
		    G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1,
			    XPnt_found->a1, a2, XPnt_found->a2);
		    if ((a1 == XPnt_found->a1 && a2 == XPnt_found->a2) ||
		        (a1 == XPnt_found->a2 && a2 == XPnt_found->a1)) {	/* identical */

		    }
		    else {
			XPnt_found->cross = 1;
			nmarks++;
		    }
		}
	    }
	    else {
		if (j == 0 || j == (Points->n_points - 1) ||
		    Points->n_points < 3) {
		    XPnt_search.a1 = 0;
		    XPnt_search.a2 = 0;
		    XPnt_search.cross = 1;
		    nmarks++;
		}
		else {
		    XPnt_search.a1 = a1;
		    XPnt_search.a2 = a2;
		    XPnt_search.cross = 0;
		}

		/* Add to tree */
		rbtree_insert(RBTree, &XPnt_search);
		npoints++;
	    }
	}
    }

    nbreaks = 0;
    nallpoints = 0;
    G_debug(2, "Break polygons: unique vertices: %ld", (long int)RBTree->count);

    /* uncomment to check if search tree is healthy */
    /* if (rbtree_debug(RBTree, RBTree->root) == 0)
	G_warning("Break polygons: RBTree not ok"); */

    /* Second loop through lines (existing when loop is started, no need to process lines written again)
     * and break at points marked for break */

    G_message(_("Breaking polygons (pass 2: break at selected points)..."));

    for (i = 1; i <= nlines; i++) {
	int n_orig_points;

	G_percent(i, nlines, 1);
	G_debug(3, "i =  %d", i);
	if (!Vect_line_alive(Map, i))
	    continue;

	ltype = Vect_read_line(Map, Points, Cats, i);
	if (!(ltype & type))
	    continue;
	if (!(ltype & GV_LINES))
	    continue;		/* Nonsense to break points */

	/* Duplicates would result in zero length lines -> prune line first */
	n_orig_points = Points->n_points;
	Vect_line_prune(Points);

	broken = 0;
	last = 0;
	G_debug(3, "n_points =  %d", Points->n_points);
	for (j = 1; j < Points->n_points; j++) {
	    G_debug(3, "j =  %d", j);
	    nallpoints++;

	    if (Points->n_points <= 1 ||
		(j == (Points->n_points - 1) && !broken))
		break;
	    /* One point only or 
	     * last point and line is not broken, do nothing */

	    XPnt_search.x = Points->x[j];
	    XPnt_search.y = Points->y[j];

	    XPnt_found = rbtree_find(RBTree, &XPnt_search);

	    /* all points must be in the search tree, without duplicates */
	    if (XPnt_found == NULL)
		G_fatal_error(_("Point not in search tree!"));

	    /* break or write last segment of broken line */
	    if ((j == (Points->n_points - 1) && broken) ||
		XPnt_found->cross) {
		Vect_reset_line(BPoints);
		for (k = last; k <= j; k++) {
		    Vect_append_point(BPoints, Points->x[k], Points->y[k],
				      Points->z[k]);
		}

		/* Result may collapse to one point */
		Vect_line_prune(BPoints);
		if (BPoints->n_points > 1) {
		    ret = Vect_write_line(Map, ltype, BPoints, Cats);
		    G_debug(3,
			    "Line %d written j = %d n_points(orig,pruned) = %d n_points(new) = %d",
			    ret, j, Points->n_points, BPoints->n_points);
		}

		if (!broken)
		    Vect_delete_line(Map, i);	/* not yet deleted */

		/* Write points on breaks */
		if (Err) {
		    if (XPnt_found->cross && !XPnt_found->used) {
			Vect_reset_line(BPoints);
			Vect_append_point(BPoints, Points->x[j], Points->y[j], 0);
			Vect_write_line(Err, GV_POINT, BPoints, ErrCats);
		    }
		    XPnt_found->used = 1;
		}

		last = j;
		broken = 1;
		nbreaks++;
	    }
	}
	if (!broken && n_orig_points > Points->n_points) {	/* was pruned before -> rewrite */
	    if (Points->n_points > 1) {
		Vect_rewrite_line(Map, i, ltype, Points, Cats);
		G_debug(3, "Line %d pruned, npoints = %d", i,
			Points->n_points);
	    }
	    else {
		Vect_delete_line(Map, i);
		G_debug(3, "Line %d was deleted", i);
	    }
	}
	else {
	    G_debug(3, "Line %d was not changed", i);
	}
    }

    rbtree_destroy(RBTree);
    Vect_destroy_line_struct(Points);
    Vect_destroy_line_struct(BPoints);
    Vect_destroy_cats_struct(Cats);
    G_verbose_message(_("Breaks: %d"), nbreaks);
}
예제 #16
0
int display_topo(struct Map_info *Map, int type, LATTR *lattr, double dsize)
{
    int ltype, num, el;
    double msize;
    struct line_pnts *Points;
    struct line_cats *Cats;
    char text[50];
    LATTR lattr2 = *lattr;

    if (Vect_level(Map) < 2) {
	G_warning(_("Unable to display topology, not available."
		    "Please try to rebuild topology using "
		    "v.build or v.build.all."));
	return 1;
    }
    
    msize = dsize * (D_d_to_u_col(2.0) - D_d_to_u_col(1.0));	/* do it better */
    
    lattr2.xref = lattr->xref == LRIGHT ? LLEFT : LRIGHT;

    G_debug(1, "display topo:");
    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    D_RGB_color(lattr->color.R, lattr->color.G, lattr->color.B);
    D_text_size(lattr->size, lattr->size);
    if (lattr->font)
	D_font(lattr->font);
    if (lattr->enc)
	D_encoding(lattr->enc);

    Vect_rewind(Map);

    num = Vect_get_num_lines(Map);
    G_debug(1, "n_lines = %d", num);

    /* Lines */
    for (el = 1; el <= num; el++) {
	if (!Vect_line_alive(Map, el))
	    continue;
	ltype = Vect_read_line(Map, Points, Cats, el);
	G_debug(3, "ltype = %d", ltype);
	switch (ltype) {
	case -1:
	    G_fatal_error(_("Unable to read vector map"));
	case -2:		/* EOF */
	    return 0;
	}

	if (!(type & ltype))
	    continue;		/* used for both lines and labels */

	sprintf(text, "%d", el);
	show_label_line(Points, ltype, lattr, text);
    }

    num = Vect_get_num_nodes(Map);
    G_debug(1, "n_nodes = %d", num);

    /* Nodes */
    for (el = 1; el <= num; el++) {
	double X, Y;
	if (!Vect_node_alive(Map, el))
	    continue;
	Vect_get_node_coor(Map, el, &X, &Y, NULL);
	G_debug(3, "node = %d", el);
	sprintf(text, "n%d", el);

	show_label(&X, &Y, &lattr2, text);

	D_plot_icon(X, Y, G_ICON_BOX, 0, msize);
    }

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return 0;
}
예제 #17
0
int main(int argc, char *argv[])
{
    struct Map_info In, Out, Buf;
    struct line_pnts *Points;
    struct line_cats *Cats, *BCats;
    char bufname[GNAME_MAX];
    struct GModule *module;
    struct Option *in_opt, *out_opt, *type_opt, *dista_opt, *distb_opt,
	*angle_opt;
    struct Flag *straight_flag, *nocaps_flag;
    struct Option *tol_opt, *bufcol_opt, *scale_opt, *field_opt;

    int verbose;
    double da, db, dalpha, tolerance, unit_tolerance;
    int type;
    int i, ret, nareas, area, nlines, line;
    char *Areas, *Lines;
    int field;
    struct buf_contours *arr_bc;
    struct buf_contours_pts arr_bc_pts;
    int buffers_count = 0, line_id;
    struct spatial_index si;
    struct bound_box bbox;

    /* Attributes if sizecol is used */
    int nrec, ctype;
    struct field_info *Fi;
    dbDriver *Driver;
    dbCatValArray cvarr;
    double size_val, scale;


    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("geometry"));
    G_add_keyword(_("buffer"));
    module->description =
	_("Creates a buffer around vector features of given type.");

    in_opt = G_define_standard_option(G_OPT_V_INPUT);

    field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
    field_opt->guisection = _("Selection");

    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->options = "point,line,boundary,centroid,area";
    type_opt->answer = "point,line,area";
    type_opt->guisection = _("Selection");

    out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    
    dista_opt = G_define_option();
    dista_opt->key = "distance";
    dista_opt->type = TYPE_DOUBLE;
    dista_opt->required = NO;
    dista_opt->description =
	_("Buffer distance along major axis in map units");
    dista_opt->guisection = _("Distance");

    distb_opt = G_define_option();
    distb_opt->key = "minordistance";
    distb_opt->type = TYPE_DOUBLE;
    distb_opt->required = NO;
    distb_opt->description =
	_("Buffer distance along minor axis in map units");
    distb_opt->guisection = _("Distance");

    angle_opt = G_define_option();
    angle_opt->key = "angle";
    angle_opt->type = TYPE_DOUBLE;
    angle_opt->required = NO;
    angle_opt->answer = "0";
    angle_opt->description = _("Angle of major axis in degrees");
    angle_opt->guisection = _("Distance");

    bufcol_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    bufcol_opt->key = "bufcolumn";
    bufcol_opt->description =
	_("Name of column to use for buffer distances");
    bufcol_opt->guisection = _("Distance");

    scale_opt = G_define_option();
    scale_opt->key = "scale";
    scale_opt->type = TYPE_DOUBLE;
    scale_opt->required = NO;
    scale_opt->answer = "1.0";
    scale_opt->description = _("Scaling factor for attribute column values");
    scale_opt->guisection = _("Distance");

    tol_opt = G_define_option();
    tol_opt->key = "tolerance";
    tol_opt->type = TYPE_DOUBLE;
    tol_opt->required = NO;
    tol_opt->answer = "0.01";
    tol_opt->description =
	_("Maximum distance between theoretical arc and polygon segments as multiple of buffer");
    tol_opt->guisection = _("Distance");

    straight_flag = G_define_flag();
    straight_flag->key = 's';
    straight_flag->description = _("Make outside corners straight");

    nocaps_flag = G_define_flag();
    nocaps_flag->key = 'c';
    nocaps_flag->description = _("Don't make caps at the ends of polylines");

    G_gisinit(argv[0]);
    
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    type = Vect_option_to_types(type_opt);

    if ((dista_opt->answer && bufcol_opt->answer) ||
	(!(dista_opt->answer || bufcol_opt->answer)))
	G_fatal_error(_("Select a buffer distance/minordistance/angle "
			"or column, but not both."));

    if (bufcol_opt->answer)
	G_warning(_("The bufcol option may contain bugs during the cleaning "
		    "step. If you encounter problems, use the debug "
		    "option or clean manually with v.clean tool=break; "
		    "v.category step=0; v.extract -d type=area"));

    if (field_opt->answer)
	field = Vect_get_field_number(&In, field_opt->answer);
    else
	field = -1;
	
    if (bufcol_opt->answer && field == -1)
	G_fatal_error(_("The bufcol option requires a valid layer."));

    tolerance = atof(tol_opt->answer);
    if (tolerance <= 0)
	G_fatal_error(_("The tolerance must be > 0."));

    if (adjust_tolerance(&tolerance))
	G_warning(_("The tolerance was reset to %g"), tolerance);

    scale = atof(scale_opt->answer);
    if (scale <= 0.0)
	G_fatal_error("Illegal scale value");

    da = db = dalpha = 0;
    if (dista_opt->answer) {
	da = atof(dista_opt->answer);

	if (distb_opt->answer)
	    db = atof(distb_opt->answer);
	else
	    db = da;

	if (angle_opt->answer)
	    dalpha = atof(angle_opt->answer);
	else
	    dalpha = 0;

	unit_tolerance = tolerance * MIN(da, db);
	G_verbose_message(_("The tolerance in map units = %g"), unit_tolerance);
    }

    Vect_check_input_output_name(in_opt->answer, out_opt->answer,
				 GV_FATAL_EXIT);

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    BCats = Vect_new_cats_struct();

    Vect_set_open_level(2); /* topology required */

    if (1 > Vect_open_old2(&In, in_opt->answer, "", field_opt->answer))
	G_fatal_error(_("Unable to open vector map <%s>"), in_opt->answer);

    if (0 > Vect_open_new(&Out, out_opt->answer, WITHOUT_Z)) {
	Vect_close(&In);
	G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);
    }

    /* open tmp vector for buffers, needed for cleaning */
    sprintf(bufname, "%s_tmp_%d", out_opt->answer, getpid());
    if (0 > Vect_open_new(&Buf, bufname, 0)) {
	Vect_close(&In);
	Vect_close(&Out);
	Vect_delete(out_opt->answer);
	exit(EXIT_FAILURE);
    }
    Vect_build_partial(&Buf, GV_BUILD_BASE);

    /* check and load attribute column data */
    if (bufcol_opt->answer) {
	db_CatValArray_init(&cvarr);

	Fi = Vect_get_field(&In, field);
	if (Fi == NULL)
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  field);

	Driver = db_start_driver_open_database(Fi->driver, Fi->database);
	if (Driver == NULL)
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  Fi->database, Fi->driver);

	/* Note do not check if the column exists in the table because it may be expression */

	/* TODO: only select values we need instead of all in column */
	nrec =
	    db_select_CatValArray(Driver, Fi->table, Fi->key,
				  bufcol_opt->answer, NULL, &cvarr);
	if (nrec < 0)
	    G_fatal_error(_("Unable to select data from table <%s>"),
			  Fi->table);
	G_debug(2, "%d records selected from table", nrec);

	ctype = cvarr.ctype;
	if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
	    G_fatal_error(_("Column type not supported"));

	db_close_database_shutdown_driver(Driver);

	/* Output cats/values list */
	for (i = 0; i < cvarr.n_values; i++) {
	    if (ctype == DB_C_TYPE_INT) {
		G_debug(4, "cat = %d val = %d", cvarr.value[i].cat,
			cvarr.value[i].val.i);
	    }
	    else if (ctype == DB_C_TYPE_DOUBLE) {
		G_debug(4, "cat = %d val = %f", cvarr.value[i].cat,
			cvarr.value[i].val.d);
	    }
	}
    }

    Vect_copy_head_data(&In, &Out);
    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);


    /* Create buffers' boundaries */
    nlines = nareas = 0;
    if ((type & GV_POINTS) || (type & GV_LINES))
	nlines += Vect_get_num_primitives(&In, type);
    if (type & GV_AREA)
	nareas = Vect_get_num_areas(&In);
    
    if (nlines + nareas == 0) {
	G_warning(_("No features available for buffering. "
	            "Check type option and features available in the input vector."));
	exit(EXIT_SUCCESS);
    }

    buffers_count = 1;
    arr_bc = G_malloc((nlines + nareas + 1) * sizeof(struct buf_contours));

    Vect_spatial_index_init(&si, 0);

    /* Lines (and Points) */
    if ((type & GV_POINTS) || (type & GV_LINES)) {
	int ltype;

	if (nlines > 0)
	    G_message(_("Buffering lines..."));
	for (line = 1; line <= nlines; line++) {
	    int cat;

	    G_debug(2, "line = %d", line);
	    G_percent(line, nlines, 2);
	    
	    if (!Vect_line_alive(&In, line))
		continue;

	    ltype = Vect_read_line(&In, Points, Cats, line);
	    if (!(ltype & type))
		continue;

	    if (field > 0 && !Vect_cat_get(Cats, field, &cat))
		continue;

	    if (bufcol_opt->answer) {
		ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
		if (ret != DB_OK) {
		    G_warning(_("No record for category %d in table <%s>"),
			      cat, Fi->table);
		    continue;
		}

		if (size_val < 0.0) {
		    G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
			      size_val, cat);
		    continue;
		}

		if (size_val == 0.0)
		    continue;

		da = size_val * scale;
		db = da;
		dalpha = 0;
		unit_tolerance = tolerance * MIN(da, db);

		G_debug(2, "    dynamic buffer size = %.2f", da);
		G_debug(2, _("The tolerance in map units: %g"),
			unit_tolerance);
	    }
	    
	    Vect_line_prune(Points);
	    if (ltype & GV_POINTS || Points->n_points == 1) {
		Vect_point_buffer2(Points->x[0], Points->y[0], da, db, dalpha,
				   !(straight_flag->answer), unit_tolerance,
				   &(arr_bc_pts.oPoints));

		Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
		line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats);
		Vect_destroy_line_struct(arr_bc_pts.oPoints);
		/* add buffer to spatial index */
		Vect_get_line_box(&Buf, line_id, &bbox);
		Vect_spatial_index_add_item(&si, buffers_count, &bbox);
		arr_bc[buffers_count].outer = line_id;
		arr_bc[buffers_count].inner_count = 0;
		arr_bc[buffers_count].inner = NULL;
		buffers_count++;

	    }
	    else {
		Vect_line_buffer2(Points, da, db, dalpha,
				  !(straight_flag->answer),
				  !(nocaps_flag->answer), unit_tolerance,
				  &(arr_bc_pts.oPoints),
				  &(arr_bc_pts.iPoints),
				  &(arr_bc_pts.inner_count));

		Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
		line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats);
		Vect_destroy_line_struct(arr_bc_pts.oPoints);
		/* add buffer to spatial index */
		Vect_get_line_box(&Buf, line_id, &bbox);
		Vect_spatial_index_add_item(&si, buffers_count, &bbox);
		arr_bc[buffers_count].outer = line_id;

		arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count;
		if (arr_bc_pts.inner_count > 0) {
		    arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int));
		    for (i = 0; i < arr_bc_pts.inner_count; i++) {
			Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
			line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], Cats);
			Vect_destroy_line_struct(arr_bc_pts.iPoints[i]);
			/* add buffer to spatial index */
			Vect_get_line_box(&Buf, line_id, &bbox);
			Vect_spatial_index_add_item(&si, buffers_count, &bbox);
			arr_bc[buffers_count].inner[i] = line_id;
		    }
		    G_free(arr_bc_pts.iPoints);
		}
		buffers_count++;
	    }
	}
    }

    /* Areas */
    if (type & GV_AREA) {
	int centroid;

	if (nareas > 0) 
	    G_message(_("Buffering areas..."));
	for (area = 1; area <= nareas; area++) {
	    int cat;

	    G_percent(area, nareas, 2);
	    
	    if (!Vect_area_alive(&In, area))
		continue;
	    
	    centroid = Vect_get_area_centroid(&In, area);
	    if (centroid == 0)
		continue;

	    Vect_read_line(&In, NULL, Cats, centroid);
	    if (field > 0 && !Vect_cat_get(Cats, field, &cat))
		continue;

	    if (bufcol_opt->answer) {
		ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
		if (ret != DB_OK) {
		    G_warning(_("No record for category %d in table <%s>"),
			      cat, Fi->table);
		    continue;
		}

		if (size_val < 0.0) {
		    G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
			      size_val, cat);
		    continue;
		}

		if (size_val == 0.0)
		    continue;

		da = size_val * scale;
		db = da;
		dalpha = 0;
		unit_tolerance = tolerance * MIN(da, db);

		G_debug(2, "    dynamic buffer size = %.2f", da);
		G_debug(2, _("The tolerance in map units: %g"),
			unit_tolerance);
	    }

	    Vect_area_buffer2(&In, area, da, db, dalpha,
			      !(straight_flag->answer),
			      !(nocaps_flag->answer), unit_tolerance,
			      &(arr_bc_pts.oPoints),
			      &(arr_bc_pts.iPoints),
			      &(arr_bc_pts.inner_count));

	    Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
	    line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats);
	    Vect_destroy_line_struct(arr_bc_pts.oPoints);
	    /* add buffer to spatial index */
	    Vect_get_line_box(&Buf, line_id, &bbox);
	    Vect_spatial_index_add_item(&si, buffers_count, &bbox);
	    arr_bc[buffers_count].outer = line_id;

	    arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count;
	    if (arr_bc_pts.inner_count > 0) {
		arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int));
		for (i = 0; i < arr_bc_pts.inner_count; i++) {
		    Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
		    line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], Cats);
		    Vect_destroy_line_struct(arr_bc_pts.iPoints[i]);
		    /* add buffer to spatial index */
		    Vect_get_line_box(&Buf, line_id, &bbox);
		    Vect_spatial_index_add_item(&si, buffers_count, &bbox);
		    arr_bc[buffers_count].inner[i] = line_id;
		}
		G_free(arr_bc_pts.iPoints);
	    }
	    buffers_count++;
	}
    }

    verbose = G_verbose();

    G_message(_("Cleaning buffers..."));
    
    /* Break lines */
    G_message(_("Building parts of topology..."));
    Vect_build_partial(&Out, GV_BUILD_BASE);

    G_message(_("Snapping boundaries..."));
    Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL);

    G_message(_("Breaking polygons..."));
    Vect_break_polygons(&Out, GV_BOUNDARY, NULL);

    G_message(_("Removing duplicates..."));
    Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);

    do {
	G_message(_("Breaking boundaries..."));
	Vect_break_lines(&Out, GV_BOUNDARY, NULL);

	G_message(_("Removing duplicates..."));
	Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);

	G_message(_("Cleaning boundaries at nodes"));

    } while (Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL) > 0);

    /* Dangles and bridges don't seem to be necessary if snapping is small enough. */
    /* Still needed for larger buffer distances ? */

    /*
    G_message(_("Removing dangles..."));
    Vect_remove_dangles(&Out, GV_BOUNDARY, -1, NULL);

    G_message (_("Removing bridges..."));
    Vect_remove_bridges(&Out, NULL);
    */

    G_message(_("Attaching islands..."));
    Vect_build_partial(&Out, GV_BUILD_ATTACH_ISLES);

    /* Calculate new centroids for all areas */
    nareas = Vect_get_num_areas(&Out);
    Areas = (char *)G_calloc(nareas + 1, sizeof(char));
    G_message(_("Calculating centroids for areas..."));
    G_percent(0, nareas, 2);
    for (area = 1; area <= nareas; area++) {
	double x, y;

	G_percent(area, nareas, 2);

	G_debug(3, "area = %d", area);

	if (!Vect_area_alive(&Out, area))
	    continue;

	ret = Vect_get_point_in_area(&Out, area, &x, &y);
	if (ret < 0) {
	    G_warning(_("Cannot calculate area centroid"));
	    continue;
	}

	ret = point_in_buffer(arr_bc, &si, &Buf, x, y);

	if (ret) {
	    G_debug(3, "  -> in buffer");
	    Areas[area] = 1;
	}
    }

    /* Make a list of boundaries to be deleted (both sides inside) */
    nlines = Vect_get_num_lines(&Out);
    G_debug(3, "nlines = %d", nlines);
    Lines = (char *)G_calloc(nlines + 1, sizeof(char));

    G_message(_("Generating list of boundaries to be deleted..."));
    for (line = 1; line <= nlines; line++) {
	int j, side[2], areas[2];

	G_percent(line, nlines, 2);

	G_debug(3, "line = %d", line);

	if (!Vect_line_alive(&Out, line))
	    continue;

	Vect_get_line_areas(&Out, line, &side[0], &side[1]);

	for (j = 0; j < 2; j++) {
	    if (side[j] == 0) {	/* area/isle not build */
		areas[j] = 0;
	    }
	    else if (side[j] > 0) {	/* area */
		areas[j] = side[j];
	    }
	    else {		/* < 0 -> island */
		areas[j] = Vect_get_isle_area(&Out, abs(side[j]));
	    }
	}

	G_debug(3, " areas = %d , %d -> Areas = %d, %d", areas[0], areas[1],
		Areas[areas[0]], Areas[areas[1]]);
	if (Areas[areas[0]] && Areas[areas[1]])
	    Lines[line] = 1;
    }
    G_free(Areas);

    /* Delete boundaries */
    G_message(_("Deleting boundaries..."));
    for (line = 1; line <= nlines; line++) {
	G_percent(line, nlines, 2);
	
	if (!Vect_line_alive(&Out, line))
	    continue;

	if (Lines[line]) {
	    G_debug(3, " delete line %d", line);
	    Vect_delete_line(&Out, line);
	}
	else {
	    /* delete incorrect boundaries */
	    int side[2];

	    Vect_get_line_areas(&Out, line, &side[0], &side[1]);
	    
	    if (!side[0] && !side[1])
		Vect_delete_line(&Out, line);
	}
    }

    G_free(Lines);

    /* Create new centroids */
    Vect_reset_cats(Cats);
    Vect_cat_set(Cats, 1, 1);
    nareas = Vect_get_num_areas(&Out);

    G_message(_("Calculating centroids for areas..."));    
    for (area = 1; area <= nareas; area++) {
	double x, y;

	G_percent(area, nareas, 2);

	G_debug(3, "area = %d", area);

	if (!Vect_area_alive(&Out, area))
	    continue;

	ret = Vect_get_point_in_area(&Out, area, &x, &y);
	if (ret < 0) {
	    G_warning(_("Cannot calculate area centroid"));
	    continue;
	}

	ret = point_in_buffer(arr_bc, &si, &Buf, x, y);

	if (ret) {
	    Vect_reset_line(Points);
	    Vect_append_point(Points, x, y, 0.);
	    Vect_write_line(&Out, GV_CENTROID, Points, Cats);
	}
    }

    /* free arr_bc[] */
    /* will only slow down the module
       for (i = 0; i < buffers_count; i++) {
       Vect_destroy_line_struct(arr_bc[i].oPoints);
       for (j = 0; j < arr_bc[i].inner_count; j++)
       Vect_destroy_line_struct(arr_bc[i].iPoints[j]);
       G_free(arr_bc[i].iPoints);
       } */

    Vect_spatial_index_destroy(&si);
    Vect_close(&Buf);
    Vect_delete(bufname);

    G_set_verbose(verbose);

    Vect_close(&In);

    Vect_build_partial(&Out, GV_BUILD_NONE);
    Vect_build(&Out);
    Vect_close(&Out);

    exit(EXIT_SUCCESS);
}
예제 #18
0
파일: main.c 프로젝트: rashadkm/grass_cmake
int main(int argc, char *argv[])
{
    struct GModule *module;
    struct {
        struct Option *input, *output, *zshift, *height, *elevation, *hcolumn,
            *type, *field, *cats, *where, *interp, *scale, *null;
    } opt;
    struct {
        struct Flag *trace;
    } flag;
    
    struct Map_info In, Out;
    struct line_pnts *Points;
    struct line_cats *Cats;
    struct bound_box map_box;

    struct cat_list *cat_list;
    
    struct Cell_head window;
    
    int field;
    int only_type, cat;
    int fdrast, interp_method, trace;
    double objheight, objheight_default, voffset;
    double scale, null_val;
    
    struct field_info *Fi;
    dbDriver *driver = NULL;
    
    char *comment;
    
    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("geometry"));
    G_add_keyword(_("sampling"));
    G_add_keyword(_("3D"));
    module->label =
	_("Extrudes flat vector features to 3D vector features with defined height.");
    module->description = 
        _("Optionally the height can be derived from sampling of elevation raster map.");
    
    flag.trace = G_define_flag();
    flag.trace->key = 't';
    flag.trace->description = _("Trace elevation");
    flag.trace->guisection = _("Elevation");

    opt.input = G_define_standard_option(G_OPT_V_INPUT);

    opt.field = G_define_standard_option(G_OPT_V_FIELD_ALL);
    opt.field->guisection = _("Selection");

    opt.cats = G_define_standard_option(G_OPT_V_CATS);
    opt.cats->guisection = _("Selection");
    
    opt.where = G_define_standard_option(G_OPT_DB_WHERE);
    opt.where->guisection = _("Selection");

    opt.type = G_define_standard_option(G_OPT_V_TYPE);
    opt.type->answer = "point,line,area";
    opt.type->options = "point,line,area";
    opt.type->guisection = _("Selection");

    opt.output = G_define_standard_option(G_OPT_V_OUTPUT);

    opt.zshift = G_define_option();
    opt.zshift->key = "zshift";
    opt.zshift->description = _("Shifting value for z coordinates");
    opt.zshift->type = TYPE_DOUBLE;
    opt.zshift->required = NO;
    opt.zshift->answer = "0";
    opt.zshift->guisection = _("Height");

    opt.height = G_define_option();
    opt.height->key = "height";
    opt.height->type = TYPE_DOUBLE;
    opt.height->required = NO;
    opt.height->multiple = NO;
    opt.height->description = _("Fixed height for 3D vector features");
    opt.height->guisection = _("Height");

    opt.hcolumn = G_define_standard_option(G_OPT_DB_COLUMN);
    opt.hcolumn->key = "height_column";
    opt.hcolumn->multiple = NO;
    opt.hcolumn->description = _("Name of attribute column with feature height");
    opt.hcolumn->guisection = _("Height");
 
    /* raster sampling */
    opt.elevation = G_define_standard_option(G_OPT_R_ELEV);
    opt.elevation->required = NO;
    opt.elevation->description = _("Elevation raster map for height extraction");
    opt.elevation->guisection = _("Elevation");

    opt.interp = G_define_standard_option(G_OPT_R_INTERP_TYPE);
    opt.interp->answer = "nearest";
    opt.interp->guisection = _("Elevation");

    opt.scale = G_define_option();
    opt.scale->key = "scale";
    opt.scale->type = TYPE_DOUBLE;
    opt.scale->description = _("Scale factor sampled raster values");
    opt.scale->answer = "1.0";
    opt.scale->guisection = _("Elevation");

    opt.null = G_define_option();
    opt.null->key = "null_value";
    opt.null->type = TYPE_DOUBLE;
    opt.null->description =
	_("Height for sampled raster NULL values");
    opt.null->guisection = _("Elevation");

    G_gisinit(argv[0]);

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    if (!opt.height->answer && !opt.hcolumn->answer) {
	G_fatal_error(_("One of '%s' or '%s' parameters must be set"),
		      opt.height->key, opt.hcolumn->key);
    }

    sscanf(opt.zshift->answer, "%lf", &voffset);
    G_debug(1, "voffset = %f", voffset);
    
    if (opt.height->answer)
	sscanf(opt.height->answer, "%lf", &objheight);
    else
	objheight = 0.;
    G_debug(1, "objheight = %f", objheight);
    objheight_default = objheight;

    only_type = Vect_option_to_types(opt.type);

    /* sampling method */
    interp_method = Rast_option_to_interp_type(opt.interp);

    /* used to scale sampled raster values */
    scale = atof(opt.scale->answer);

    /* is null value defined */
    if (opt.null->answer)
	null_val = atof(opt.null->answer);

    /* trace elevation */
    trace = flag.trace->answer ? TRUE : FALSE;
    
    /* set input vector map name and mapset */
    Vect_check_input_output_name(opt.input->answer, opt.output->answer, G_FATAL_EXIT);

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    Vect_set_open_level(2); /* topology required for input */

    /* opening input vector map */
    if (Vect_open_old2(&In, opt.input->answer, "", opt.field->answer) < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), opt.input->answer);

    Vect_set_error_handler_io(&In, &Out);

    /* creating output vector map */
    if (Vect_open_new(&Out, opt.output->answer, WITH_Z) < 0)
	G_fatal_error(_("Unable to create vector map <%s>"),
			opt.output->answer);

    field = Vect_get_field_number(&In, opt.field->answer);

    if ((opt.hcolumn->answer || opt.cats->answer || opt.where->answer) && field == -1) {
        G_warning(_("Invalid layer number (%d). "
                    "Parameter '%s', '%s' or '%s' specified, assuming layer '1'."),
                  field, opt.hcolumn->key, opt.cats->key, opt.where->key);
        field = 1;
    }

    /* set constraint for cats or where */
    cat_list = NULL;
    if (field > 0)
	cat_list = Vect_cats_set_constraint(&In, field, opt.where->answer,
                                            opt.cats->answer);
    
    
    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);

    /* opening database connection, if required */
    if (opt.hcolumn->answer) {
        int ctype;
        dbColumn *column;
        
	if ((Fi = Vect_get_field(&In, field)) == NULL)
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  field);

	if ((driver =
	     db_start_driver_open_database(Fi->driver, Fi->database)) == NULL)
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  Fi->database, Fi->driver);
        db_set_error_handler_driver(driver);
        
	if (db_get_column(driver, Fi->table, opt.hcolumn->answer, &column) != DB_OK)
	    G_fatal_error(_("Column <%s> does not exist"),
			  opt.hcolumn->answer);
	else
	    db_free_column(column);

	ctype = db_column_Ctype(driver, Fi->table, opt.hcolumn->answer);

	if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_STRING &&
	    ctype != DB_C_TYPE_DOUBLE) {
	    G_fatal_error(_("Column <%s>: invalid data type"),
			  opt.hcolumn->answer);
	}
    }

    /* do we work with elevation raster? */
    fdrast = -1;
    if (opt.elevation->answer) {
	/* raster setup */
	G_get_window(&window);

	/* open the elev raster, and check for error condition */
	fdrast = Rast_open_old(opt.elevation->answer, "");
    }

    /* if area */
    if (only_type & GV_AREA) {
        int area, nareas, centroid;
        
        nareas = Vect_get_num_areas(&In);
	G_debug(2, "n_areas = %d", nareas);
	if (nareas > 0)
	    G_message(_("Extruding areas..."));
	for (area = 1; area <= nareas; area++) {
	    G_debug(3, "area = %d", area);
	    G_percent(area, nareas, 2);
            
	    if (!Vect_area_alive(&In, area))
		continue;
            
	    centroid = Vect_get_area_centroid(&In, area);
	    if (!centroid) {
		G_warning(_("Skipping area %d without centroid"), area);
		continue;
	    }

	    Vect_read_line(&In, NULL, Cats, centroid);
	    if (field > 0 && !Vect_cats_in_constraint(Cats, field, cat_list))
		continue;
            
	    /* height attribute */
	    if (opt.hcolumn->answer) {
		cat = Vect_get_area_cat(&In, area, field);
                if (cat == -1) {
                    G_warning(_("No category defined for area %d. Using default fixed height %f."),
                              area, objheight_default);
                    objheight = objheight_default;
                }
                if (get_height(Fi, opt.hcolumn->answer,
                               driver, cat, &objheight) != 0) {
                    G_warning(_("Unable to fetch height from DB for area %d. Using default fixed height %f."),
                              area, objheight_default);
                    objheight = objheight_default;
                }
	    } /* if opt.hcolumn->answer */

	    Vect_get_area_points(&In, area, Points);

	    G_debug(3, "area: %d height: %f", area, objheight);

	    extrude(&In, &Out, Cats, Points,
		    fdrast, trace, interp_method, scale,
                    opt.null->answer ? TRUE : FALSE, null_val,
                    objheight, voffset, &window, GV_AREA,
		    centroid);
	} /* foreach area */

    }

    if (only_type > 0) {
        int line, nlines;
        int type;
        
	G_debug(1, "other than areas");
	/* loop through each line in the dataset */
        nlines = Vect_get_num_lines(&In);
	G_message(_("Extruding features..."));
	for (line = 1; line <= nlines; line++) {
	    /* progress feedback */
	    G_percent(line, nlines, 2);

	    if (!Vect_line_alive(&In, line))
		continue;

	    /* read line */
	    type = Vect_read_line(&In, Points, Cats, line);

	    if (!(type & only_type))
		continue;

	    if (field > 0 && !Vect_cats_in_constraint(Cats, field, cat_list))
		continue;

	    /* height attribute */
	    if (opt.hcolumn->answer) {
		cat = Vect_get_line_cat(&In, line, field);
                if (cat == -1) {
                    G_warning(_("No category defined for feature %d. Using default fixed height %f."),
                              line, objheight_default);
                    objheight = objheight_default;
                }
                if (get_height(Fi, opt.hcolumn->answer,
                               driver, cat, &objheight) != 0) {
                    G_warning(_("Unable to fetch height from DB for line %d. Using default fixed height %f."),
                              line, objheight_default);
                    objheight = objheight_default;
                }
	    } /* if opt.hcolumn->answer */
            
	    extrude(&In, &Out, Cats, Points,
		    fdrast, trace, interp_method, scale,
                    opt.null->answer ? TRUE : FALSE, null_val,
                    objheight, voffset, &window, type, -1);
	} /* for each line */
    }	  /* else if area */

    if (driver) {
	db_close_database(driver);
	db_shutdown_driver(driver);
    }

    G_important_message(_("Copying attribute table..."));
    if (field < 0)
        Vect_copy_tables(&In, &Out, 0);
    else 
        Vect_copy_table_by_cat_list(&In, &Out, field, field, NULL,
                                    GV_1TABLE, cat_list);
    
    Vect_build(&Out);

    /* header */
    G_asprintf(&comment, "Generated by %s from vector map <%s>",
	       G_program_name(), Vect_get_full_name(&In));
    Vect_set_comment(&Out, comment);
    G_free(comment);

    Vect_get_map_box(&Out, &map_box);

    Vect_close(&In);
    Vect_close(&Out);

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    G_done_msg("T: %f B: %f.", map_box.T, map_box.B);
    
    exit(EXIT_SUCCESS);
}
예제 #19
0
int area_area(struct Map_info *In, int *field, struct Map_info *Tmp,
	      struct Map_info *Out, struct field_info *Fi,
	      dbDriver * driver, int operator, int *ofield,
	      ATTRIBUTES * attr, struct ilist *BList, double snap)
{
    int ret, input, line, nlines, area, nareas;
    int in_area, in_centr, out_cat;
    struct line_pnts *Points;
    struct line_cats *Cats;
    CENTR *Centr;
    char buf[1000];
    dbString stmt;
    int nmodif;
    int verbose;

    verbose = G_verbose();

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    /* optional snap */
    if (snap > 0) {
	int i, j, snapped_lines = 0;
	struct bound_box box;
	struct boxlist *boxlist = Vect_new_boxlist(0);
	struct ilist *reflist = Vect_new_list();
	
	G_message(_("Snapping boundaries with %g ..."), snap);

	/* snap boundaries in B to boundaries in A,
	 * not modifying boundaries in A */

	if (BList->n_values > 1)
	    qsort(BList->value, BList->n_values, sizeof(int), cmp_int);

	snapped_lines = 0;
	nlines = BList->n_values;
	for (i = 0; i < nlines; i++) {
	    line = BList->value[i];
	    Vect_read_line(Tmp, Points, Cats, line);
	    /* select lines by box */
	    Vect_get_line_box(Tmp, line, &box);
	    box.E += snap;
	    box.W -= snap;
	    box.N += snap;
	    box.S -= snap;
	    box.T = 0.0;
	    box.B = 0.0;
	    Vect_select_lines_by_box(Tmp, &box, GV_BOUNDARY, boxlist);
	    
	    if (boxlist->n_values > 0) {
		Vect_reset_list(reflist);
		for (j = 0; j < boxlist->n_values; j++) {
		    int aline = boxlist->id[j];

		    if (!bsearch(&aline, BList->value, BList->n_values,
			sizeof(int), cmp_int)) {
			G_ilist_add(reflist, aline);
		    }
		}
		
		/* snap bline to alines */
		if (Vect_snap_line(Tmp, reflist, Points, snap, 0, NULL, NULL)) {
		    /* rewrite bline*/
		    Vect_delete_line(Tmp, line);
		    ret = Vect_write_line(Tmp, GV_BOUNDARY, Points, Cats);
		    G_ilist_add(BList, ret);
		    snapped_lines++;
		    G_debug(3, "line %d snapped", line);
		}
	    }
	}
	Vect_destroy_boxlist(boxlist);
	Vect_destroy_list(reflist);

	G_verbose_message(n_("%d boundary snapped",
                             "%d boundaries snapped",
                             snapped_lines), snapped_lines);
    }

    /* same procedure like for v.in.ogr:
     * Vect_clean_small_angles_at_nodes() can change the geometry so that new intersections
     * are created. We must call Vect_break_lines(), Vect_remove_duplicates()
     * and Vect_clean_small_angles_at_nodes() until no more small dangles are found */
    do {
	G_message(_("Breaking lines..."));
	Vect_break_lines_list(Tmp, NULL, BList, GV_BOUNDARY, NULL);

	/* Probably not necessary for LINE x AREA */
	G_message(_("Removing duplicates..."));
	Vect_remove_duplicates(Tmp, GV_BOUNDARY, NULL);

	G_message(_("Cleaning boundaries at nodes..."));
	nmodif =
	    Vect_clean_small_angles_at_nodes(Tmp, GV_BOUNDARY, NULL);
    } while (nmodif > 0);

    /* ?: May be result of Vect_break_lines() + Vect_remove_duplicates() any dangle or bridge?
     * In that case, calls to Vect_remove_dangles() and Vect_remove_bridges() would be also necessary */

    G_set_verbose(0);
    /* should be fast, be silent */
    Vect_build_partial(Tmp, GV_BUILD_AREAS);
    G_set_verbose(verbose);
    nlines = Vect_get_num_lines(Tmp);
    ret = 0;
    for (line = 1; line <= nlines; line++) {
	if (!Vect_line_alive(Tmp, line))
	    continue;
	if (Vect_get_line_type(Tmp, line) == GV_BOUNDARY) {
	    int left, rite;
	    
	    Vect_get_line_areas(Tmp, line, &left, &rite);
	    
	    if (left == 0 || rite == 0) {
		/* invalid boundary */
		ret = 1;
		break;
	    }
	}
    }
    if (ret) {
	Vect_remove_dangles(Tmp, GV_BOUNDARY, -1, NULL);
	Vect_remove_bridges(Tmp, NULL, NULL, NULL);
    }

    G_set_verbose(0);
    Vect_build_partial(Tmp, GV_BUILD_NONE);
    Vect_build_partial(Tmp, GV_BUILD_BASE);
    G_set_verbose(verbose);
    G_message(_("Merging lines..."));
    Vect_merge_lines(Tmp, GV_BOUNDARY, NULL, NULL);

    /* Attach islands */
    G_message(_("Attaching islands..."));
    /* can take some time, show messages */
    Vect_build_partial(Tmp, GV_BUILD_ATTACH_ISLES);

    /* Calculate new centroids for all areas */
    nareas = Vect_get_num_areas(Tmp);

    Centr = (CENTR *) G_malloc((nareas + 1) * sizeof(CENTR));	/* index from 1 ! */
    for (area = 1; area <= nareas; area++) {
	ret =
	    Vect_get_point_in_area(Tmp, area, &(Centr[area].x),
				   &(Centr[area].y));
	if (ret < 0) {
	    G_warning(_("Cannot calculate area centroid"));
	    Centr[area].valid = 0;
	}
	else {
	    Centr[area].valid = 1;
	}
    }

    /* Query input maps */
    for (input = 0; input < 2; input++) {
	G_message(_("Querying vector map <%s>..."),
		  Vect_get_full_name(&(In[input])));

	for (area = 1; area <= nareas; area++) {
	    Centr[area].cat[input] = Vect_new_cats_struct();

	    G_percent(area, nareas, 1);

	    in_area =
		Vect_find_area(&(In[input]), Centr[area].x, Centr[area].y);
	    if (in_area > 0) {
		in_centr = Vect_get_area_centroid(&(In[input]), in_area);
		if (in_centr > 0) {
		    int i;

		    Vect_read_line(&(In[input]), NULL, Cats, in_centr);
		    /* Add all cats with original field number */
		    for (i = 0; i < Cats->n_cats; i++) {
			if (Cats->field[i] == field[input]) {
			    ATTR *at;

			    Vect_cat_set(Centr[area].cat[input], ofield[input + 1],
					 Cats->cat[i]);

			    /* Mark as used */
			    at = find_attr(&(attr[input]), Cats->cat[i]);
			    if (!at)
				G_fatal_error(_("Attribute not found"));

			    at->used = 1;
			}
		    }
		}
	    }
	}
    }

    G_message(_("Writing centroids..."));

    db_init_string(&stmt);
    out_cat = 1;
    for (area = 1; area <= nareas; area++) {
	int i;

	G_percent(area, nareas, 1);

	/* check the condition */
	switch (operator) {
	case OP_AND:
	    if (!
		(Centr[area].cat[0]->n_cats > 0 &&
		 Centr[area].cat[1]->n_cats > 0))
		continue;
	    break;
	case OP_OR:
	    if (!
		(Centr[area].cat[0]->n_cats > 0 ||
		 Centr[area].cat[1]->n_cats > 0))
		continue;
	    break;
	case OP_NOT:
	    if (!
		(Centr[area].cat[0]->n_cats > 0 &&
		 !(Centr[area].cat[1]->n_cats > 0)))
		continue;
	    break;
	case OP_XOR:
	    if ((Centr[area].cat[0]->n_cats > 0 &&
		 Centr[area].cat[1]->n_cats > 0) ||
		(!(Centr[area].cat[0]->n_cats > 0) &&
		 !(Centr[area].cat[1]->n_cats > 0)))
		continue;
	    break;
	}

	Vect_reset_line(Points);
	Vect_reset_cats(Cats);

	Vect_append_point(Points, Centr[area].x, Centr[area].y, 0.0);

	if (ofield[0] > 0) {
	    /* Add new cats for all combinations of input cats (-1 in cycle for null) */
	    for (i = -1; i < Centr[area].cat[0]->n_cats; i++) {
		int j;

		if (i == -1 && Centr[area].cat[0]->n_cats > 0)
		    continue;	/* no need to make null */

		for (j = -1; j < Centr[area].cat[1]->n_cats; j++) {
		    if (j == -1 && Centr[area].cat[1]->n_cats > 0)
			continue;	/* no need to make null */

		    if (ofield[0] > 0)
			Vect_cat_set(Cats, ofield[0], out_cat);

		    /* attributes */
		    if (driver) {
			ATTR *at;

			sprintf(buf, "insert into %s values ( %d", Fi->table,
				out_cat);
			db_set_string(&stmt, buf);

			/* cata */
			if (i >= 0) {
			    if (attr[0].columns) {
				at = find_attr(&(attr[0]),
					       Centr[area].cat[0]->cat[i]);
				if (!at)
				    G_fatal_error(_("Attribute not found"));

				if (at->values)
				    db_append_string(&stmt, at->values);
				else
				    db_append_string(&stmt, attr[0].null_values);
			    }
			    else {
				sprintf(buf, ", %d", Centr[area].cat[0]->cat[i]);
				db_append_string(&stmt, buf);
			    }
			}
			else {
			    if (attr[0].columns) {
				db_append_string(&stmt, attr[0].null_values);
			    }
			    else {
				sprintf(buf, ", null");
				db_append_string(&stmt, buf);
			    }
			}

			/* catb */
			if (j >= 0) {
			    if (attr[1].columns) {
				at = find_attr(&(attr[1]),
					       Centr[area].cat[1]->cat[j]);
				if (!at)
				    G_fatal_error(_("Attribute not found"));

				if (at->values)
				    db_append_string(&stmt, at->values);
				else
				    db_append_string(&stmt, attr[1].null_values);
			    }
			    else {
				sprintf(buf, ", %d", Centr[area].cat[1]->cat[j]);
				db_append_string(&stmt, buf);
			    }
			}
			else {
			    if (attr[1].columns) {
				db_append_string(&stmt, attr[1].null_values);
			    }
			    else {
				sprintf(buf, ", null");
				db_append_string(&stmt, buf);
			    }
			}

			db_append_string(&stmt, " )");

			G_debug(3, "%s", db_get_string(&stmt));

			if (db_execute_immediate(driver, &stmt) != DB_OK)
			    G_warning(_("Unable to insert new record: '%s'"),
				      db_get_string(&stmt));
		    }
		    out_cat++;
		}
	    }
	}

	/* Add all cats from input vectors */
	if (ofield[1] > 0 && field[0] > 0) {
	    for (i = 0; i < Centr[area].cat[0]->n_cats; i++) {
		if (Centr[area].cat[0]->field[i] == field[0])
		    Vect_cat_set(Cats, ofield[1], Centr[area].cat[0]->cat[i]);
	    }
	}

	if (ofield[2] > 0 && field[1] > 0 && ofield[1] != ofield[2]) {
	    for (i = 0; i < Centr[area].cat[1]->n_cats; i++) {
		if (Centr[area].cat[1]->field[i] == field[1])
		    Vect_cat_set(Cats, ofield[2], Centr[area].cat[1]->cat[i]);
	    }
	}

	Vect_write_line(Tmp, GV_CENTROID, Points, Cats);
	Vect_write_line(Out, GV_CENTROID, Points, Cats);
    }

    G_set_verbose(0);
    /* should be fast, be silent */
    Vect_build_partial(Tmp, GV_BUILD_CENTROIDS);
    G_set_verbose(verbose);
    /* Copy valid boundaries to final output */
    nlines = Vect_get_num_lines(Tmp);

    for (line = 1; line <= nlines; line++) {
	int i, ltype, side[2], centr[2];

	G_percent(line, nlines, 1);	/* must be before any continue */

	if (!Vect_line_alive(Tmp, line))
	    continue;

	ltype = Vect_read_line(Tmp, Points, Cats, line);
	if (!(ltype & GV_BOUNDARY))
	    continue;

	Vect_get_line_areas(Tmp, line, &side[0], &side[1]);

	for (i = 0; i < 2; i++) {
	    if (side[i] == 0) {	/* This should not happen ! */
		centr[i] = 0;
		continue;
	    }

	    if (side[i] > 0) {
		area = side[i];
	    }
	    else {		/* island */
		area = Vect_get_isle_area(Tmp, abs(side[i]));
	    }

	    if (area > 0)
		centr[i] = Vect_get_area_centroid(Tmp, area);
	    else
		centr[i] = 0;
	}

	if (centr[0] || centr[1])
	    Vect_write_line(Out, GV_BOUNDARY, Points, Cats);
    }

    return 0;
}
예제 #20
0
파일: break.c 프로젝트: caomw/grass
/*!
  \brief Connect lines in given threshold
  
  \code
        \	             \
   id1   \           ->	      \
                               \
   id2 ---------           -----+---
   \endcode

   If two lines are selected and <i>thresh</i> is -1, no limit is
   applied.

   \param Map pointer to Map_info
   \param List list of selected lines
   \param thresh threshold value

   \return number of modified lines
   \return -1 on error
 */
int Vedit_connect_lines(struct Map_info *Map, struct ilist *List,
			double thresh)
{
    int nlines_modified, connected;
    int i, j, node[2], n_nodes;
    int line, found;
    double x, y, z;

    struct ilist *List_exclude, *List_found;

    nlines_modified = 0;

    List_exclude = Vect_new_list();
    List_found = Vect_new_list();

    n_nodes = 2;

    /* collect lines to be modified */
    for (i = 0; i < List->n_values; i++) {
	line = List->value[i];

	if (!Vect_line_alive(Map, line))
	    continue;

	if (Vect_get_line_type(Map, line) & GV_POINTS)
	    continue;

	node[0] = node[1] = -1;
	Vect_get_line_nodes(Map, line, &(node[0]), &(node[1]));
	if (node[0] < 0 || node[1] < 0)
	    continue;

	connected = 0;
	Vect_reset_list(List_exclude);
	Vect_list_append(List_exclude, line);
	for (j = 0; j < n_nodes && !connected; j++) {
	    /* for each line node find lines in threshold */
	    Vect_get_node_coor(Map, node[j], &x, &y, &z);

	    do {
		/* find first nearest line */
		found = Vect_find_line_list(Map, x, y, z,
					    GV_LINES, thresh, WITHOUT_Z,
					    List_exclude, List_found);
		
		if (found > 0 && Vect_line_alive(Map, found)) {
		    /* try to connect lines (given node) */
		    G_debug(3, "Vedit_connect_lines(): lines=%d,%d", line, found);
		    if (connect_lines(Map, !j, line, found, thresh, List)) {
			G_debug(3, "Vedit_connect_lines(): lines=%d,%d -> connected",
				line, found);
			nlines_modified += 2;
			connected = 1;
		    }
		}
		
		Vect_list_append(List_exclude, found);
	    } while(List_found->n_values > 0 && !connected);
	}
    }
    
    Vect_destroy_list(List_exclude);
    Vect_destroy_list(List_found);

    return nlines_modified;
}
예제 #21
0
int main(int argc, char *argv[])
{
    struct GModule *module;
    struct Option *in_opt, *layer_opt, *out_opt, *length_opt, *units_opt, *vertices_opt;
    
    struct Map_info In, Out;
    struct line_pnts *Points, *Points2;
    struct line_cats *Cats;

    int line, nlines, layer;
    double length = -1;
    int vertices = 0;
    double (*line_length) ();
    int latlon = 0;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("geometry"));
    module->description = _("Splits vector lines to shorter segments.");
    
    in_opt = G_define_standard_option(G_OPT_V_INPUT);

    layer_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);

    out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    
    length_opt = G_define_option();
    length_opt->key = "length";
    length_opt->type = TYPE_DOUBLE;
    length_opt->required = NO;
    length_opt->multiple = NO;
    length_opt->description = _("Maximum segment length");

    units_opt = G_define_option();
    units_opt->key = "units";
    units_opt->type = TYPE_STRING;
    units_opt->required = NO;
    units_opt->multiple = NO;
    units_opt->options = "meters,kilometers,feet,miles,nautmiles";
    units_opt->answer = "meters";
    units_opt->description = _("Length units");
    
    vertices_opt = G_define_option();
    vertices_opt->key = "vertices";
    vertices_opt->type = TYPE_INTEGER;
    vertices_opt->required = NO;
    vertices_opt->multiple = NO;
    vertices_opt->description = _("Maximum number of vertices in segment");
    
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);
    
    if ((length_opt->answer && vertices_opt->answer) ||
	!(length_opt->answer || vertices_opt->answer))
	G_fatal_error(_("Use either length or vertices"));

    line_length = NULL;

    if (length_opt->answer) {
	length = atof(length_opt->answer);
	if (length <= 0)
	    G_fatal_error(_("Length must be positive but is %g"), length);

	/* convert length to meters */
	if (strcmp(units_opt->answer, "meters") == 0)
	    /* do nothing */ ;
	else if (strcmp(units_opt->answer, "kilometers") == 0)
	    length *= FROM_KILOMETERS;
	else if (strcmp(units_opt->answer, "feet") == 0)
	    length *= FROM_FEET;
	else if (strcmp(units_opt->answer, "miles") == 0)
	    length *= FROM_MILES;
	else if (strcmp(units_opt->answer, "nautmiles") == 0)
	    length *= FROM_NAUTMILES;
	else
	    G_fatal_error(_("Unknown unit %s"), units_opt->answer); 

	/* set line length function */
	if ((latlon = (G_projection() == PROJECTION_LL)) == 1)
	    line_length = Vect_line_geodesic_length;
	else {
	    double factor;
	    
	    line_length = Vect_line_length;
	    
	    /* convert length to map units */
	    if ((factor = G_database_units_to_meters_factor()) == 0)
		G_fatal_error(_("Can not get projection units"));
	    else {
		/* meters to units */
		length = length / factor;
	    }
	}
	G_verbose_message(_("length in %s: %g"), (latlon ? "meters" : "map units"), length);
    }

    if (vertices_opt->answer) {
	vertices = atoi(vertices_opt->answer);
	if (vertices < 2)
	    G_fatal_error(_("Number of vertices must be at least 2"));
    }
    
    Vect_set_open_level(2);
    Vect_open_old2(&In, in_opt->answer, "", layer_opt->answer);
    layer = Vect_get_field_number(&In, layer_opt->answer);
    
    Vect_open_new(&Out, out_opt->answer, Vect_is_3d(&In));
    
    Vect_copy_head_data(&In, &Out);
    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);
    Vect_copy_tables(&In, &Out, layer);
    
    Points = Vect_new_line_struct();
    Points2 = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    nlines = Vect_get_num_lines(&In);

    for (line = 1; line <= nlines; line++) {
	int ltype;

	G_percent(line, nlines, 1);

	if (!Vect_line_alive(&In, line))
	    continue;

	ltype = Vect_read_line(&In, Points, Cats, line);

	if (layer != -1 && !Vect_cat_get(Cats, layer, NULL))
	  continue;

	if (ltype & GV_LINES) {
	    if (length > 0) {
		double l, from, to, step;

		l = line_length(Points);

		if (l <= length) {
		    Vect_write_line(&Out, ltype, Points, Cats);
		}
		else {
		    int n, i;

		    n = ceil(l / length);
		    if (latlon)
			l = Vect_line_length(Points);

		    step = l / n;
		    from = 0.;

		    for (i = 0; i < n; i++) {
			int ret;
			double x, y, z;

			if (i == n - 1) {
			    to = l;	/* to be sure that it goes to end */
			}
			else {
			    to = from + step;
			}

			ret = Vect_line_segment(Points, from, to, Points2);
			if (ret == 0) {
			    G_warning(_("Unable to make line segment: %f - %f (line length = %f)"),
				      from, to, l);
			    continue;
			}

			/* To be sure that the coordinates are identical */
			if (i > 0) {
			    Points2->x[0] = x;
			    Points2->y[0] = y;
			    Points2->z[0] = z;
			}
			if (i == n - 1) {
			    Points2->x[Points2->n_points - 1] =
				Points->x[Points->n_points - 1];
			    Points2->y[Points2->n_points - 1] =
				Points->y[Points->n_points - 1];
			    Points2->z[Points2->n_points - 1] =
				Points->z[Points->n_points - 1];
			}

			Vect_write_line(&Out, ltype, Points2, Cats);

			/* last point */
			x = Points2->x[Points2->n_points - 1];
			y = Points2->y[Points2->n_points - 1];
			z = Points2->z[Points2->n_points - 1];

			from += step;
		    }
		}
	    }
	    else {
		int start = 0;	/* number of coordinates written */

		while (start < Points->n_points - 1) {
		    int i, v;

		    Vect_reset_line(Points2);
		    for (i = 0; i < vertices; i++) {
			v = start + i;
			if (v == Points->n_points)
			    break;

			Vect_append_point(Points2, Points->x[v], Points->y[v],
					  Points->z[v]);
		    }

		    Vect_write_line(&Out, ltype, Points2, Cats);

		    start = v;
		}
	    }
	}
	else {
	    Vect_write_line(&Out, ltype, Points, Cats);
	}
    }

    Vect_close(&In);
    Vect_build(&Out);
    Vect_close(&Out);
    
    exit(EXIT_SUCCESS);
}
예제 #22
0
파일: break.c 프로젝트: caomw/grass
/*!
  \brief Split selected lines on given position
  
  \param Map pointer to Map_info
  \param List list of selected lines
  \param coord points location
  \param thresh threshold
  \param[out] List_updated list of rewritten features (or NULL)
  
  \return number of modified lines
  \return -1 on error
*/
int Vedit_split_lines(struct Map_info *Map, struct ilist *List,
		      struct line_pnts *coord, double thresh,
		      struct ilist *List_updated)
{
    int i, j, l;
    int type, line, seg, newline;
    int nlines_modified;
    double px, py, spdist, lpdist, dist;
    double *x, *y, *z;

    struct line_pnts *Points, *Points2;
    struct line_cats *Cats;
    struct ilist *List_in_box;

    nlines_modified = 0;

    Points = Vect_new_line_struct();
    Points2 = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    List_in_box = Vect_new_list();

    for (i = 0; i < List->n_values; i++) {
	line = List->value[i];

	if (!Vect_line_alive(Map, line))
	    continue;

	type = Vect_read_line(Map, Points, Cats, line);

	if (!(type & GV_LINES))
	    continue;

	x = Points->x;
	y = Points->y;
	z = Points->z;

	for (j = 0; j < coord->n_points; j++) {
	    seg =
		Vect_line_distance(Points, coord->x[j], coord->y[j],
				   coord->z[j], WITHOUT_Z, &px, &py, NULL,
				   &dist, &spdist, &lpdist);

	    if (dist > thresh) {
		continue;
	    }

	    G_debug(3, "Vedit_split_lines(): line=%d, x=%f, y=%f, px=%f, py=%f, seg=%d, "
		    "dist=%f, spdist=%f, lpdist=%f", line, coord->x[j],
		    coord->y[j], px, py, seg, dist, spdist, lpdist);
	    
	    if (spdist <= 0.0 || spdist >= Vect_line_length(Points))
		continue;

	    G_debug(3, "Vedit_split_lines(): line=%d", line);

	    /* copy first line part */
	    for (l = 0; l < seg; l++) {
		Vect_append_point(Points2, x[l], y[l], z[l]);
	    }

	    /* add last vertex */
	    Vect_append_point(Points2, px, py, 0.0);

	    /* rewrite the line */
	    newline = Vect_rewrite_line(Map, line, type, Points2, Cats);
	    if (newline < 0) {
		return -1;
	    }
	    if (List_updated)
		Vect_list_append(List_updated, newline);
	    Vect_reset_line(Points2);

	    /* add given vertex */
	    Vect_append_point(Points2, px, py, 0.0);

	    /* copy second line part */
	    for (l = seg; l < Points->n_points; l++) {
		Vect_append_point(Points2, x[l], y[l], z[l]);
	    }

	    /* rewrite the line */
	    newline = Vect_write_line(Map, type, Points2, Cats);
	    if (newline < 0) {
		return -1;
	    }
	    if (List_updated)
		Vect_list_append(List_updated, newline);

	    nlines_modified++;
	}			/* for each bounding box */
    }				/* for each selected line */

    Vect_destroy_line_struct(Points);
    Vect_destroy_line_struct(Points2);
    Vect_destroy_cats_struct(Cats);
    Vect_destroy_list(List_in_box);

    return nlines_modified;
}
예제 #23
0
/* merge a given line with all other lines of the same type and 
 * with the same categories */
static int merge_line(struct Map_info *Map, int line,
		      struct line_pnts *MPoints, struct line_cats *MCats)
{
    int nlines, i, first, last, next_line, curr_line;
    int merged = 0, newl = 0;
    int next_node, direction, node_n_lines, type, ltype, lines_type;
    static struct ilist *List = NULL;
    static struct line_pnts *Points = NULL;
    static struct line_cats *Cats = NULL;
    type = GV_LINE;

    nlines = Vect_get_num_lines(Map);

    if (!Points)
	Points = Vect_new_line_struct();
    if (!Cats)
	Cats = Vect_new_cats_struct();
    if (!List)
	List = Vect_new_list();

    Vect_reset_line(Points);
    Vect_reset_cats(Cats);
    Vect_reset_cats(MCats);
    Vect_reset_list(List);

    if (!Vect_line_alive(Map, line))
	return 0;

    ltype = Vect_get_line_type(Map, line);

    if (!(ltype & type))
	return 0;
	
    Vect_read_line(Map, MPoints, MCats, line);

    /* special cases:
     *  - loop back to start boundary via several other boundaries
     *  - one boundary forming closed loop
     *  - node with 3 entries but only 2 boundaries, one of them connecting twice,
     *    the other one must then be topologically incorrect in case of boundary */

    /* go backward as long as there is only one other line/boundary at the current node */
    G_debug(3, "go backward");
    Vect_get_line_nodes(Map, line, &next_node, NULL);

    first = -line;
    while (1) {
	node_n_lines = Vect_get_node_n_lines(Map, next_node);
	/* count lines/boundaries at this node */
	lines_type = 0;
	next_line = first;
	for (i = 0; i < node_n_lines; i++) {
	    curr_line = Vect_get_node_line(Map, next_node, i);
	    if ((Vect_get_line_type(Map, abs(curr_line)) & GV_LINES))
		lines_type++;
	    if ((Vect_get_line_type(Map, abs(curr_line)) == ltype)) {
		if (abs(curr_line) != abs(first)) {
		    Vect_read_line(Map, NULL, Cats, abs(curr_line));
		    
		    /* catgories must be identical */
		    if (compare_cats(MCats, Cats) == 0)
			next_line = curr_line;
		}
	    }
	}
	if (lines_type == 2 && abs(next_line) != abs(first) &&
	    abs(next_line) != line) {
	    first = next_line;

	    if (first < 0) {
		Vect_get_line_nodes(Map, -first, &next_node, NULL);
	    }
	    else {
		Vect_get_line_nodes(Map, first, NULL, &next_node);
	    }
	}
	else
	    break;
    }

    /* go forward as long as there is only one other line/boundary at the current node */
    G_debug(3, "go forward");

    /* reverse direction */
    last = -first;

    if (last < 0) {
	Vect_get_line_nodes(Map, -last, &next_node, NULL);
    }
    else {
	Vect_get_line_nodes(Map, last, NULL, &next_node);
    }

    Vect_reset_list(List);
    while (1) {
	G_ilist_add(List, last);
	node_n_lines = Vect_get_node_n_lines(Map, next_node);
	lines_type = 0;
	next_line = last;
	for (i = 0; i < node_n_lines; i++) {
	    curr_line = Vect_get_node_line(Map, next_node, i);
	    if ((Vect_get_line_type(Map, abs(curr_line)) & GV_LINES))
		lines_type++;
	    if ((Vect_get_line_type(Map, abs(curr_line)) == ltype)) {
		if (abs(curr_line) != abs(last)) {
		    Vect_read_line(Map, NULL, Cats, abs(curr_line));
		    
		    if (compare_cats(MCats, Cats) == 0)
			next_line = curr_line;
		}
	    }
	}

	if (lines_type == 2 && abs(next_line) != abs(last) &&
	    abs(next_line) != abs(first)) {
	    last = next_line;

	    if (last < 0) {
		Vect_get_line_nodes(Map, -last, &next_node, NULL);
	    }
	    else {
		Vect_get_line_nodes(Map, last, NULL, &next_node);
	    }
	}
	else
	    break;
    }

    /* merge lines */
    G_debug(3, "merge %d lines", List->n_values);
    Vect_reset_line(MPoints);

    for (i = 0; i < List->n_values; i++) {
	Vect_reset_line(Points);
	Vect_read_line(Map, Points, Cats, abs(List->value[i]));
	direction = (List->value[i] < 0 ? GV_BACKWARD : GV_FORWARD);
	Vect_append_points(MPoints, Points, direction);
	MPoints->n_points--;
	Vect_delete_line(Map, abs(List->value[i]));
    }
    MPoints->n_points++;
    merged += List->n_values;
    newl++;

    return merged;
}
예제 #24
0
/*!
  \brief Lines z-bulk labeling
  
  Automated labeling (z coordinate assignment) of vector lines (iso-lines).
  
  \param Map pointer to Map_info
  \param List list of selected lines
  \param point_start_end staring and ending point
  \param start starting value
  \param step step value
  
  \return number of modified features
  \return -1 on error
*/
int Vedit_bulk_labeling(struct Map_info *Map, struct ilist *List,
			double x1, double y1, double x2, double y2,
			double start, double step)
{
    int i, cv_i, p_i;
    int line, type, temp_line;
    int nlines_modified;
    double value, dist;

    struct line_cats *Cats;
    struct line_pnts *Points, *Points_se;	/* start - end */
    struct bound_box box, box_se;

    /* for intersection */
    struct line_pnts **Points_a, **Points_b;
    int nlines_a, nlines_b;

    dbCatValArray cv;		/* line_id / dist */

    nlines_modified = 0;

    value = start;

    Points = Vect_new_line_struct();
    Points_se = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    db_CatValArray_alloc(&cv, List->n_values);
    cv.ctype = DB_C_TYPE_DOUBLE;
    cv.n_values = 0;

    Vect_append_point(Points_se, x1, y1, -PORT_DOUBLE_MAX);
    Vect_append_point(Points_se, x2, y2, PORT_DOUBLE_MAX);

    /* write temporaly line */
    temp_line = Vect_write_line(Map, GV_LINE, Points_se, Cats);
    if (temp_line < 0) {
	return -1;
    }
    
    Vect_line_box(Points_se, &box_se);

    /* determine order of lines */
    cv_i = 0;
    for (i = 0; i < List->n_values; i++) {
	line = List->value[i];

	if (!Vect_line_alive(Map, line))
	    continue;

	type = Vect_read_line(Map, Points, NULL, line);

	if (!(type & GV_LINE))
	    continue;

	Vect_line_box(Points, &box);
	if (Vect_line_check_intersection(Points_se, Points, WITH_Z)) {
	    Vect_line_intersection(Points_se, Points, &box_se, &box,
				   &Points_a, &Points_b, &nlines_a, &nlines_b,
				   WITHOUT_Z);

	    if (nlines_a < 2 || nlines_b < 1)	/* should not happen */
		continue;

	    /* calculate distance start point -> point of intersection */
	    for (p_i = 0; p_i < Points_a[0]->n_points; p_i++) {
		Points_a[0]->z[p_i] = 0;
	    }
	    dist = Vect_line_length(Points_a[0]);	/* always first line in array? */

	    cv.value[cv_i].cat = line;
	    cv.value[cv_i++].val.d = dist;
	    cv.n_values++;
	}
    }

    /* sort array by distance */
    db_CatValArray_sort_by_value(&cv);

    /* z bulk-labeling */
    for (cv_i = 0; cv_i < cv.n_values; cv_i++) {
	line = cv.value[cv_i].cat;
	type = Vect_read_line(Map, Points, Cats, line);

	for (p_i = 0; p_i < Points->n_points; p_i++) {
	    Points->z[p_i] = value;
	}

	if (Vect_rewrite_line(Map, line, type, Points, Cats) < 0) {
	    return -1;
	}
	nlines_modified++;

	value += step;
    }

    if (Vect_delete_line(Map, temp_line) < 0) {
	return -1;
    }

    db_CatValArray_free(&cv);
    Vect_destroy_line_struct(Points);
    Vect_destroy_line_struct(Points_se);
    Vect_destroy_cats_struct(Cats);

    return nlines_modified;
}