7 #define DEBUG_PARTS(x) ;
8 #define DEBUG_JOIN(x) ;
9 #define DEBUG_APATH(x) ;
10 #define DEBUG_SCAN(x) ;
11 #define DEBUG_ISRECT(x) ;
12 #define DEBUG_LOOPS(x)
13 #define DEBUG_BEZIER(x) ;
15 #define dprintf printf
17 inline double length(double x
, double y
) { return sqrt(x
* x
+ y
* y
); }
21 void APath::print(const Part
* parts
)
23 for (const Part
* p
= parts
; p
; p
= p
->next
)
27 printf(" x %f y %f", p
->x
, p
->y
);
29 printf(" closed %p", p
->close
);
34 void APath::print() const
36 printf("APath %p\n", this);
40 void APath::Move::print() const
45 void APath::Line::print() const
50 void APath::Bezier2::print() const
52 printf("bezier x1 %f y1 %f", x1
, y1
);
55 void APath::Bezier3::print() const
57 printf("bezier x1 %f y1 %f x2 %f y2 %f", x1
, y1
, x2
, y2
);
62 static inline int _iround(double x
)
64 return int(x
+ 65536.5) - 65536;
67 bool APath::is_rect(int& x1
, int& y1
, int& x2
, int& y2
) const
75 DEBUG_ISRECT(printf("is_rect:\n"); print());
79 if (!p
|| !p
->close
|| p
->type
!= Part::type_move
)
87 DEBUG_ISRECT(printf("\t%f,%f\t%d,%d\n", x0
, y0
, x
[0], y
[0]));
89 for (int k
= 1; k
< 4; ++k
, p
= p
->next
)
91 if (!p
|| p
->type
!= Part::type_line
)
98 DEBUG_ISRECT(printf("\t%f,%f\t%d,%d\n", x0
, y0
, x
[k
], y
[k
]));
100 if (x
[k
] <= x
[i
] && y
[k
] <= y
[i
])
103 if (x
[k
] >= x
[j
] && y
[k
] >= y
[j
])
107 if (p
&& (p
->next
|| p
->type
!= Part::type_line
||
108 _iround(x0
+ p
->x
) != x
[0] || _iround(y0
+ p
->y
) != y
[0]))
110 DEBUG_ISRECT(printf("too many components\n"));
114 DEBUG_ISRECT(printf("i %d j %d\n", i
, j
));
116 if (i
!= j
&& x
[i
] != x
[j
] && y
[i
] != y
[j
])
118 if (j
!= ((i
+ 2) & 3))
128 int t
= l
; l
= k
; k
= t
;
131 DEBUG_ISRECT(printf("k %d l %d\n", k
, l
));
133 if (x
[k
] != x
[j
] || x
[l
] != x
[i
] || y
[k
] != y
[i
] || y
[l
] != y
[j
])
142 DEBUG_ISRECT(printf("-> ok: (%d,%d)-(%d,%d)\n", x1
, y1
, x2
, y2
));
147 void APath::Scanner::scan(const APath
* path
)
149 DEBUG_SCAN(dprintf("APath::Scanner::scan: path %p\n", path
));
151 for (Part
* p
= path
->parts
; p
; p
= p
->next
)
155 DEBUG_SCAN(dprintf("APath::Scanner::scan: open %p\n", p
->close
));
159 DEBUG_SCAN(dprintf("APath::Scanner::scan: %p\n", p
));
163 DEBUG_SCAN(dprintf("APath::Scanner::scan: close\n"));
169 void APath::Move::callback(CallBack
& s
) const
174 void APath::Line::callback(CallBack
& s
) const
179 void APath::Bezier2::callback(CallBack
& s
) const
181 s
.bezier(x1
, y1
, x
, y
);
184 void APath::Bezier3::callback(CallBack
& s
) const
186 s
.bezier(x1
, y1
, x2
, y2
, x
, y
);
189 APath::Part
* APath::Move::validate(Part
* start
)
195 APath::Part
* APath::Part::validate(Part
* start
)
206 APath::Part
* APath::join(Part
* p1
, Part
*p2
)
208 DEBUG_JOIN(dprintf("APath::join: p1 %p p2 %p\n", p1
, p2
));
222 APath::Part
* APath::join(Part
* p1
, APath
* p2
)
224 DEBUG_JOIN(dprintf("APath::join: p1 %p p2 %p\n", p1
, p2
));
232 p1
->end
->next
= p2
->parts
;
233 p1
->end
= p2
->parts
->end
;
234 p2
->parts
->end
= NULL
;
243 APath::Part
* APath::clone(Part
* p
)
247 Part
* q
= p
->clone();
256 void APath::destroy(Part
* p
)
266 APath::Part
* APath::close(Part
* p
)
271 for (Part
* q
= p
->next
; q
; q
= q
->next
)
276 if (x
!= 0 || y
!= 0)
278 Part
* q
= line(-x
, -y
);
282 p
->end
->close
= p
->end
;
287 void APath::move(Part
* p
, double x
, double y
)
293 APath::Move
* APath::move(double x
, double y
)
295 DEBUG_APATH(printf("move(%f, %f)\n", x
, y
));
296 return new Move(x
, y
);
299 APath::Line
* APath::line(double x
, double y
)
301 DEBUG_APATH(printf("line(%f, %f)\n", x
, y
));
302 return new Line(x
, y
);
305 APath::Bezier2
* APath::bezier(double x1
, double y1
, double x2
, double y2
)
307 DEBUG_APATH(printf("bezier(%f, %f, %f, %f)\n", x1
, y1
, x2
, y2
));
308 return new Bezier2(x1
, y1
, x2
, y2
);
311 APath::Bezier3
* APath::bezier(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
)
313 DEBUG_APATH(printf("bezier(%f, %f, %f, %f, %f, %f)\n", x1
, y1
, x2
, y2
, x3
, y3
));
314 return new Bezier3(x1
, y1
, x2
, y2
, x3
, y3
);
317 APath::APath(Part
* p
)
319 DEBUG_APATH(dprintf("APath::ctor: parts %p\n", p
));
321 for (Part
* q
= p
; q
; q
= q
->next
)
323 start
= q
->validate(start
);
334 void APath::get_delta(Part
* parts
, double& dx
, double& dy
)
337 for (Part
* p
= parts
; p
; p
= p
->next
)
348 void APath::get_delta(double& dx
, double& dy
) const
350 get_delta(parts
, dx
, dy
);
353 class StrokePathBuilder
: public APath::Scanner
356 StrokePathBuilder(double lw
, CapStyle c
, JoinStyle j
, double ml
)
357 : full_path(NULL
), path1(NULL
), path2(NULL
), first(true),
358 x1(0), y1(0), totx(0), toty(0), line_width(lw
/ 2), is_closed(false),
359 cap_style(c
), join_style(j
), miter_limit(ml
), xe(0), ye(0) {}
361 virtual void move(double x
, double y
);
362 virtual void line(double x
, double y
);
363 virtual void bezier(double x1
, double y1
, double x2
, double y2
);
364 virtual void bezier(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
);
365 virtual void open(APath::Part
*);
367 void set_pos(double x
, double y
) { totx
+= x
; toty
+= y
; }
368 void add_pos(double x
, double y
) { x1
+= x
; y1
+= y
; }
369 void add_err(double x
, double y
) { xe
+= x
; ye
+= y
; }
370 void set_dir(double x
, double y
);
374 APath
* get() { return new APath(full_path
); }
375 void add1(APath::Part
* p
) { path1
= APath::join(path1
, p
); }
376 void add2(APath::Part
* p
) { path2
= APath::join(p
, path2
); }
378 void add_correction(double& x
, double& y
)
385 class LastDir
: public APath::CallBack
388 virtual void line(double x
, double y
) { dx
= x
; dy
= y
; }
389 virtual void bezier(double x1
, double y1
, double x2
, double y2
)
391 dx
= x2
- x1
; dy
= y2
- y1
;
393 virtual void bezier(double x1
, double y1
, double x2
, double y2
,
394 double x3
, double y3
)
396 dx
= x3
- x2
; dy
= y3
- y2
;
402 APath::Part
* full_path
;
410 const double line_width
;
413 JoinStyle join_style
;
419 void StrokePathBuilder::set_dir(double x
, double y
)
427 void StrokePathBuilder::start()
429 PATHDB(printf("starting (%f,%f), (%f,%f) closed %d\n", x1
, y1
, dx2
, dy2
, is_closed
));
432 path1
= APath::move(x1
+ dy1
, y1
- dx1
);
442 path1
= APath::move(x1
- dx2
, y1
- dy2
);
443 path1
->join(APath::bezier(dy2
, -dx2
, dx2
+ dy2
, dy2
- dx2
));
444 path2
= APath::bezier(-dx2
, -dy2
, dy2
- dx2
, -dx2
- dy2
);
449 path1
= APath::move(x1
+ dy2
- dx2
, y1
- dx2
- dy2
);
450 path1
->join(APath::line(dx2
, dy2
));
451 path2
= APath::line(-dx2
, -dy2
);
455 default: /* cap_butt */
456 path1
= APath::move(x1
+ dy2
, y1
- dx2
);
466 void StrokePathBuilder::join()
468 double tdx1
, tdy1
, tdx2
, tdy2
;
469 bool side
= dx1
* dy2
- dy1
* dx2
< 0;
470 tdx1
= dx1
; tdy1
= dy1
; tdx2
= dx2
; tdy2
= dy2
;
471 PATHDB(printf("joining (%f,%f)-(%f,%f)\n", dx1
, dy1
, dx2
, dy2
));
472 APath::Part
* seg1
= NULL
;
473 APath::Part
* seg2
= APath::line(tdy2
- tdy1
, tdx1
- tdx2
);
478 double d
= tdx2
* tdy1
- tdx1
* tdy2
;
479 if (fabs(d
) > 0.0001)
481 double a
= (tdx2
* (tdx1
- tdx2
) - tdy2
* (tdy2
- tdy1
)) / d
;
485 seg1
= APath::bezier(tdy2
- tdy1
- x
, tdx1
- tdx2
- y
, tdy2
- tdy1
, tdx1
- tdx2
);
487 seg1
= APath::bezier(x
, y
, tdy2
- tdy1
, tdx1
- tdx2
);
491 seg1
= APath::clone(seg2
);
497 double d
= tdx2
* tdy1
- tdx1
* tdy2
;
498 if (fabs(d
* miter_limit
) > line_width
* line_width
)
500 double a
= (tdx2
* (tdx1
- tdx2
) - tdy2
* (tdy2
- tdy1
)) / d
;
503 APath::Part
* p1
= APath::line(x
, y
);
504 APath::Part
* p2
= APath::line(tdy2
- tdy1
- x
, tdx1
- tdx2
- y
);
507 APath::Part
*t
= p1
; p1
= p2
; p2
= t
;
513 default: /*join_bevel*/
514 seg1
= APath::clone(seg2
);
519 APath::Part
* t
= seg1
; seg1
= seg2
; seg2
= t
;
521 path1
= APath::join(path1
, seg1
);
522 path2
= APath::join(seg2
, path2
);
525 void StrokePathBuilder::do_close()
527 PATHDB(printf("closing (%f, %f) is_closed %d\n", dx2
, dy2
, is_closed
));
530 path1
= APath::close(path1
);
531 path2
= APath::close(APath::move(-2 * totx
, -2 * toty
)->join(path2
));
532 path1
= APath::join(path1
, path2
);
539 path1
= APath::join(path1
, APath::bezier(dx2
, dy2
, dx2
- dy2
, dx2
+ dy2
));
540 path1
->join(APath::bezier(-dy2
, dx2
, -dx2
- dy2
, dx2
- dy2
));
543 path1
= APath::join(path1
, APath::line(dx2
, dy2
));
544 path1
->join(APath::line(-2 * dy2
, 2 * dx2
));
545 path1
->join(APath::line(-dx2
, -dy2
));
547 default: /* cap_butt */
548 path1
= APath::join(path1
, APath::line(-2 * dy2
, 2 * dx2
));
551 path1
= APath::join(path1
, path2
);
552 path1
= APath::close(path1
);
554 full_path
= APath::join(full_path
, path1
);
555 path1
= path2
= NULL
;
561 void StrokePathBuilder::move(double x
, double y
)
563 PATHDB(printf("move(%f, %f) first %d\n", x
, y
, first
));
566 add_correction(x
, y
);
571 void StrokePathBuilder::open(APath::Part
* end
)
573 PATHDB(printf("open(%p)\n", end
));
581 double d
= length(x
, y
);
585 set_dir(x
/ d
, y
/ d
);
592 void StrokePathBuilder::line(double x
, double y
)
594 PATHDB(printf("line(%f, %f)\n", x
, y
));
595 add_correction(x
, y
);
596 double d
= length(x
, y
);
600 set_dir(x
/ d
, y
/ d
);
605 add1(APath::line(x
, y
));
606 add2(APath::line(-x
, -y
));
614 void StrokePathBuilder::bezier(double x1
, double y1
, double x
, double y
)
616 PATHDB(printf("bezier(%f, %f, %f, %f)\n", x1
, y1
, x
, y
));
617 add_correction(x
, y
);
622 double D1
= length(X1
, Y1
);
623 double D2
= length(X2
, Y2
);
624 if (D1
>= 0.0001 || D2
>= 0.0001)
626 double DX1
, DY1
, DX2
, DY2
;
629 const double eps
= 0.0001 / line_width
;//1 / (line_width * 16);
656 //printf("(%f,%f) (%f,%f) (%f,%f) lw=%f\n",X1,Y1,X2,Y2,X3,Y3,lw);
657 //printf("dx1=%f dy1=%f dx2=%f dy2=%f dx3=%f dy3=%f\n",DX1,DY1,DX2,DY2,DX3,DY3);
659 double d
= DX2
* DY1
- DY2
* DX1
;
660 if (fabs(d
) < 0.0001)
667 double a
= (DX2
* (Y1
+ DX1
- DX2
) - DY2
* (X1
+ DY2
- DY1
)) / d
;
668 DX4
= DY1
+ a
* DX1
- X1
;
669 DY4
= -DX1
+ a
* DY1
- Y1
;
671 //printf("dx4=%f dy4=%f\n",DX4,DY4);
672 //printf("dx5=%f dy5=%f\n",DX5,DY5);
673 add1(APath::bezier(x1
+ DX4
- DY1
, y1
+ DY4
+ DX1
,
674 x
+ dy2
- dy1
, y
- dx2
+ dx1
));
675 add2(APath::bezier(x1
- x
- DX4
+ DY2
, y1
- y
- DY4
- DX2
,
676 dy2
- dy1
- x
, dx1
- dx2
- y
));
684 void StrokePathBuilder::bezier(double x1
, double y1
, double x2
, double y2
, double x
, double y
)
686 const int max_levels
= 13;
691 } *s
, stack
[max_levels
];
697 PATHDB(printf("bezier(%f, %f, %f, %f, %f, %f)\n", x1
, y1
, x2
, y2
, x
, y
));
705 double D1
= length(X1
, Y1
);
706 double D2
= length(X2
, Y2
);
707 double D3
= length(X3
, Y3
);
709 if (s
< stack
+ max_levels
- 3 &&
710 //(D1 >= 0.01 || D2 >= 0.01 || D3 >= 0.01) &&
711 (X1
* X2
+ Y1
* Y2
< -0.5 * D1
* D2
- 0.00005 ||
712 X2
* X3
+ Y2
* Y3
< -0.5 * D2
* D3
- 0.00005))
714 PATHDB(printf("split: (%f,%f) (%f,%f) (%f,%f)\n",
715 X1
, Y1
, X2
, Y2
, X3
, Y3
));
718 double xb
= (x1
+ x2
) / 2;
719 double yb
= (y1
+ y2
) / 2;
720 double xc
= (x2
+ x
) / 2;
721 double yc
= (y2
+ y
) / 2;
722 double xd
= (xa
+ xb
) / 2;
723 double yd
= (ya
+ yb
) / 2;
724 double xe
= (xb
+ xc
) / 2;
725 double ye
= (yb
+ yc
) / 2;
726 double xf
= (xd
+ xe
) / 2;
727 double yf
= (yd
+ ye
) / 2;
747 add_correction(x
, y
);
751 if (D1
>= 0.01 || D2
>= 0.01 || D3
>= 0.01)
753 double DX1
, DY1
, DX2
, DY2
, DX3
, DY3
;
757 const double eps
= 0.005 / line_width
;//1 / (line_width * 16);
802 //printf("(%f,%f) (%f,%f) (%f,%f) lw=%f\n",X1,Y1,X2,Y2,X3,Y3,lw);
803 //printf("dx1=%f dy1=%f dx2=%f dy2=%f dx3=%f dy3=%f\n",DX1,DY1,DX2,DY2,DX3,DY3);
805 double d
= DX2
* DY1
- DY2
* DX1
;
813 double a
= (DX2
* (Y1
+ DX1
- DX2
) - DY2
* (X1
+ DY2
- DY1
)) / d
;
814 DX4
= DY1
+ a
* DX1
- X1
;
815 DY4
= -DX1
+ a
* DY1
- Y1
;
817 //printf("dx4=%f dy4=%f\n",DX4,DY4);
819 d
= DX3
* DY2
- DY3
* DX2
;
827 double a
= (DX3
* (Y2
+ DX2
- DX3
) - DY3
* (X2
- DY2
+ DY3
)) / d
;
828 DX5
= DY2
+ a
* DX2
- X2
;
829 DY5
= -DX2
+ a
* DY2
- Y2
;
831 //printf("dx5=%f dy5=%f\n",DX5,DY5);
832 add1(APath::bezier(x1
+ DX4
- DY1
, y1
+ DY4
+ DX1
,
833 x2
+ DX5
- DY1
, y2
+ DY5
+ DX1
,
834 x
+ dy2
- dy1
, y
- dx2
+ dx1
));
835 add2(APath::bezier(x2
- x
- DX5
+ DY3
, y2
- y
- DY5
- DX3
,
836 x1
- x
- DX4
+ DY3
, y1
- y
- DY4
- DX3
,
837 dy2
- dy1
- x
, dx1
- dx2
- y
));
855 PATHDB(printf("~bezier\n"));
858 APath
* APath::thicken(double lw
, CapStyle cap_style
, JoinStyle join_style
, double miter_limit
) const
861 printf("thicken(%f, %d, %d, %f)\n", lw
, cap_style
, join_style
, miter_limit
);
864 StrokePathBuilder
builder(lw
, cap_style
, join_style
, miter_limit
);
871 APath
* result
= builder
.get();
882 class DashPathBuilder
: public APath::Scanner
885 DashPathBuilder(DashState
& d
)
890 virtual void move(double x
, double y
);
891 virtual void line(double x
, double y
);
892 virtual void bezier(double x1
, double y1
, double x2
, double y2
);
893 virtual void bezier(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
);
894 //virtual void open(APath::Part*);
895 virtual void close();
897 APath
* get() { return new APath(path
); }
904 void DashPathBuilder::move(double x
, double y
)
906 PATHDB(printf("move(%f, %f) first %d\n", x
, y
, first
));
907 path
= APath::join(path
, APath::move(x
, y
));
910 void DashPathBuilder::line(double x
, double y
)
912 PATHDB(printf("line(%f, %f)\n", x
, y
));
914 double l
= sqrt(x
* x
+ y
* y
);
922 int cnt
= ds
.raw_count();
923 double l1
= double(cnt
) / (1 << DashState::fract_bits
);
931 APath::Part
* p
= ds
.is_on() ? APath::line(x1
, y1
) : APath::move(x1
, y1
);
932 path
= APath::join(path
, p
);
946 APath::Part
* p
= ds
.is_on() ? APath::line(x
, y
) : APath::move(x
, y
);
947 path
= APath::join(path
, p
);
948 ds
.advance(int(l
* (1 << DashState::fract_bits
)));
952 void DashPathBuilder::bezier(double x1
, double y1
, double x
, double y
)
954 PATHDB(printf("bezier(%f, %f, %f, %f)\n", x1
, y1
, x
, y
));
956 const int max_levels
= 15;
962 } *s
, stack
[max_levels
];
966 DEBUG_LOOPS(int n
= 0);
972 DEBUG_BEZIER(printf("bezier: %f,%f %f,%f level %d\n",
973 x1
, y1
, x
, y
, (s
- stack
) / 2));
975 DEBUG_LOOPS(if (n
> 200) printf("too many iterations: %f,%f %f,%f\n", x1
,y1
,x
,y
); else)
976 if (s
< stack
+ max_levels
- 2)
978 double dx
= fabs(x
- 2 * x1
);
979 double dy
= fabs(y
- 2 * y1
);
980 if (dx
< dy
) dx
= dy
;
984 DEBUG_BEZIER(printf("bezier: split\n"));
985 double x2
= (x1
+ x
) / 2;
986 double y2
= (y1
+ y
) / 2;
989 double x3
= (x1
+ x2
) / 2;
990 double y3
= (y1
+ y2
) / 2;
1002 double midx
= (2 * x1
+ x
) / 4;
1003 double midy
= (2 * y1
+ y
) / 4;
1005 DEBUG_BEZIER(printf("bezier: line %f,%f + line %f,%f\n", midx
, midy
, x
- midx
, y
- midy
));
1008 line(x
- midx
, y
- midy
);
1022 DEBUG_BEZIER(printf("bezier: done\n"));
1025 void DashPathBuilder::bezier(double x1
, double y1
, double x2
, double y2
, double x
, double y
)
1027 PATHDB(printf("bezier(%f, %f, %f, %f, %f, %f)\n", x1
, y1
, x2
, y2
, x
, y
));
1029 const int max_levels
= 22;
1035 } *s
, stack
[max_levels
];
1039 DEBUG_LOOPS(int n
= 0);
1043 DEBUG_LOOPS(if (++n
> 400) printf("too many iterations: %f,%f %f,%f %f,%f\n", x1
,y1
,x2
,y2
,x
,y
); else)
1044 if (s
< stack
+ max_levels
- 3)
1046 double dx
= fabs(x
- x1
- x2
);
1047 double dy
= fabs(y
- y1
- y2
);
1048 if (dx
< dy
) dx
= dy
;
1052 double xa
= (x1
+ x2
) / 2;
1053 double ya
= (y1
+ y2
) / 2;
1054 double xb
= (x2
+ x
) / 2;
1055 double yb
= (y2
+ y
) / 2;
1060 double xc
= (xa
+ xb
) / 2;
1061 double yc
= (ya
+ yb
) / 2;
1062 double xe
= (x2
+ xc
) / 2;
1063 double ye
= (y2
+ yc
) / 2;
1079 double midx
= (3 * (x1
+ x2
) + x
) / 8;
1080 double midy
= (3 * (y1
+ y2
) + y
) / 8;
1083 line(x
- midx
, y
- midy
);
1099 DEBUG_BEZIER(printf("bezier: done\n"));
1102 void DashPathBuilder::close()
1104 path
= APath::close(path
);
1107 APath
* APath::make_dashes(DashState
& ds
) const
1110 printf("make_dashes\n");
1114 DashPathBuilder
builder(ds
);
1118 APath
* result
= builder
.get();
1121 printf("result:\n");