17dd7cddfSDavid du Colombier #include "../lib9.h" 27dd7cddfSDavid du Colombier 37dd7cddfSDavid du Colombier #include "../libdraw/draw.h" 47dd7cddfSDavid du Colombier #include "../libmemdraw/memdraw.h" 57dd7cddfSDavid du Colombier #include "../libmemlayer/memlayer.h" 67dd7cddfSDavid du Colombier 77dd7cddfSDavid du Colombier /* 87dd7cddfSDavid du Colombier * ellipse(dst, c, a, b, t, src, sp) 97dd7cddfSDavid du Colombier * draws an ellipse centered at c with semiaxes a,b>=0 107dd7cddfSDavid du Colombier * and semithickness t>=0, or filled if t<0. point sp 117dd7cddfSDavid du Colombier * in src maps to c in dst 127dd7cddfSDavid du Colombier * 137dd7cddfSDavid du Colombier * very thick skinny ellipses are brushed with circles (slow) 147dd7cddfSDavid du Colombier * others are approximated by filling between 2 ellipses 157dd7cddfSDavid du Colombier * criterion for very thick when b<a: t/b > 0.5*x/(1-x) 167dd7cddfSDavid du Colombier * where x = b/a 177dd7cddfSDavid du Colombier */ 187dd7cddfSDavid du Colombier 197dd7cddfSDavid du Colombier typedef struct Param Param; 207dd7cddfSDavid du Colombier typedef struct State State; 217dd7cddfSDavid du Colombier 227dd7cddfSDavid du Colombier static void bellipse(int, State*, Param*); 237dd7cddfSDavid du Colombier static void erect(int, int, int, int, Param*); 247dd7cddfSDavid du Colombier static void eline(int, int, int, int, Param*); 257dd7cddfSDavid du Colombier 267dd7cddfSDavid du Colombier struct Param { 277dd7cddfSDavid du Colombier Memimage *dst; 287dd7cddfSDavid du Colombier Memimage *src; 297dd7cddfSDavid du Colombier Point c; 307dd7cddfSDavid du Colombier int t; 317dd7cddfSDavid du Colombier Point sp; 327dd7cddfSDavid du Colombier Memimage *disc; 337dd7cddfSDavid du Colombier }; 347dd7cddfSDavid du Colombier 357dd7cddfSDavid du Colombier /* 367dd7cddfSDavid du Colombier * denote residual error by e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 377dd7cddfSDavid du Colombier * e(x,y) = 0 on ellipse, e(x,y) < 0 inside, e(x,y) > 0 outside 387dd7cddfSDavid du Colombier */ 397dd7cddfSDavid du Colombier 407dd7cddfSDavid du Colombier struct State { 417dd7cddfSDavid du Colombier int a; 427dd7cddfSDavid du Colombier int x; 437dd7cddfSDavid du Colombier vlong a2; /* a^2 */ 447dd7cddfSDavid du Colombier vlong b2; /* b^2 */ 457dd7cddfSDavid du Colombier vlong b2x; /* b^2 * x */ 467dd7cddfSDavid du Colombier vlong a2y; /* a^2 * y */ 477dd7cddfSDavid du Colombier vlong c1; 487dd7cddfSDavid du Colombier vlong c2; /* test criteria */ 497dd7cddfSDavid du Colombier vlong ee; /* ee = e(x+1/2,y-1/2) - (a^2+b^2)/4 */ 507dd7cddfSDavid du Colombier vlong dxe; 517dd7cddfSDavid du Colombier vlong dye; 527dd7cddfSDavid du Colombier vlong d2xe; 537dd7cddfSDavid du Colombier vlong d2ye; 547dd7cddfSDavid du Colombier }; 557dd7cddfSDavid du Colombier 567dd7cddfSDavid du Colombier static 577dd7cddfSDavid du Colombier State* 587dd7cddfSDavid du Colombier newstate(State *s, int a, int b) 597dd7cddfSDavid du Colombier { 607dd7cddfSDavid du Colombier s->x = 0; 617dd7cddfSDavid du Colombier s->a = a; 627dd7cddfSDavid du Colombier s->a2 = (vlong)(a*a); 637dd7cddfSDavid du Colombier s->b2 = (vlong)(b*b); 647dd7cddfSDavid du Colombier s->b2x = (vlong)0; 657dd7cddfSDavid du Colombier s->a2y = s->a2*(vlong)b; 667dd7cddfSDavid du Colombier s->c1 = -((s->a2>>2) + (vlong)(a&1) + s->b2); 677dd7cddfSDavid du Colombier s->c2 = -((s->b2>>2) + (vlong)(b&1)); 687dd7cddfSDavid du Colombier s->ee = -s->a2y; 697dd7cddfSDavid du Colombier s->dxe = (vlong)0; 707dd7cddfSDavid du Colombier s->dye = s->ee<<1; 717dd7cddfSDavid du Colombier s->d2xe = s->b2<<1; 727dd7cddfSDavid du Colombier s->d2ye = s->a2<<1; 737dd7cddfSDavid du Colombier return s; 747dd7cddfSDavid du Colombier } 757dd7cddfSDavid du Colombier 767dd7cddfSDavid du Colombier /* 777dd7cddfSDavid du Colombier * return x coord of rightmost pixel on next scan line 787dd7cddfSDavid du Colombier */ 797dd7cddfSDavid du Colombier static 807dd7cddfSDavid du Colombier int 817dd7cddfSDavid du Colombier step(State *s) 827dd7cddfSDavid du Colombier { 837dd7cddfSDavid du Colombier while(s->x < s->a) { 847dd7cddfSDavid du Colombier if(s->ee+s->b2x <= s->c1 || /* e(x+1,y-1/2) <= 0 */ 857dd7cddfSDavid du Colombier s->ee+s->a2y <= s->c2) { /* e(x+1/2,y) <= 0 (rare) */ 867dd7cddfSDavid du Colombier s->dxe += s->d2xe; 877dd7cddfSDavid du Colombier s->ee += s->dxe; 887dd7cddfSDavid du Colombier s->b2x += s->b2; 897dd7cddfSDavid du Colombier s->x++; 907dd7cddfSDavid du Colombier continue; 917dd7cddfSDavid du Colombier } 927dd7cddfSDavid du Colombier s->dye += s->d2ye; 937dd7cddfSDavid du Colombier s->ee += s->dye; 947dd7cddfSDavid du Colombier s->a2y -= s->a2; 957dd7cddfSDavid du Colombier if(s->ee-s->a2y <= s->c2) { /* e(x+1/2,y-1) <= 0 */ 967dd7cddfSDavid du Colombier s->dxe += s->d2xe; 977dd7cddfSDavid du Colombier s->ee += s->dxe; 987dd7cddfSDavid du Colombier s->b2x += s->b2; 997dd7cddfSDavid du Colombier return s->x++; 1007dd7cddfSDavid du Colombier } 1017dd7cddfSDavid du Colombier break; 1027dd7cddfSDavid du Colombier } 1037dd7cddfSDavid du Colombier return s->x; 1047dd7cddfSDavid du Colombier } 1057dd7cddfSDavid du Colombier 1067dd7cddfSDavid du Colombier void 1077dd7cddfSDavid du Colombier memellipse(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp) 1087dd7cddfSDavid du Colombier { 1097dd7cddfSDavid du Colombier State in, out; 1107dd7cddfSDavid du Colombier int y, inb, inx, outx, u; 1117dd7cddfSDavid du Colombier Param p; 1127dd7cddfSDavid du Colombier 1137dd7cddfSDavid du Colombier if(a < 0) 1147dd7cddfSDavid du Colombier a = -a; 1157dd7cddfSDavid du Colombier if(b < 0) 1167dd7cddfSDavid du Colombier b = -b; 1177dd7cddfSDavid du Colombier p.dst = dst; 1187dd7cddfSDavid du Colombier p.src = src; 1197dd7cddfSDavid du Colombier p.c = c; 1207dd7cddfSDavid du Colombier p.t = t; 1217dd7cddfSDavid du Colombier p.sp = subpt(sp, c); 1227dd7cddfSDavid du Colombier p.disc = nil; 1237dd7cddfSDavid du Colombier 1247dd7cddfSDavid du Colombier u = (t<<1)*(a-b); 1257dd7cddfSDavid du Colombier if((b<a && u>b*b) || (a<b && -u>a*a)) { 1267dd7cddfSDavid du Colombier /* if(b<a&&(t<<1)>b*b/a || a<b&&(t<<1)>a*a/b) # very thick */ 1277dd7cddfSDavid du Colombier bellipse(b, newstate(&in, a, b), &p); 1287dd7cddfSDavid du Colombier return; 1297dd7cddfSDavid du Colombier } 1307dd7cddfSDavid du Colombier 1317dd7cddfSDavid du Colombier if(t < 0) { 1327dd7cddfSDavid du Colombier inb = -1; 1337dd7cddfSDavid du Colombier newstate(&out, a, y = b); 1347dd7cddfSDavid du Colombier } else { 1357dd7cddfSDavid du Colombier inb = b - t; 1367dd7cddfSDavid du Colombier newstate(&out, a+t, y = b+t); 1377dd7cddfSDavid du Colombier } 1387dd7cddfSDavid du Colombier if(t > 0) 1397dd7cddfSDavid du Colombier newstate(&in, a-t, inb); 1407dd7cddfSDavid du Colombier inx = 0; 1417dd7cddfSDavid du Colombier for( ; y>=0; y--) { 1427dd7cddfSDavid du Colombier outx = step(&out); 1437dd7cddfSDavid du Colombier if(y > inb) { 1447dd7cddfSDavid du Colombier erect(-outx, y, outx, y, &p); 145*59cc4ca5SDavid du Colombier if(y != 0) 1467dd7cddfSDavid du Colombier erect(-outx, -y, outx, -y, &p); 1477dd7cddfSDavid du Colombier continue; 1487dd7cddfSDavid du Colombier } 1497dd7cddfSDavid du Colombier if(t > 0) { 1507dd7cddfSDavid du Colombier inx = step(&in); 1517dd7cddfSDavid du Colombier if(y == inb) 1527dd7cddfSDavid du Colombier inx = 0; 1537dd7cddfSDavid du Colombier } else if(inx > outx) 1547dd7cddfSDavid du Colombier inx = outx; 1557dd7cddfSDavid du Colombier erect(inx, y, outx, y, &p); 156*59cc4ca5SDavid du Colombier if(y != 0) 1577dd7cddfSDavid du Colombier erect(inx, -y, outx, -y, &p); 1587dd7cddfSDavid du Colombier erect(-outx, y, -inx, y, &p); 159*59cc4ca5SDavid du Colombier if(y != 0) 1607dd7cddfSDavid du Colombier erect(-outx, -y, -inx, -y, &p); 1617dd7cddfSDavid du Colombier inx = outx + 1; 1627dd7cddfSDavid du Colombier } 1637dd7cddfSDavid du Colombier } 1647dd7cddfSDavid du Colombier 1657dd7cddfSDavid du Colombier static Point p00 = {0, 0}; 1667dd7cddfSDavid du Colombier 1677dd7cddfSDavid du Colombier /* 1687dd7cddfSDavid du Colombier * a brushed ellipse 1697dd7cddfSDavid du Colombier */ 1707dd7cddfSDavid du Colombier static 1717dd7cddfSDavid du Colombier void 1727dd7cddfSDavid du Colombier bellipse(int y, State *s, Param *p) 1737dd7cddfSDavid du Colombier { 1747dd7cddfSDavid du Colombier int t, ox, oy, x, nx; 1757dd7cddfSDavid du Colombier 1767dd7cddfSDavid du Colombier t = p->t; 1777dd7cddfSDavid du Colombier p->disc = allocmemimage(Rect(-t,-t,t+1,t+1), GREY1); 1787dd7cddfSDavid du Colombier if(p->disc == nil) 1797dd7cddfSDavid du Colombier return; 1807dd7cddfSDavid du Colombier memfillcolor(p->disc, DTransparent); 1817dd7cddfSDavid du Colombier memellipse(p->disc, p00, t, t, -1, memopaque, p00); 1827dd7cddfSDavid du Colombier oy = y; 1837dd7cddfSDavid du Colombier ox = 0; 1847dd7cddfSDavid du Colombier nx = x = step(s); 1857dd7cddfSDavid du Colombier do { 1867dd7cddfSDavid du Colombier while(nx==x && y-->0) 1877dd7cddfSDavid du Colombier nx = step(s); 1887dd7cddfSDavid du Colombier y++; 1897dd7cddfSDavid du Colombier eline(-x,-oy,-ox, -y, p); 1907dd7cddfSDavid du Colombier eline(ox,-oy, x, -y, p); 1917dd7cddfSDavid du Colombier eline(-x, y,-ox, oy, p); 1927dd7cddfSDavid du Colombier eline(ox, y, x, oy, p); 1937dd7cddfSDavid du Colombier ox = x+1; 1947dd7cddfSDavid du Colombier x = nx; 1957dd7cddfSDavid du Colombier y--; 1967dd7cddfSDavid du Colombier oy = y; 1977dd7cddfSDavid du Colombier } while(oy > 0); 1987dd7cddfSDavid du Colombier } 1997dd7cddfSDavid du Colombier 2007dd7cddfSDavid du Colombier /* 2017dd7cddfSDavid du Colombier * a rectangle with closed (not half-open) coordinates expressed 2027dd7cddfSDavid du Colombier * relative to the center of the ellipse 2037dd7cddfSDavid du Colombier */ 2047dd7cddfSDavid du Colombier static 2057dd7cddfSDavid du Colombier void 2067dd7cddfSDavid du Colombier erect(int x0, int y0, int x1, int y1, Param *p) 2077dd7cddfSDavid du Colombier { 2087dd7cddfSDavid du Colombier Rectangle r; 2097dd7cddfSDavid du Colombier 2107dd7cddfSDavid du Colombier /* print("R %d,%d %d,%d\n", x0, y0, x1, y1); */ 2117dd7cddfSDavid du Colombier r = Rect(p->c.x+x0, p->c.y+y0, p->c.x+x1+1, p->c.y+y1+1); 2127dd7cddfSDavid du Colombier memdraw(p->dst, r, p->src, addpt(p->sp, r.min), memopaque, p00); 2137dd7cddfSDavid du Colombier } 2147dd7cddfSDavid du Colombier 2157dd7cddfSDavid du Colombier /* 2167dd7cddfSDavid du Colombier * a brushed point similarly specified 2177dd7cddfSDavid du Colombier */ 2187dd7cddfSDavid du Colombier static 2197dd7cddfSDavid du Colombier void 2207dd7cddfSDavid du Colombier epoint(int x, int y, Param *p) 2217dd7cddfSDavid du Colombier { 2227dd7cddfSDavid du Colombier Point p0; 2237dd7cddfSDavid du Colombier Rectangle r; 2247dd7cddfSDavid du Colombier 2257dd7cddfSDavid du Colombier /* print("P%d %d,%d\n", p->t, x, y); */ 2267dd7cddfSDavid du Colombier p0 = Pt(p->c.x+x, p->c.y+y); 2277dd7cddfSDavid du Colombier r = Rpt(addpt(p0, p->disc->r.min), addpt(p0, p->disc->r.max)); 2287dd7cddfSDavid du Colombier memdraw(p->dst, r, p->src, addpt(p->sp, r.min), p->disc, p->disc->r.min); 2297dd7cddfSDavid du Colombier } 2307dd7cddfSDavid du Colombier 2317dd7cddfSDavid du Colombier /* 2327dd7cddfSDavid du Colombier * a brushed horizontal or vertical line similarly specified 2337dd7cddfSDavid du Colombier */ 2347dd7cddfSDavid du Colombier static 2357dd7cddfSDavid du Colombier void 2367dd7cddfSDavid du Colombier eline(int x0, int y0, int x1, int y1, Param *p) 2377dd7cddfSDavid du Colombier { 2387dd7cddfSDavid du Colombier /* print("L%d %d,%d %d,%d\n", p->t, x0, y0, x1, y1); */ 2397dd7cddfSDavid du Colombier if(x1 > x0+1) 2407dd7cddfSDavid du Colombier erect(x0+1, y0-p->t, x1-1, y1+p->t, p); 2417dd7cddfSDavid du Colombier else if(y1 > y0+1) 2427dd7cddfSDavid du Colombier erect(x0-p->t, y0+1, x1+p->t, y1-1, p); 2437dd7cddfSDavid du Colombier epoint(x0, y0, p); 2447dd7cddfSDavid du Colombier if(x1-x0 || y1-y0) 2457dd7cddfSDavid du Colombier epoint(x1, y1, p); 2467dd7cddfSDavid du Colombier } 247