61b8f9bb3cd7d2b67e8c698c9657efd6df58b309 hiram Thu Nov 12 20:52:14 2020 -0800 better isolation of the mouseOver calculations refs #21980 diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c index f73de33..2784455 100644 --- src/hg/hgTracks/wigTrack.c +++ src/hg/hgTracks/wigTrack.c @@ -867,75 +867,76 @@ struct wigCartOptions *wigCart, struct pixelCountBin *pixelBins) /* 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); +boolean skipMouseOvers = FALSE; /* start new data for a new track, freez old data if exists */ if (enableMouseOver) { if (mouseOverData) { mouseOverIdx = -1; freez(&mouseOverData); } AllocArray(mouseOverData, width); } - -int mouseOverX2 = -1; -double previousValue = 0; -boolean skipMouseOvers = FALSE; -#define epsilonLimit 1.0e-6 +else + skipMouseOvers = TRUE; /* 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]; /* ===== mouseOver calculations===== */ if (enableMouseOver) { + int mouseOverX2 = -1; + double previousValue = 0; if (!skipMouseOvers && (p->count > 0)) /* checking mouseOver construction */ { if (p->count > 0) /* allow any number of values to display */ { double thisValue = p->sumData/p->count; /* average if 2 */ if (mouseOverX2 < 0) /* first valid data found */ { ++mouseOverIdx; mouseOverX2 = x1+1; mouseOverData[mouseOverIdx].x1 = x1; mouseOverData[mouseOverIdx].x2 = mouseOverX2; mouseOverData[mouseOverIdx].value = thisValue; mouseOverData[mouseOverIdx].valueCount = p->count; previousValue = thisValue; } else /* see if we need a new item */ { +#define epsilonLimit 1.0e-6 if (fabs(thisValue - previousValue) > epsilonLimit) { /* finish off the existing run of data */ mouseOverData[mouseOverIdx].x2 = mouseOverX2; mouseOverX2 = x1+1; ++mouseOverIdx; mouseOverData[mouseOverIdx].x1 = x1; mouseOverData[mouseOverIdx].x2 = mouseOverX2; mouseOverData[mouseOverIdx].value = thisValue; mouseOverData[mouseOverIdx].valueCount = p->count; previousValue = thisValue; } else /* continue run of same data value */ mouseOverX2 = x1+1; } @@ -1590,57 +1591,63 @@ * * The data to be drawn: to be read from file f at offset wi->Offset * data points available: wi->Count, representing wi->Span bases * for each data point * * The drawing window, in pixels: * xOff = left margin, yOff = top margin, h = height of drawing window * drawing window in chrom coords: seqStart, seqEnd * 'basesPerPixel' is known, 'pixelsPerBase' is known */ /* let's check end point screen coordinates. If they are * the same, then this entire data block lands on one pixel, * no need to walk through it, just use the block's specified * max/min. It is OK if these end up + or - values, we do want to * keep track of pixels before and after the screen for - * later smoothing operations. + * later smoothing operations. x1d,x2d are pixel coordinates */ double x1d = (double)(wi->start - seqStart) * pixelsPerBase; - x1 = round(x1d); double x2d = (double)((wi->start+(wi->count * usingDataSpan))-seqStart) * pixelsPerBase; - x2 = round(x2d); /* this used to be if (x2 > x1) which often caused reading of blocks * when they were merely x2 = x1 + 1 due to rounding errors as * they became integers. This double comparison for something over * 0.5 will account for rounding errors that are really small, but * still handle a slipping window size as it walks across the screen */ if ((x2d - x1d) > 0.5) { unsigned char *readData; /* the bytes read in from the file */ udcSeek(wibFH, wi->offset); readData = (unsigned char *) needMem((size_t) (wi->count + 1)); udcRead(wibFH, readData, (size_t) wi->count * (size_t) sizeof(unsigned char)); - /* walk through all the data in this block */ + /* walk through all the data in this wiggle data block */ for (dataOffset = 0; dataOffset < wi->count; ++dataOffset) { unsigned char datum = readData[dataOffset]; if (datum != WIG_NO_DATA) { + /* (wi->start-seqStart) == base where this wiggle data block + * begins. Add to that (dataOffset * usingDataSpan) which + * is how many bases this specific datum is from the start + * of this wiggle data block. + * x1,x2 are the pixel begin and end for this data item */ x1 = ((wi->start-seqStart) + (dataOffset * usingDataSpan)) * pixelsPerBase; + /* (usingDataSpan * pixelsPerBase) is the number of pixels + * occupied by this one data item + */ x2 = x1 + (usingDataSpan * pixelsPerBase); for (i = x1; i <= x2; ++i) { int xCoord = preDrawZero + i; if ((xCoord >= 0) && (xCoord < preDrawSize)) { double dataValue = BIN_TO_VALUE(datum,wi->lowerLimit,wi->dataRange); ++preDraw[xCoord].count; if (dataValue > preDraw[xCoord].max) preDraw[xCoord].max = dataValue; if (dataValue < preDraw[xCoord].min) preDraw[xCoord].min = dataValue; preDraw[xCoord].sumData += dataValue;