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 <ieeefp.h>
 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; i<width; ++i)
     {
     x = xOff + i;
     c = dots[i];
     if (c != MG_WHITE || !zeroClear)
 	{
 	pscmSetColor(pscm, c);
@@ -346,31 +341,30 @@
     if (p == poly->ptList)
 	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;
 }