/* calculate the DXF polyline "bulge" value corresponding to the angle between two vectors. In case of "infinity" return 0.0. */ static double bulge(dpoint_t v, dpoint_t w) { double v2, w2, vw, vxw, nvw; v2 = iprod(v, v); w2 = iprod(w, w); vw = iprod(v, w); vxw = xprod(v, w); nvw = sqrt(v2 * w2); if (vxw == 0.0) { return 0.0; } return (nvw - vw) / vxw; }
/* Output vertices (with bulges) corresponding to a smooth pair of circular arcs from A to B, tangent to AC at A and to CB at B. Segments are meant to be concatenated, so don't output the final vertex. */ static void pseudo_quad(FILE *fout, char *layer, dpoint_t A, dpoint_t C, dpoint_t B) { dpoint_t v, w; double v2, w2, vw, vxw, nvw; double a, b, c, y; dpoint_t G; double bulge1, bulge2; v = sub(A, C); w = sub(B, C); v2 = iprod(v, v); w2 = iprod(w, w); vw = iprod(v, w); vxw = xprod(v, w); nvw = sqrt(v2 * w2); a = v2 + 2*vw + w2; b = v2 + 2*nvw + w2; c = 4*nvw; if (vxw == 0 || a == 0) { goto degenerate; } /* assert: a,b,c >= 0, b*b - a*c >= 0, and 0 <= b - sqrt(b*b - a*c) <= a */ y = (b - sqrt(b*b - a*c)) / a; G = interval(y, C, interval(0.5, A, B)); bulge1 = bulge(sub(A,G), v); bulge2 = bulge(w, sub(B,G)); ship_vertex(fout, layer, A, -bulge1); ship_vertex(fout, layer, G, -bulge2); return; degenerate: ship_vertex(fout, layer, A, 0); return; }
/* returns 0 on success, 1 on error with errno set */ static int calc_lon(privpath_t *pp) { point_t *pt = pp->pt; int n = pp->len; int i, j, k, k1; int ct[4], dir; point_t constraint[2]; point_t cur; point_t off; int *pivk = NULL; /* pivk[n] */ int *nc = NULL; /* nc[n]: next corner */ point_t dk; /* direction of k-k1 */ int a, b, c, d; SAFE_MALLOC(pivk, n, int); SAFE_MALLOC(nc, n, int); /* initialize the nc data structure. Point from each point to the furthest future point to which it is connected by a vertical or horizontal segment. We take advantage of the fact that there is always a direction change at 0 (due to the path decomposition algorithm). But even if this were not so, there is no harm, as in practice, correctness does not depend on the word "furthest" above. */ k = 0; for (i=n-1; i>=0; i--) { if (pt[i].x != pt[k].x && pt[i].y != pt[k].y) { k = i+1; /* necessarily i<n-1 in this case */ } nc[i] = k; } SAFE_MALLOC(pp->lon, n, int); /* determine pivot points: for each i, let pivk[i] be the furthest k such that all j with i<j<k lie on a line connecting i,k. */ for (i=n-1; i>=0; i--) { ct[0] = ct[1] = ct[2] = ct[3] = 0; /* keep track of "directions" that have occurred */ dir = (3+3*(pt[mod(i+1,n)].x-pt[i].x)+(pt[mod(i+1,n)].y-pt[i].y))/2; ct[dir]++; constraint[0].x = 0; constraint[0].y = 0; constraint[1].x = 0; constraint[1].y = 0; /* find the next k such that no straight line from i to k */ k = nc[i]; k1 = i; while (1) { dir = (3+3*sign(pt[k].x-pt[k1].x)+sign(pt[k].y-pt[k1].y))/2; ct[dir]++; /* if all four "directions" have occurred, cut this path */ if (ct[0] && ct[1] && ct[2] && ct[3]) { pivk[i] = k1; goto foundk; } cur.x = pt[k].x - pt[i].x; cur.y = pt[k].y - pt[i].y; /* see if current constraint is violated */ if (xprod(constraint[0], cur) < 0 || xprod(constraint[1], cur) > 0) { goto constraint_viol; } /* else, update constraint */ if (abs(cur.x) <= 1 && abs(cur.y) <= 1) { /* no constraint */ } else { off.x = cur.x + ((cur.y>=0 && (cur.y>0 || cur.x<0)) ? 1 : -1); off.y = cur.y + ((cur.x<=0 && (cur.x<0 || cur.y<0)) ? 1 : -1); if (xprod(constraint[0], off) >= 0) { constraint[0] = off; } off.x = cur.x + ((cur.y<=0 && (cur.y<0 || cur.x<0)) ? 1 : -1); off.y = cur.y + ((cur.x>=0 && (cur.x>0 || cur.y<0)) ? 1 : -1); if (xprod(constraint[1], off) <= 0) { constraint[1] = off; } } k1 = k; k = nc[k1]; if (!cyclic(k,i,k1)) { break; } } constraint_viol: /* k1 was the last "corner" satisfying the current constraint, and k is the first one violating it. We now need to find the last point along k1..k which satisfied the constraint. */ dk.x = sign(pt[k].x-pt[k1].x); dk.y = sign(pt[k].y-pt[k1].y); cur.x = pt[k1].x - pt[i].x; cur.y = pt[k1].y - pt[i].y; /* find largest integer j such that xprod(constraint[0], cur+j*dk) >= 0 and xprod(constraint[1], cur+j*dk) <= 0. Use bilinearity of xprod. */ a = xprod(constraint[0], cur); b = xprod(constraint[0], dk); c = xprod(constraint[1], cur); d = xprod(constraint[1], dk); /* find largest integer j such that a+j*b>=0 and c+j*d<=0. This can be solved with integer arithmetic. */ j = INFTY; if (b<0) { j = floordiv(a,-b); } if (d>0) { j = min(j, floordiv(-c,d)); } pivk[i] = mod(k1+j,n); foundk: ; } /* for i */ /* clean up: for each i, let lon[i] be the largest k such that for all i' with i<=i'<k, i'<k<=pivk[i']. */ j=pivk[n-1]; pp->lon[n-1]=j; for (i=n-2; i>=0; i--) { if (cyclic(i+1,pivk[i],j)) { j=pivk[i]; } pp->lon[i]=j; } for (i=n-1; cyclic(mod(i+1,n),j,pp->lon[i]); i--) { pp->lon[i] = j; } free(pivk); free(nc); return 0; malloc_error: free(pivk); free(nc); return 1; }