8 * ellipse(dst, c, a, b, t, src, sp)
9 * draws an ellipse centered at c with semiaxes a,b>=0
10 * and semithickness t>=0, or filled if t<0. point sp
11 * in src maps to c in dst
13 * very thick skinny ellipses are brushed with circles (slow)
14 * others are approximated by filling between 2 ellipses
15 * criterion for very thick when b<a: t/b > 0.5*x/(1-x)
19 typedef struct Param Param;
20 typedef struct State State;
22 static void bellipse(int, State*, Param*);
23 static void erect(int, int, int, int, Param*);
24 static void eline(int, int, int, int, Param*);
37 * denote residual error by e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2
38 * e(x,y) = 0 on ellipse, e(x,y) < 0 inside, e(x,y) > 0 outside
46 vlong b2x; /* b^2 * x */
47 vlong a2y; /* a^2 * y */
49 vlong c2; /* test criteria */
50 vlong ee; /* ee = e(x+1/2,y-1/2) - (a^2+b^2)/4 */
59 newstate(State *s, int a, int b)
66 s->a2y = s->a2*(vlong)b;
67 s->c1 = -((s->a2>>2) + (vlong)(a&1) + s->b2);
68 s->c2 = -((s->b2>>2) + (vlong)(b&1));
78 * return x coord of rightmost pixel on next scan line
85 if(s->ee+s->b2x <= s->c1 || /* e(x+1,y-1/2) <= 0 */
86 s->ee+s->a2y <= s->c2) { /* e(x+1/2,y) <= 0 (rare) */
96 if(s->ee-s->a2y <= s->c2) { /* e(x+1/2,y-1) <= 0 */
108 memellipse(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int op)
111 int y, inb, inx, outx, u;
127 if(b<a && u>b*b || a<b && -u>a*a) {
128 /* if(b<a&&(t<<1)>b*b/a || a<b&&(t<<1)>a*a/b) # very thick */
129 bellipse(b, newstate(&in, a, b), &p);
135 newstate(&out, a, y = b);
138 newstate(&out, a+t, y = b+t);
141 newstate(&in, a-t, inb);
146 erect(-outx, y, outx, y, &p);
148 erect(-outx, -y, outx, -y, &p);
155 } else if(inx > outx)
157 erect(inx, y, outx, y, &p);
159 erect(inx, -y, outx, -y, &p);
160 erect(-outx, y, -inx, y, &p);
162 erect(-outx, -y, -inx, -y, &p);
167 static Point p00 = {0, 0};
174 bellipse(int y, State *s, Param *p)
176 int t, ox, oy, x, nx;
179 p->disc = allocmemimage(Rect(-t,-t,t+1,t+1), GREY1);
182 memfillcolor(p->disc, DTransparent);
183 memellipse(p->disc, p00, t, t, -1, memopaque, p00, p->op);
188 while(nx==x && y-->0)
191 eline(-x,-oy,-ox, -y, p);
192 eline(ox,-oy, x, -y, p);
193 eline(-x, y,-ox, oy, p);
194 eline(ox, y, x, oy, p);
203 * a rectangle with closed (not half-open) coordinates expressed
204 * relative to the center of the ellipse
208 erect(int x0, int y0, int x1, int y1, Param *p)
212 /* print("R %d,%d %d,%d\n", x0, y0, x1, y1); /**/
213 r = Rect(p->c.x+x0, p->c.y+y0, p->c.x+x1+1, p->c.y+y1+1);
214 memdraw(p->dst, r, p->src, addpt(p->sp, r.min), memopaque, p00, p->op);
218 * a brushed point similarly specified
222 epoint(int x, int y, Param *p)
227 /* print("P%d %d,%d\n", p->t, x, y); /**/
228 p0 = Pt(p->c.x+x, p->c.y+y);
229 r = Rpt(addpt(p0, p->disc->r.min), addpt(p0, p->disc->r.max));
230 memdraw(p->dst, r, p->src, addpt(p->sp, r.min), p->disc, p->disc->r.min, p->op);
234 * a brushed horizontal or vertical line similarly specified
238 eline(int x0, int y0, int x1, int y1, Param *p)
240 /* print("L%d %d,%d %d,%d\n", p->t, x0, y0, x1, y1); /**/
242 erect(x0+1, y0-p->t, x1-1, y1+p->t, p);
244 erect(x0-p->t, y0+1, x1+p->t, y1-1, p);