fb0d415d29a5786b48478ef7fb87b8adc8d8af61
kent
  Sun Feb 17 10:51:11 2013 -0800
Changing way transparency is done so that it shows up in PDF, and also can be normalized when we add more cell lines.
diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c
index 922462f..a63eb4a 100644
--- src/hg/hgTracks/wigTrack.c
+++ src/hg/hgTracks/wigTrack.c
@@ -5,30 +5,31 @@
 #include "common.h"
 #include "obscure.h"
 #include "hash.h"
 #include "linefile.h"
 #include "jksql.h"
 #include "hdb.h"
 #include "hgTracks.h"
 #include "wiggle.h"
 #include "hmmstats.h"
 #include "scoredRef.h"
 #ifndef GBROWSE
 #include "customTrack.h"
 #endif /* GBROWSE */
 #include "wigCommon.h"
 #include "imageV2.h"
+#include "memgfx.h"
 
 
 struct wigItem
 /* A wig track item. */
     {
     struct wigItem *next;
     int start, end;	/* Start/end in chrom (aka browser) coordinates. */
     char *db;		/* Database */
     int ix;		/* Position in list. */
     int height;		/* Pixel height of item. */
     unsigned span;      /* each value spans this many bases */
     unsigned count;     /* number of values to use */
     unsigned offset;    /* offset in File to fetch data */
     char *file; /* path name to data file, one byte per value */
     double lowerLimit;  /* lowest data value in this block */
@@ -777,68 +778,99 @@
 	    colorArray[x1] = tg->ixColor;
 	}
     }
 
 /* Fill in colors from alternate track if necessary. */
 if (colorTrack != NULL)
     {
     struct track *cTrack = hashMustFindVal(trackHash, colorTrack);
 
     wigFillInColorArray(tg, hvg, colorArray, width, cTrack);
     }
 
 return colorArray;
 }
 
-void graphPreDraw(struct preDrawElement *preDraw, int preDrawZero, int width,
-    struct track *tg, struct hvGfx *hvg, int xOff, int yOff,
+void vLineViaHvg(void *image, int x, int y, int height, Color color)
+/* A vertical line drawer that works via hvGfx system. */
+{
+hvGfxBox(image, x, y, 1, height, color);
+}
+
+Color somewhatLighterColor32(Color color)
+/* Get a somewhat lighter shade of a color - 1/3 of the way towards white. 
+ * Specialized here to bypass image parameter requirement.*/
+{
+#ifndef COLOR32
+#error COLOR32 must be defined these days, transparency depends on it.
+#endif /* COLOR32 */
+struct rgbColor rgbColor =  mgColorIxToRgb(NULL, color);
+rgbColor.r = (2*rgbColor.r+255)/3;
+rgbColor.g = (2*rgbColor.g+255)/3;
+rgbColor.b = (2*rgbColor.b+255)/3;
+return MAKECOLOR_32(rgbColor.r, rgbColor.g, rgbColor.b);
+}
+
+struct wigGraphOutput *wigGraphOutputSolid(int xOff, int yOff, struct hvGfx *image)
+/* Get appropriate wigGraphOutput for non-transparent rendering */
+{
+struct wigGraphOutput *wgo;
+AllocVar(wgo);
+wgo->image = image;
+wgo->vLine = vLineViaHvg;
+wgo->xOff = xOff;
+wgo->yOff = yOff;
+return wgo;
+}
+
+static void graphPreDraw(struct preDrawElement *preDraw, int preDrawZero, int width,
+    struct track *tg, void *image, WigVerticalLineVirtual vLine, int xOff, int yOff,
     double graphUpperLimit, double graphLowerLimit, double graphRange,
     double epsilon, Color *colorArray, enum trackVisibility vis,
     struct wigCartOptions *wigCart)
 /*	graph the preDraw array */
 {
 int x1;
 int h = tg->lineHeight;	/*	the height of our drawing window */
 double scaleFactor = h/graphRange;
 Color oldDrawColor = colorArray[0] + 1;	/* Just to be different from 1st drawColor. */
 Color mediumColor = MG_BLACK;	// Will be overriden
 Color lightColor = MG_BLACK;	// Will be overriden
 Color clipColor = MG_MAGENTA;
 enum wiggleTransformFuncEnum transformFunc = wigCart->transformFunc;
 enum wiggleGraphOptEnum lineBar = wigCart->lineBar;
 boolean whiskers = (wigCart->windowingFunction == wiggleWindowingWhiskers
 			&& width < winEnd-winStart);
 
 /*	right now this is a simple pixel by pixel loop.  Future
  *	enhancements could draw boxes where pixels
  *	are all the same height in a run.
  */
 for (x1 = 0; x1 < width; ++x1)
     {
     int x = x1 + xOff;
     int preDrawIndex = x1 + preDrawZero;
     struct preDrawElement *p = &preDraw[preDrawIndex];
 
     Color drawColor = colorArray[x1];
     if (drawColor != oldDrawColor)
         {
-	mediumColor = somewhatLighterColor(hvg, drawColor);
-	lightColor = somewhatLighterColor(hvg, mediumColor);
+	mediumColor = somewhatLighterColor32(drawColor);
+	lightColor = somewhatLighterColor32(mediumColor);
 	oldDrawColor = drawColor;
         }
 
-
     /*	count is non-zero meaning valid data exists here	*/
     if (p->count)
 	{
 	/*	data value has been picked by previous scanning.
 	 *	Could be smoothed, maybe not.
 	 */
 	double dataValue = p->smooth;
 
 	/*	The graphing coordinate conversion situation is:
 	 *	graph coordinate y = 0 is graphUpperLimit data space
 	 *	and total graph height is h which is graphRange in data space
 	 *	The Y axis is positive down, negative up.
 	 *
 	 *	Taking a simple coordinate conversion from data space
 	 *	to the graphing space, the data value is at:
@@ -867,34 +899,34 @@
 		        {
 			int scaledMin = scaleHeightToPixels(doTransform(p->min, transformFunc));
 			int lightHeight = max(1,scaledMin-zeroPos);
 			int mediumHeight = lightHeight;
 			if (!isnan(std))
 			    { // Test needed due to bug in version 1.5 bigWiles
 			    double minus = doTransform(mean - std, transformFunc);
 			    int scaledMinus = scaleHeightToPixels(minus);
 			    mediumHeight = max(1,scaledMinus-zeroPos);
 			    }
 			int darkHeight = max(1,scaledVal-zeroPos);
 			if (zeroPos == (yOff+h))  // bottom pixel special case
 			    zeroPos -= 1;
 		        if (((zeroPos-yOff)+darkHeight) == 0)
 			    darkHeight += 1;	  // top pixel special case
-			hvGfxBox(hvg, x,zeroPos,1, darkHeight, drawColor);
-                        hvGfxBox(hvg, x, zeroPos+darkHeight, 1, mediumHeight-darkHeight,
+			vLine(image, x,zeroPos, darkHeight, drawColor);
+                        vLine(image, x, zeroPos+darkHeight, mediumHeight-darkHeight,
 				mediumColor);
-                        hvGfxBox(hvg, x, zeroPos+mediumHeight,1, lightHeight-mediumHeight,
+                        vLine(image, x, zeroPos+mediumHeight, lightHeight-mediumHeight,
 				lightColor);
 			}
 		    else
 		        {
                         /* The calculations here are a little convoluted because
                          * of the history.  Originally it drew from the baseline
                          * up to the max first in the lightest color, then from the
                          * baseline to the mean+std in medium color, and finally
                          * from baseline to mean in dark color.  This ended up
                          * drawing the same pixels up to three times which messed
                          * things up in transparent overlay mode.   The code was
                          * refactored to accomplish this without having to worry
                          * about +/- 1 differences.   In particular be aware the
                          * xyzHeight calculations are done assuming the other end is
                          * the baseline. */
@@ -914,121 +946,118 @@
 			    double plus = doTransform(mean + std, transformFunc);
 			    int scaledPlus = scaleHeightToPixels(plus);
 			    int boxHeight = max(1,zeroPos-scaledPlus);
 			    mediumTop = scaledPlus, mediumHeight = boxHeight;
 			    }
 
 			/* Calculate light part from max. */
 			int scaledMax = scaleHeightToPixels(doTransform(p->max, transformFunc));
 			if (scaledMax == (h+yOff))
                             scaledMax = (h+yOff) - 1;
                         boxHeight = max(1,zeroPos-scaledMax);
                         int lightTop = scaledMax, lightHeight = boxHeight;
 
                         /* Draw, making sure not to overwrite pixels since
                          * would mess up transparent drawing. */
-                        hvGfxBox(hvg,x,darkTop,1, darkHeight, drawColor);
-			hvGfxBox(hvg, x, mediumTop, 1, mediumHeight-darkHeight, mediumColor);
-			hvGfxBox(hvg,x,lightTop,1,lightHeight-mediumHeight, lightColor);
+                        vLine(image,x,darkTop, darkHeight, drawColor);
+			vLine(image, x, mediumTop, mediumHeight-darkHeight, mediumColor);
+			vLine(image,x,lightTop,lightHeight-mediumHeight, lightColor);
 			}
 		    }
 		else
 		    {
 		    int y0 = graphUpperLimit * scaleFactor;
 		    int y1 = (graphUpperLimit - dataValue)*scaleFactor;
 
 		    int boxHeight = max(1,abs(y1 - y0));
 		    int boxTop = min(y1,y0);
 
 		    //	positive data value exactly equal to Bottom pixel
 		    //  make sure it draws at least a pixel there
 		    if (boxTop == h)
 			boxTop = h - 1;
 
 		    // negative data value exactly equal to top pixel
 		    // make sure it draws something
 		    if ((boxTop+boxHeight) == 0)
 			boxHeight += 1;
-		    hvGfxBox(hvg,x, yOff+boxTop, 1, boxHeight, drawColor);
+		    vLine(image,x, yOff+boxTop, boxHeight, drawColor);
 		    }
 		}
 	    else
 		{	/*	draw a 3 pixel height box	*/
 		if (whiskers)
 		    {
 		    int scaledMin = scaleHeightToPixels(doTransform(p->min, transformFunc));
 		    int scaledMax = scaleHeightToPixels(doTransform(p->max, transformFunc));
 		    double mean = p->sumData/p->count;
 		    int boxHeight = max(1,scaledMin - scaledMax);
-		    hvGfxBox(hvg, x, scaledMax, 1, boxHeight, lightColor);
+		    vLine(image, x, scaledMax, boxHeight, lightColor);
 		    int scaledMean = scaleHeightToPixels(dataValue);
 		    double std = calcStdFromSums(p->sumData, p->sumSquares, p->count);
 		    if (!isnan(std))  // Test needed because of bug in version 1.5 bigWiles
 			{
 			int scaledPlus = scaleHeightToPixels(doTransform(mean+std, transformFunc));
 			int scaledMinus = scaleHeightToPixels(doTransform(mean-std, transformFunc));
 			int boxHeight = max(1,scaledMinus - scaledPlus);
-			hvGfxBox(hvg, x, scaledPlus, 1, boxHeight, mediumColor);
+			vLine(image, x, scaledPlus, boxHeight, mediumColor);
 			}
-		    hvGfxBox(hvg, x, scaledMean, 1, 1, drawColor);
+		    vLine(image, x, scaledMean, 1, drawColor);
 		    }
 		else
 		    {
 		    int yPointGraph = scaleHeightToPixels(dataValue) - 1;
-		    hvGfxBox(hvg, x, yPointGraph, 1, 3, drawColor);
+		    vLine(image, x, yPointGraph, 3, drawColor);
 		    }
 		}
 	    if (dataValue > graphUpperLimit)
-		hvGfxBox(hvg, x, yOff, 1, 2, clipColor);
+		vLine(image, x, yOff, 2, clipColor);
 	    else if (dataValue < graphLowerLimit)
-		hvGfxBox(hvg, x, yOff + h - 1, 1, 2, clipColor);
+		vLine(image, x, yOff + h - 1, 2, clipColor);
 #undef scaleHeightToPixels	/* No longer use this symbol */
             }   /*	vis == tvFull || vis == tvPack */
         else if (vis == tvDense || vis == tvSquish)
 	    {
 	    double grayValue;
 	    int grayIndex;
 	    /* honor the viewLimits, data below is white, data above is black */
 	    grayValue = max(dataValue,graphLowerLimit);
 	    grayValue = min(grayValue,graphUpperLimit);
 	    grayIndex = ((grayValue-graphLowerLimit)/graphRange)*MAX_WIG_VALUE;
 
 	    drawColor =
 		tg->colorShades[grayInRange(grayIndex, 0, MAX_WIG_VALUE)];
-	    hvGfxBox(hvg, x, yOff, 1, tg->lineHeight, drawColor);
+	    vLine(image, x, yOff, tg->lineHeight, drawColor);
             }   /*	vis == tvDense || vis == tvSquish	*/
 	}	/*	if (preDraw[].count)	*/
     }	/*	for (x1 = 0; x1 < width; ++x1)	*/
 }	/*	graphPreDraw()	*/
 
-static void graphAllInContainer(struct preDrawContainer *preDrawList, int preDrawZero, int width,
-    struct track *tg, struct hvGfx *hvg, int xOff, int yOff,
-    double graphUpperLimit, double graphLowerLimit, double graphRange,
-    enum trackVisibility vis, struct wigCartOptions *wigCart)
+static void graphPreDrawContainer(struct preDrawContainer *preDrawContainer, 
+    int preDrawZero, int width, struct track *tg, struct hvGfx *hvg, 
+    int xOff, int yOff, double graphUpperLimit, double graphLowerLimit, 
+    double graphRange, enum trackVisibility vis, struct wigCartOptions *wigCart)
 /* Draw the graphs for all tracks in container. */
 {
 double epsilon = graphRange / tg->lineHeight;
-struct preDrawElement *preDraw = preDrawList->preDraw;
+struct preDrawElement *preDraw = preDrawContainer->preDraw;
 Color *colorArray = makeColorArray(preDraw, width, preDrawZero, wigCart, tg, hvg);
-struct preDrawContainer *preContainer;
-for(preContainer = preDrawList; preContainer; preContainer = preContainer->next)
-    {
-    struct preDrawElement *preDraw = preContainer->preDraw;
+struct wigGraphOutput *wgo = tg->wigGraphOutput;
     graphPreDraw(preDraw, preDrawZero, width,
-	tg, hvg, xOff, yOff, graphUpperLimit, graphLowerLimit, graphRange,
+	tg, wgo->image, wgo->vLine, wgo->xOff, wgo->yOff, 
+	graphUpperLimit, graphLowerLimit, graphRange,
 	epsilon, colorArray, vis, wigCart);
-    }
 
 freez(&colorArray);
 }
 
 
 void drawZeroLine(enum trackVisibility vis,
     enum wiggleGridOptEnum horizontalGrid,
     double graphUpperLimit, double graphLowerLimit,
     struct hvGfx *hvg, int xOff, int yOff, int width, int lineHeight)
 /*	draw a line at y=0 on the graph	*/
 {
 /*	Do we need to draw a zero line ?
  *	This is to be generalized in the future to allow horizontal grid
  *	lines, perhaps user specified to indicate thresholds.
  */
@@ -1133,119 +1162,107 @@
     Span = ptToInt(el->val);
     if ((Span < basesPerPixel) && (Span > usingDataSpan))
 	usingDataSpan = Span;
     if (Span < minimalSpan)
 	minimalSpan = Span;
     }
 hashElFreeList(&elList);
 
 /*	There may not be a span of 1, use whatever is lowest	*/
 if (minimalSpan > usingDataSpan)
     usingDataSpan = minimalSpan;
 
 return usingDataSpan;
 }
 
+void wigTrackSetGraphOutputDefault(struct track *tg, int xOff, int yOff, struct hvGfx *hvg)
+/* Set up to draw on hvg if no other destination set already */
+{
+if (tg->wigGraphOutput == NULL)
+    tg->wigGraphOutput = wigGraphOutputSolid(xOff, yOff, hvg);
+}
+
 void wigDrawPredraw(struct track *tg, int seqStart, int seqEnd,
                     struct hvGfx *hvg, int xOff, int yOff, int width,
                     MgFont *font, Color color, enum trackVisibility vis,
-                    struct preDrawContainer *preDrawList, int preDrawZero,
+                    struct preDrawContainer *preContainer, int preDrawZero,
                     int preDrawSize, double *retGraphUpperLimit, double *retGraphLowerLimit)
 /* Draw once we've figured out predraw (numerical values to graph) we draw it here.
  * This code is shared by wig, bigWig, and bedGraph drawers. */
 {
+wigTrackSetGraphOutputDefault(tg, xOff, yOff, hvg);
 enum wiggleYLineMarkEnum yLineOnOff;
 double yLineMark;
 
 /*	determined from data	*/
 double overallUpperLimit = wigEncodeStartingUpperLimit;
 double overallLowerLimit = wigEncodeStartingLowerLimit;
 double overallRange=0;		/*	determined from data	*/
 double graphUpperLimit=0;	/*	scaling choice will set these	*/
 double graphLowerLimit=0;	/*	scaling choice will set these	*/
 double graphRange=0;		/*	scaling choice will set these	*/
 double epsilon;			/*	range of data in one pixel	*/
 struct wigCartOptions *wigCart = (struct wigCartOptions *) tg->extraUiData;
 
 yLineOnOff = wigCart->yLineOnOff;
 yLineMark = wigCart->yLineMark;
 
 /*	width - width of drawing window in pixels
  *	pixelsPerBase - pixels per base
  *	basesPerPixel - calculated as 1.0/pixelsPerBase
  */
 
-struct preDrawContainer *preContainer;
-
-/* loop through all the preDraw containers */
-for(preContainer = preDrawList; preContainer; preContainer = preContainer->next)
-    {
     struct preDrawElement *preDraw = preContainer->preDraw;
     double thisOverallUpperLimit;
     double thisOverallLowerLimit;
     double thisGraphUpperLimit;
     double thisGraphLowerLimit;
 
     preDrawWindowFunction(preDraw, preDrawSize, wigCart->windowingFunction,
 	    wigCart->transformFunc);
     preDrawSmoothing(preDraw, preDrawSize, wigCart->smoothingWindow);
     overallRange = preDrawLimits(preDraw, preDrawZero, width,
 	&thisOverallUpperLimit, &thisOverallLowerLimit);
     graphRange = preDrawAutoScale(preDraw, preDrawZero, width,
 	wigCart->autoScale,
 	&thisOverallUpperLimit, &thisOverallLowerLimit,
 	&thisGraphUpperLimit, &thisGraphLowerLimit,
 	&overallRange, &epsilon, tg->lineHeight,
 	wigCart->maxY, wigCart->minY, wigCart->alwaysZero);
 
-    if (preContainer == preDrawList) // first time through
-	{
-	overallUpperLimit = thisOverallUpperLimit;
-	overallLowerLimit = thisOverallLowerLimit;
-	graphUpperLimit = thisGraphUpperLimit;
-	graphLowerLimit = thisGraphLowerLimit;
-	}
-    else
-	{
-	if (overallUpperLimit < thisOverallUpperLimit)
 	    overallUpperLimit = thisOverallUpperLimit;
-	if (overallLowerLimit > thisOverallLowerLimit)
 	    overallLowerLimit = thisOverallLowerLimit;
-	if (graphUpperLimit < thisGraphUpperLimit)
 	    graphUpperLimit = thisGraphUpperLimit;
-	if (graphLowerLimit > thisGraphLowerLimit)
 	    graphLowerLimit = thisGraphLowerLimit;
-	}
-    }
 
 overallRange = overallUpperLimit - overallLowerLimit;
 
 /* if we're autoscaling and the range is 0 this implies that all values 
  * in the given range are the same.  We create a bottom of the scale  
  * by subtracting one from the only value.
  * This results in drawing a box that fills the range. */
 if ((graphUpperLimit == graphLowerLimit))
     {
     graphRange = 1.0;
     graphLowerLimit = graphUpperLimit - 1;
     }
 else
     {
     graphRange = graphUpperLimit - graphLowerLimit;
     }
 
-graphAllInContainer(preDrawList, preDrawZero, width, tg, hvg, xOff, yOff, 
+graphPreDrawContainer(preContainer, preDrawZero, width, tg, hvg, xOff, yOff, 
     graphUpperLimit, graphLowerLimit, graphRange, vis, wigCart);
 
 drawZeroLine(vis, wigCart->horizontalGrid,
     graphUpperLimit, graphLowerLimit,
     hvg, xOff, yOff, width, tg->lineHeight);
 
 drawArbitraryYLine(vis, wigCart->yLineOnOff,
     graphUpperLimit, graphLowerLimit,
     hvg, xOff, yOff, width, tg->lineHeight, wigCart->yLineMark, graphRange,
     wigCart->yLineOnOff);
 
 wigMapSelf(tg, hvg, seqStart, seqEnd, xOff, yOff, width);
 
 if (retGraphUpperLimit != NULL)
     *retGraphUpperLimit = graphUpperLimit;