66ee7c172964fe9665479973fa7c7536afe03fa2 kate Tue Apr 10 22:05:33 2018 -0700 Add Postscript for bezier curve. Fix ellipse. refs #21109 diff --git src/hg/lib/hvGfx.c src/hg/lib/hvGfx.c index 97a40a7..6ef915e 100644 --- src/hg/lib/hvGfx.c +++ src/hg/lib/hvGfx.c @@ -221,62 +221,30 @@ gfxPolyAddPoint(t1, x+w/2, y+h); gfxPolyAddPoint(t2, x+w/2, y+h/2); gfxPolyAddPoint(t2, x+w, y); gfxPolyAddPoint(t2, x+w, y+h); } /* The two filled triangles. */ vgDrawPoly(hvg->vg, t1, hvgColor, TRUE); vgDrawPoly(hvg->vg, t2, hvgColor, TRUE); /* The two outline triangles. */ vgDrawPoly(hvg->vg, t1, color, FALSE); vgDrawPoly(hvg->vg, t2, color, FALSE); gfxPolyFree(&t1); gfxPolyFree(&t2); } -/* from memgfx.c and vPng.c*/ - -struct memPng -/* Something that handles a PNG. */ - { - struct memGfx mg; /* Memory form. This needs to be first field. */ - char *fileName; /* PNG file name. */ - boolean useTransparency; /* Make background color transparent if TRUE. */ - }; - -#define _mgBpr(mg) ((mg)->width) -#define _mgPixAdr(mg,x,y) ((mg)->pixels+_mgBpr(mg) * (y) + (x)) - -INLINE void mixDot(struct hvGfx *hvg, int x, int y, float frac, Color col) -/* Puts a single dot on the image, mixing it with what is already there - * based on the frac argument. */ -{ -struct memPng *png = (struct memPng *)hvg->vg->data; -struct memGfx *img = (struct memGfx *)png; -if ((x < img->clipMinX) || (x > img->clipMaxX) || (y < img->clipMinY) || (y > img->clipMaxY)) - return; - -Color *pt = _mgPixAdr(img,x,y); -float invFrac = 1 - frac; - -int r = COLOR_32_RED(*pt) * invFrac + COLOR_32_RED(col) * frac; -int g = COLOR_32_GREEN(*pt) * invFrac + COLOR_32_GREEN(col) * frac; -int b = COLOR_32_BLUE(*pt) * invFrac + COLOR_32_BLUE(col) * frac; -hvGfxDot(hvg, x, y, MAKECOLOR_32(r,g,b)); -hvGfxDot(hvg, x, y, MAKECOLOR_32(r,g,b)); -} - void hvGfxDottedLine(struct hvGfx *hvg, int x1, int y1, int x2, int y2, Color color, boolean isDash) /* Brezenham line algorithm, alternating dots, by 1 pixel or two (isDash true) */ { int duty_cycle; int incy; int delta_x, delta_y; int dots; int dotFreq = (isDash ? 3 : 2); delta_y = y2-y1; delta_x = x2-x1; if (delta_y < 0) { delta_y = -delta_y; incy = -1; } @@ -313,129 +281,15 @@ dots = delta_y+1; while (--dots >= 0) { if (dots % dotFreq) hvGfxDot(hvg,x1,y1,color); duty_cycle += delta_x; y1+=incy; if (duty_cycle > 0) { duty_cycle -= delta_y; /* update duty cycle */ x1 += 1; } } } } - -int hvGfxCurveSegAA(struct hvGfx *hvg, int x0, int y0, int x1, int y1, int x2, int y2, - Color color, boolean isDashed) -/* Draw a segment of an anti-aliased curve within 3 points (quadratic Bezier) - * Return max y value. Optionally alternate dots. - * Adapted trivially from code posted on github and at http://members.chello.at/~easyfilter/bresenham.html */ - /* Thanks to author * @author Zingl Alois - * @date 22.08.2016 */ -{ - int yMax = 0; - int sx = x2-x1, sy = y2-y1; - long xx = x0-x1, yy = y0-y1, xy; /* relative values for checks */ - double dx, dy, err, ed, cur = xx*sy-yy*sx; /* curvature */ - - assert(xx*sx <= 0 && yy*sy <= 0); /* sign of gradient must not change */ - - if (sx*(long)sx+sy*(long)sy > xx*xx+yy*yy) { /* begin with longer part */ - x2 = x0; x0 = sx+x1; y2 = y0; y0 = sy+y1; cur = -cur; /* swap P0 P2 */ - } - if (cur != 0) - { /* no straight line */ - xx += sx; xx *= sx = x0 < x2 ? 1 : -1; /* x step direction */ - yy += sy; yy *= sy = y0 < y2 ? 1 : -1; /* y step direction */ - xy = 2*xx*yy; xx *= xx; yy *= yy; /* differences 2nd degree */ - if (cur*sx*sy < 0) { /* negated curvature? */ - xx = -xx; yy = -yy; xy = -xy; cur = -cur; - } - dx = 4.0*sy*(x1-x0)*cur+xx-xy; /* differences 1st degree */ - dy = 4.0*sx*(y0-y1)*cur+yy-xy; - xx += xx; yy += yy; err = dx+dy+xy; /* error 1st step */ - int dots = 0; - do { - cur = fmin(dx+xy,-xy-dy); - ed = fmax(dx+xy,-xy-dy); /* approximate error distance */ - ed += 2*ed*cur*cur/(4*ed*ed+cur*cur); - if (!isDashed || (++dots % 3)) - { - mixDot(hvg, x0,y0, 1-fabs(err-dx-dy-xy)/ed, color); /* plot curve */ - if (y0 > yMax) - yMax = y0; - } - if (x0 == x2 || y0 == y2) break; /* last pixel -> curve finished */ - x1 = x0; cur = dx-err; y1 = 2*err+dy < 0; - if (2*err+dx > 0) { /* x step */ - if (err-dy < ed) - { - mixDot(hvg, x0,y0+sy, 1-fabs(err-dy)/ed, color); - if (y0 > yMax) - yMax = y0; - } - x0 += sx; dx -= xy; err += dy += yy; - } - if (y1) { /* y step */ - if (cur < ed) - { - mixDot(hvg, x1+sx,y0, 1-fabs(cur)/ed, color); - if (y0 > yMax) - yMax = y0; - } - y0 += sy; dy -= xy; err += dx += xx; - } - } while (dy < dx); /* gradient negates -> close curves */ - } - hvGfxLine(hvg, x0,y0, x2,y2, color); /* plot remaining needle to end */ - if (y0 > yMax) - yMax = y0; - return yMax; -} - -int hvGfxCurve(struct hvGfx *hvg, int x0, int y0, int x1, int y1, int x2, int y2, - Color color, boolean isDashed) -/* Draw a segment of an anti-aliased curve within 3 points (quadratic Bezier) - * Return max y value. Optionally alternate dots. - * Adapted trivially from code posted at http://members.chello.at/~easyfilter/bresenham.html - */ -/* TODO: allow specifying a third point on the line - * P(t) = (1-t)^2 * p0 + 2 * (1-t) * t * p1 + t^2 * p2 - */ -{ - int x = x0-x1, y = y0-y1; - double t = x0-2*x1+x2, r; - int yMax = 0, yMaxRet = 0; - if ((long)x*(x2-x1) > 0) { /* horizontal cut at P4? */ - if ((long)y*(y2-y1) > 0) /* vertical cut at P6 too? */ - if (fabs((y0-2*y1+y2)/t*x) > abs(y)) { /* which first? */ - x0 = x2; x2 = x+x1; y0 = y2; y2 = y+y1; /* swap points */ - } /* now horizontal cut at P4 comes first */ - t = (x0-x1)/t; - r = (1-t)*((1-t)*y0+2.0*t*y1)+t*t*y2; /* By(t=P4) */ - t = (x0*x2-x1*x1)*t/(x0-x1); /* gradient dP4/dx=0 */ - x = floor(t+0.5); y = floor(r+0.5); - r = (y1-y0)*(t-x0)/(x1-x0)+y0; /* intersect P3 | P0 P1 */ - yMax = hvGfxCurveSegAA(hvg,x0,y0, x,floor(r+0.5), x,y, color, isDashed); - r = (y1-y2)*(t-x2)/(x1-x2)+y2; /* intersect P4 | P1 P2 */ - x0 = x1 = x; y0 = y; y1 = floor(r+0.5); /* P0 = P4, P1 = P8 */ - } - if ((long)(y0-y1)*(y2-y1) > 0) { /* vertical cut at P6? */ - t = y0-2*y1+y2; t = (y0-y1)/t; - r = (1-t)*((1-t)*x0+2.0*t*x1)+t*t*x2; /* Bx(t=P6) */ - t = (y0*y2-y1*y1)*t/(y0-y1); /* gradient dP6/dy=0 */ - x = floor(r+0.5); y = floor(t+0.5); - r = (x1-x0)*(t-y0)/(y1-y0)+x0; /* intersect P6 | P0 P1 */ - yMaxRet = hvGfxCurveSegAA(hvg,x0,y0, floor(r+0.5),y, x,y, color, isDashed); - if (yMaxRet > yMax) - yMax = yMaxRet; - r = (x1-x2)*(t-y2)/(y1-y2)+x2; /* intersect P7 | P1 P2 */ - x0 = x; x1 = floor(r+0.5); y0 = y1 = y; /* P0 = P6, P1 = P7 */ - } - yMaxRet = hvGfxCurveSegAA(hvg,x0,y0, x1,y1, x2,y2, color, isDashed); /* remaining part */ - if (yMaxRet > yMax) - yMax = yMaxRet; - return yMax; -} -