[GRASS-SVN] r45832 - grass/branches/develbranch_6/lib/vector/Vlib

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Apr 3 08:42:05 EDT 2011


Author: mmetz
Date: 2011-04-03 05:42:04 -0700 (Sun, 03 Apr 2011)
New Revision: 45832

Modified:
   grass/branches/develbranch_6/lib/vector/Vlib/buffer.c
Log:
more thorough cleaning for v.buffer/v.parallel

Modified: grass/branches/develbranch_6/lib/vector/Vlib/buffer.c
===================================================================
--- grass/branches/develbranch_6/lib/vector/Vlib/buffer.c	2011-04-03 10:09:55 UTC (rev 45831)
+++ grass/branches/develbranch_6/lib/vector/Vlib/buffer.c	2011-04-03 12:42:04 UTC (rev 45832)
@@ -5,7 +5,7 @@
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   (C) 2001-2008 by the GRASS Development Team
+   (C) 2001-2011 by the GRASS Development Team
 
    This program is free software under the 
    GNU General Public License (>=v2). 
@@ -94,7 +94,7 @@
 }
 
 /* find_cross2 find first crossing between segments from s1 to s2 and from s3 to s4
- ** proceed from s1 to s2 and from s4 to s3
+ ** proceed from s1 to s2 and from s4 to s3, i.e. forward/backward
  ** s5 is set to first segment and s6 to second
  ** neighbours are taken as crossing each other only if overlap
  ** returns: 1 found
@@ -143,6 +143,106 @@
     return 0;
 }
 
+/* find_cross3 find first crossing of segment s1 to s1 + 1 with all
+ ** segments from s1 + 1 to Points->n_points - 2
+ ** ix is set to East crossing and iy to North crossing
+ ** s2 is set to the intersecting segment
+ ** neighbours are taken as crossing each other only if overlap
+ ** returns: 1 found
+ **          0 not found
+ */
+static int find_cross3(struct line_pnts *Points, int s1, int *s2, double *ix, double *iy)
+{
+    int i, np, ret, found = 0;
+    double *x, *y, min_dist, new_dist, new_x, new_y, dx, dy;
+
+    G_debug(5,
+	    "find_cross3(): npoints = %d, s1 = %d", Points->n_points, s1);
+
+    x = Points->x;
+    y = Points->y;
+    np = Points->n_points;
+    
+    min_dist = PORT_DOUBLE_MAX;
+
+    for (i = np - 2; i > s1; i--) {
+	ret =
+	    dig_test_for_intersection(x[s1], y[s1], x[s1 + 1], y[s1 + 1],
+				      x[i], y[i], x[i + 1], y[i + 1]);
+				      
+	if (ret) {
+	    dig_find_intersection(x[s1], y[s1], x[s1 + 1], y[s1 + 1], x[i],
+				  y[i], x[i + 1], y[i + 1], &new_x, &new_y);
+	    if ((new_x != x[s1] || new_y != y[s1]) && 
+	        (new_x != x[s1 + 1] || new_y != y[s1 + 1])) {
+		found = 1;
+		dx = x[s1] - new_x;
+		dy = y[s1] - new_y;
+		new_dist = LENGTH(dx, dy);
+		if (min_dist > new_dist) {
+		    min_dist = new_dist;
+		    *ix = new_x;
+		    *iy = new_y;
+		    *s2 = i;
+		}
+	    }
+	}
+    }
+
+    G_debug(5, "find_cross3(): intersection %s", found ? "found" : "not found");
+    return found;
+}
+
+/* find_cross4 find first crossing of segment s1 to s1 + 1 with all
+ ** segments from 0 to s1 - 1
+ ** ix is set to East crossing and iy to North crossing
+ ** s2 is set to the intersecting segment
+ ** neighbours are taken as crossing each other only if overlap
+ ** returns: 1 found
+ **          0 not found
+ */
+static int find_cross4(struct line_pnts *Points, int s1, int *s2, double *ix, double *iy)
+{
+    int i, np, ret, found = 0;
+    double *x, *y, min_dist, new_dist, new_x, new_y, dx, dy;
+
+    G_debug(5,
+	    "find_cross4(): npoints = %d, s1 = %d", Points->n_points, s1);
+
+    x = Points->x;
+    y = Points->y;
+    np = Points->n_points;
+    
+    min_dist = PORT_DOUBLE_MAX;
+
+    for (i = 0; i < s1; i++) {
+	ret =
+	    dig_test_for_intersection(x[s1], y[s1], x[s1 + 1], y[s1 + 1],
+				      x[i], y[i], x[i + 1], y[i + 1]);
+				      
+	if (ret) {
+	    dig_find_intersection(x[s1], y[s1], x[s1 + 1], y[s1 + 1], x[i],
+				  y[i], x[i + 1], y[i + 1], &new_x, &new_y);
+	    if ((new_x != x[s1] || new_y != y[s1]) && 
+	        (new_x != x[s1 + 1] || new_y != y[s1 + 1])) {
+		found = 1;
+		dx = x[s1 + 1] - new_x;
+		dy = y[s1 + 1] - new_y;
+		new_dist = LENGTH(dx, dy);
+		if (min_dist > new_dist) {
+		    min_dist = new_dist;
+		    *ix = new_x;
+		    *iy = new_y;
+		    *s2 = i;
+		}
+	    }
+	}
+    }
+
+    G_debug(5, "find_cross4(): intersection %s", found ? "found" : "not found");
+    return found;
+}
+
 /* point_in_buf - test if point px,py is in d buffer of Points
  ** returns:  1 in buffer
  **           0 not  in buffer
@@ -185,9 +285,9 @@
  */
 static void clean_parallel(struct line_pnts *Points,
 			   struct line_pnts *origPoints,
-			   double d, double tol, int rm_end)
+			   double d, double tol, int rm_end, int close_loop)
 {
-    int i, j, np, npn, sa, sb, ret;
+    int i, j, np, npn, sa, sb, ret, side;
     int sa_max = 0;
     int first = 0, current, last, lcount;
     double *x, *y, px, py, ix, iy;
@@ -196,6 +296,7 @@
     G_debug(4, "clean_parallel(): npoints = %d, d = %f, rm_end = %d",
 	    Points->n_points, d, rm_end);
 
+    Vect_line_prune(Points);
     x = Points->x;
     y = Points->y;
     np = Points->n_points;
@@ -204,14 +305,51 @@
 	return;
 
     if (rm_end) {
+	int inserted;
+
 	/* remove points from start in buffer */
-	j = 0;
+	j = inserted = 0;
 	for (i = 0; i < Points->n_points - 1; i++) {
 	    px = (x[i] + x[i + 1]) / 2;
 	    py = (y[i] + y[i + 1]) / 2;
-	    if (point_in_buf(origPoints, x[i], y[i], d * 0.99999999)
-		&& point_in_buf(origPoints, px, py, d * 0.99999999)) {
-		j++;
+	    if (point_in_buf(origPoints, x[i], y[i], d * 0.99999999)) {
+		
+		/* check for intersection of this segment */
+		/* most not be the first or last point of this segment */
+		current = i;
+		if (find_cross3(Points, current, &sa, &ix, &iy) != 0) {
+		    /* insert intersection point into this segment */
+		    /* and adjust i and Points->n_points */
+		    int k = 0;
+		    
+		    Vect_append_point(Points, Points->x[Points->n_points - 1],
+		                      Points->y[Points->n_points - 1], 0);
+		    Vect_append_point(Points, Points->x[Points->n_points - 1],
+		                      Points->y[Points->n_points - 1], 0);
+		    
+		    for (k = Points->n_points - 2; k > sa + 2; k--) {
+			Points->x[k] = Points->x[k - 2];
+			Points->y[k] = Points->y[k - 2];
+		    }
+		    Points->x[sa + 2] = ix;
+		    Points->y[sa + 2] = iy;
+		    for (k = sa + 1; k > current + 1; k--) {
+			Points->x[k] = Points->x[k - 1];
+			Points->y[k] = Points->y[k - 1];
+		    }
+		    Points->x[current + 1] = ix;
+		    Points->y[current + 1] = iy;
+		    i--;
+		    inserted++;
+		}
+		else if (point_in_buf(origPoints, px, py, d * 0.99999999)) {
+		    j++;
+		    if (inserted)
+			close_loop = 0;
+		}
+		else {
+		    break;
+		}
 	    }
 	    else {
 		break;
@@ -227,45 +365,89 @@
 	    Points->n_points = npn;
 	}
 	/* remove points from end in buffer */
-	j = 0;
+	j = inserted = 0;
 	for (i = Points->n_points - 1; i >= 1; i--) {
-	    px = (x[i] + x[i - 1]) / 2;
-	    py = (y[i] + y[i - 1]) / 2;
-	    if (point_in_buf(origPoints, x[i], y[i], d * 0.99999999)
-		&& point_in_buf(origPoints, px, py, d * 0.99999999)) {
-		j++;
+	    if (rm_end < 2) {
+		px = (x[i] + x[i - 1]) / 2;
+		py = (y[i] + y[i - 1]) / 2;
 	    }
 	    else {
+		/* this is for the last arc created by Vect_line_buffer() */
+		px = x[i - 1];
+		py = y[i - 1];
+	    }
+	    if (point_in_buf(origPoints, x[i], y[i], d * 0.99999999)) {
+		
+		/* check for intersection of this segment */
+		/* most not be the first or last point of this segment */
+		current = i - 1;
+		if (find_cross4(Points, current, &sa, &ix, &iy) != 0) {
+		    /* insert intersection point into this segment */
+		    /* and adjust i and Points->n_points */
+		    int k = 0;
+		    
+		    Vect_append_point(Points, Points->x[Points->n_points - 1],
+		                      Points->y[Points->n_points - 1], 0);
+		    Vect_append_point(Points, Points->x[Points->n_points - 1],
+		                      Points->y[Points->n_points - 1], 0);
+		    
+		    for (k = Points->n_points - 2; k > current + 2; k--) {
+			Points->x[k] = Points->x[k - 2];
+			Points->y[k] = Points->y[k - 2];
+		    }
+		    Points->x[current + 2] = ix;
+		    Points->y[current + 2] = iy;
+		    for (k = current + 1; k > sa + 1; k--) {
+			Points->x[k] = Points->x[k - 1];
+			Points->y[k] = Points->y[k - 1];
+		    }
+		    Points->x[sa + 1] = ix;
+		    Points->y[sa + 1] = iy;
+		    i += 3;
+		    inserted++;
+		}
+		else if (point_in_buf(origPoints, px, py, d * 0.99999999)) {
+		    j++;
+		    if (inserted)
+			close_loop = 0;
+		}
+		else {
+		    break;
+		}
+	    }
+	    else {
 		break;
 	    }
 	}
 	if (j > 0) {
 	    Points->n_points -= j;
 	}
-	
+
 	/* test for intersection of end segments */
 	/* need to do this here, otherwise remove loops below will
 	 * remove everything but the end dangles */
 	np = Points->n_points;
-	i = 0;
-	j = np - 2;
-	ret =
-	    dig_test_for_intersection(x[i], y[i], x[i + 1], y[i + 1],
-				      x[j], y[j], x[j + 1], y[j + 1]);
-				      
-	if (ret == -1) {
-	    /* overlap */
-	    x[np - 1] = x[0];
-	    y[np - 1] = y[0];
+	if (np > 3 && (x[0] != x[np - 1] || y[0] != y[np - 1])) {
+	    i = 0;
+	    j = np - 2;
+	    ret =
+		dig_test_for_intersection(x[i], y[i], x[i + 1], y[i + 1],
+					  x[j], y[j], x[j + 1], y[j + 1]);
+					  
+	    if (ret == -1) {
+		/* overlap */
+		x[np - 1] = x[0];
+		y[np - 1] = y[0];
+	    }
+	    else if (ret == 1) {
+		dig_find_intersection(x[i], y[i], x[i + 1], y[i + 1], x[j],
+				      y[j], x[j + 1], y[j + 1], &ix, &iy);
+		x[0] = ix;
+		y[0] = iy;
+		x[np - 1] = ix;
+		y[np - 1] = iy;
+	    }
 	}
-	else if (ret == 1) {
-	    dig_find_intersection(x[i], y[i], x[i + 1], y[i + 1], x[j],
-				  y[j], x[j + 1], y[j + 1], &ix, &iy);
-	    x[0] = ix;
-	    x[np - 1] = ix;
-	    y[0] = iy;
-	    y[np - 1] = iy;
-	}
 	Vect_line_prune(Points);
     }
 
@@ -277,8 +459,10 @@
     np = Points->n_points;
     npn = 1;
 
+    side = (int)(d / fabs(d));
+    
     /* remove loops */
-    while (first < np - 2) {
+    while (np > 3 && first < np - 2) {
 	/* find first loop which doesn't contain any other loop */
 	current = first;
 	G_debug(5, "current: %d", current);
@@ -317,15 +501,25 @@
 	    /* first = sa; */
 	}
 	else {
+	    double area_size;
+
 	    Vect_reset_line(sPoints);
 	    dig_find_intersection(x[sa], y[sa], x[sa + 1], y[sa + 1], x[sb],
 				  y[sb], x[sb + 1], y[sb + 1], &ix, &iy);
+				  
+	    if (ix == x[0] && iy == y[0] && ix == x[np - 1] && iy == y[np - 1])
+		break;
 	    Vect_append_point(sPoints, ix, iy, 0);
 	    for (i = sa + 1; i < sb + 1; i++) {	/* create loop polygon */
 		Vect_append_point(sPoints, x[i], y[i], 0);
 	    }
-	    Vect_find_poly_centroid(sPoints, &px, &py);
-	    if (point_in_buf(origPoints, px, py, d)) {	/* is loop in buffer ? */
+
+	    Vect_append_point(sPoints, ix, iy, 0);
+	    dig_find_area_poly(sPoints, &area_size);
+
+	    /*Vect_find_poly_centroid(sPoints, &px, &py);
+	    if (point_in_buf(origPoints, px, py, d)) { */	/* is loop in buffer ? */
+	    if (area_size * side < 0) {
 		npn = sa + 1;
 		x[npn] = ix;
 		y[npn] = iy;
@@ -355,7 +549,8 @@
 
     /* looped input line ? */
     if (origPoints->x[0] == origPoints->x[origPoints->n_points - 1] &&
-        origPoints->y[0] == origPoints->y[origPoints->n_points - 1]) {
+        origPoints->y[0] == origPoints->y[origPoints->n_points - 1] &&
+	close_loop) {
 	double tx, ty, vx, vy, ux, uy, wx, wy, a, aw, av;
 	int sa, sb, side;
 	double atol, atol2;
@@ -410,7 +605,7 @@
 		int na;
 		double nx, ny;
 
-		/* close parallel line */
+		/* OK to close parallel line ? */
 		na = (int)(a / atol);
 		atol2 = a / (na + 1) * side;
 		for (j = 0; j < na; j++) {
@@ -447,7 +642,6 @@
 
     Vect_reset_line(nPoints);
 
-    Vect_line_prune(Points);
     np = Points->n_points;
     x = Points->x;
     y = Points->y;
@@ -529,7 +723,7 @@
     parallel_line(InPoints, distance, tolerance, OutPoints);
     G_debug(4, "%d outpoints", OutPoints->n_points);
 
-    clean_parallel(OutPoints, InPoints, distance, tolerance, rm_end);
+    clean_parallel(OutPoints, InPoints, distance, tolerance, rm_end, 1);
     G_debug(4, "%d outpoints after cleaning", OutPoints->n_points);
 
     return;
@@ -565,10 +759,9 @@
     if (PPoints == NULL)
 	PPoints = Vect_new_line_struct();
 
-    /* Copy and prune input */
+    /* Copy input */
     Vect_reset_line(Points);
     Vect_append_points(Points, InPoints, GV_FORWARD);
-    Vect_line_prune(Points);
 
     Vect_reset_line(OutPoints);
 
@@ -595,16 +788,25 @@
 
 	    /* Parallel on one side */
 	    if (side == 0) {
-		Vect_line_parallel(Points, distance, tolerance, 0, PPoints);
+		/* Vect_line_parallel(Points, distance, tolerance, 0, PPoints); */
+
+		/* just create parallel line, clean later */
+		parallel_line(InPoints, distance, tolerance, PPoints);
+		G_debug(4, "%d outpoints", PPoints->n_points);
+
 		Vect_append_points(OutPoints, PPoints, GV_FORWARD);
 	    }
 	    else {
-		Vect_line_parallel(Points, -distance, tolerance, 0, PPoints);
+		/* Vect_line_parallel(Points, -distance, tolerance, 0, PPoints); */
+
+		parallel_line(InPoints, -distance, tolerance, PPoints);
+		G_debug(4, "%d outpoints", PPoints->n_points);
+
 		Vect_append_points(OutPoints, PPoints, GV_BACKWARD);
 	    }
 
 	    /* Arc at the end */
-	    /* 2 points at theend of original line */
+	    /* 2 points at the end of original line */
 	    if (side == 0) {
 		lx1 = Points->x[npoints - 2];
 		ly1 = Points->y[npoints - 2];
@@ -643,10 +845,31 @@
 	    Vect_append_point(OutPoints, ex, ey, 0);
 	}
 
+	/* clean up arcs at the end of input lines */
+	Vect_line_prune(OutPoints);
+	if (OutPoints->x[0] == OutPoints->x[OutPoints->n_points - 1] &&
+	    OutPoints->y[0] == OutPoints->y[OutPoints->n_points - 1])
+	    OutPoints->n_points--;
+
+	clean_parallel(OutPoints, InPoints, distance, tolerance, 2, 0);
+
 	/* Close polygon */
-	Vect_append_point(OutPoints, OutPoints->x[0], OutPoints->y[0], 0);
+	if (OutPoints->x[0] != OutPoints->x[OutPoints->n_points - 1] ||
+	    OutPoints->y[0] != OutPoints->y[OutPoints->n_points - 1]) {
+
+	    if (point_in_buf(InPoints, OutPoints->x[0], OutPoints->y[0], distance * 0.99999999)) {
+		OutPoints->x[0] = OutPoints->x[OutPoints->n_points - 1];
+		OutPoints->y[0] = OutPoints->y[OutPoints->n_points - 1];
+	    }
+	    else if (point_in_buf(InPoints, OutPoints->x[OutPoints->n_points - 1],
+				  OutPoints->y[OutPoints->n_points - 1], distance * 0.99999999)) {
+		OutPoints->x[OutPoints->n_points - 1] = OutPoints->x[0];
+		OutPoints->y[OutPoints->n_points - 1] = OutPoints->y[0];
+	    }
+	    else
+		Vect_append_point(OutPoints, OutPoints->x[0], OutPoints->y[0], 0);
+	}
     }
-    Vect_line_prune(OutPoints);
 
     return;
 }



More information about the grass-commit mailing list