[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