xref: /plan9/sys/src/cmd/unix/drawterm/libmemdraw/arc.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 #include <memlayer.h>
6 
7 /*
8  * elarc(dst,c,a,b,t,src,sp,alpha,phi)
9  *   draws the part of an ellipse between rays at angles alpha and alpha+phi
10  *   measured counterclockwise from the positive x axis. other
11  *   arguments are as for ellipse(dst,c,a,b,t,src,sp)
12  */
13 
14 enum
15 {
16 	R, T, L, B	/* right, top, left, bottom */
17 };
18 
19 static
20 Point corners[] = {
21 	{1,1},
22 	{-1,1},
23 	{-1,-1},
24 	{1,-1}
25 };
26 
27 static
28 Point p00;
29 
30 /*
31  * make a "wedge" mask covering the desired angle and contained in
32  * a surrounding square; draw a full ellipse; intersect that with the
33  * wedge to make a mask through which to copy src to dst.
34  */
35 void
memarc(Memimage * dst,Point c,int a,int b,int t,Memimage * src,Point sp,int alpha,int phi,int op)36 memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op)
37 {
38 	int i, w, beta, tmp, c1, c2, m, m1;
39 	Rectangle rect;
40 	Point p,	bnd[8];
41 	Memimage *wedge, *figure, *mask;
42 
43 	if(a < 0)
44 		a = -a;
45 	if(b < 0)
46 		b = -b;
47 	w = t;
48 	if(w < 0)
49 		w = 0;
50 	alpha = -alpha;		/* compensate for upside-down coords */
51 	phi = -phi;
52 	beta = alpha + phi;
53 	if(phi < 0){
54 		tmp = alpha;
55 		alpha = beta;
56 		beta = tmp;
57 		phi = -phi;
58 	}
59 	if(phi >= 360){
60 		memellipse(dst, c, a, b, t, src, sp, op);
61 		return;
62 	}
63 	while(alpha < 0)
64 		alpha += 360;
65 	while(beta < 0)
66 		beta += 360;
67 	c1 = alpha/90 & 3;	/* number of nearest corner */
68 	c2 = beta/90 & 3;
69 		/*
70 		 * icossin returns point at radius ICOSSCALE.
71 		 * multiplying by m1 moves it outside the ellipse
72 		*/
73 	rect = Rect(-a-w, -b-w, a+w+1, b+w+1);
74 	m = rect.max.x;	/* inradius of bounding square */
75 	if(m < rect.max.y)
76 		m = rect.max.y;
77 	m1 = (m+ICOSSCALE-1) >> 10;
78 	m = m1 << 10;		/* assure m1*cossin is inside */
79 	i = 0;
80 	bnd[i++] = Pt(0,0);
81 	icossin(alpha, &p.x, &p.y);
82 	bnd[i++] = mulpt(p, m1);
83 	for(;;) {
84 		bnd[i++] = mulpt(corners[c1], m);
85 		if(c1==c2 && phi<180)
86 			break;
87 		c1 = (c1+1) & 3;
88 		phi -= 90;
89 	}
90 	icossin(beta, &p.x, &p.y);
91 	bnd[i++] = mulpt(p, m1);
92 
93 	figure = nil;
94 	mask = nil;
95 	wedge = allocmemimage(rect, GREY1);
96 	if(wedge == nil)
97 		goto Return;
98 	memfillcolor(wedge, DTransparent);
99 	memfillpoly(wedge, bnd, i, ~0, memopaque, p00, S);
100 	figure = allocmemimage(rect, GREY1);
101 	if(figure == nil)
102 		goto Return;
103 	memfillcolor(figure, DTransparent);
104 	memellipse(figure, p00, a, b, t, memopaque, p00, S);
105 	mask = allocmemimage(rect, GREY1);
106 	if(mask == nil)
107 		goto Return;
108 	memfillcolor(mask, DTransparent);
109 	memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S);
110 	c = subpt(c, dst->r.min);
111 	memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(p00, c), op);
112 
113     Return:
114 	freememimage(wedge);
115 	freememimage(figure);
116 	freememimage(mask);
117 }
118