static int psdist(Point p, Point a, Point b) { int num, den; p = subpt(p, a); b = subpt(b, a); num = p.x*b.x + p.y*b.y; if(num <= 0) return normsq(p); den = normsq(b); if(num >= den) return normsq(subpt(b, p)); return normsq(subpt(divpt(mulpt(b, num), den), p)); }
static void _bezsplinepts(Plist *l, Point *pt, int npt) { Point *p, *ep; Point a, b, c, d; int periodic; if(npt<3) return; ep = &pt[npt-3]; periodic = eqpt(pt[0], ep[2]); if(periodic){ a = divpt(addpt(ep[1], pt[0]), 2); b = divpt(addpt(ep[1], mulpt(pt[0], 5)), 6); c = divpt(addpt(mulpt(pt[0], 5), pt[1]), 6); d = divpt(addpt(pt[0], pt[1]), 2); bpts(l, a, b, c, d); } for(p=pt; p<=ep; p++){ if(p==pt && !periodic){ a = p[0]; b = divpt(addpt(p[0], mulpt(p[1], 2)), 3); } else{ a = divpt(addpt(p[0], p[1]), 2); b = divpt(addpt(p[0], mulpt(p[1], 5)), 6); } if(p==ep && !periodic){ c = divpt(addpt(mulpt(p[1], 2), p[2]), 3); d = p[2]; } else{ c = divpt(addpt(mulpt(p[1], 5), p[2]), 6); d = divpt(addpt(p[1], p[2]), 2); } bpts(l, a, b, c, d); } appendpt(l, d); }
/* * Convert cubic Bezier curve control points to polyline * vertices. Leaves the last vertex off, so you can continue * with another curve. */ static void bpts1(Plist *l, Point p0, Point p1, Point p2, Point p3, int scale) { Point p01, p12, p23, p012, p123, p0123; Point tp0, tp1, tp2, tp3; tp0=divpt(p0, scale); tp1=divpt(p1, scale); tp2=divpt(p2, scale); tp3=divpt(p3, scale); if(psdist(tp1, tp0, tp3)<=1 && psdist(tp2, tp0, tp3)<=1){ appendpt(l, tp0); appendpt(l, tp1); appendpt(l, tp2); } else{ /* * if scale factor is getting too big for comfort, * rescale now & concede the rounding error */ if(scale>(1<<12)){ p0=tp0; p1=tp1; p2=tp2; p3=tp3; scale=1; } p01=addpt(p0, p1); p12=addpt(p1, p2); p23=addpt(p2, p3); p012=addpt(p01, p12); p123=addpt(p12, p23); p0123=addpt(p012, p123); bpts1(l, mulpt(p0, 8), mulpt(p01, 4), mulpt(p012, 2), p0123, scale*8); bpts1(l, p0123, mulpt(p123, 2), mulpt(p23, 4), mulpt(p3, 8), scale*8); } }
/* * make a "wedge" mask covering the desired angle and contained in * a surrounding square; draw a full ellipse; intersect that with the * wedge to make a mask through which to copy src to dst. */ void memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op) { int i, w, beta, tmp, c1, c2, m, m1; Rectangle rect; Point p, bnd[8]; Memimage *wedge, *figure, *mask; if(a < 0) a = -a; if(b < 0) b = -b; w = t; if(w < 0) w = 0; alpha = -alpha; /* compensate for upside-down coords */ phi = -phi; beta = alpha + phi; if(phi < 0){ tmp = alpha; alpha = beta; beta = tmp; phi = -phi; } if(phi >= 360){ memellipse(dst, c, a, b, t, src, sp, op); return; } while(alpha < 0) alpha += 360; while(beta < 0) beta += 360; c1 = alpha/90 & 3; /* number of nearest corner */ c2 = beta/90 & 3; /* * icossin returns point at radius ICOSSCALE. * multiplying by m1 moves it outside the ellipse */ rect = Rect(-a-w, -b-w, a+w+1, b+w+1); m = rect.max.x; /* inradius of bounding square */ if(m < rect.max.y) m = rect.max.y; m1 = (m+ICOSSCALE-1) >> 10; m = m1 << 10; /* assure m1*cossin is inside */ i = 0; bnd[i++] = Pt(0,0); icossin(alpha, &p.x, &p.y); bnd[i++] = mulpt(p, m1); for(;;) { bnd[i++] = mulpt(corners[c1], m); if(c1==c2 && phi<180) break; c1 = (c1+1) & 3; phi -= 90; } icossin(beta, &p.x, &p.y); bnd[i++] = mulpt(p, m1); figure = nil; mask = nil; wedge = allocmemimage(rect, GREY1); if(wedge == nil) goto Return; memfillcolor(wedge, DTransparent); memfillpoly(wedge, bnd, i, ~0, memopaque, p00, S); figure = allocmemimage(rect, GREY1); if(figure == nil) goto Return; memfillcolor(figure, DTransparent); memellipse(figure, p00, a, b, t, memopaque, p00, S); mask = allocmemimage(rect, GREY1); if(mask == nil) goto Return; memfillcolor(mask, DTransparent); memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S); c = subpt(c, dst->r.min); memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(p00, c), op); Return: freememimage(wedge); freememimage(figure); freememimage(mask); }