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