[GRASS-SVN] r31892 - grass-addons/vector/v.parallel2

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Jun 30 05:49:09 EDT 2008


Author: rmatev
Date: 2008-06-30 05:49:08 -0400 (Mon, 30 Jun 2008)
New Revision: 31892

Modified:
   grass-addons/vector/v.parallel2/main.c
   grass-addons/vector/v.parallel2/vlib_buffer.c
Log:
Added partial support of buffer-like type of parallel lines

Modified: grass-addons/vector/v.parallel2/main.c
===================================================================
--- grass-addons/vector/v.parallel2/main.c	2008-06-30 08:08:04 UTC (rev 31891)
+++ grass-addons/vector/v.parallel2/main.c	2008-06-30 09:49:08 UTC (rev 31892)
@@ -28,11 +28,11 @@
     struct Option *in_opt, *out_opt, *dista_opt;
     struct Option *distb_opt, *angle_opt, *side_opt;
     struct Option *tol_opt;
-    struct Flag *round_flag, *loops_flag;
+    struct Flag *round_flag, *buf_flag;
     struct Map_info In, Out;
-    struct line_pnts *Points, *Points2;
+    struct line_pnts *Points, *Points2, *oPoints, **iPoints;
     struct line_cats *Cats;
-    int    line, nlines;
+    int    line, nlines, inner_count, j;
     double da, db, dalpha, tolerance;
     int side;
 
@@ -50,6 +50,7 @@
     dista_opt->key = "distance";
     dista_opt->type =  TYPE_DOUBLE;
     dista_opt->required = YES;
+    dista_opt->options = "0-100000000";
     dista_opt->multiple = NO;
     dista_opt->description = _("Offset along major axis in map units");
 
@@ -57,6 +58,7 @@
     distb_opt->key = "minordistance";
     distb_opt->type =  TYPE_DOUBLE;
     distb_opt->required = NO;
+    dista_opt->options = "0-100000000";
     distb_opt->multiple = NO;
     distb_opt->description = _("Offset along minor axis in map units");
 
@@ -81,6 +83,7 @@
     tol_opt->key = "tolerance";
     tol_opt->type =  TYPE_DOUBLE;
     tol_opt->required = NO;
+    tol_opt->options = "0-100000000";
     tol_opt->multiple = NO;
     tol_opt->description = _("Tolerance of arc polylines in map units");
 
@@ -88,9 +91,9 @@
     round_flag->key = 'r';
     round_flag->description = _("Make outside corners round");
 
-    loops_flag = G_define_flag();
-    loops_flag->key = 'l';
-    loops_flag->description = _("Don't remove loops");
+    buf_flag = G_define_flag();
+    buf_flag->key = 'b';
+    buf_flag->description = _("Create buffer-like parallel lines");
     
     if (G_parser (argc, argv))
         exit(EXIT_FAILURE);
@@ -111,7 +114,7 @@
     if (tol_opt->answer)
         tolerance = atof(tol_opt->answer);
     else
-        tolerance = ((db<da)?db:da)/10.;
+        tolerance = ((db<da)?db:da)/100.;
             
     if (strcmp(side_opt->answer, "right") == 0)
         side = 1;
@@ -139,8 +142,17 @@
         ltype = Vect_read_line ( &In, Points, Cats, line);
         
         if ( ltype & GV_LINES ) {
-            Vect_line_parallel2(Points, da, db, dalpha, side, round_flag->answer, loops_flag->answer, tolerance, Points2);
-            Vect_write_line(&Out, ltype, Points2, Cats);
+            if (!(buf_flag->answer)) {
+                Vect_line_parallel2(Points, da, db, dalpha, side, round_flag->answer, tolerance, Points2);
+                Vect_write_line(&Out, ltype, Points2, Cats);
+            }
+            else {
+                parallel_line_b(Points, da, db, dalpha, round_flag->answer, 1, tolerance, &oPoints, &iPoints, &inner_count);
+                Vect_write_line(&Out, ltype, oPoints, Cats);
+                for (j = 0; j < inner_count; j++) {
+                    Vect_write_line(&Out, ltype, iPoints[j], Cats); 
+                }
+            }
         } else {
             Vect_write_line(&Out, ltype, Points, Cats);
         }

Modified: grass-addons/vector/v.parallel2/vlib_buffer.c
===================================================================
--- grass-addons/vector/v.parallel2/vlib_buffer.c	2008-06-30 08:08:04 UTC (rev 31891)
+++ grass-addons/vector/v.parallel2/vlib_buffer.c	2008-06-30 09:49:08 UTC (rev 31892)
@@ -17,7 +17,23 @@
     #define MAX(X,Y) ((X>Y)?X:Y)
 #endif    
 #define PI M_PI
+#define RIGHT_SIDE 1
+#define LEFT_SIDE -1
+#define LOOPED_LINE 1
+#define NON_LOOPED_LINE 0
 
+/*
+* a[i] = 0 means i-th line segment is not visited
+* a[i] = 1 means i-th line segment is visited on it's right side
+* a[i] = 2 means i-th line segment is visited on it's left side
+* a[i] = 3 means i-th line segment is visited on both sides
+*/
+struct visited_segments
+{
+    char *a;
+    int n;
+};
+
 /* norm_vector() calculates normalized vector form two points */
 static void norm_vector(double x1, double y1, double x2, double y2, double *x, double *y )
 {
@@ -237,88 +253,7 @@
     }
 }
 
-#ifdef this_is_comment
-/* parallel_line - remove duplicate points from input line and
-*  creates new parallel line in 'd' offset distance;
-*  'tol' is tolerance between arc and polyline;
-*  this function doesn't care about created loops;
-*
-*  New line is written to existing nPoints structure.
-*/
 
-void parallel_line (struct line_pnts *Points, double d, double tol, struct line_pnts *nPoints)
-{
-    int i, j, np, na, side;
-    double *x, *y, nx, ny, tx, ty, vx, vy, ux, uy, wx, wy;
-    double atol, atol2, a, av, aw;
-
-    G_debug (4, "parallel_line()" );
-
-    Vect_reset_line ( nPoints );
-
-    Vect_line_prune ( Points );
-    np = Points->n_points;
-    x = Points->x;
-    y = Points->y;
-
-    if ( np == 0 )
-	return;
-
-    if ( np == 1 ) {
-	Vect_append_point ( nPoints, x[0], y[0], 0 ); /* ? OK, should make circle for points ? */
-	return;
-    }
-
-    if ( d == 0 ) {
-	Vect_copy_xyz_to_pnts ( nPoints, x, y, NULL, np );
-	return;
-    }
-
-    side = (int)(d/fabs(d));
-    atol = 2 * acos( 1-tol/fabs(d) );
-
-    for (i = 0; i < np-1; i++)
-    {
-	norm_vector( x[i], y[i], x[i+1], y[i+1], &tx, &ty);
-	vx  = ty * d;
-	vy  = -tx * d;
-
-	nx = x[i] + vx;
-	ny = y[i] + vy;
-	Vect_append_point ( nPoints, nx, ny, 0 );
-
-	nx = x[i+1] + vx;
-	ny = y[i+1] + vy;
-	Vect_append_point ( nPoints, nx, ny, 0 );
-
-	if ( i < np-2 ) {  /* use polyline instead of arc between line segments */
-	    norm_vector( x[i+1], y[i+1], x[i+2], y[i+2], &ux, &uy);
-	    wx  =  uy * d;
-	    wy  = -ux * d;
-	    av = atan2 ( vy, vx );
-	    aw = atan2 ( wy, wx );
-	    a = (aw - av) * side;
-	    if ( a < 0 )  a+=2*PI;
-
-            /* TODO: a <= PI can probably fail because of representation error */
-	    if ( a <= PI && a > atol)
-	    {
-		na = (int) (a/atol);
-		atol2 = a/(na+1) * side;
-		for (j = 0; j < na; j++)
-		{
-		    av+=atol2;
-		    nx = x[i+1] + fabs(d) * cos(av);
-		    ny = y[i+1] + fabs(d) * sin(av);
-		    Vect_append_point ( nPoints, nx, ny, 0 );
-		}
-	    }
-	}
-    }
-    Vect_line_prune ( nPoints );
-}
-#endif
-
 static void rotate_vector(double x, double y, double cosa, double sina, double *nx, double *ny) {
     *nx = x*cosa - y*sina;
     *ny = x*sina + y*cosa;
@@ -386,14 +321,10 @@
 * !!!!!!!!!!!!!!!! FIX THIS TOLLERANCE CONSTANTS BAD (and UGLY) CODE !!!!!!!!!
 */
 static int line_intersection(double a1, double b1, double c1, double a2, double b2, double c2, double *x, double *y) {
-    double ka = a2/a1;
-    double kb = b2/b1;
-    double kc;
     double d;
     
-    if (fabs(ka - kb) < 1e-10) {
-        kc = c2/c1;
-        if (fabs(ka-kc) < 1e-10)
+    if (fabs(a2*b1 - a1*b2) == 0) {
+        if (fabs(a2*c1 - a1*c2) == 0)
             return 2;
         else                   
             return 0;
@@ -427,11 +358,10 @@
 * side: side >= 0 - right side, side < 0 - left side
 * when (da == db) we have plain distances (old case)
 * round - 1 for round corners, 0 for sharp corners. (tol is used only if round == 1)
-* round == 1 will be implemented soon
 */
-void parallel_line(struct line_pnts *Points, double da, double db, double dalpha, int side, int round, double tol, struct line_pnts *nPoints)
+void parallel_line(struct line_pnts *Points, double da, double db, double dalpha, int side, int round, int caps, int looped, double tol, struct line_pnts *nPoints)
 {
-    int i, j, res, np;
+    int i, i_minus_1, j, res, np;
     double *x, *y;
     double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry;
     double vx1, vy1, wx1, wy1;
@@ -439,14 +369,12 @@
     double phi1, phi2, delta_phi;
     double nsegments, angular_tol, angular_step;
     double cosa, sina, r;
-    int inner_corner;
-
-    G_debug(4, "parallel_line2()");
+    int inner_corner, turns180, loop_flag;
     
+    G_debug(4, "parallel_line()");
     
-    Vect_reset_line ( nPoints );
-
-    Vect_line_prune ( Points );
+    Vect_reset_line(nPoints);
+    
     np = Points->n_points;
     x = Points->x;
     y = Points->y;
@@ -462,14 +390,23 @@
     side = (side >= 0)?(1):(-1); /* normalize variable */
     dalpha *= PI/180; /* convert dalpha from degrees to radians */
     angular_tol = angular_tolerance(tol, da, db);
+    loop_flag = 1;
     
-    for (i = 0; i < np-1; i++)
+    for (i = 0; (i < np)&&(loop_flag); i++)
     {
-        wx = vx; /* save the old values */
-        wy = vy;
+        i_minus_1 = i - 1;
+        if (i == np-1) {
+            if (!looped) {
+                break;
+            }
+            else {
+                i = 0;
+                i_minus_1 = np - 2;
+                loop_flag = 0;
+            }
+        }
         
         norm_vector(x[i], y[i], x[i+1], y[i+1], &tx, &ty);
-        /* elliptic_transform(ty*side, -tx*side, da, db, dalpha, &vx, &vy); */
         elliptic_tangent(side*tx, side*ty, da, db, dalpha, &vx, &vy);
         
         nx = x[i] + vx;
@@ -480,30 +417,44 @@
 
         line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
         
-        if (i == 0) {
-            Vect_append_point(nPoints, nx, ny, 0);
+        if ((i == 0) && loop_flag) {
+            if (!looped) {
+                Vect_append_point(nPoints, nx, ny, 0);
+                G_debug(4, "append point x=%.18f y=%.18f i=%d", nx, ny, i);
+            }
         }
         else {
-            /* delta_phi = atan2(y[i+1]-y[i],x[i+1]-x[i]) - atan2(y[i]-y[i-1], x[i]-x[i-1])) */
-            delta_phi = atan2(ty, tx) - atan2(y[i]-y[i-1], x[i]-x[i-1]);
+            delta_phi = atan2(ty, tx) - atan2(y[i_minus_1+1]-y[i_minus_1], x[i_minus_1+1]-x[i_minus_1]);
             if (delta_phi > PI)
                 delta_phi -= 2*PI;
             else if (delta_phi <= -PI)
                 delta_phi += 2*PI;
-            /* now delta_phi is in (-pi;pi] */
-            inner_corner = (side*delta_phi <= 0);
-                 
-            if ((!round) || inner_corner) {
+            /* now delta_phi is in [-pi;pi] */
+            turns180 = (fabs(fabs(delta_phi) - PI) < 1e-15);
+            inner_corner = (side*delta_phi <= 0) && (!turns180);
+            
+            if ((turns180) && (!(caps && round))) {
+                if (caps) {
+                    norm_vector(0, 0, vx, vy, &tx, &ty);
+                    elliptic_tangent(side*tx, side*ty, da, db, dalpha, &tx, &ty);
+                }
+                else {
+                    tx = 0;
+                    ty = 0;
+                }
+                Vect_append_point(nPoints, x[i] + wx + tx, y[i] + wy + ty, 0);
+                Vect_append_point(nPoints, nx + tx, ny + ty, 0); /* nx == x[i] + vx, ny == y[i] + vy */
+            }
+            else if ((!round) || inner_corner) {
                 res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry);
-                if (res == 0) {
-                    /* THIS ISN'T SUPPOSED TO HAPPEN, MUST THROW ERROR*/
-                    G_fatal_error("Two consequtive line segments are parallel, but not on one straight line!\nThis should never happen.");
+/*                if (res == 0) {
+                    G_debug(4, "a0=%.18f, b0=%.18f, c0=%.18f, a1=%.18f, b1=%.18f, c1=%.18f", a0, b0, c0, a1, b1, c1);
+                    G_fatal_error("Two consequtive line segments are parallel, but not on one straight line! This should never happen.");
                     return;
-                }
-                else if (res == 1) {
+                }  */
+                if (res == 1) {
                     Vect_append_point(nPoints, rx, ry, 0);
                 }
-                /* else if (res == 2) do nothing; we have line segments, which are on one straight line */
             }
             else {
                 /* we should draw elliptical arc for outside corner */
@@ -515,7 +466,6 @@
                 phi1 = atan2(wy1, wx1);
                 phi2 = atan2(vy1, vx1);
                 delta_phi = side*(phi2 - phi1);
-                /*G_message("phi1=%f phi2=%f d_phi=%f", phi1, phi2, delta_phi);*/
                 
                 /* make delta_phi in [0, 2pi] */
                 if (delta_phi < 0)
@@ -532,18 +482,375 @@
             }
         }
         
-        if (i == np-2) {
+        if ((i == np-2) && (!looped)) {
             Vect_append_point(nPoints, mx, my, 0);
         }
         
+        /* save the old values */
         a0 = a1;
         b0 = b1;
         c0 = c1;
+        wx = vx;
+        wy = vy;        
     }
+    i = nPoints->n_points - 1;
+    Vect_line_insert_point(nPoints, 0, nPoints->x[i], nPoints->y[i], 0); 
     Vect_line_prune ( nPoints );
 }
 
+static void split_at_intersections(struct line_pnts *Points, struct line_pnts *nPoints)
+{
+    #define MAX_SEGMENT_INTERSECTIONS 10  /* we should make dynamic array here? */
+    #define EPSILON 1e-10 /*  */
+    int i, j, k, res, np;
+    double *x, *y; /* input coordinates */
+    double x1, y1, z1, x2, y2, z2; /* intersection points */
+    double len; /* current i-th line length */
+    double tdist, min;
+    double px[MAX_SEGMENT_INTERSECTIONS], py[MAX_SEGMENT_INTERSECTIONS], pdist[MAX_SEGMENT_INTERSECTIONS];
+    int pcount, min_i;
+
+    G_debug(1, "split_at_intersections()");
+    
+    Vect_reset_line(nPoints);
+
+    Vect_line_prune(Points);
+    np = Points->n_points;
+    x = Points->x;
+    y = Points->y;
+
+    if ((np == 0) || (np == 1))
+        return;
+
+    for (i = 0; i < np-1; i++) {
+        Vect_append_point(nPoints, x[i], y[i], 0);
+        G_debug(1, "appended point x=%f y=%f", x[i], y[i]);
+        
+        
+        /* find all intersections */
+        pcount = 0;
+        len = LENGTH((x[i]-x[i+1]), (y[i]-y[i+1]));
+        for (j = 0; j < np-1; j++) {
+            /* exclude previous (i-1)th, current i-th, and next (i+1)th line */
+            if ((j < i-1) || (j > i+1)) {
+                res = Vect_segment_intersection(x[i], y[i], 0, x[i+1], y[i+1], 0,
+                                                x[j], y[j], 0, x[j+1], y[j+1], 0,
+                                                &x1, &y1, &z1, &x2, &y2, &z2, 0);
+                G_debug(1, "intersection=%d", res);
+                if (res == 1) {
+                    /* generall intersection */
+                    tdist = LENGTH((x[i]-x1), (y[i]-y1));
+                    /* we only want intersections on the inside */
+                    G_debug(1, "x1=%f y1=%f tdist=%f len=%f, eps=%f", x1, y1, tdist, len, EPSILON);
+                    if ((tdist > EPSILON) && (tdist < len - EPSILON)) {
+                        px[pcount] = x1;
+                        py[pcount] = y1;
+                        pdist[pcount] = tdist;
+                        pcount++;
+                    }
+                }
+                /* TODO: implement cases of overlappings */
+            }
+        }
+        
+        /* now we shoud output interserction points ordered by distance to (x[i],y[i]) */
+        /* we do it in O(pcount^2) time, since pcount is usually small it's okey */
+        G_debug(1, "pcount=%d", pcount);
+        for (j = 0; j < pcount; j++) {
+            min = 2*len;
+            for (k = 0; k < pcount; k++) {
+                if (pdist[k] < min) {
+                    min = pdist[k];
+                    min_i = k;
+                }
+            }
+            pdist[min_i] = 4*len;
+            Vect_append_point(nPoints, px[min_i], py[min_i], 0);
+            G_debug(1, "appended point x=%f y=%f", px[min_i], py[min_i]);
+            
+        }
+    }
+    Vect_append_point(nPoints, x[np-1], y[np-1], 0);
+    G_debug(1, "appended point x=%f y=%f", x[i], y[i]);
+    Vect_line_prune(nPoints);    
+}
+
 /*
+* IMPORTANT: split_at_intersections() must be applied to input line before calling extract_contour
+*            when visited != NULL, extract_contour() marks the sides of lines as visited along the contour
+*            visited->a must have at least Points->n_points elements
+*
+* side: side >= 0 - right contour, side < 0 - left contour
+* returns: -1 when contour is a loop; 0 or Points->n_points-1 when contour finishes at line end (depending on which one)
+*/
+static int extract_contour(struct line_pnts *Points, int first_point, int first_step, int side, int stop_at_line_end, struct line_pnts *nPoints, struct visited_segments *visited) {
+    int i, is, j, k, step, np;
+    int ret;
+    double *x, *y;
+    double cx, cy, tx, ty;
+    double u, v, len, new_len, new_step;
+    int intersection_flag;
+    double x1, y1, z1, x2, y2, z2;
+    double opt_angle, tangle;
+    int opt_j, opt_step, opt_flag;
+    
+    G_debug(4, "extract_contour(): first_point=%d, first_step=%d, side=%d, stop_at_line_end=%d", first_point, first_step, side, stop_at_line_end);
+
+    Vect_reset_line(nPoints);
+            
+    np = Points->n_points;
+    x = Points->x;
+    y = Points->y;
+    G_debug(4, "ec: Points->n_points=%d", np);
+    
+    if ((np == 0) || (np == 1))
+        return;
+
+    /* normalize parameter side */
+    if (side >= 0)
+        side = 1;
+    else if (side < 0)
+        side = -1;
+    
+    i = first_point;
+    step = first_step;
+    while (1) {
+        /* precessing segment AB: A=(x[i],y[i]) B=(x[i+step],y[i+step]) */
+        Vect_append_point(nPoints, x[i], y[i], 0);
+        G_debug(4, "ec: append point x=%.18f y=%.18f", x[i], y[i]);
+        is = i + step;
+        
+        if (visited != NULL) {
+            j = (3-step*side)/2; /* j is 1 when (step*side == 1), and j is 2 when (step*side == -1) */
+            k = MIN(i, is);
+            if ((visited->a[k] & j) == 0)
+                visited->n++;
+            visited->a[k] |= j;
+        }
+                
+        cx = x[i] - x[is];
+        cy = y[i] - y[is];
+        opt_flag = 1;
+        for (j = 0; j < np-1; j++) {
+            /* exclude current segment AB */
+            if (j != i - (1-step)/2) {
+                if ((fabs(x[j]-x[is]) < EPSILON) && (fabs(y[j]-y[is]) < EPSILON)) {
+                    tx = x[j+1] - x[j];
+                    ty = y[j+1] - y[j];
+                    tangle = atan2(ty, tx) - atan2(cy, cx);
+                    if (tangle < 0)
+                        tangle += 2*PI;
+                    /* now tangle is in [0, 2PI) */
+                    
+                    if (opt_flag || (side*tangle < side*opt_angle)) {
+                        opt_j = j;
+                        opt_step = 1;
+                        opt_angle = tangle;
+                        opt_flag = 0;
+                    }
+                }
+                else if ((fabs(x[j+1]-x[is]) < EPSILON) && (fabs(y[j+1]-y[is]) < EPSILON)) {
+                    tx = x[j] - x[j+1];
+                    ty = y[j] - y[j+1];
+                    tangle = atan2(ty, tx) - atan2(cy, cx);
+                    if (tangle < 0)
+                        tangle += 2*PI;
+                    /* now tangle is in [0, 2PI) */
+                    
+                    if (opt_flag || (side*tangle < side*opt_angle)) {
+                        opt_j = j+1;
+                        opt_step = -1;
+                        opt_angle = tangle;
+                        opt_flag = 0;
+                    }
+                    
+                }
+            }
+        }
+        
+        /* if line end is reached */
+        if (opt_flag) {
+            if (stop_at_line_end) {
+                Vect_append_point(nPoints, x[is], y[is], 0);
+                ret = is;
+                break;
+            }
+            else {
+                opt_j = is;
+                opt_step = -step;
+            }
+        }
+        
+        if ((opt_j == first_point) && (opt_step == first_step)) {
+            Vect_append_point(nPoints, x[is], y[is], 0);
+            ret = -1;
+            break;
+        }
+        
+        i = opt_j;
+        step = opt_step;
+    }        
+    Vect_line_prune(nPoints);
+
+    return ret;
+}
+
+/*
+* This function extracts the outer contour of a (self crossing) line.
+* It can generate left/right contour if none of the line ends are in a loop.
+* If one or both of them is in a loop, then there's only one contour
+* 
+* side: side > 0 - right contour, side < 0 - left contour, side = 0 - outer contour
+*       if side != 0 and there's only one contour, the function returns it
+* 
+* IMPORTANT: split_at_intersections() must be applied to input line before calling extract_outer_contour
+* TODO: Implement side != 0 feature;
+* returns: returns on which side of output line is the exterior of the input line
+*/
+static int extract_outer_contour(struct line_pnts *Points, int side, struct line_pnts *nPoints, struct visited_segments *visited) {
+    int i, np, res, ret;
+    double *x, *y;
+    double min_x, min_angle, ta;
+    int t1, t2, j1=-1, j2=-1;
+
+    G_debug(4, "extract_outer_contour()");
+
+    np = Points->n_points;
+    x = Points->x;
+    y = Points->y;
+    
+    if (side != 0) {
+        res = extract_contour(Points, 0, 1, side, 1, nPoints, NULL); /* should save visited and later restore it if needed */
+        /* if we have finished at the other end */
+        if (res == Points->n_points-1) {
+            /* !!! WE ARE STILL NOT SURE WHETHER THIS IS PROPER OUTER CONTOUR.
+             * !!! CONSIDER THE CASE WHERE BOTH LINE ENDS ARE IN THE SAME LOOP. 
+            */
+            return side;
+        }
+    }
+    
+    /* find a line segment which is on the outer contour */
+    min_x = 1e300;
+    for (i = 0; i < np-1; i++) {
+        if (x[i] <= x[i+1]) {
+            t1 = i;
+            t2 = i+1;
+        }
+        else {
+            t1 = i+1;
+            t2 = i;
+        }
+        G_debug(4, "t1=%d (%f,%f) t2=%d (%f,%f)", t1, x[t1], y[t1], t2, x[t2], y[t2]);
+        if (x[t1] < min_x) {
+            min_x = x[t1];
+            min_angle = atan2(y[t2]-y[t1], x[t2]-x[t1]);
+            j1 = t1;
+            j2 = t2;
+            G_debug(4, "j1=%d j2=%d", j1, j2);
+        }
+        else if ((x[t1] == min_x) && (y[t1] == y[j1])) {
+            ta = atan2(y[t2]-y[t1], x[t2]-x[t1]);
+            if (ta < min_angle) {
+                min_angle = ta;
+                j1 = t1;
+                j2 = t2;
+                G_debug(4, "j1=%d j2=%d", j1, j2);
+            }
+        }
+    }
+    
+    G_debug(4, "j1=%d, j2-j1=%d, side=%d", j1, j2-j1, RIGHT_SIDE);
+    res = extract_contour(Points, j1, j2-j1, RIGHT_SIDE, 0, nPoints, visited);
+    
+    return RIGHT_SIDE;
+}
+
+/*
+* Extracts contours which are not visited. Generates counterclockwise closed lines.
+* IMPORTANT: split_at_intersections() must be applied to input line before calling extract_inner_contour
+* IMPORTANT: the outer contour must be visited, so that extract_inner_contour() doesn't return it
+* returns: 0 when there are no more inner contours; otherwise, returns on which side of output line is the interior of the loop
+*/
+int extract_inner_contour(struct line_pnts *Points, struct line_pnts *nPoints, struct visited_segments *visited) {
+    int i, j, np, res;
+    double *x, *y;
+    
+    G_debug(4, "extract_inner_contour()");
+
+    np = Points->n_points;
+    x = Points->x;
+    y = Points->y;
+    
+    for (i = 0; i < np-1; i++) {
+        /* if right side is not visited */
+        if ((visited->a[i] & 1) == 0) {
+            res = extract_contour(Points, i+1, -1, LEFT_SIDE, 0, nPoints, visited);
+            return LEFT_SIDE;
+        }
+        /* if left side is not visited */
+        if ((visited->a[i] & 2) == 0) {
+            res = extract_contour(Points, i, 1, LEFT_SIDE, 0, nPoints, visited);
+            return LEFT_SIDE;
+        }
+    }
+    
+    return 0;
+}
+
+void parallel_line_b(struct line_pnts *Points, double da, double db, double dalpha, int round, int caps, double tol, struct line_pnts **oPoints, struct line_pnts ***iPoints, int *inner_count) {
+    struct line_pnts *Points2, *tPoints;
+    struct line_pnts **arrPoints;
+    int i, side, count;
+    int more = 8;
+    int allocated = more;
+    struct visited_segments visited;
+    
+    G_debug(4, "parallel_line_b()");
+    
+    /* initializations and spliting of the input line */
+    tPoints = Vect_new_line_struct();
+    Points2 = Vect_new_line_struct();
+    split_at_intersections(Points, Points2);
+    
+    visited.a = (char *)G_malloc(sizeof(char)*Points2->n_points);
+    memset(visited.a, 0, sizeof(char)*Points2->n_points);
+    
+    arrPoints = G_malloc(allocated*sizeof(struct line_pnts *));
+    
+    /* outer contour */
+    side = extract_outer_contour(Points2, 0, tPoints, &visited);
+    *oPoints = Vect_new_line_struct();
+    parallel_line(tPoints, da, db, dalpha, side, round, caps, LOOPED_LINE, tol, *oPoints);
+    
+    /* inner contours */
+    count = 0;
+    side = extract_inner_contour(Points2, tPoints, &visited);
+    while (side != 0) {
+        if (allocated < count+1) {
+            allocated += more;
+            arrPoints = G_realloc(arrPoints, allocated*sizeof(struct line_pnts *));
+        }
+        arrPoints[count] = Vect_new_line_struct();
+/*        Vect_copy_xyz_to_pnts(arrPoints[count], tPoints->x, tPoints->y, tPoints->z, tPoints->n_points); */
+        parallel_line(tPoints, da, db, dalpha, side, round, caps, LOOPED_LINE, tol, arrPoints[count]);
+        count++;
+        
+        side = extract_inner_contour(Points2, tPoints, &visited);
+    }
+    
+    arrPoints = G_realloc(arrPoints, count*sizeof(struct line_pnts *));
+    *inner_count = count;
+    *iPoints = arrPoints;
+        
+    G_free(visited.a);
+    Vect_destroy_line_struct(tPoints);
+    Vect_destroy_line_struct(Points2);
+    
+    return;
+}
+
+/*
   \fn void Vect_line_parallel2 ( struct line_pnts *InPoints, double distance, double tolerance, int rm_end,
                        struct line_pnts *OutPoints )
   \brief Create parrallel line
@@ -553,16 +860,17 @@
   \param rm_end remove end points falling into distance
   \param OutPoints output line
 */
-void Vect_line_parallel2(struct line_pnts *InPoints, double da, double db, double dalpha, int side, int round, int loops, double tol, struct line_pnts *OutPoints )
+void Vect_line_parallel2(struct line_pnts *InPoints, double da, double db, double dalpha, int side, int round, double tol, struct line_pnts *OutPoints )
 {
-    G_debug(4, "Vect_line_parallel(): npoints = %d, da = %f, db = %f, dalpha = %f, side = %d, round_corners = %d, loops = %d, tol = %f",
-            InPoints->n_points, da, db, dalpha, side, round, loops, tol);
+    G_debug(4, "Vect_line_parallel(): npoints = %d, da = %f, db = %f, dalpha = %f, side = %d, round_corners = %d, tol = %f",
+            InPoints->n_points, da, db, dalpha, side, round, tol);
 
-    parallel_line (InPoints, da, db, dalpha, side, round, tol, OutPoints);
+    parallel_line(InPoints, da, db, dalpha, side, round, 1, NON_LOOPED_LINE, tol, OutPoints);
     
 /*    if (!loops)
         clean_parallel(OutPoints, InPoints, distance, rm_end);
-        */
+*/
+    return;
 }
 
 /*!



More information about the grass-commit mailing list