1*7dd7cddfSDavid du Colombier #include "../lib9.h" 2*7dd7cddfSDavid du Colombier 3*7dd7cddfSDavid du Colombier #include "../libdraw/draw.h" 4*7dd7cddfSDavid du Colombier #include "../libmemdraw/memdraw.h" 5*7dd7cddfSDavid du Colombier #include "../libmemlayer/memlayer.h" 6*7dd7cddfSDavid du Colombier 7*7dd7cddfSDavid du Colombier /* 8*7dd7cddfSDavid du Colombier * ellipse(dst, c, a, b, t, src, sp) 9*7dd7cddfSDavid du Colombier * draws an ellipse centered at c with semiaxes a,b>=0 10*7dd7cddfSDavid du Colombier * and semithickness t>=0, or filled if t<0. point sp 11*7dd7cddfSDavid du Colombier * in src maps to c in dst 12*7dd7cddfSDavid du Colombier * 13*7dd7cddfSDavid du Colombier * very thick skinny ellipses are brushed with circles (slow) 14*7dd7cddfSDavid du Colombier * others are approximated by filling between 2 ellipses 15*7dd7cddfSDavid du Colombier * criterion for very thick when b<a: t/b > 0.5*x/(1-x) 16*7dd7cddfSDavid du Colombier * where x = b/a 17*7dd7cddfSDavid du Colombier */ 18*7dd7cddfSDavid du Colombier 19*7dd7cddfSDavid du Colombier typedef struct Param Param; 20*7dd7cddfSDavid du Colombier typedef struct State State; 21*7dd7cddfSDavid du Colombier 22*7dd7cddfSDavid du Colombier static void bellipse(int, State*, Param*); 23*7dd7cddfSDavid du Colombier static void erect(int, int, int, int, Param*); 24*7dd7cddfSDavid du Colombier static void eline(int, int, int, int, Param*); 25*7dd7cddfSDavid du Colombier 26*7dd7cddfSDavid du Colombier struct Param { 27*7dd7cddfSDavid du Colombier Memimage *dst; 28*7dd7cddfSDavid du Colombier Memimage *src; 29*7dd7cddfSDavid du Colombier Point c; 30*7dd7cddfSDavid du Colombier int t; 31*7dd7cddfSDavid du Colombier Point sp; 32*7dd7cddfSDavid du Colombier Memimage *disc; 33*7dd7cddfSDavid du Colombier }; 34*7dd7cddfSDavid du Colombier 35*7dd7cddfSDavid du Colombier /* 36*7dd7cddfSDavid du Colombier * denote residual error by e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 37*7dd7cddfSDavid du Colombier * e(x,y) = 0 on ellipse, e(x,y) < 0 inside, e(x,y) > 0 outside 38*7dd7cddfSDavid du Colombier */ 39*7dd7cddfSDavid du Colombier 40*7dd7cddfSDavid du Colombier struct State { 41*7dd7cddfSDavid du Colombier int a; 42*7dd7cddfSDavid du Colombier int x; 43*7dd7cddfSDavid du Colombier vlong a2; /* a^2 */ 44*7dd7cddfSDavid du Colombier vlong b2; /* b^2 */ 45*7dd7cddfSDavid du Colombier vlong b2x; /* b^2 * x */ 46*7dd7cddfSDavid du Colombier vlong a2y; /* a^2 * y */ 47*7dd7cddfSDavid du Colombier vlong c1; 48*7dd7cddfSDavid du Colombier vlong c2; /* test criteria */ 49*7dd7cddfSDavid du Colombier vlong ee; /* ee = e(x+1/2,y-1/2) - (a^2+b^2)/4 */ 50*7dd7cddfSDavid du Colombier vlong dxe; 51*7dd7cddfSDavid du Colombier vlong dye; 52*7dd7cddfSDavid du Colombier vlong d2xe; 53*7dd7cddfSDavid du Colombier vlong d2ye; 54*7dd7cddfSDavid du Colombier }; 55*7dd7cddfSDavid du Colombier 56*7dd7cddfSDavid du Colombier static 57*7dd7cddfSDavid du Colombier State* 58*7dd7cddfSDavid du Colombier newstate(State *s, int a, int b) 59*7dd7cddfSDavid du Colombier { 60*7dd7cddfSDavid du Colombier s->x = 0; 61*7dd7cddfSDavid du Colombier s->a = a; 62*7dd7cddfSDavid du Colombier s->a2 = (vlong)(a*a); 63*7dd7cddfSDavid du Colombier s->b2 = (vlong)(b*b); 64*7dd7cddfSDavid du Colombier s->b2x = (vlong)0; 65*7dd7cddfSDavid du Colombier s->a2y = s->a2*(vlong)b; 66*7dd7cddfSDavid du Colombier s->c1 = -((s->a2>>2) + (vlong)(a&1) + s->b2); 67*7dd7cddfSDavid du Colombier s->c2 = -((s->b2>>2) + (vlong)(b&1)); 68*7dd7cddfSDavid du Colombier s->ee = -s->a2y; 69*7dd7cddfSDavid du Colombier s->dxe = (vlong)0; 70*7dd7cddfSDavid du Colombier s->dye = s->ee<<1; 71*7dd7cddfSDavid du Colombier s->d2xe = s->b2<<1; 72*7dd7cddfSDavid du Colombier s->d2ye = s->a2<<1; 73*7dd7cddfSDavid du Colombier return s; 74*7dd7cddfSDavid du Colombier } 75*7dd7cddfSDavid du Colombier 76*7dd7cddfSDavid du Colombier /* 77*7dd7cddfSDavid du Colombier * return x coord of rightmost pixel on next scan line 78*7dd7cddfSDavid du Colombier */ 79*7dd7cddfSDavid du Colombier static 80*7dd7cddfSDavid du Colombier int 81*7dd7cddfSDavid du Colombier step(State *s) 82*7dd7cddfSDavid du Colombier { 83*7dd7cddfSDavid du Colombier while(s->x < s->a) { 84*7dd7cddfSDavid du Colombier if(s->ee+s->b2x <= s->c1 || /* e(x+1,y-1/2) <= 0 */ 85*7dd7cddfSDavid du Colombier s->ee+s->a2y <= s->c2) { /* e(x+1/2,y) <= 0 (rare) */ 86*7dd7cddfSDavid du Colombier s->dxe += s->d2xe; 87*7dd7cddfSDavid du Colombier s->ee += s->dxe; 88*7dd7cddfSDavid du Colombier s->b2x += s->b2; 89*7dd7cddfSDavid du Colombier s->x++; 90*7dd7cddfSDavid du Colombier continue; 91*7dd7cddfSDavid du Colombier } 92*7dd7cddfSDavid du Colombier s->dye += s->d2ye; 93*7dd7cddfSDavid du Colombier s->ee += s->dye; 94*7dd7cddfSDavid du Colombier s->a2y -= s->a2; 95*7dd7cddfSDavid du Colombier if(s->ee-s->a2y <= s->c2) { /* e(x+1/2,y-1) <= 0 */ 96*7dd7cddfSDavid du Colombier s->dxe += s->d2xe; 97*7dd7cddfSDavid du Colombier s->ee += s->dxe; 98*7dd7cddfSDavid du Colombier s->b2x += s->b2; 99*7dd7cddfSDavid du Colombier return s->x++; 100*7dd7cddfSDavid du Colombier } 101*7dd7cddfSDavid du Colombier break; 102*7dd7cddfSDavid du Colombier } 103*7dd7cddfSDavid du Colombier return s->x; 104*7dd7cddfSDavid du Colombier } 105*7dd7cddfSDavid du Colombier 106*7dd7cddfSDavid du Colombier void 107*7dd7cddfSDavid du Colombier memellipse(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp) 108*7dd7cddfSDavid du Colombier { 109*7dd7cddfSDavid du Colombier State in, out; 110*7dd7cddfSDavid du Colombier int y, inb, inx, outx, u; 111*7dd7cddfSDavid du Colombier Param p; 112*7dd7cddfSDavid du Colombier 113*7dd7cddfSDavid du Colombier if(a < 0) 114*7dd7cddfSDavid du Colombier a = -a; 115*7dd7cddfSDavid du Colombier if(b < 0) 116*7dd7cddfSDavid du Colombier b = -b; 117*7dd7cddfSDavid du Colombier p.dst = dst; 118*7dd7cddfSDavid du Colombier p.src = src; 119*7dd7cddfSDavid du Colombier p.c = c; 120*7dd7cddfSDavid du Colombier p.t = t; 121*7dd7cddfSDavid du Colombier p.sp = subpt(sp, c); 122*7dd7cddfSDavid du Colombier p.disc = nil; 123*7dd7cddfSDavid du Colombier 124*7dd7cddfSDavid du Colombier u = (t<<1)*(a-b); 125*7dd7cddfSDavid du Colombier if((b<a && u>b*b) || (a<b && -u>a*a)) { 126*7dd7cddfSDavid du Colombier /* if(b<a&&(t<<1)>b*b/a || a<b&&(t<<1)>a*a/b) # very thick */ 127*7dd7cddfSDavid du Colombier bellipse(b, newstate(&in, a, b), &p); 128*7dd7cddfSDavid du Colombier return; 129*7dd7cddfSDavid du Colombier } 130*7dd7cddfSDavid du Colombier 131*7dd7cddfSDavid du Colombier if(t < 0) { 132*7dd7cddfSDavid du Colombier inb = -1; 133*7dd7cddfSDavid du Colombier newstate(&out, a, y = b); 134*7dd7cddfSDavid du Colombier } else { 135*7dd7cddfSDavid du Colombier inb = b - t; 136*7dd7cddfSDavid du Colombier newstate(&out, a+t, y = b+t); 137*7dd7cddfSDavid du Colombier } 138*7dd7cddfSDavid du Colombier if(t > 0) 139*7dd7cddfSDavid du Colombier newstate(&in, a-t, inb); 140*7dd7cddfSDavid du Colombier inx = 0; 141*7dd7cddfSDavid du Colombier for( ; y>=0; y--) { 142*7dd7cddfSDavid du Colombier outx = step(&out); 143*7dd7cddfSDavid du Colombier if(y > inb) { 144*7dd7cddfSDavid du Colombier erect(-outx, y, outx, y, &p); 145*7dd7cddfSDavid du Colombier erect(-outx, -y, outx, -y, &p); 146*7dd7cddfSDavid du Colombier continue; 147*7dd7cddfSDavid du Colombier } 148*7dd7cddfSDavid du Colombier if(t > 0) { 149*7dd7cddfSDavid du Colombier inx = step(&in); 150*7dd7cddfSDavid du Colombier if(y == inb) 151*7dd7cddfSDavid du Colombier inx = 0; 152*7dd7cddfSDavid du Colombier } else if(inx > outx) 153*7dd7cddfSDavid du Colombier inx = outx; 154*7dd7cddfSDavid du Colombier erect(inx, y, outx, y, &p); 155*7dd7cddfSDavid du Colombier erect(inx, -y, outx, -y, &p); 156*7dd7cddfSDavid du Colombier erect(-outx, y, -inx, y, &p); 157*7dd7cddfSDavid du Colombier erect(-outx, -y, -inx, -y, &p); 158*7dd7cddfSDavid du Colombier inx = outx + 1; 159*7dd7cddfSDavid du Colombier } 160*7dd7cddfSDavid du Colombier } 161*7dd7cddfSDavid du Colombier 162*7dd7cddfSDavid du Colombier static Point p00 = {0, 0}; 163*7dd7cddfSDavid du Colombier 164*7dd7cddfSDavid du Colombier /* 165*7dd7cddfSDavid du Colombier * a brushed ellipse 166*7dd7cddfSDavid du Colombier */ 167*7dd7cddfSDavid du Colombier static 168*7dd7cddfSDavid du Colombier void 169*7dd7cddfSDavid du Colombier bellipse(int y, State *s, Param *p) 170*7dd7cddfSDavid du Colombier { 171*7dd7cddfSDavid du Colombier int t, ox, oy, x, nx; 172*7dd7cddfSDavid du Colombier 173*7dd7cddfSDavid du Colombier t = p->t; 174*7dd7cddfSDavid du Colombier p->disc = allocmemimage(Rect(-t,-t,t+1,t+1), GREY1); 175*7dd7cddfSDavid du Colombier if(p->disc == nil) 176*7dd7cddfSDavid du Colombier return; 177*7dd7cddfSDavid du Colombier memfillcolor(p->disc, DTransparent); 178*7dd7cddfSDavid du Colombier memellipse(p->disc, p00, t, t, -1, memopaque, p00); 179*7dd7cddfSDavid du Colombier oy = y; 180*7dd7cddfSDavid du Colombier ox = 0; 181*7dd7cddfSDavid du Colombier nx = x = step(s); 182*7dd7cddfSDavid du Colombier do { 183*7dd7cddfSDavid du Colombier while(nx==x && y-->0) 184*7dd7cddfSDavid du Colombier nx = step(s); 185*7dd7cddfSDavid du Colombier y++; 186*7dd7cddfSDavid du Colombier eline(-x,-oy,-ox, -y, p); 187*7dd7cddfSDavid du Colombier eline(ox,-oy, x, -y, p); 188*7dd7cddfSDavid du Colombier eline(-x, y,-ox, oy, p); 189*7dd7cddfSDavid du Colombier eline(ox, y, x, oy, p); 190*7dd7cddfSDavid du Colombier ox = x+1; 191*7dd7cddfSDavid du Colombier x = nx; 192*7dd7cddfSDavid du Colombier y--; 193*7dd7cddfSDavid du Colombier oy = y; 194*7dd7cddfSDavid du Colombier } while(oy > 0); 195*7dd7cddfSDavid du Colombier } 196*7dd7cddfSDavid du Colombier 197*7dd7cddfSDavid du Colombier /* 198*7dd7cddfSDavid du Colombier * a rectangle with closed (not half-open) coordinates expressed 199*7dd7cddfSDavid du Colombier * relative to the center of the ellipse 200*7dd7cddfSDavid du Colombier */ 201*7dd7cddfSDavid du Colombier static 202*7dd7cddfSDavid du Colombier void 203*7dd7cddfSDavid du Colombier erect(int x0, int y0, int x1, int y1, Param *p) 204*7dd7cddfSDavid du Colombier { 205*7dd7cddfSDavid du Colombier Rectangle r; 206*7dd7cddfSDavid du Colombier 207*7dd7cddfSDavid du Colombier /* print("R %d,%d %d,%d\n", x0, y0, x1, y1); */ 208*7dd7cddfSDavid du Colombier r = Rect(p->c.x+x0, p->c.y+y0, p->c.x+x1+1, p->c.y+y1+1); 209*7dd7cddfSDavid du Colombier memdraw(p->dst, r, p->src, addpt(p->sp, r.min), memopaque, p00); 210*7dd7cddfSDavid du Colombier } 211*7dd7cddfSDavid du Colombier 212*7dd7cddfSDavid du Colombier /* 213*7dd7cddfSDavid du Colombier * a brushed point similarly specified 214*7dd7cddfSDavid du Colombier */ 215*7dd7cddfSDavid du Colombier static 216*7dd7cddfSDavid du Colombier void 217*7dd7cddfSDavid du Colombier epoint(int x, int y, Param *p) 218*7dd7cddfSDavid du Colombier { 219*7dd7cddfSDavid du Colombier Point p0; 220*7dd7cddfSDavid du Colombier Rectangle r; 221*7dd7cddfSDavid du Colombier 222*7dd7cddfSDavid du Colombier /* print("P%d %d,%d\n", p->t, x, y); */ 223*7dd7cddfSDavid du Colombier p0 = Pt(p->c.x+x, p->c.y+y); 224*7dd7cddfSDavid du Colombier r = Rpt(addpt(p0, p->disc->r.min), addpt(p0, p->disc->r.max)); 225*7dd7cddfSDavid du Colombier memdraw(p->dst, r, p->src, addpt(p->sp, r.min), p->disc, p->disc->r.min); 226*7dd7cddfSDavid du Colombier } 227*7dd7cddfSDavid du Colombier 228*7dd7cddfSDavid du Colombier /* 229*7dd7cddfSDavid du Colombier * a brushed horizontal or vertical line similarly specified 230*7dd7cddfSDavid du Colombier */ 231*7dd7cddfSDavid du Colombier static 232*7dd7cddfSDavid du Colombier void 233*7dd7cddfSDavid du Colombier eline(int x0, int y0, int x1, int y1, Param *p) 234*7dd7cddfSDavid du Colombier { 235*7dd7cddfSDavid du Colombier /* print("L%d %d,%d %d,%d\n", p->t, x0, y0, x1, y1); */ 236*7dd7cddfSDavid du Colombier if(x1 > x0+1) 237*7dd7cddfSDavid du Colombier erect(x0+1, y0-p->t, x1-1, y1+p->t, p); 238*7dd7cddfSDavid du Colombier else if(y1 > y0+1) 239*7dd7cddfSDavid du Colombier erect(x0-p->t, y0+1, x1+p->t, y1-1, p); 240*7dd7cddfSDavid du Colombier epoint(x0, y0, p); 241*7dd7cddfSDavid du Colombier if(x1-x0 || y1-y0) 242*7dd7cddfSDavid du Colombier epoint(x1, y1, p); 243*7dd7cddfSDavid du Colombier } 244