[GRASS-SVN] r70560 - grass/trunk/lib/vector/vedit
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Feb 14 03:59:16 PST 2017
Author: hcho
Date: 2017-02-14 03:59:15 -0800 (Tue, 14 Feb 2017)
New Revision: 70560
Added:
grass/trunk/lib/vector/vedit/extend.c
Log:
vedit: Add Vedit_extend_lines()
Added: grass/trunk/lib/vector/vedit/extend.c
===================================================================
--- grass/trunk/lib/vector/vedit/extend.c (rev 0)
+++ grass/trunk/lib/vector/vedit/extend.c 2017-02-14 11:59:15 UTC (rev 70560)
@@ -0,0 +1,331 @@
+/*!
+ \file lib/vector/vedit/extend.c
+
+ \brief Vedit library - extend lines (adopted from break.c)
+
+ (C) 2017 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 Huidae Cho <grass4u gmail.com>
+*/
+
+#include <math.h>
+#include <grass/vedit.h>
+
+#define TOL 1e-9
+
+static int extend_lines(struct Map_info *, int, int, int, int, double,
+ struct ilist *);
+static int find_extended_intersection(double, double, double, double, double,
+ double, double *, double *);
+
+/*!
+ \brief Extend lines in given threshold
+
+ \code
+ 1. Extend first line only
+ \ \
+ id1 \ -> \
+ \
+ id2 ---------- -----+----
+
+
+ 2. Extend both lines
+ \ \
+ id1 \ -> \
+ \
+ id2 --- +----
+
+
+ 3. Extend first line when both are on the same line
+ id1 --- --- id2 -> -----+----
+
+
+ 4. Connect two parallel lines (parallel=1)
+ id1 ------ -------
+ -> /
+ id2 ------ +-----
+
+
+ 5. Don't connect two parallel lines (parallel=0)
+ id1 ------ ------
+ ->
+ id2 ------ ------
+ \endcode
+
+ \param Map pointer to Map_info
+ \param List list of selected lines
+ \param nodes 1 for start node, 2 for end node, other for both
+ \param parallel connect parallel lines
+ \param thresh threshold value
+
+ \return number of modified lines
+ */
+int Vedit_extend_lines(struct Map_info *Map, struct ilist *List, int nodes,
+ int parallel, double thresh)
+{
+ int nlines_modified, extended;
+ int i, j, node[2], first_node, 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();
+
+ first_node = 0;
+ n_nodes = 2;
+
+ switch (nodes) {
+ case 1:
+ n_nodes = 1;
+ break;
+ case 2:
+ first_node = 1;
+ break;
+ }
+
+ /* 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;
+
+ extended = 0;
+ Vect_reset_list(List_exclude);
+ Vect_list_append(List_exclude, line);
+ for (j = first_node; j < n_nodes && !extended; 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 extend lines (given node) */
+ G_debug(3, "Vedit_extend_lines(): lines=%d,%d", line, found);
+ if (extend_lines(Map, !j, line, found, parallel, thresh,
+ List)) {
+ G_debug(3, "Vedit_extend_lines(): lines=%d,%d -> extended",
+ line, found);
+ nlines_modified += 2;
+ extended = 1;
+ }
+ }
+
+ Vect_list_append(List_exclude, found);
+ } while(List_found->n_values > 0 && !extended);
+ }
+ }
+
+ Vect_destroy_list(List_exclude);
+ Vect_destroy_list(List_found);
+
+ return nlines_modified;
+}
+
+int extend_lines(struct Map_info *Map, int first, int line_from, int line_to,
+ int parallel, double thresh, struct ilist *List)
+{
+ /* TODO: If line_from extends to the i'th segment of line_to but the
+ * line_from node is closest to the j'th segment of line_to, this function
+ * wouldn't work because it only checks intersection of the start/end
+ * segment of line_from and the closest segment of line_to (i'th segment).
+ */
+ int line_new;
+ int type_from, type_to;
+ int n_points, seg, is;
+ double x, y, px, py, x1, y1;
+ double dist, spdist, lpdist, length;
+ double angle_t, angle_f;
+
+ struct line_pnts *Points_from, *Points_to, *Points_final;
+ struct line_cats *Cats_from, *Cats_to;
+
+ Points_from = Vect_new_line_struct();
+ Points_to = Vect_new_line_struct();
+ Points_final = Vect_new_line_struct();
+ Cats_from = Vect_new_cats_struct();
+ Cats_to = Vect_new_cats_struct();
+
+ type_from = Vect_read_line(Map, Points_from, Cats_from, line_from);
+ type_to = Vect_read_line(Map, Points_to, Cats_to, line_to);
+
+ line_new = 0;
+ if (!(type_from & GV_LINES) || !(type_to & GV_LINES))
+ line_new = -1;
+
+ /* avoid too much indentation */
+ do {
+ if (line_new == -1)
+ break;
+
+ n_points = Points_from->n_points - 1;
+
+ if (first) {
+ x = Points_from->x[0];
+ y = Points_from->y[0];
+ }
+ else {
+ x = Points_from->x[n_points];
+ y = Points_from->y[n_points];
+ }
+ seg = Vect_line_distance(Points_to, x, y, 0.0, WITHOUT_Z,
+ &px, &py, NULL, &dist, &spdist, &lpdist);
+
+ if (!(seg > 0 && dist > 0.0 && (thresh < 0. || dist <= thresh)))
+ break;
+
+ /* lines in threshold */
+ length = first ? 0 : Vect_line_length(Points_from);
+
+ /* find angles */
+ if (!Vect_point_on_line(Points_from, length, NULL, NULL, NULL, &angle_f,
+ NULL) ||
+ !Vect_point_on_line(Points_to, lpdist, NULL, NULL, NULL, &angle_t,
+ NULL))
+ break;
+
+ /* extend both lines and find intersection */
+ if (!find_extended_intersection(x, y, angle_f, px, py, angle_t,
+ &x1, &y1)) {
+ if (!parallel)
+ break;
+
+ /* parallel lines */
+ x1 = px;
+ y1 = py;
+ if (first)
+ Vect_line_insert_point(Points_from, 0, x1, y1, 0.0);
+ else
+ Vect_append_point(Points_from, x1, y1, 0.0);
+ } else {
+ /* if intersection point lies on line_from or is beyond threshold,
+ * skip */
+ /* TODO: Get rid of tolerance */
+ if (!Vect_line_distance(Points_from, x1, y1, 0.0, WITHOUT_Z, NULL,
+ NULL, NULL, &dist, NULL, NULL) ||
+ dist <= TOL || dist > thresh)
+ break;
+
+ /* lines extended -> extend/split line_to */
+ /* update line_from */
+ if (first) {
+ Points_from->x[0] = x1;
+ Points_from->y[0] = y1;
+ } else {
+ Points_from->x[n_points] = x1;
+ Points_from->y[n_points] = y1;
+ }
+ }
+
+ line_new = Vect_rewrite_line(Map, line_from, type_from, Points_from,
+ Cats_from);
+ /* Vect_list_append(List, line_new); */
+
+ length = Vect_line_length(Points_to);
+ Vect_reset_line(Points_final);
+ if (lpdist == 0.0) {
+ /* extend line_to start node */
+ Vect_append_point(Points_final, x1, y1, 0.0);
+ for (is = 0; is < Points_to->n_points; is++)
+ Vect_append_point(Points_final, Points_to->x[is],
+ Points_to->y[is], Points_to->z[is]);
+ line_new = Vect_rewrite_line(Map, line_to, type_to, Points_final,
+ Cats_to);
+ } else if (lpdist == length) {
+ /* extend line_to end node */
+ for (is = 0; is < Points_to->n_points; is++)
+ Vect_append_point(Points_final, Points_to->x[is],
+ Points_to->y[is], Points_to->z[is]);
+ Vect_append_point(Points_final, x1, y1, 0.0);
+ line_new = Vect_rewrite_line(Map, line_to, type_to, Points_final,
+ Cats_to);
+ } else {
+ /* break line_to */
+ /* update line_to -- first part */
+ for (is = 0; is < seg; is++)
+ Vect_append_point(Points_final, Points_to->x[is],
+ Points_to->y[is], Points_to->z[is]);
+ Vect_append_point(Points_final, x1, y1, 0.0);
+ line_new = Vect_rewrite_line(Map, line_to, type_to, Points_final,
+ Cats_to);
+ /* Vect_list_append(List, line_new); */
+
+ /* write second part */
+ Vect_reset_line(Points_final);
+ Vect_append_point(Points_final, x1, y1, 0.0);
+ for (is = seg; is < Points_to->n_points; is++)
+ Vect_append_point(Points_final, Points_to->x[is],
+ Points_to->y[is], Points_to->z[is]);
+
+ /* rewrite first part */
+ line_new = Vect_write_line(Map, type_to, Points_final, Cats_to);
+ /* Vect_list_append(List, line_new); */
+ }
+ } while(0);
+
+ Vect_destroy_line_struct(Points_from);
+ Vect_destroy_line_struct(Points_to);
+ Vect_destroy_line_struct(Points_final);
+ Vect_destroy_cats_struct(Cats_from);
+ Vect_destroy_cats_struct(Cats_to);
+
+ return line_new > 0 ? 1 : 0;
+}
+
+static int find_extended_intersection(double x1, double y1, double angle1,
+ double x2, double y2, double angle2,
+ double *x, double *y)
+{
+ double c1, s1, c2, s2, d, a;
+
+ if (fabs(sin(angle1 - angle2)) <= TOL) {
+ /* two lines are parallel */
+ double angle;
+
+ angle = atan2(y2 - y1, x2 - x1);
+ if (fabs(sin(angle - angle1)) <= TOL) {
+ /* they are on the same line */
+ *x = x2;
+ *y = y2;
+
+ return 1;
+ }
+
+ /* two lines don't intersect */
+ return 0;
+ }
+
+ c1 = cos(angle1);
+ s1 = sin(angle1);
+ c2 = cos(angle2);
+ s2 = sin(angle2);
+ d = -c1 * s2 + c2 * s1;
+ if (d == 0.0)
+ /* shouldn't happen again */
+ return 0;
+
+ a = (-s2 * (x2 - x1) + c2 * (y2 - y1)) / d;
+ *x = x1 + a * c1;
+ *y = y1 + a * s1;
+
+ return 1;
+}
More information about the grass-commit
mailing list