31059016e90d9d6d65e11f55808869efacb8d4e2 kate Tue Apr 10 18:16:17 2018 -0700 Add postscript for ellipse drawing. refs #21109 diff --git src/lib/pscmGfx.c src/lib/pscmGfx.c index 2234994..9d8c9ac 100644 --- src/lib/pscmGfx.c +++ src/lib/pscmGfx.c @@ -8,32 +8,30 @@ #ifdef MACHTYPE_sparc #include int isinf(double x) { return !finite(x) && x==x; } #endif #include "common.h" #include "hash.h" #include "memgfx.h" #include "gfxPoly.h" #include "colHash.h" #include "psGfx.h" #include "pscmGfx.h" #include "gemfont.h" #include "vGfx.h" #include "vGfxPrivate.h" - - static struct pscmGfx *boxPscm; /* Used to keep from drawing the same box again * and again with no other calls between. This * ends up cutting down the file size by 5x * in the whole chromosome case of the browser. */ void pscmSetHint(struct pscmGfx *pscm, char *hint, char *value) /* set a hint */ { if (!value) return; if (sameString(value,"")) { hashRemove(pscm->hints, hint); } struct hashEl *el = hashLookup(pscm->hints, hint); if (el) @@ -89,31 +87,30 @@ void pscmUnclip(struct pscmGfx *pscm) /* Set clipping rect to cover full thing. */ { pscmSetClip(pscm, 0, 0, pscm->ps->userWidth, pscm->ps->userHeight); } int pscmFindColorIx(struct pscmGfx *pscm, int r, int g, int b) /* Returns closest color in color map to rgb values. If it doesn't * already exist in color map and there's room, it will create * exact color in map. */ { return MAKECOLOR_32(r,g,b); } - struct rgbColor pscmColorIxToRgb(struct pscmGfx *pscm, int colorIx) /* Return rgb value at color index. */ { static struct rgbColor rgb; rgb.r = (colorIx >> 0) & 0xff; rgb.g = (colorIx >> 8) & 0xff; rgb.b = (colorIx >> 16) & 0xff; return rgb; } void pscmSetWriteMode(struct pscmGfx *pscm, unsigned int writeMode) /* Set write mode */ { pscm->writeMode = writeMode; @@ -210,32 +207,30 @@ lx = x; ly = y; lw = width; lh = height; lc = color; boxPscm = pscm; } } void pscmDot(struct pscmGfx *pscm, int x, int y, int color) /* Set a dot. */ { pscmBox(pscm, x, y, 1, 1, color); } - - static void pscmVerticalSmear(struct pscmGfx *pscm, int xOff, int yOff, int width, int height, Color *dots, boolean zeroClear) /* Put a series of one 'pixel' width vertical lines. */ { int x, i; struct psGfx *ps = pscm->ps; Color c; for (i=0; iptList) break; double m1 = gfxSlope(q,p); if (!(isinf(m0) && isinf(m1)) && (m1 != m0)) return FALSE; } return TRUE; } double fatPixel(double c, double center, double fat) /* fatten coordinate by scaling */ { return center+((c-center)*fat); } - void pscmPolyFatten(struct psPoly *psPoly, int minX, int maxX, int minY, int maxY) /* Fatten polygon by finding the center and then * scaling by 0.5 pixel from the center in all directions. * Caller assures dx and dy will NOT be zero. */ { int dx = maxX - minX; int dy = maxY - minY; double centerX = (maxX + minX) / 2.0; double centerY = (maxY + minY) / 2.0; double fatX = (dx + 1.0)/dx; double fatY = (dy + 1.0)/dy; struct psPoint *p = psPoly->ptList; for (;;) { @@ -593,31 +587,30 @@ psPolyAddPoint(inner,px0, py0); psPolyAddPoint(inner,px1, py1); psPolyAddPoint(inner,ix1, iy1); psPolyAddPoint(inner,ix0, iy0); psDrawPoly(pscm->ps, inner, TRUE); psPolyFree(&inner); px0 = px1; py0 = py1; px1 = p->x; py1 = p->y; p = p->next; if (p == q) break; } - } void pscmDrawPoly(struct pscmGfx *pscm, struct gfxPoly *poly, Color color, boolean filled) /* Draw a polygon, possibly filled, in color. */ { struct gfxPoint *p = poly->ptList; struct psPoly *psPoly = psPolyNew(); int minX, maxX, minY, maxY; if (poly->ptCount < 1) /* nothing to do */ { return; } psPolyFindExtremes(poly, &minX, &maxX, &minY, &maxY); /* check for co-linear polygon, render as line instead */ @@ -633,103 +626,121 @@ psPolyAddPoint(psPoly,p->x, p->y); p = p->next; if (p == poly->ptList) break; } boolean fat = sameString(pscmGetHint(pscm,"fat"),"on"); if (fat) pscmPolyFatten(psPoly, minX, maxX, minY, maxY); if (fat && !filled) pscmPolyTrapStrokeOutline(pscm,psPoly); else psDrawPoly(pscm->ps, psPoly, filled); psPolyFree(&psPoly); } - - void pscmFatLine(struct pscmGfx *pscm, double x1, double y1, double x2, double y2) /* Draw a line from x1/y1 to x2/y2 by making a filled polygon. * This also avoids some problems with stroke-width variation * from different postscript implementations. */ { struct psPoly *psPoly = psPolyNew(); double cX = (x1+x2)/2.0; double cY = (y1+y2)/2.0; double fX; double fY; /* fatten by lengthing line by 0.5 at each end */ fX = fY = 1.0+0.5*sqrt(0.5); /* expand the length of the line by a half-pixel on each end */ x1 = fatPixel(x1,cX,fX); x2 = fatPixel(x2,cX,fX); y1 = fatPixel(y1,cY,fY); y2 = fatPixel(y2,cY,fY); - /* calculate 4 corners {h,i,j,k} of the rectangle covered */ double m = (y2 - y1)/(x2 - x1); m = -1/m; /* rotate slope 90 degrees */ double ddX = sqrt( (0.5*0.5) / (m*m+1) ); double ddY = m * ddX; double hX = x1-ddX, hY = y1-ddY; double iX = x1+ddX, iY = y1+ddY; double jX = x2+ddX, jY = y2+ddY; double kX = x2-ddX, kY = y2-ddY; psPolyAddPoint(psPoly,hX,hY); psPolyAddPoint(psPoly,iX,iY); psPolyAddPoint(psPoly,jX,jY); psPolyAddPoint(psPoly,kX,kY); psDrawPoly(pscm->ps, psPoly, TRUE); psPolyFree(&psPoly); } - void pscmLine(struct pscmGfx *pscm, int x1, int y1, int x2, int y2, int color) /* Draw a line from one point to another. */ { pscmSetColor(pscm, color); boolean fat = sameString(pscmGetHint(pscm,"fat"),"on"); if (fat) pscmFatLine(pscm, x1, y1, x2, y2); else psDrawLine(pscm->ps, x1, y1, x2, y2); boxPscm = NULL; } +void pscmEllipse(struct pscmGfx *pscm, + int x1, int y1, int x2, int y2, int color, int mode, boolean isDashed) +/* Draw an ellipse specified as a rectangle. Args are left-most and top-most points. + * Optionally draw half-ellipse (top or bottom) */ +{ +pscmSetColor(pscm, color); +if (isDashed) + psSetDash(pscm->ps, TRUE); +else + psSetDash(pscm->ps, FALSE); +int startAngle = 0; +int endAngle = 360; +if (mode == ELLIPSE_TOP) + endAngle = 180; +else if (mode == ELLIPSE_BOTTOM) + startAngle = 180; +psDrawEllipse(pscm->ps, (double)x2, 0.0, (double)x2 - (double)x1, (double)y2, + startAngle, endAngle); +//warn("drawing ellipse: center: (%d,%d), xrad: %d, yrad=%d", x2, 0, x2-x1, y2); +psSetDash(pscm->ps, FALSE); +} struct vGfx *vgOpenPostScript(int width, int height, char *fileName) /* Open up something that will someday be a PostScript file. */ { struct vGfx *vg = vgHalfInit(width, height); vg->data = pscmOpen(width, height, fileName); vg->close = (vg_close)pscmClose; vg->dot = (vg_dot)pscmDot; vg->box = (vg_box)pscmBox; vg->line = (vg_line)pscmLine; vg->text = (vg_text)pscmText; vg->textRight = (vg_textRight)pscmTextRight; vg->textCentered = (vg_textCentered)pscmTextCentered; vg->findColorIx = (vg_findColorIx)pscmFindColorIx; vg->colorIxToRgb = (vg_colorIxToRgb)pscmColorIxToRgb; vg->setClip = (vg_setClip)pscmSetClip; vg->unclip = (vg_unclip)pscmUnclip; vg->verticalSmear = (vg_verticalSmear)pscmVerticalSmear; vg->fillUnder = (vg_fillUnder)pscmFillUnder; vg->drawPoly = (vg_drawPoly)pscmDrawPoly; +vg->ellipse = (vg_ellipse)pscmEllipse; vg->setHint = (vg_setHint)pscmSetHint; vg->getHint = (vg_getHint)pscmGetHint; vg->getFontPixelHeight = (vg_getFontPixelHeight)pscmGetFontPixelHeight; vg->getFontStringWidth = (vg_getFontStringWidth)pscmGetFontStringWidth; vg->setWriteMode = (vg_setWriteMode)pscmSetWriteMode; return vg; }