1
4
5
6
7#ifdef HAVE_CONFIG_H
8#include <config.h>
9#endif
10
11#include <stdio.h>
12#include <math.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include "potracelib.h"
17#include "curve.h"
18#include "lists.h"
19#include "auxiliary.h"
20#include "trace.h"
21#include "progress.h"
22
23#define INFTY 10000000
25#define COS179 -0.999847695156
26
27
28#define SAFE_CALLOC(var, n, typ) \
29 if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error
30
31
32
33
34
36static inline point_t dorth_infty(dpoint_t p0, dpoint_t p2) {
37 point_t r;
38
39 r.y = sign(p2.x-p0.x);
40 r.x = -sign(p2.y-p0.y);
41
42 return r;
43}
44
45
46static inline double dpara(dpoint_t p0, dpoint_t p1, dpoint_t p2) {
47 double x1, y1, x2, y2;
48
49 x1 = p1.x-p0.x;
50 y1 = p1.y-p0.y;
51 x2 = p2.x-p0.x;
52 y2 = p2.y-p0.y;
53
54 return x1*y2 - x2*y1;
55}
56
57
59static inline double ddenom(dpoint_t p0, dpoint_t p2) {
60 point_t r = dorth_infty(p0, p2);
61
62 return r.y*(p2.x-p0.x) - r.x*(p2.y-p0.y);
63}
64
65
66static inline int cyclic(int a, int b, int c) {
67 if (a<=c) {
68 return (a<=b && b<c);
69 } else {
70 return (a<=b || b<c);
71 }
72}
73
74
76static void pointslope(privpath_t *pp, int i, int j, dpoint_t *ctr, dpoint_t *dir) {
77
78
79 int n = pp->len;
80 sums_t *sums = pp->sums;
81
82 double x, y, x2, xy, y2;
83 double k;
84 double a, b, c, lambda2, l;
85 int r=0;
86
87 while (j>=n) {
88 j-=n;
89 r+=1;
90 }
91 while (i>=n) {
92 i-=n;
93 r-=1;
94 }
95 while (j<0) {
96 j+=n;
97 r-=1;
98 }
99 while (i<0) {
100 i+=n;
101 r+=1;
102 }
103
104 x = sums[j+1].x-sums[i].x+r*sums[n].x;
105 y = sums[j+1].y-sums[i].y+r*sums[n].y;
106 x2 = sums[j+1].x2-sums[i].x2+r*sums[n].x2;
107 xy = sums[j+1].xy-sums[i].xy+r*sums[n].xy;
108 y2 = sums[j+1].y2-sums[i].y2+r*sums[n].y2;
109 k = j+1-i+r*n;
110
111 ctr->x = x/k;
112 ctr->y = y/k;
113
114 a = (x2-(double)x*x/k)/k;
115 b = (xy-(double)x*y/k)/k;
116 c = (y2-(double)y*y/k)/k;
117
118 lambda2 = (a+c+sqrt((a-c)*(a-c)+4*b*b))/2;
119
120
121 a -= lambda2;
122 c -= lambda2;
123
124 if (fabs(a) >= fabs(c)) {
125 l = sqrt(a*a+b*b);
126 if (l!=0) {
127 dir->x = -b/l;
128 dir->y = a/l;
129 }
130 } else {
131 l = sqrt(c*c+b*b);
132 if (l!=0) {
133 dir->x = -c/l;
134 dir->y = b/l;
135 }
136 }
137 if (l==0) {
138 dir->x = dir->y = 0;
140 }
141}
142
143
146typedef double quadform_t[3][3];
147
148
149static inline double quadform(quadform_t Q, dpoint_t w) {
150 double v[3];
151 int i, j;
152 double sum;
153
154 v[0] = w.x;
155 v[1] = w.y;
156 v[2] = 1;
157 sum = 0.0;
158
159 for (i=0; i<3; i++) {
160 for (j=0; j<3; j++) {
161 sum += v[i] * Q[i][j] * v[j];
162 }
163 }
164 return sum;
165}
166
167
168static inline int xprod(point_t p1, point_t p2) {
169 return p1.x*p2.y - p1.y*p2.x;
170}
171
172
173static inline double cprod(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) {
174 double x1, y1, x2, y2;
175
176 x1 = p1.x - p0.x;
177 y1 = p1.y - p0.y;
178 x2 = p3.x - p2.x;
179 y2 = p3.y - p2.y;
180
181 return x1*y2 - x2*y1;
182}
183
184
185static inline double iprod(dpoint_t p0, dpoint_t p1, dpoint_t p2) {
186 double x1, y1, x2, y2;
187
188 x1 = p1.x - p0.x;
189 y1 = p1.y - p0.y;
190 x2 = p2.x - p0.x;
191 y2 = p2.y - p0.y;
192
193 return x1*x2 + y1*y2;
194}
195
196
197static inline double iprod1(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) {
198 double x1, y1, x2, y2;
199
200 x1 = p1.x - p0.x;
201 y1 = p1.y - p0.y;
202 x2 = p3.x - p2.x;
203 y2 = p3.y - p2.y;
204
205 return x1*x2 + y1*y2;
206}
207
208
209static inline double ddist(dpoint_t p, dpoint_t q) {
210 return sqrt(sq(p.x-q.x)+sq(p.y-q.y));
211}
212
213
214static inline dpoint_t bezier(double t, dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) {
215 double s = 1-t;
216 dpoint_t res;
217
218
221
222 res.x = s*s*s*p0.x + 3*(s*s*t)*p1.x + 3*(t*t*s)*p2.x + t*t*t*p3.x;
223 res.y = s*s*s*p0.y + 3*(s*s*t)*p1.y + 3*(t*t*s)*p2.y + t*t*t*p3.y;
224
225 return res;
226}
227
228
231static double tangent(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3, dpoint_t q0, dpoint_t q1) {
232 double A, B, C;
233 double a, b, c;
234 double d, s, r1, r2;
235
236 A = cprod(p0, p1, q0, q1);
237 B = cprod(p1, p2, q0, q1);
238 C = cprod(p2, p3, q0, q1);
239
240 a = A - 2*B + C;
241 b = -2*A + 2*B;
242 c = A;
243
244 d = b*b - 4*a*c;
245
246 if (a==0 || d<0) {
247 return -1.0;
248 }
249
250 s = sqrt(d);
251
252 r1 = (-b + s) / (2 * a);
253 r2 = (-b - s) / (2 * a);
254
255 if (r1 >= 0 && r1 <= 1) {
256 return r1;
257 } else if (r2 >= 0 && r2 <= 1) {
258 return r2;
259 } else {
260 return -1.0;
261 }
262}
263
264
265
268static int calc_sums(privpath_t *pp) {
269 int i, x, y;
270 int n = pp->len;
271
272 SAFE_CALLOC(pp->sums, pp->len+1, sums_t);
273
274
275 pp->x0 = pp->pt[0].x;
276 pp->y0 = pp->pt[0].y;
277
278
279 pp->sums[0].x2 = pp->sums[0].xy = pp->sums[0].y2 = pp->sums[0].x = pp->sums[0].y = 0;
280 for (i=0; i<n; i++) {
281 x = pp->pt[i].x - pp->x0;
282 y = pp->pt[i].y - pp->y0;
283 pp->sums[i+1].x = pp->sums[i].x + x;
284 pp->sums[i+1].y = pp->sums[i].y + y;
285 pp->sums[i+1].x2 = pp->sums[i].x2 + (double)x*x;
286 pp->sums[i+1].xy = pp->sums[i].xy + (double)x*y;
287 pp->sums[i+1].y2 = pp->sums[i].y2 + (double)y*y;
288 }
289 return 0;
290
291 calloc_error:
292 return 1;
293}
294
295
296
300
301
305
306
310
311
323
324
325static int calc_lon(privpath_t *pp) {
326 point_t *pt = pp->pt;
327 int n = pp->len;
328 int i, j, k, k1;
329 int ct[4], dir;
330 point_t constraint[2];
331 point_t cur;
332 point_t off;
333 int *pivk = NULL;
334 int *nc = NULL;
335 point_t dk;
336 int a, b, c, d;
337
338 SAFE_CALLOC(pivk, n, int);
339 SAFE_CALLOC(nc, n, int);
340
341
348 k = 0;
349 for (i=n-1; i>=0; i--) {
350 if (pt[i].x != pt[k].x && pt[i].y != pt[k].y) {
351 k = i+1;
352 }
353 nc[i] = k;
354 }
355
356 SAFE_CALLOC(pp->lon, n, int);
357
358
360
361 for (i=n-1; i>=0; i--) {
362 ct[0] = ct[1] = ct[2] = ct[3] = 0;
363
364
365 dir = (3+3*(pt[mod(i+1,n)].x-pt[i].x)+(pt[mod(i+1,n)].y-pt[i].y))/2;
366 ct[dir]++;
367
368 constraint[0].x = 0;
369 constraint[0].y = 0;
370 constraint[1].x = 0;
371 constraint[1].y = 0;
372
373
374 k = nc[i];
375 k1 = i;
376 while (1) {
377
378 dir = (3+3*sign(pt[k].x-pt[k1].x)+sign(pt[k].y-pt[k1].y))/2;
379 ct[dir]++;
380
381
382 if (ct[0] && ct[1] && ct[2] && ct[3]) {
383 pivk[i] = k1;
384 goto foundk;
385 }
386
387 cur.x = pt[k].x - pt[i].x;
388 cur.y = pt[k].y - pt[i].y;
389
390
391 if (xprod(constraint[0], cur) < 0 || xprod(constraint[1], cur) > 0) {
392 goto constraint_viol;
393 }
394
395
396 if (abs(cur.x) <= 1 && abs(cur.y) <= 1) {
397
398 } else {
399 off.x = cur.x + ((cur.y>=0 && (cur.y>0 || cur.x<0)) ? 1 : -1);
400 off.y = cur.y + ((cur.x<=0 && (cur.x<0 || cur.y<0)) ? 1 : -1);
401 if (xprod(constraint[0], off) >= 0) {
402 constraint[0] = off;
403 }
404 off.x = cur.x + ((cur.y<=0 && (cur.y<0 || cur.x<0)) ? 1 : -1);
405 off.y = cur.y + ((cur.x>=0 && (cur.x>0 || cur.y<0)) ? 1 : -1);
406 if (xprod(constraint[1], off) <= 0) {
407 constraint[1] = off;
408 }
409 }
410 k1 = k;
411 k = nc[k1];
412 if (!cyclic(k,i,k1)) {
413 break;
414 }
415 }
416 constraint_viol:
417
420 dk.x = sign(pt[k].x-pt[k1].x);
421 dk.y = sign(pt[k].y-pt[k1].y);
422 cur.x = pt[k1].x - pt[i].x;
423 cur.y = pt[k1].y - pt[i].y;
424
427 a = xprod(constraint[0], cur);
428 b = xprod(constraint[0], dk);
429 c = xprod(constraint[1], cur);
430 d = xprod(constraint[1], dk);
431
433 j = INFTY;
434 if (b<0) {
435 j = floordiv(a,-b);
436 }
437 if (d>0) {
438 j = min(j, floordiv(-c,d));
439 }
440 pivk[i] = mod(k1+j,n);
441 foundk:
442 ;
443 }
444
445
447
448 j=pivk[n-1];
449 pp->lon[n-1]=j;
450 for (i=n-2; i>=0; i--) {
451 if (cyclic(i+1,pivk[i],j)) {
452 j=pivk[i];
453 }
454 pp->lon[i]=j;
455 }
456
457 for (i=n-1; cyclic(mod(i+1,n),j,pp->lon[i]); i--) {
458 pp->lon[i] = j;
459 }
460
461 free(pivk);
462 free(nc);
463 return 0;
464
465 calloc_error:
466 free(pivk);
467 free(nc);
468 return 1;
469}
470
471
472
473
474
475
477
478static double penalty3(privpath_t *pp, int i, int j) {
479 int n = pp->len;
480 point_t *pt = pp->pt;
481 sums_t *sums = pp->sums;
482
483
484 double x, y, x2, xy, y2;
485 double k;
486 double a, b, c, s;
487 double px, py, ex, ey;
488
489 int r = 0;
490
491 if (j>=n) {
492 j -= n;
493 r = 1;
494 }
495
496
497 if (r == 0) {
498 x = sums[j+1].x - sums[i].x;
499 y = sums[j+1].y - sums[i].y;
500 x2 = sums[j+1].x2 - sums[i].x2;
501 xy = sums[j+1].xy - sums[i].xy;
502 y2 = sums[j+1].y2 - sums[i].y2;
503 k = j+1 - i;
504 } else {
505 x = sums[j+1].x - sums[i].x + sums[n].x;
506 y = sums[j+1].y - sums[i].y + sums[n].y;
507 x2 = sums[j+1].x2 - sums[i].x2 + sums[n].x2;
508 xy = sums[j+1].xy - sums[i].xy + sums[n].xy;
509 y2 = sums[j+1].y2 - sums[i].y2 + sums[n].y2;
510 k = j+1 - i + n;
511 }
512
513 px = (pt[i].x + pt[j].x) / 2.0 - pt[0].x;
514 py = (pt[i].y + pt[j].y) / 2.0 - pt[0].y;
515 ey = (pt[j].x - pt[i].x);
516 ex = -(pt[j].y - pt[i].y);
517
518 a = ((x2 - 2*x*px) / k + px*px);
519 b = ((xy - x*py - y*px) / k + px*py);
520 c = ((y2 - 2*y*py) / k + py*py);
521
522 s = ex*ex*a + 2*ex*ey*b + ey*ey*c;
523
524 return sqrt(s);
525}
526
527
530static int bestpolygon(privpath_t *pp)
531{
532 int i, j, m, k;
533 int n = pp->len;
534 double *pen = NULL;
535 int *prev = NULL;
536 int *clip0 = NULL;
537 int *clip1 = NULL;
538 int *seg0 = NULL;
539 int *seg1 = NULL;
540 double thispen;
541 double best;
542 int c;
543
544 SAFE_CALLOC(pen, n+1, double);
545 SAFE_CALLOC(prev, n+1, int);
546 SAFE_CALLOC(clip0, n, int);
547 SAFE_CALLOC(clip1, n+1, int);
548 SAFE_CALLOC(seg0, n+1, int);
549 SAFE_CALLOC(seg1, n+1, int);
550
551
552 for (i=0; i<n; i++) {
553 c = mod(pp->lon[mod(i-1,n)]-1,n);
554 if (c == i) {
555 c = mod(i+1,n);
556 }
557 if (c < i) {
558 clip0[i] = n;
559 } else {
560 clip0[i] = c;
561 }
562 }
563
564
566 j = 1;
567 for (i=0; i<n; i++) {
568 while (j <= clip0[i]) {
569 clip1[j] = i;
570 j++;
571 }
572 }
573
574
575 i = 0;
576 for (j=0; i<n; j++) {
577 seg0[j] = i;
578 i = clip0[i];
579 }
580 seg0[j] = n;
581 m = j;
582
583
584 i = n;
585 for (j=m; j>0; j--) {
586 seg1[j] = i;
587 i = clip1[i];
588 }
589 seg1[0] = 0;
590
591
592
595 pen[0]=0;
596 for (j=1; j<=m; j++) {
597 for (i=seg1[j]; i<=seg0[j]; i++) {
598 best = -1;
599 for (k=seg0[j-1]; k>=clip1[i]; k--) {
600 thispen = penalty3(pp, k, i) + pen[k];
601 if (best < 0 || thispen < best) {
602 prev[i] = k;
603 best = thispen;
604 }
605 }
606 pen[i] = best;
607 }
608 }
609
610 pp->m = m;
611 SAFE_CALLOC(pp->po, m, int);
612
613
614 for (i=n, j=m-1; i>0; j--) {
615 i = prev[i];
616 pp->po[j] = i;
617 }
618
619 free(pen);
620 free(prev);
621 free(clip0);
622 free(clip1);
623 free(seg0);
624 free(seg1);
625 return 0;
626
627 calloc_error:
628 free(pen);
629 free(prev);
630 free(clip0);
631 free(clip1);
632 free(seg0);
633 free(seg1);
634 return 1;
635}
636
637
638
639
640
644
645static int adjust_vertices(privpath_t *pp) {
646 int m = pp->m;
647 int *po = pp->po;
648 int n = pp->len;
649 point_t *pt = pp->pt;
650 int x0 = pp->x0;
651 int y0 = pp->y0;
652
653 dpoint_t *ctr = NULL;
654 dpoint_t *dir = NULL;
655 quadform_t *q = NULL;
656 double v[3];
657 double d;
658 int i, j, k, l;
659 dpoint_t s;
660 int r;
661
662 SAFE_CALLOC(ctr, m, dpoint_t);
663 SAFE_CALLOC(dir, m, dpoint_t);
664 SAFE_CALLOC(q, m, quadform_t);
665
666 r = privcurve_init(&pp->curve, m);
667 if (r) {
668 goto calloc_error;
669 }
670
671
673 for (i=0; i<m; i++) {
674 j = po[mod(i+1,m)];
675 j = mod(j-po[i],n)+po[i];
676 pointslope(pp, po[i], j, &ctr[i], &dir[i]);
677 }
678
679
682 for (i=0; i<m; i++) {
683 d = sq(dir[i].x) + sq(dir[i].y);
684 if (d == 0.0) {
685 for (j=0; j<3; j++) {
686 for (k=0; k<3; k++) {
687 q[i][j][k] = 0;
688 }
689 }
690 } else {
691 v[0] = dir[i].y;
692 v[1] = -dir[i].x;
693 v[2] = - v[1] * ctr[i].y - v[0] * ctr[i].x;
694 for (l=0; l<3; l++) {
695 for (k=0; k<3; k++) {
696 q[i][l][k] = v[l] * v[k] / d;
697 }
698 }
699 }
700 }
701
702
706 for (i=0; i<m; i++) {
707 quadform_t Q;
708 dpoint_t w;
709 double dx, dy;
710 double det;
711 double min, cand;
712 double xmin, ymin;
713 int z;
714
715
716 s.x = pt[po[i]].x-x0;
717 s.y = pt[po[i]].y-y0;
718
719
720
721 j = mod(i-1,m);
722
723
724 for (l=0; l<3; l++) {
725 for (k=0; k<3; k++) {
726 Q[l][k] = q[j][l][k] + q[i][l][k];
727 }
728 }
729
730 while(1) {
731
732
733
734#ifdef HAVE_GCC_LOOP_BUG
735
736 free(NULL);
737#endif
738
739 det = Q[0][0]*Q[1][1] - Q[0][1]*Q[1][0];
740 if (det != 0.0) {
741 w.x = (-Q[0][2]*Q[1][1] + Q[1][2]*Q[0][1]) / det;
742 w.y = ( Q[0][2]*Q[1][0] - Q[1][2]*Q[0][0]) / det;
743 break;
744 }
745
746
748 if (Q[0][0]>Q[1][1]) {
749 v[0] = -Q[0][1];
750 v[1] = Q[0][0];
751 } else if (Q[1][1]) {
752 v[0] = -Q[1][1];
753 v[1] = Q[1][0];
754 } else {
755 v[0] = 1;
756 v[1] = 0;
757 }
758 d = sq(v[0]) + sq(v[1]);
759 v[2] = - v[1] * s.y - v[0] * s.x;
760 for (l=0; l<3; l++) {
761 for (k=0; k<3; k++) {
762 Q[l][k] += v[l] * v[k] / d;
763 }
764 }
765 }
766 dx = fabs(w.x-s.x);
767 dy = fabs(w.y-s.y);
768 if (dx <= .5 && dy <= .5) {
769 pp->curve.vertex[i].x = w.x+x0;
770 pp->curve.vertex[i].y = w.y+y0;
771 continue;
772 }
773
774
776 min = quadform(Q, s);
777 xmin = s.x;
778 ymin = s.y;
779
780 if (Q[0][0] == 0.0) {
781 goto fixx;
782 }
783 for (z=0; z<2; z++) {
784 w.y = s.y-0.5+z;
785 w.x = - (Q[0][1] * w.y + Q[0][2]) / Q[0][0];
786 dx = fabs(w.x-s.x);
787 cand = quadform(Q, w);
788 if (dx <= .5 && cand < min) {
789 min = cand;
790 xmin = w.x;
791 ymin = w.y;
792 }
793 }
794 fixx:
795 if (Q[1][1] == 0.0) {
796 goto corners;
797 }
798 for (z=0; z<2; z++) {
799 w.x = s.x-0.5+z;
800 w.y = - (Q[1][0] * w.x + Q[1][2]) / Q[1][1];
801 dy = fabs(w.y-s.y);
802 cand = quadform(Q, w);
803 if (dy <= .5 && cand < min) {
804 min = cand;
805 xmin = w.x;
806 ymin = w.y;
807 }
808 }
809 corners:
810
811 for (l=0; l<2; l++) {
812 for (k=0; k<2; k++) {
813 w.x = s.x-0.5+l;
814 w.y = s.y-0.5+k;
815 cand = quadform(Q, w);
816 if (cand < min) {
817 min = cand;
818 xmin = w.x;
819 ymin = w.y;
820 }
821 }
822 }
823
824 pp->curve.vertex[i].x = xmin + x0;
825 pp->curve.vertex[i].y = ymin + y0;
826 continue;
827 }
828
829 free(ctr);
830 free(dir);
831 free(q);
832 return 0;
833
834 calloc_error:
835 free(ctr);
836 free(dir);
837 free(q);
838 return 1;
839}
840
841
842
843
844
845static void reverse(privcurve_t *curve) {
846 int m = curve->n;
847 int i, j;
848 dpoint_t tmp;
849
850 for (i=0, j=m-1; i<j; i++, j--) {
851 tmp = curve->vertex[i];
852 curve->vertex[i] = curve->vertex[j];
853 curve->vertex[j] = tmp;
854 }
855}
856
857
858static void smooth(privcurve_t *curve, double alphamax) {
859 int m = curve->n;
860
861 int i, j, k;
862 double dd, denom, alpha;
863 dpoint_t p2, p3, p4;
864
865
866 for (i=0; i<m; i++) {
867 j = mod(i+1, m);
868 k = mod(i+2, m);
869 p4 = interval(1/2.0, curve->vertex[k], curve->vertex[j]);
870
871 denom = ddenom(curve->vertex[i], curve->vertex[k]);
872 if (denom != 0.0) {
873 dd = dpara(curve->vertex[i], curve->vertex[j], curve->vertex[k]) / denom;
874 dd = fabs(dd);
875 alpha = dd>1 ? (1 - 1.0/dd) : 0;
876 alpha = alpha / 0.75;
877 } else {
878 alpha = 4/3.0;
879 }
880 curve->alpha0[j] = alpha;
881
882 if (alpha >= alphamax) {
883 curve->tag[j] = POTRACE_CORNER;
884 curve->c[j][1] = curve->vertex[j];
885 curve->c[j][2] = p4;
886 } else {
887 if (alpha < 0.55) {
888 alpha = 0.55;
889 } else if (alpha > 1) {
890 alpha = 1;
891 }
892 p2 = interval(.5+.5*alpha, curve->vertex[i], curve->vertex[j]);
893 p3 = interval(.5+.5*alpha, curve->vertex[k], curve->vertex[j]);
894 curve->tag[j] = POTRACE_CURVETO;
895 curve->c[j][0] = p2;
896 curve->c[j][1] = p3;
897 curve->c[j][2] = p4;
898 }
899 curve->alpha[j] = alpha;
900 curve->beta[j] = 0.5;
901 }
902 curve->alphacurve = 1;
903
904 return;
905}
906
907
908
909
910
911struct opti_s {
912 double pen;
913 dpoint_t c[2];
914 double t, s;
915 double alpha;
916};
917typedef struct opti_s opti_t;
918
919
922static int opti_penalty(privpath_t *pp, int i, int j, opti_t *res, double opttolerance, int *convc, double *areac) {
923 int m = pp->curve.n;
924 int k, k1, k2, conv, i1;
925 double area, alpha, d, d1, d2;
926 dpoint_t p0, p1, p2, p3, pt;
927 double A, R, A1, A2, A3, A4;
928 double s, t;
929
930
931
932 if (i==j) {
933 return 1;
934 }
935
936 k = i;
937 i1 = mod(i+1, m);
938 k1 = mod(k+1, m);
939 conv = convc[k1];
940 if (conv == 0) {
941 return 1;
942 }
943 d = ddist(pp->curve.vertex[i], pp->curve.vertex[i1]);
944 for (k=k1; k!=j; k=k1) {
945 k1 = mod(k+1, m);
946 k2 = mod(k+2, m);
947 if (convc[k1] != conv) {
948 return 1;
949 }
950 if (sign(cprod(pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], pp->curve.vertex[k2])) != conv) {
951 return 1;
952 }
953 if (iprod1(pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], pp->curve.vertex[k2]) < d * ddist(pp->curve.vertex[k1], pp->curve.vertex[k2]) * COS179) {
954 return 1;
955 }
956 }
957
958
959 p0 = pp->curve.c[mod(i,m)][2];
960 p1 = pp->curve.vertex[mod(i+1,m)];
961 p2 = pp->curve.vertex[mod(j,m)];
962 p3 = pp->curve.c[mod(j,m)][2];
963
964
965 area = areac[j] - areac[i];
966 area -= dpara(pp->curve.vertex[0], pp->curve.c[i][2], pp->curve.c[j][2])/2;
967 if (i>=j) {
968 area += areac[m];
969 }
970
971
974
975 A1 = dpara(p0, p1, p2);
976 A2 = dpara(p0, p1, p3);
977 A3 = dpara(p0, p2, p3);
978
979 A4 = A1+A3-A2;
980
981 if (A2 == A1) {
982 return 1;
983 }
984
985 t = A3/(A3-A4);
986 s = A2/(A2-A1);
987 A = A2 * t / 2.0;
988
989 if (A == 0.0) {
990 return 1;
991 }
992
993 R = area / A;
994 alpha = 2 - sqrt(4 - R / 0.3);
995
996 res->c[0] = interval(t * alpha, p0, p1);
997 res->c[1] = interval(s * alpha, p3, p2);
998 res->alpha = alpha;
999 res->t = t;
1000 res->s = s;
1001
1002 p1 = res->c[0];
1003 p2 = res->c[1];
1004
1005 res->pen = 0;
1006
1007
1008
1009 for (k=mod(i+1,m); k!=j; k=k1) {
1010 k1 = mod(k+1,m);
1011 t = tangent(p0, p1, p2, p3, pp->curve.vertex[k], pp->curve.vertex[k1]);
1012 if (t<-.5) {
1013 return 1;
1014 }
1015 pt = bezier(t, p0, p1, p2, p3);
1016 d = ddist(pp->curve.vertex[k], pp->curve.vertex[k1]);
1017 if (d == 0.0) {
1018 return 1;
1019 }
1020 d1 = dpara(pp->curve.vertex[k], pp->curve.vertex[k1], pt) / d;
1021 if (fabs(d1) > opttolerance) {
1022 return 1;
1023 }
1024 if (iprod(pp->curve.vertex[k], pp->curve.vertex[k1], pt) < 0 || iprod(pp->curve.vertex[k1], pp->curve.vertex[k], pt) < 0) {
1025 return 1;
1026 }
1027 res->pen += sq(d1);
1028 }
1029
1030
1031 for (k=i; k!=j; k=k1) {
1032 k1 = mod(k+1,m);
1033 t = tangent(p0, p1, p2, p3, pp->curve.c[k][2], pp->curve.c[k1][2]);
1034 if (t<-.5) {
1035 return 1;
1036 }
1037 pt = bezier(t, p0, p1, p2, p3);
1038 d = ddist(pp->curve.c[k][2], pp->curve.c[k1][2]);
1039 if (d == 0.0) {
1040 return 1;
1041 }
1042 d1 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pt) / d;
1043 d2 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pp->curve.vertex[k1]) / d;
1044 d2 *= 0.75 * pp->curve.alpha[k1];
1045 if (d2 < 0) {
1046 d1 = -d1;
1047 d2 = -d2;
1048 }
1049 if (d1 < d2 - opttolerance) {
1050 return 1;
1051 }
1052 if (d1 < d2) {
1053 res->pen += sq(d1 - d2);
1054 }
1055 }
1056
1057 return 0;
1058}
1059
1060
1063static int opticurve(privpath_t *pp, double opttolerance) {
1064 int m = pp->curve.n;
1065 int *pt = NULL;
1066 double *pen = NULL;
1067 int *len = NULL;
1068 opti_t *opt = NULL;
1069 int om;
1070 int i,j,r;
1071 opti_t o;
1072 dpoint_t p0;
1073 int i1;
1074 double area;
1075 double alpha;
1076 double *s = NULL;
1077 double *t = NULL;
1078
1079 int *convc = NULL;
1080 double *areac = NULL;
1081
1082 SAFE_CALLOC(pt, m+1, int);
1083 SAFE_CALLOC(pen, m+1, double);
1084 SAFE_CALLOC(len, m+1, int);
1085 SAFE_CALLOC(opt, m+1, opti_t);
1086 SAFE_CALLOC(convc, m, int);
1087 SAFE_CALLOC(areac, m+1, double);
1088
1089
1090 for (i=0; i<m; i++) {
1091 if (pp->curve.tag[i] == POTRACE_CURVETO) {
1092 convc[i] = sign(dpara(pp->curve.vertex[mod(i-1,m)], pp->curve.vertex[i], pp->curve.vertex[mod(i+1,m)]));
1093 } else {
1094 convc[i] = 0;
1095 }
1096 }
1097
1098
1099 area = 0.0;
1100 areac[0] = 0.0;
1101 p0 = pp->curve.vertex[0];
1102 for (i=0; i<m; i++) {
1103 i1 = mod(i+1, m);
1104 if (pp->curve.tag[i1] == POTRACE_CURVETO) {
1105 alpha = pp->curve.alpha[i1];
1106 area += 0.3*alpha*(4-alpha)*dpara(pp->curve.c[i][2], pp->curve.vertex[i1], pp->curve.c[i1][2])/2;
1107 area += dpara(p0, pp->curve.c[i][2], pp->curve.c[i1][2])/2;
1108 }
1109 areac[i+1] = area;
1110 }
1111
1112 pt[0] = -1;
1113 pen[0] = 0;
1114 len[0] = 0;
1115
1116
1118
1119 for (j=1; j<=m; j++) {
1120
1121 pt[j] = j-1;
1122 pen[j] = pen[j-1];
1123 len[j] = len[j-1]+1;
1124
1125 for (i=j-2; i>=0; i--) {
1126 r = opti_penalty(pp, i, mod(j,m), &o, opttolerance, convc, areac);
1127 if (r) {
1128 break;
1129 }
1130 if (len[j] > len[i]+1 || (len[j] == len[i]+1 && pen[j] > pen[i] + o.pen)) {
1131 pt[j] = i;
1132 pen[j] = pen[i] + o.pen;
1133 len[j] = len[i] + 1;
1134 opt[j] = o;
1135 }
1136 }
1137 }
1138 om = len[m];
1139 r = privcurve_init(&pp->ocurve, om);
1140 if (r) {
1141 goto calloc_error;
1142 }
1143 SAFE_CALLOC(s, om, double);
1144 SAFE_CALLOC(t, om, double);
1145
1146 j = m;
1147 for (i=om-1; i>=0; i--) {
1148 if (pt[j]==j-1) {
1149 pp->ocurve.tag[i] = pp->curve.tag[mod(j,m)];
1150 pp->ocurve.c[i][0] = pp->curve.c[mod(j,m)][0];
1151 pp->ocurve.c[i][1] = pp->curve.c[mod(j,m)][1];
1152 pp->ocurve.c[i][2] = pp->curve.c[mod(j,m)][2];
1153 pp->ocurve.vertex[i] = pp->curve.vertex[mod(j,m)];
1154 pp->ocurve.alpha[i] = pp->curve.alpha[mod(j,m)];
1155 pp->ocurve.alpha0[i] = pp->curve.alpha0[mod(j,m)];
1156 pp->ocurve.beta[i] = pp->curve.beta[mod(j,m)];
1157 s[i] = t[i] = 1.0;
1158 } else {
1159 pp->ocurve.tag[i] = POTRACE_CURVETO;
1160 pp->ocurve.c[i][0] = opt[j].c[0];
1161 pp->ocurve.c[i][1] = opt[j].c[1];
1162 pp->ocurve.c[i][2] = pp->curve.c[mod(j,m)][2];
1163 pp->ocurve.vertex[i] = interval(opt[j].s, pp->curve.c[mod(j,m)][2], pp->curve.vertex[mod(j,m)]);
1164 pp->ocurve.alpha[i] = opt[j].alpha;
1165 pp->ocurve.alpha0[i] = opt[j].alpha;
1166 s[i] = opt[j].s;
1167 t[i] = opt[j].t;
1168 }
1169 j = pt[j];
1170 }
1171
1172
1173 for (i=0; i<om; i++) {
1174 i1 = mod(i+1,om);
1175 pp->ocurve.beta[i] = s[i] / (s[i] + t[i1]);
1176 }
1177 pp->ocurve.alphacurve = 1;
1178
1179 free(pt);
1180 free(pen);
1181 free(len);
1182 free(opt);
1183 free(s);
1184 free(t);
1185 free(convc);
1186 free(areac);
1187 return 0;
1188
1189 calloc_error:
1190 free(pt);
1191 free(pen);
1192 free(len);
1193 free(opt);
1194 free(s);
1195 free(t);
1196 free(convc);
1197 free(areac);
1198 return 1;
1199}
1200
1201
1202
1203#define TRY(x) if (x) goto try_error
1204
1205
1206int process_path(path_t *plist, const potrace_param_t *param, progress_t *progress) {
1207 path_t *p;
1208 double nn = 0, cn = 0;
1209
1210 if (progress->callback) {
1211
1212 nn = 0;
1213 list_forall (p, plist) {
1214 nn += p->priv->len;
1215 }
1216 cn = 0;
1217 }
1218
1219
1220 list_forall (p, plist) {
1221 TRY(calc_sums(p->priv));
1222 TRY(calc_lon(p->priv));
1223 TRY(bestpolygon(p->priv));
1224 TRY(adjust_vertices(p->priv));
1225 if (p->sign == '-') {
1226 reverse(&p->priv->curve);
1227 }
1228 smooth(&p->priv->curve, param->alphamax);
1229 if (param->opticurve) {
1230 TRY(opticurve(p->priv, param->opttolerance));
1231 p->priv->fcurve = &p->priv->ocurve;
1232 } else {
1233 p->priv->fcurve = &p->priv->curve;
1234 }
1235 privcurve_to_curve(p->priv->fcurve, &p->curve);
1236
1237 if (progress->callback) {
1238 cn += p->priv->len;
1239 progress_update(cn/nn, progress);
1240 }
1241 }
1242
1243 progress_update(1.0, progress);
1244
1245 return 0;
1246
1247 try_error:
1248 return 1;
1249}
1250 |