/*! \file lib/vector/vedit/snap.c \brief Vedit library - snapping (C) 2007-2008 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. \author Martin Landa */ #include /*! \brief Snap given point to the nearest primitive \param Map pointer to Map_info \param line line to be excluded (point on line) \param x,y,z point on line to be snapped \param thresh snapping threshold (>0) \param vertex snap also to vertex (non-zero) \return 1 snapped \return 0 not snapped */ int Vedit_snap_point(struct Map_info *Map, int line, double *x, double *y, double *z, double thresh, int vertex) { struct line_pnts *Points; int i, snapped; int line2snap, mindist_idx; double dist, mindist; snapped = 0; mindist_idx = -1; mindist = thresh; Points = Vect_new_line_struct(); line2snap = Vect_find_line(Map, *x, *y, *z, -1, thresh, WITHOUT_Z, line); if (line2snap > 0) { Vect_read_line(Map, Points, NULL, line2snap); if (!Vect_line_alive(Map, line2snap)) { Vect_destroy_line_struct(Points); return snapped; } for (i = 0; i < Points->n_points; i++) { if (i > 0 && i < Points->n_points - 1) if (!vertex) continue; dist = Vect_points_distance(*x, *y, *z, Points->x[i], Points->y[i], Points->z[i], WITHOUT_Z); if (mindist >= dist) { mindist = dist; mindist_idx = i; } } if (mindist_idx > -1) { *x = Points->x[mindist_idx]; *y = Points->y[mindist_idx]; *z = Points->z[mindist_idx]; snapped = 1; } } G_debug(3, "Vedit_snap_point(): map=%s, line2snap=%d, snapped=%d", Map->name, line2snap, snapped); Vect_destroy_line_struct(Points); return snapped; } /*! \brief Snap selected primitive to its nearest primitive \param Map pointer to Map_info \param BgMap,nbgmaps list of background maps used for snapping \param line line id to be snapped (if already written, otherwise -1) \param Points line geometry \param layer layer number \param thresh threshold value used for snapping (>0) \param to_vertex allow snapping also to vertex \return 1 line snapped \return 0 line not snapped \return -1 line is dead (if 'line' is > 0) */ int Vedit_snap_line(struct Map_info *Map, struct Map_info **BgMap, int nbgmaps, int line, struct line_pnts *Points, double thresh, int to_vertex) { int i, npoints, node, rewrite; double *x, *y, *z; struct line_cats *Cats; Cats = Vect_new_cats_struct(); G_debug(3, "Vedit_snap_line(): thresh=%g, to_vertex=%d", thresh, to_vertex); if (line > 0 && !Vect_line_alive(Map, line)) return -1; npoints = Points->n_points; x = Points->x; y = Points->y; z = Points->z; rewrite = 0; for (node = 0; node < npoints; node++) { if ((node > 0 && node < npoints - 1) && !to_vertex) continue; if (Vedit_snap_point(Map, line, &x[node], &y[node], &z[node], thresh, to_vertex)) { rewrite = 1; } else { /* check also background maps */ for (i = 0; i < nbgmaps; i++) { if (Vedit_snap_point (BgMap[i], -1, &x[node], &y[node], &z[node], thresh, to_vertex)) { rewrite = 1; break; /* snapped, don't continue */ } } } } /* for each line vertex */ /* close boundaries or lines */ if (!rewrite && Vect_points_distance(x[0], y[0], z[0], x[npoints - 1], y[npoints - 1], z[npoints - 1], WITHOUT_Z) <= thresh) { x[npoints - 1] = x[0]; y[npoints - 1] = y[0]; z[npoints - 1] = z[0]; rewrite = 1; } G_debug(3, "Vedit_snap_line(): line=%d, snapped=%d", line, rewrite); Vect_destroy_cats_struct(Cats); return rewrite; } /*! \brief Snap lines/boundaries \param Map pointer to Map_info \param BgMap,nbgmaps list of background maps used for snapping \param List list of lines to be snapped \param layer layer number \param thresh threshold value used for snapping (>0) \param to_vertex allow snapping also to vertex \return number of snapped lines \return -1 on error */ int Vedit_snap_lines(struct Map_info *Map, struct Map_info **BgMap, int nbgmaps, struct ilist *List, double thresh, int to_vertex) { int i, line, type; int nlines_modified = 0; struct line_pnts *Points; struct line_cats *Cats; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); for (i = 0; i < List->n_values; i++) { line = List->value[i]; type = Vect_read_line(Map, Points, Cats, line); if (!(type & (GV_POINT | GV_LINES))) { continue; } if (Vedit_snap_line(Map, BgMap, nbgmaps, line, Points, thresh, to_vertex) == 1) { if (Vect_rewrite_line(Map, line, type, Points, Cats) < 0) { return -1; } nlines_modified++; } } Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); return nlines_modified; }