pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00021 /* trace.c 147 2007-04-09 00:44:09Z selinger */ 00022 00023 #include <stdio.h> 00024 #include <math.h> 00025 #include <stdlib.h> 00026 #include <string.h> 00027 00028 #include "global.h" 00029 #include "potracelib.h" 00030 #include "curve.h" 00031 #include "lists.h" 00032 #include "auxiliary.h" 00033 #include "trace.h" 00034 #include "pcb-printf.h" 00035 //#include "progress.h" 00036 00040 #define INFTY 10000000 00041 00044 #define COS179 -0.999847695156 00045 00046 /* ---------------------------------------------------------------------- */ 00047 #define SAFE_MALLOC(var, n, typ) \ 00048 if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error 00049 00050 /* ---------------------------------------------------------------------- */ 00051 /* auxiliary functions */ 00052 00058 static inline point_t 00059 dorth_infty (dpoint_t p0, dpoint_t p2) 00060 { 00061 point_t r; 00062 00063 r.y = sign (p2.x - p0.x); 00064 r.x = -sign (p2.y - p0.y); 00065 00066 return r; 00067 } 00068 00072 static inline double 00073 dpara (dpoint_t p0, dpoint_t p1, dpoint_t p2) 00074 { 00075 double x1, y1, x2, y2; 00076 00077 x1 = p1.x - p0.x; 00078 y1 = p1.y - p0.y; 00079 x2 = p2.x - p0.x; 00080 y2 = p2.y - p0.y; 00081 00082 return x1 * y2 - x2 * y1; 00083 } 00084 00090 static inline double 00091 ddenom (dpoint_t p0, dpoint_t p2) 00092 { 00093 point_t r = dorth_infty (p0, p2); 00094 00095 return r.y * (p2.x - p0.x) - r.x * (p2.y - p0.y); 00096 } 00097 00101 static inline int 00102 cyclic (int a, int b, int c) 00103 { 00104 if (a <= c) 00105 { 00106 return (a <= b && b < c); 00107 } 00108 else 00109 { 00110 return (a <= b || b < c); 00111 } 00112 } 00113 00119 static void 00120 pointslope (privpath_t * pp, int i, int j, dpoint_t * ctr, dpoint_t * dir) 00121 { 00122 /* assume i<j */ 00123 00124 int n = pp->len; 00125 sums_t *sums = pp->sums; 00126 00127 double x, y, x2, xy, y2; 00128 double k; 00129 double a, b, c, lambda2, l; 00130 int r = 0; /* rotations from i to j */ 00131 00132 while (j >= n) 00133 { 00134 j -= n; 00135 r += 1; 00136 } 00137 while (i >= n) 00138 { 00139 i -= n; 00140 r -= 1; 00141 } 00142 while (j < 0) 00143 { 00144 j += n; 00145 r -= 1; 00146 } 00147 while (i < 0) 00148 { 00149 i += n; 00150 r += 1; 00151 } 00152 00153 x = sums[j + 1].x - sums[i].x + r * sums[n].x; 00154 y = sums[j + 1].y - sums[i].y + r * sums[n].y; 00155 x2 = sums[j + 1].x2 - sums[i].x2 + r * sums[n].x2; 00156 xy = sums[j + 1].xy - sums[i].xy + r * sums[n].xy; 00157 y2 = sums[j + 1].y2 - sums[i].y2 + r * sums[n].y2; 00158 k = j + 1 - i + r * n; 00159 00160 ctr->x = x / k; 00161 ctr->y = y / k; 00162 00163 a = (x2 - (double) x * x / k) / k; 00164 b = (xy - (double) x * y / k) / k; 00165 c = (y2 - (double) y * y / k) / k; 00166 00167 lambda2 = (a + c + hypot (a - c, 2 * b)) / 2; /* larger e.value */ 00168 00169 /* now find e.vector for lambda2 */ 00170 a -= lambda2; 00171 c -= lambda2; 00172 00173 if (fabs (a) >= fabs (c)) 00174 { 00175 l = hypot (a, b); 00176 if (l != 0) 00177 { 00178 dir->x = -b / l; 00179 dir->y = a / l; 00180 } 00181 } 00182 else 00183 { 00184 l = hypot (c, b); 00185 if (l != 0) 00186 { 00187 dir->x = -c / l; 00188 dir->y = b / l; 00189 } 00190 } 00191 if (l == 0) 00192 { 00193 dir->x = dir->y = 0; /* sometimes this can happen when k=4: 00194 the two eigenvalues coincide */ 00195 } 00196 } 00197 00205 typedef double quadform_t[3][3]; 00206 00210 static inline double 00211 quadform (quadform_t Q, dpoint_t w) 00212 { 00213 double v[3]; 00214 int i, j; 00215 double sum; 00216 00217 v[0] = w.x; 00218 v[1] = w.y; 00219 v[2] = 1; 00220 sum = 0.0; 00221 00222 for (i = 0; i < 3; i++) 00223 { 00224 for (j = 0; j < 3; j++) 00225 { 00226 sum += v[i] * Q[i][j] * v[j]; 00227 } 00228 } 00229 return sum; 00230 } 00231 00235 static inline int 00236 xprod (point_t p1, point_t p2) 00237 { 00238 return p1.x * p2.y - p1.y * p2.x; 00239 } 00240 00244 static inline double 00245 cprod (dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) 00246 { 00247 double x1, y1, x2, y2; 00248 00249 x1 = p1.x - p0.x; 00250 y1 = p1.y - p0.y; 00251 x2 = p3.x - p2.x; 00252 y2 = p3.y - p2.y; 00253 00254 return x1 * y2 - x2 * y1; 00255 } 00256 00260 static inline double 00261 iprod (dpoint_t p0, dpoint_t p1, dpoint_t p2) 00262 { 00263 double x1, y1, x2, y2; 00264 00265 x1 = p1.x - p0.x; 00266 y1 = p1.y - p0.y; 00267 x2 = p2.x - p0.x; 00268 y2 = p2.y - p0.y; 00269 00270 return x1 * x2 + y1 * y2; 00271 } 00272 00276 static inline double 00277 iprod1 (dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) 00278 { 00279 double x1, y1, x2, y2; 00280 00281 x1 = p1.x - p0.x; 00282 y1 = p1.y - p0.y; 00283 x2 = p3.x - p2.x; 00284 y2 = p3.y - p2.y; 00285 00286 return x1 * x2 + y1 * y2; 00287 } 00288 00292 static inline double 00293 ddist (dpoint_t p, dpoint_t q) 00294 { 00295 return hypot (p.x - q.x, p.y - q.y); 00296 } 00297 00301 static inline dpoint_t 00302 bezier (double t, dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) 00303 { 00304 double s = 1 - t; 00305 dpoint_t res; 00306 00307 /* Note: a good optimizing compiler (such as gcc-3) reduces the 00308 following to 16 multiplications, using common subexpression 00309 elimination. */ 00310 00311 res.x = 00312 s * s * s * p0.x + 3 * (s * s * t) * p1.x + 3 * (t * t * s) * p2.x + 00313 t * t * t * p3.x; 00314 res.y = 00315 s * s * s * p0.y + 3 * (s * s * t) * p1.y + 3 * (t * t * s) * p2.y + 00316 t * t * t * p3.y; 00317 00318 return res; 00319 } 00320 00327 static double 00328 tangent (dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3, dpoint_t q0, 00329 dpoint_t q1) 00330 { 00331 double A, B, C; /* (1-t)^2 A + 2(1-t)t B + t^2 C = 0 */ 00332 double a, b, c; /* a t^2 + b t + c = 0 */ 00333 double d, s, r1, r2; 00334 00335 A = cprod (p0, p1, q0, q1); 00336 B = cprod (p1, p2, q0, q1); 00337 C = cprod (p2, p3, q0, q1); 00338 00339 a = A - 2 * B + C; 00340 b = -2 * A + 2 * B; 00341 c = A; 00342 00343 d = b * b - 4 * a * c; 00344 00345 if (a == 0 || d < 0) 00346 { 00347 return -1.0; 00348 } 00349 00350 s = sqrt (d); 00351 00352 r1 = (-b + s) / (2 * a); 00353 r2 = (-b - s) / (2 * a); 00354 00355 if (r1 >= 0 && r1 <= 1) 00356 { 00357 return r1; 00358 } 00359 else if (r2 >= 0 && r2 <= 1) 00360 { 00361 return r2; 00362 } 00363 else 00364 { 00365 return -1.0; 00366 } 00367 } 00368 00375 static int 00376 calc_sums (privpath_t * pp) 00377 { 00378 int i, x, y; 00379 int n = pp->len; 00380 00381 SAFE_MALLOC (pp->sums, pp->len + 1, sums_t); 00382 00383 /* origin */ 00384 pp->x0 = pp->pt[0].x; 00385 pp->y0 = pp->pt[0].y; 00386 00387 /* preparatory computation for later fast summing */ 00388 pp->sums[0].x2 = pp->sums[0].xy = pp->sums[0].y2 = pp->sums[0].x = 00389 pp->sums[0].y = 0; 00390 for (i = 0; i < n; i++) 00391 { 00392 x = pp->pt[i].x - pp->x0; 00393 y = pp->pt[i].y - pp->y0; 00394 pp->sums[i + 1].x = pp->sums[i].x + x; 00395 pp->sums[i + 1].y = pp->sums[i].y + y; 00396 pp->sums[i + 1].x2 = pp->sums[i].x2 + x * x; 00397 pp->sums[i + 1].xy = pp->sums[i].xy + x * y; 00398 pp->sums[i + 1].y2 = pp->sums[i].y2 + y * y; 00399 } 00400 return 0; 00401 00402 malloc_error: 00403 return 1; 00404 } 00405 00438 static int 00439 calc_lon (privpath_t * pp) 00440 { 00441 point_t *pt = pp->pt; 00442 int n = pp->len; 00443 int i, j, k, k1; 00444 int ct[4], dir; 00445 point_t constraint[2]; 00446 point_t cur; 00447 point_t off; 00448 int *pivk = NULL; /* pivk[n] */ 00449 int *nc = NULL; /* nc[n]: next corner */ 00450 point_t dk; /* direction of k-k1 */ 00451 int a, b, c, d; 00452 00453 SAFE_MALLOC (pivk, n, int); 00454 SAFE_MALLOC (nc, n, int); 00455 00456 /* initialize the nc data structure. Point from each point to the 00457 furthest future point to which it is connected by a vertical or 00458 horizontal segment. We take advantage of the fact that there is 00459 always a direction change at 0 (due to the path decomposition 00460 algorithm). But even if this were not so, there is no harm, as 00461 in practice, correctness does not depend on the word "furthest" 00462 above. */ 00463 k = 0; 00464 for (i = n - 1; i >= 0; i--) 00465 { 00466 if (pt[i].x != pt[k].x && pt[i].y != pt[k].y) 00467 { 00468 k = i + 1; /* necessarily i<n-1 in this case */ 00469 } 00470 nc[i] = k; 00471 } 00472 00473 SAFE_MALLOC (pp->lon, n, int); 00474 00475 /* determine pivot points: for each i, let pivk[i] be the furthest k 00476 such that all j with i<j<k lie on a line connecting i,k. */ 00477 00478 for (i = n - 1; i >= 0; i--) 00479 { 00480 ct[0] = ct[1] = ct[2] = ct[3] = 0; 00481 00482 /* keep track of "directions" that have occurred */ 00483 dir = 00484 (3 + 3 * (pt[mod (i + 1, n)].x - pt[i].x) + 00485 (pt[mod (i + 1, n)].y - pt[i].y)) / 2; 00486 ct[dir]++; 00487 00488 constraint[0].x = 0; 00489 constraint[0].y = 0; 00490 constraint[1].x = 0; 00491 constraint[1].y = 0; 00492 00493 /* find the next k such that no straight line from i to k */ 00494 k = nc[i]; 00495 k1 = i; 00496 while (1) 00497 { 00498 00499 dir = 00500 (3 + 3 * sign (pt[k].x - pt[k1].x) + 00501 sign (pt[k].y - pt[k1].y)) / 2; 00502 ct[dir]++; 00503 00504 /* if all four "directions" have occurred, cut this path */ 00505 if (ct[0] && ct[1] && ct[2] && ct[3]) 00506 { 00507 pivk[i] = k1; 00508 goto foundk; 00509 } 00510 00511 cur.x = pt[k].x - pt[i].x; 00512 cur.y = pt[k].y - pt[i].y; 00513 00514 /* see if current constraint is violated */ 00515 if (xprod (constraint[0], cur) < 0 00516 || xprod (constraint[1], cur) > 0) 00517 { 00518 goto constraint_viol; 00519 } 00520 00521 /* else, update constraint */ 00522 if (abs (cur.x) <= 1 && abs (cur.y) <= 1) 00523 { 00524 /* no constraint */ 00525 } 00526 else 00527 { 00528 off.x = 00529 cur.x + ((cur.y >= 0 && (cur.y > 0 || cur.x < 0)) ? 1 : -1); 00530 off.y = 00531 cur.y + ((cur.x <= 0 && (cur.x < 0 || cur.y < 0)) ? 1 : -1); 00532 if (xprod (constraint[0], off) >= 0) 00533 { 00534 constraint[0] = off; 00535 } 00536 off.x = 00537 cur.x + ((cur.y <= 0 && (cur.y < 0 || cur.x < 0)) ? 1 : -1); 00538 off.y = 00539 cur.y + ((cur.x >= 0 && (cur.x > 0 || cur.y < 0)) ? 1 : -1); 00540 if (xprod (constraint[1], off) <= 0) 00541 { 00542 constraint[1] = off; 00543 } 00544 } 00545 k1 = k; 00546 k = nc[k1]; 00547 if (!cyclic (k, i, k1)) 00548 { 00549 break; 00550 } 00551 } 00552 constraint_viol: 00553 /* k1 was the last "corner" satisfying the current constraint, and 00554 k is the first one violating it. We now need to find the last 00555 point along k1..k which satisfied the constraint. */ 00556 dk.x = sign (pt[k].x - pt[k1].x); 00557 dk.y = sign (pt[k].y - pt[k1].y); 00558 cur.x = pt[k1].x - pt[i].x; 00559 cur.y = pt[k1].y - pt[i].y; 00560 /* find largest integer j such that xprod(constraint[0], cur+j*dk) 00561 >= 0 and xprod(constraint[1], cur+j*dk) <= 0. Use bilinearity 00562 of xprod. */ 00563 a = xprod (constraint[0], cur); 00564 b = xprod (constraint[0], dk); 00565 c = xprod (constraint[1], cur); 00566 d = xprod (constraint[1], dk); 00567 /* find largest integer j such that a+j*b>=0 and c+j*d<=0. This 00568 can be solved with integer arithmetic. */ 00569 j = INFTY; 00570 if (b < 0) 00571 { 00572 j = floordiv (a, -b); 00573 } 00574 if (d > 0) 00575 { 00576 j = min (j, floordiv (-c, d)); 00577 } 00578 pivk[i] = mod (k1 + j, n); 00579 foundk: 00580 ; 00581 } /* for i */ 00582 00583 /* clean up: for each i, let lon[i] be the largest k such that for 00584 all i' with i<=i'<k, i'<k<=pivk[i']. */ 00585 00586 j = pivk[n - 1]; 00587 pp->lon[n - 1] = j; 00588 for (i = n - 2; i >= 0; i--) 00589 { 00590 if (cyclic (i + 1, pivk[i], j)) 00591 { 00592 j = pivk[i]; 00593 } 00594 pp->lon[i] = j; 00595 } 00596 00597 for (i = n - 1; cyclic (mod (i + 1, n), j, pp->lon[i]); i--) 00598 { 00599 pp->lon[i] = j; 00600 } 00601 00602 free (pivk); 00603 free (nc); 00604 return 0; 00605 00606 malloc_error: 00607 free (pivk); 00608 free (nc); 00609 return 1; 00610 } 00611 00612 00619 static double 00620 penalty3 (privpath_t * pp, int i, int j) 00621 { 00622 int n = pp->len; 00623 point_t *pt = pp->pt; 00624 sums_t *sums = pp->sums; 00625 00626 /* assume 0<=i<j<=n */ 00627 double x, y, x2, xy, y2; 00628 double k; 00629 double a, b, c, s; 00630 double px, py, ex, ey; 00631 00632 int r = 0; /* rotations from i to j */ 00633 00634 if (j >= n) 00635 { 00636 j -= n; 00637 r += 1; 00638 } 00639 00640 x = sums[j + 1].x - sums[i].x + r * sums[n].x; 00641 y = sums[j + 1].y - sums[i].y + r * sums[n].y; 00642 x2 = sums[j + 1].x2 - sums[i].x2 + r * sums[n].x2; 00643 xy = sums[j + 1].xy - sums[i].xy + r * sums[n].xy; 00644 y2 = sums[j + 1].y2 - sums[i].y2 + r * sums[n].y2; 00645 k = j + 1 - i + r * n; 00646 00647 px = (pt[i].x + pt[j].x) / 2.0 - pt[0].x; 00648 py = (pt[i].y + pt[j].y) / 2.0 - pt[0].y; 00649 ey = (pt[j].x - pt[i].x); 00650 ex = -(pt[j].y - pt[i].y); 00651 00652 a = ((x2 - 2 * x * px) / k + px * px); 00653 b = ((xy - x * py - y * px) / k + px * py); 00654 c = ((y2 - 2 * y * py) / k + py * py); 00655 00656 s = ex * ex * a + 2 * ex * ey * b + ey * ey * c; 00657 00658 return sqrt (s); 00659 } 00660 00671 static int 00672 bestpolygon (privpath_t * pp) 00673 { 00674 int i, j, m, k; 00675 int n = pp->len; 00676 double *pen = NULL; /* pen[n+1]: penalty vector */ 00677 int *prev = NULL; /* prev[n+1]: best path pointer vector */ 00678 int *clip0 = NULL; /* clip0[n]: longest segment pointer, non-cyclic */ 00679 int *clip1 = NULL; /* clip1[n+1]: backwards segment pointer, non-cyclic */ 00680 int *seg0 = NULL; /* seg0[m+1]: forward segment bounds, m<=n */ 00681 int *seg1 = NULL; /* seg1[m+1]: backward segment bounds, m<=n */ 00682 double thispen; 00683 double best; 00684 int c; 00685 00686 SAFE_MALLOC (pen, n + 1, double); 00687 SAFE_MALLOC (prev, n + 1, int); 00688 SAFE_MALLOC (clip0, n, int); 00689 SAFE_MALLOC (clip1, n + 1, int); 00690 SAFE_MALLOC (seg0, n + 1, int); 00691 SAFE_MALLOC (seg1, n + 1, int); 00692 00693 /* calculate clipped paths */ 00694 for (i = 0; i < n; i++) 00695 { 00696 c = mod (pp->lon[mod (i - 1, n)] - 1, n); 00697 if (c == i) 00698 { 00699 c = mod (i + 1, n); 00700 } 00701 if (c < i) 00702 { 00703 clip0[i] = n; 00704 } 00705 else 00706 { 00707 clip0[i] = c; 00708 } 00709 } 00710 00711 /* calculate backwards path clipping, non-cyclic. j <= clip0[i] iff 00712 clip1[j] <= i, for i,j=0..n. */ 00713 j = 1; 00714 for (i = 0; i < n; i++) 00715 { 00716 while (j <= clip0[i]) 00717 { 00718 clip1[j] = i; 00719 j++; 00720 } 00721 } 00722 00723 /* calculate seg0[j] = longest path from 0 with j segments */ 00724 i = 0; 00725 for (j = 0; i < n; j++) 00726 { 00727 seg0[j] = i; 00728 i = clip0[i]; 00729 } 00730 seg0[j] = n; 00731 m = j; 00732 00733 /* calculate seg1[j] = longest path to n with m-j segments */ 00734 i = n; 00735 for (j = m; j > 0; j--) 00736 { 00737 seg1[j] = i; 00738 i = clip1[i]; 00739 } 00740 seg1[0] = 0; 00741 00742 /* now find the shortest path with m segments, based on penalty3 */ 00743 /* note: the outer 2 loops jointly have at most n interations, thus 00744 the worst-case behavior here is quadratic. In practice, it is 00745 close to linear since the inner loop tends to be short. */ 00746 pen[0] = 0; 00747 for (j = 1; j <= m; j++) 00748 { 00749 for (i = seg1[j]; i <= seg0[j]; i++) 00750 { 00751 best = -1; 00752 for (k = seg0[j - 1]; k >= clip1[i]; k--) 00753 { 00754 thispen = penalty3 (pp, k, i) + pen[k]; 00755 if (best < 0 || thispen < best) 00756 { 00757 prev[i] = k; 00758 best = thispen; 00759 } 00760 } 00761 pen[i] = best; 00762 } 00763 } 00764 00765 pp->m = m; 00766 SAFE_MALLOC (pp->po, m, int); 00767 00768 /* read off shortest path */ 00769 for (i = n, j = m - 1; i > 0; j--) 00770 { 00771 i = prev[i]; 00772 pp->po[j] = i; 00773 } 00774 00775 free (pen); 00776 free (prev); 00777 free (clip0); 00778 free (clip1); 00779 free (seg0); 00780 free (seg1); 00781 return 0; 00782 00783 malloc_error: 00784 free (pen); 00785 free (prev); 00786 free (clip0); 00787 free (clip1); 00788 free (seg0); 00789 free (seg1); 00790 return 1; 00791 } 00792 00802 static int 00803 adjust_vertices (privpath_t * pp) 00804 { 00805 int m = pp->m; 00806 int *po = pp->po; 00807 int n = pp->len; 00808 point_t *pt = pp->pt; 00809 int x0 = pp->x0; 00810 int y0 = pp->y0; 00811 00812 dpoint_t *ctr = NULL; /* ctr[m] */ 00813 dpoint_t *dir = NULL; /* dir[m] */ 00814 quadform_t *q = NULL; /* q[m] */ 00815 double v[3]; 00816 double d; 00817 int i, j, k, l; 00818 dpoint_t s; 00819 int r; 00820 00821 SAFE_MALLOC (ctr, m, dpoint_t); 00822 SAFE_MALLOC (dir, m, dpoint_t); 00823 SAFE_MALLOC (q, m, quadform_t); 00824 00825 r = privcurve_init (&pp->curve, m); 00826 if (r) 00827 { 00828 goto malloc_error; 00829 } 00830 00831 /* calculate "optimal" point-slope representation for each line 00832 segment */ 00833 for (i = 0; i < m; i++) 00834 { 00835 j = po[mod (i + 1, m)]; 00836 j = mod (j - po[i], n) + po[i]; 00837 pointslope (pp, po[i], j, &ctr[i], &dir[i]); 00838 } 00839 00840 /* represent each line segment as a singular quadratic form; the 00841 distance of a point (x,y) from the line segment will be 00842 (x,y,1)Q(x,y,1)^t, where Q=q[i]. */ 00843 for (i = 0; i < m; i++) 00844 { 00845 d = sq (dir[i].x) + sq (dir[i].y); 00846 if (d == 0.0) 00847 { 00848 for (j = 0; j < 3; j++) 00849 { 00850 for (k = 0; k < 3; k++) 00851 { 00852 q[i][j][k] = 0; 00853 } 00854 } 00855 } 00856 else 00857 { 00858 v[0] = dir[i].y; 00859 v[1] = -dir[i].x; 00860 v[2] = -v[1] * ctr[i].y - v[0] * ctr[i].x; 00861 for (l = 0; l < 3; l++) 00862 { 00863 for (k = 0; k < 3; k++) 00864 { 00865 q[i][l][k] = v[l] * v[k] / d; 00866 } 00867 } 00868 } 00869 } 00870 00871 /* now calculate the "intersections" of consecutive segments. 00872 Instead of using the actual intersection, we find the point 00873 within a given unit square which minimizes the square distance to 00874 the two lines. */ 00875 for (i = 0; i < m; i++) 00876 { 00877 quadform_t Q; 00878 dpoint_t w; 00879 double dx, dy; 00880 double det; 00881 double min, cand; /* minimum and candidate for minimum of quad. form */ 00882 double xmin, ymin; /* coordinates of minimum */ 00883 int z; 00884 00885 /* let s be the vertex, in coordinates relative to x0/y0 */ 00886 s.x = pt[po[i]].x - x0; 00887 s.y = pt[po[i]].y - y0; 00888 00889 /* intersect segments i-1 and i */ 00890 00891 j = mod (i - 1, m); 00892 00893 /* add quadratic forms */ 00894 for (l = 0; l < 3; l++) 00895 { 00896 for (k = 0; k < 3; k++) 00897 { 00898 Q[l][k] = q[j][l][k] + q[i][l][k]; 00899 } 00900 } 00901 00902 while (1) 00903 { 00904 /* minimize the quadratic form Q on the unit square */ 00905 /* find intersection */ 00906 00907 #ifdef HAVE_GCC_LOOP_BUG 00908 /* work around gcc bug #12243 */ 00909 free (NULL); 00910 #endif 00911 00912 det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0]; 00913 if (det != 0.0) 00914 { 00915 w.x = (-Q[0][2] * Q[1][1] + Q[1][2] * Q[0][1]) / det; 00916 w.y = (Q[0][2] * Q[1][0] - Q[1][2] * Q[0][0]) / det; 00917 break; 00918 } 00919 00920 /* matrix is singular - lines are parallel. Add another, 00921 orthogonal axis, through the center of the unit square */ 00922 if (Q[0][0] > Q[1][1]) 00923 { 00924 v[0] = -Q[0][1]; 00925 v[1] = Q[0][0]; 00926 } 00927 else if (Q[1][1]) 00928 { 00929 v[0] = -Q[1][1]; 00930 v[1] = Q[1][0]; 00931 } 00932 else 00933 { 00934 v[0] = 1; 00935 v[1] = 0; 00936 } 00937 d = sq (v[0]) + sq (v[1]); 00938 v[2] = -v[1] * s.y - v[0] * s.x; 00939 for (l = 0; l < 3; l++) 00940 { 00941 for (k = 0; k < 3; k++) 00942 { 00943 Q[l][k] += v[l] * v[k] / d; 00944 } 00945 } 00946 } 00947 dx = fabs (w.x - s.x); 00948 dy = fabs (w.y - s.y); 00949 if (dx <= .5 && dy <= .5) 00950 { 00951 pp->curve.vertex[i].x = w.x + x0; 00952 pp->curve.vertex[i].y = w.y + y0; 00953 continue; 00954 } 00955 00956 /* the minimum was not in the unit square; now minimize quadratic 00957 on boundary of square */ 00958 min = quadform (Q, s); 00959 xmin = s.x; 00960 ymin = s.y; 00961 00962 if (Q[0][0] == 0.0) 00963 { 00964 goto fixx; 00965 } 00966 for (z = 0; z < 2; z++) 00967 { /* value of the y-coordinate */ 00968 w.y = s.y - 0.5 + z; 00969 w.x = -(Q[0][1] * w.y + Q[0][2]) / Q[0][0]; 00970 dx = fabs (w.x - s.x); 00971 cand = quadform (Q, w); 00972 if (dx <= .5 && cand < min) 00973 { 00974 min = cand; 00975 xmin = w.x; 00976 ymin = w.y; 00977 } 00978 } 00979 fixx: 00980 if (Q[1][1] == 0.0) 00981 { 00982 goto corners; 00983 } 00984 for (z = 0; z < 2; z++) 00985 { /* value of the x-coordinate */ 00986 w.x = s.x - 0.5 + z; 00987 w.y = -(Q[1][0] * w.x + Q[1][2]) / Q[1][1]; 00988 dy = fabs (w.y - s.y); 00989 cand = quadform (Q, w); 00990 if (dy <= .5 && cand < min) 00991 { 00992 min = cand; 00993 xmin = w.x; 00994 ymin = w.y; 00995 } 00996 } 00997 corners: 00998 /* check four corners */ 00999 for (l = 0; l < 2; l++) 01000 { 01001 for (k = 0; k < 2; k++) 01002 { 01003 w.x = s.x - 0.5 + l; 01004 w.y = s.y - 0.5 + k; 01005 cand = quadform (Q, w); 01006 if (cand < min) 01007 { 01008 min = cand; 01009 xmin = w.x; 01010 ymin = w.y; 01011 } 01012 } 01013 } 01014 01015 pp->curve.vertex[i].x = xmin + x0; 01016 pp->curve.vertex[i].y = ymin + y0; 01017 continue; 01018 } 01019 01020 free (ctr); 01021 free (dir); 01022 free (q); 01023 return 0; 01024 01025 malloc_error: 01026 free (ctr); 01027 free (dir); 01028 free (q); 01029 return 1; 01030 } 01031 01037 static int 01038 ATTRIBUTE_UNUSED smooth (privcurve_t * curve, int sign, double alphamax) 01039 { 01040 int m = curve->n; 01041 01042 int i, j, k; 01043 double dd, denom, alpha; 01044 dpoint_t p2, p3, p4; 01045 01046 if (sign == '-') 01047 { 01048 /* reverse orientation of negative paths */ 01049 for (i = 0, j = m - 1; i < j; i++, j--) 01050 { 01051 dpoint_t tmp; 01052 tmp = curve->vertex[i]; 01053 curve->vertex[i] = curve->vertex[j]; 01054 curve->vertex[j] = tmp; 01055 } 01056 } 01057 01058 /* examine each vertex and find its best fit */ 01059 for (i = 0; i < m; i++) 01060 { 01061 j = mod (i + 1, m); 01062 k = mod (i + 2, m); 01063 p4 = interval (1 / 2.0, curve->vertex[k], curve->vertex[j]); 01064 01065 denom = ddenom (curve->vertex[i], curve->vertex[k]); 01066 if (denom != 0.0) 01067 { 01068 dd = 01069 dpara (curve->vertex[i], curve->vertex[j], 01070 curve->vertex[k]) / denom; 01071 dd = fabs (dd); 01072 alpha = dd > 1 ? (1 - 1.0 / dd) : 0; 01073 alpha = alpha / 0.75; 01074 } 01075 else 01076 { 01077 alpha = 4 / 3.0; 01078 } 01079 curve->alpha0[j] = alpha; /* remember "original" value of alpha */ 01080 01081 if (alpha > alphamax) 01082 { /* pointed corner */ 01083 curve->tag[j] = POTRACE_CORNER; 01084 curve->c[j][1] = curve->vertex[j]; 01085 curve->c[j][2] = p4; 01086 } 01087 else 01088 { 01089 if (alpha < 0.55) 01090 { 01091 alpha = 0.55; 01092 } 01093 else if (alpha > 1) 01094 { 01095 alpha = 1; 01096 } 01097 p2 = interval (.5 + .5 * alpha, curve->vertex[i], curve->vertex[j]); 01098 p3 = interval (.5 + .5 * alpha, curve->vertex[k], curve->vertex[j]); 01099 curve->tag[j] = POTRACE_CURVETO; 01100 curve->c[j][0] = p2; 01101 curve->c[j][1] = p3; 01102 curve->c[j][2] = p4; 01103 } 01104 curve->alpha[j] = alpha; /* store the "cropped" value of alpha */ 01105 curve->beta[j] = 0.5; 01106 } 01107 curve->alphacurve = 1; 01108 01109 return 0; 01110 } 01111 01112 /* ---------------------------------------------------------------------- */ 01113 /* Stage 5: Curve optimization (Sec. 2.4) */ 01114 01118 struct opti_s 01119 { 01120 double pen; 01121 dpoint_t c[2]; 01122 double t; 01123 double s; 01124 double alpha; 01125 }; 01126 typedef struct opti_s opti_t; 01127 01136 static int 01137 opti_penalty (privpath_t * pp, int i, int j, opti_t * res, 01138 double opttolerance, int *convc, double *areac) 01139 { 01140 int m = pp->curve.n; 01141 int k, k1, k2, conv, i1; 01142 double area, alpha, d, d1, d2; 01143 dpoint_t p0, p1, p2, p3, pt; 01144 double A, R, A1, A2, A3, A4; 01145 double s, t; 01146 01147 /* check convexity, corner-freeness, and maximum bend < 179 degrees */ 01148 01149 if (i == j) 01150 { /* sanity - a full loop can never be an opticurve */ 01151 return 1; 01152 } 01153 01154 k = i; 01155 i1 = mod (i + 1, m); 01156 k1 = mod (k + 1, m); 01157 conv = convc[k1]; 01158 if (conv == 0) 01159 { 01160 return 1; 01161 } 01162 d = ddist (pp->curve.vertex[i], pp->curve.vertex[i1]); 01163 for (k = k1; k != j; k = k1) 01164 { 01165 k1 = mod (k + 1, m); 01166 k2 = mod (k + 2, m); 01167 if (convc[k1] != conv) 01168 { 01169 return 1; 01170 } 01171 if (sign 01172 (cprod 01173 (pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], 01174 pp->curve.vertex[k2])) != conv) 01175 { 01176 return 1; 01177 } 01178 if (iprod1 01179 (pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], 01180 pp->curve.vertex[k2]) < d * ddist (pp->curve.vertex[k1], 01181 pp->curve.vertex[k2]) * COS179) 01182 { 01183 return 1; 01184 } 01185 } 01186 01187 /* the curve we're working in: */ 01188 p0 = pp->curve.c[mod (i, m)][2]; 01189 p1 = pp->curve.vertex[mod (i + 1, m)]; 01190 p2 = pp->curve.vertex[mod (j, m)]; 01191 p3 = pp->curve.c[mod (j, m)][2]; 01192 01193 /* determine its area */ 01194 area = areac[j] - areac[i]; 01195 area -= 01196 dpara (pp->curve.vertex[0], pp->curve.c[i][2], pp->curve.c[j][2]) / 2; 01197 if (i >= j) 01198 { 01199 area += areac[m]; 01200 } 01201 01202 /* find intersection o of p0p1 and p2p3. Let t,s such that o = 01203 interval(t,p0,p1) = interval(s,p3,p2). Let A be the area of the 01204 triangle (p0,o,p3). */ 01205 01206 A1 = dpara (p0, p1, p2); 01207 A2 = dpara (p0, p1, p3); 01208 A3 = dpara (p0, p2, p3); 01209 /* A4 = dpara(p1, p2, p3); */ 01210 A4 = A1 + A3 - A2; 01211 01212 if (A2 == A1) 01213 { /* this should never happen */ 01214 return 1; 01215 } 01216 01217 t = A3 / (A3 - A4); 01218 s = A2 / (A2 - A1); 01219 A = A2 * t / 2.0; 01220 01221 if (A == 0.0) 01222 { /* this should never happen */ 01223 return 1; 01224 } 01225 01226 R = area / A; /* relative area */ 01227 alpha = 2 - sqrt (4 - R / 0.3); /* overall alpha for p0-o-p3 curve */ 01228 01229 res->c[0] = interval (t * alpha, p0, p1); 01230 res->c[1] = interval (s * alpha, p3, p2); 01231 res->alpha = alpha; 01232 res->t = t; 01233 res->s = s; 01234 01235 p1 = res->c[0]; 01236 p2 = res->c[1]; /* the proposed curve is now (p0,p1,p2,p3) */ 01237 01238 res->pen = 0; 01239 01240 /* calculate penalty */ 01241 /* check tangency with edges */ 01242 for (k = mod (i + 1, m); k != j; k = k1) 01243 { 01244 k1 = mod (k + 1, m); 01245 t = tangent (p0, p1, p2, p3, pp->curve.vertex[k], pp->curve.vertex[k1]); 01246 if (t < -.5) 01247 { 01248 return 1; 01249 } 01250 pt = bezier (t, p0, p1, p2, p3); 01251 d = ddist (pp->curve.vertex[k], pp->curve.vertex[k1]); 01252 if (d == 0.0) 01253 { /* this should never happen */ 01254 return 1; 01255 } 01256 d1 = dpara (pp->curve.vertex[k], pp->curve.vertex[k1], pt) / d; 01257 if (fabs (d1) > opttolerance) 01258 { 01259 return 1; 01260 } 01261 if (iprod (pp->curve.vertex[k], pp->curve.vertex[k1], pt) < 0 01262 || iprod (pp->curve.vertex[k1], pp->curve.vertex[k], pt) < 0) 01263 { 01264 return 1; 01265 } 01266 res->pen += sq (d1); 01267 } 01268 01269 /* check corners */ 01270 for (k = i; k != j; k = k1) 01271 { 01272 k1 = mod (k + 1, m); 01273 t = tangent (p0, p1, p2, p3, pp->curve.c[k][2], pp->curve.c[k1][2]); 01274 if (t < -.5) 01275 { 01276 return 1; 01277 } 01278 pt = bezier (t, p0, p1, p2, p3); 01279 d = ddist (pp->curve.c[k][2], pp->curve.c[k1][2]); 01280 if (d == 0.0) 01281 { /* this should never happen */ 01282 return 1; 01283 } 01284 d1 = dpara (pp->curve.c[k][2], pp->curve.c[k1][2], pt) / d; 01285 d2 = 01286 dpara (pp->curve.c[k][2], pp->curve.c[k1][2], 01287 pp->curve.vertex[k1]) / d; 01288 d2 *= 0.75 * pp->curve.alpha[k1]; 01289 if (d2 < 0) 01290 { 01291 d1 = -d1; 01292 d2 = -d2; 01293 } 01294 if (d1 < d2 - opttolerance) 01295 { 01296 return 1; 01297 } 01298 if (d1 < d2) 01299 { 01300 res->pen += sq (d1 - d2); 01301 } 01302 } 01303 01304 return 0; 01305 } 01306 01313 static int 01314 ATTRIBUTE_UNUSED opticurve (privpath_t * pp, double opttolerance) 01315 { 01316 int m = pp->curve.n; 01317 int *pt = NULL; /* pt[m+1] */ 01318 double *pen = NULL; /* pen[m+1] */ 01319 int *len = NULL; /* len[m+1] */ 01320 opti_t *opt = NULL; /* opt[m+1] */ 01321 int om; 01322 int i, j, r; 01323 opti_t o; 01324 dpoint_t p0; 01325 int i1; 01326 double area; 01327 double alpha; 01328 double *s = NULL; 01329 double *t = NULL; 01330 01331 int *convc = NULL; /* conv[m]: pre-computed convexities */ 01332 double *areac = NULL; /* cumarea[m+1]: cache for fast area computation */ 01333 01334 SAFE_MALLOC (pt, m + 1, int); 01335 SAFE_MALLOC (pen, m + 1, double); 01336 SAFE_MALLOC (len, m + 1, int); 01337 SAFE_MALLOC (opt, m + 1, opti_t); 01338 SAFE_MALLOC (convc, m, int); 01339 SAFE_MALLOC (areac, m + 1, double); 01340 01341 /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */ 01342 for (i = 0; i < m; i++) 01343 { 01344 if (pp->curve.tag[i] == POTRACE_CURVETO) 01345 { 01346 convc[i] = 01347 sign (dpara 01348 (pp->curve.vertex[mod (i - 1, m)], pp->curve.vertex[i], 01349 pp->curve.vertex[mod (i + 1, m)])); 01350 } 01351 else 01352 { 01353 convc[i] = 0; 01354 } 01355 } 01356 01357 /* pre-calculate areas */ 01358 area = 0.0; 01359 areac[0] = 0.0; 01360 p0 = pp->curve.vertex[0]; 01361 for (i = 0; i < m; i++) 01362 { 01363 i1 = mod (i + 1, m); 01364 if (pp->curve.tag[i1] == POTRACE_CURVETO) 01365 { 01366 alpha = pp->curve.alpha[i1]; 01367 area += 01368 0.3 * alpha * (4 - alpha) * dpara (pp->curve.c[i][2], 01369 pp->curve.vertex[i1], 01370 pp->curve.c[i1][2]) / 2; 01371 area += dpara (p0, pp->curve.c[i][2], pp->curve.c[i1][2]) / 2; 01372 } 01373 areac[i + 1] = area; 01374 } 01375 01376 pt[0] = -1; 01377 pen[0] = 0; 01378 len[0] = 0; 01379 01380 /* Fixme: we always start from a fixed point -- should find the best 01381 curve cyclically ### */ 01382 01383 for (j = 1; j <= m; j++) 01384 { 01385 /* calculate best path from 0 to j */ 01386 pt[j] = j - 1; 01387 pen[j] = pen[j - 1]; 01388 len[j] = len[j - 1] + 1; 01389 01390 for (i = j - 2; i >= 0; i--) 01391 { 01392 r = 01393 opti_penalty (pp, i, mod (j, m), &o, opttolerance, convc, areac); 01394 if (r) 01395 { 01396 break; 01397 } 01398 if (len[j] > len[i] + 1 01399 || (len[j] == len[i] + 1 && pen[j] > pen[i] + o.pen)) 01400 { 01401 pt[j] = i; 01402 pen[j] = pen[i] + o.pen; 01403 len[j] = len[i] + 1; 01404 opt[j] = o; 01405 } 01406 } 01407 } 01408 om = len[m]; 01409 r = privcurve_init (&pp->ocurve, om); 01410 if (r) 01411 { 01412 goto malloc_error; 01413 } 01414 SAFE_MALLOC (s, om, double); 01415 SAFE_MALLOC (t, om, double); 01416 01417 j = m; 01418 for (i = om - 1; i >= 0; i--) 01419 { 01420 if (pt[j] == j - 1) 01421 { 01422 pp->ocurve.tag[i] = pp->curve.tag[mod (j, m)]; 01423 pp->ocurve.c[i][0] = pp->curve.c[mod (j, m)][0]; 01424 pp->ocurve.c[i][1] = pp->curve.c[mod (j, m)][1]; 01425 pp->ocurve.c[i][2] = pp->curve.c[mod (j, m)][2]; 01426 pp->ocurve.vertex[i] = pp->curve.vertex[mod (j, m)]; 01427 pp->ocurve.alpha[i] = pp->curve.alpha[mod (j, m)]; 01428 pp->ocurve.alpha0[i] = pp->curve.alpha0[mod (j, m)]; 01429 pp->ocurve.beta[i] = pp->curve.beta[mod (j, m)]; 01430 s[i] = t[i] = 1.0; 01431 } 01432 else 01433 { 01434 pp->ocurve.tag[i] = POTRACE_CURVETO; 01435 pp->ocurve.c[i][0] = opt[j].c[0]; 01436 pp->ocurve.c[i][1] = opt[j].c[1]; 01437 pp->ocurve.c[i][2] = pp->curve.c[mod (j, m)][2]; 01438 pp->ocurve.vertex[i] = 01439 interval (opt[j].s, pp->curve.c[mod (j, m)][2], 01440 pp->curve.vertex[mod (j, m)]); 01441 pp->ocurve.alpha[i] = opt[j].alpha; 01442 pp->ocurve.alpha0[i] = opt[j].alpha; 01443 s[i] = opt[j].s; 01444 t[i] = opt[j].t; 01445 } 01446 j = pt[j]; 01447 } 01448 01449 /* calculate beta parameters */ 01450 for (i = 0; i < om; i++) 01451 { 01452 i1 = mod (i + 1, om); 01453 pp->ocurve.beta[i] = s[i] / (s[i] + t[i1]); 01454 } 01455 pp->ocurve.alphacurve = 1; 01456 01457 free (pt); 01458 free (pen); 01459 free (len); 01460 free (opt); 01461 free (s); 01462 free (t); 01463 free (convc); 01464 free (areac); 01465 return 0; 01466 01467 malloc_error: 01468 free (pt); 01469 free (pen); 01470 free (len); 01471 free (opt); 01472 free (s); 01473 free (t); 01474 free (convc); 01475 free (areac); 01476 return 1; 01477 } 01478 01479 /* ---------------------------------------------------------------------- */ 01480 double 01481 plotpolygon (privpath_t * pp, FILE * f, double scale, 01482 const char *var_cutdepth, const char *var_safeZ, 01483 const char *var_plunge, const char *var_feedrate) 01484 { 01485 int i; 01486 int m = pp->m; 01487 int *po = pp->po; 01488 point_t *pt = pp->pt; 01489 /* double scale=1.0/dpi; */ 01490 double dm = 0; 01491 01492 if (!m) 01493 return 0; 01494 01495 po = pp->po; 01496 pt = pp->pt; 01497 01498 pcb_fprintf (f, "G0 X%`f Y%`f (start point)\n", pt[po[0]].x * scale, 01499 pt[po[0]].y * scale); 01500 pcb_fprintf (f, "G1 Z%s F%s\n", var_cutdepth, var_plunge); 01501 pcb_fprintf (f, "F%s\n", var_feedrate); 01502 for (i = 1; i < m; i++) 01503 { 01504 pcb_fprintf (f, "G1 X%`f Y%`f\n", 01505 pt[po[i]].x * scale, pt[po[i]].y * scale); 01506 dm += fabs (scale) * hypot (pt[po[i]].x - pt[po[i - 1]].x, pt[po[i]].y - pt[po[i - 1]].y); 01507 } 01508 pcb_fprintf (f, "G1 X%`f Y%`f\n", pt[po[0]].x * scale, pt[po[0]].y * scale); 01509 pcb_fprintf (f, "G0 Z%s\n", var_safeZ); 01510 dm += fabs (scale) * hypot (pt[po[m - 1]].x - pt[po[0]].x, pt[po[m - 1]].y - pt[po[0]].y); 01511 pcb_fprintf (f, "(polygon end, distance %`.2f)\n", dm); 01512 return dm; 01513 } 01514 01515 #define TRY(x) if (x) goto try_error 01516 01522 double 01523 process_path (path_t * plist, const potrace_param_t * param, 01524 const potrace_bitmap_t * bm, FILE * f, double scale, 01525 const char *var_cutdepth, const char *var_safeZ, 01526 const char *var_plunge, const char *var_feedrate) 01527 { 01528 path_t *p; 01529 double dm = 0; 01530 int n = 0; 01531 /* call downstream function with each path */ 01532 list_forall (p, plist) 01533 { 01534 TRY (calc_sums (p->priv)); 01535 TRY (calc_lon (p->priv)); 01536 TRY (bestpolygon (p->priv)); 01537 TRY (adjust_vertices (p->priv)); 01538 fprintf (f, "(polygon %d)\n", ++n); 01539 dm += plotpolygon (p->priv, f, scale, var_cutdepth, var_safeZ, var_plunge, 01540 var_feedrate); 01541 /* No need to extract curves 01542 TRY(smooth(&p->priv->curve, p->sign, param->alphamax)); 01543 if (param->opticurve) { 01544 TRY(opticurve(p->priv, param->opttolerance)); 01545 p->priv->fcurve = &p->priv->ocurve; 01546 } else { 01547 p->priv->fcurve = &p->priv->curve; 01548 } 01549 privcurve_to_curve(p->priv->fcurve, &p->curve);*/ 01550 } 01551 /* fprintf(f,"(end, total distance %.2fmm = %.2fin)\n",25.4*dm,dm); */ 01552 return dm; 01553 01554 try_error: 01555 return -1; 01556 }