beb83a212f64459820772f85f7369a55b567a25c braney Sat Feb 5 14:59:24 2011 -0800 add some code to draw snakes which will be used to draw Benedict's cactus graphs in ancestrla root browsers diff --git src/hg/hgTracks/snakeTrack.c src/hg/hgTracks/snakeTrack.c new file mode 100644 index 0000000..de97348 --- /dev/null +++ src/hg/hgTracks/snakeTrack.c @@ -0,0 +1,917 @@ +/* chainTrack - stuff to load and display chain type tracks in + * browser. Chains are typically from cross-species genomic + * alignments. */ + +#include "common.h" +#include "hash.h" +#include "localmem.h" +#include "linefile.h" +#include "jksql.h" +#include "hdb.h" +#include "hgTracks.h" +#include "chainBlock.h" +#include "chainLink.h" +#include "chainDb.h" +#include "chainCart.h" + +static char const rcsid[] = "$Id: chainTrack.c,v 1.27 2006/02/23 01:41:31 baertsch Exp $"; + + +struct cartOptions + { + enum chainColorEnum chainColor; /* ChromColors, ScoreColors, NoColors */ + int scoreFilter ; /* filter chains by score if > 0 */ + }; + +static void doQuery(struct sqlConnection *conn, char *fullName, + struct lm *lm, struct hash *hash, + int start, int end, boolean isSplit, int chainId) +/* doQuery- check the database for chain elements between + * start and end. Use the passed hash to resolve chain + * id's and place the elements into the right + * linkedFeatures structure + */ +{ +struct sqlResult *sr = NULL; +char **row; +struct linkedFeatures *lf; +struct simpleFeature *sf; +struct dyString *query = newDyString(1024); +char *force = ""; + +if (isSplit) + force = "force index (bin)"; + +if (chainId == -1) + dyStringPrintf(query, + "select chainId,tStart,tEnd,qStart from %sLink %s where ", + fullName, force); +else + dyStringPrintf(query, + "select chainId, tStart,tEnd,qStart from %sLink where chainId=%d and ", + fullName, chainId); +if (!isSplit) + dyStringPrintf(query, "tName='%s' and ", chromName); +hAddBinToQuery(start, end, query); +dyStringPrintf(query, "tStart<%u and tEnd>%u", end, start); +sr = sqlGetResult(conn, query->string); + +/* Loop through making up simple features and adding them + * to the corresponding linkedFeature. */ +//printf("read chain\n"); +while ((row = sqlNextRow(sr)) != NULL) + { + lf = hashFindVal(hash, row[0]); + if (lf != NULL) + { + struct chain *pChain = lf->extra; + lmAllocVar(lm, sf); + sf->start = sqlUnsigned(row[1]); + sf->end = sqlUnsigned(row[2]); + sf->qStart = sqlUnsigned(row[3]); + + sf->qEnd = sf->qStart + (sf->end - sf->start); + if ((pChain) && pChain->qStrand == '-') + { + int temp; + + temp = sf->qStart; + sf->qStart = pChain->qSize - sf->qEnd; + sf->qEnd = pChain->qSize - temp; + } + //printf("%d \n",sf->qStart); + sf->grayIx = lf->orientation; + slAddHead(&lf->components, sf); + } + } +sqlFreeResult(&sr); +dyStringFree(&query); +} + +int snakeItemHeight(struct track *tg, void *item) +{ +//printf("snakeItemHeight\n"); +//return 40; +struct linkedFeatures *lf = (struct linkedFeatures *)item; +struct simpleFeature *sf; +int s, e; +int lineHeight = tg->lineHeight ; +int oldOrient = 0; +int tStart, tEnd; +int size = lineHeight; +//int count = 0; +tStart = 0; +tEnd = 0; +for (sf = lf->components; sf ; sf = sf->next) + { + int orient = sf->grayIx; + + s = sf->start; e = sf->end; + /* + if ((e < winStart) || (s > winEnd)) + continue; + if (s < winStart) s = winStart; + */ + //printf("bounds %d %d\n",winStart, winEnd); + + if (((oldOrient) && (oldOrient != orient)) + || ((oldOrient == 1) && (tEnd) && (s < tEnd)) + || ((oldOrient == -1) && (tStart) && (e > tStart))) + { + //printf("plus \n"); + size += lineHeight; + } + oldOrient = orient; + tEnd = e; + tStart = s; + } +//printf("snakeItemHieght %d\n",size); +return size; +} + +static int linkedFeaturesCmpScore(const void *va, const void *vb) +/* Help sort linkedFeatures by starting pos. */ +{ +const struct linkedFeatures *a = *((struct linkedFeatures **)va); +const struct linkedFeatures *b = *((struct linkedFeatures **)vb); +if (a->score > b->score) + return -1; +else if (a->score < b->score) + return 1; +return 0; +} + +void snakeDraw(struct track *tg, int seqStart, int seqEnd, + struct hvGfx *hvg, int xOff, int yOff, int width, + MgFont *font, Color color, enum trackVisibility vis) +/* Draw linked features items. */ +{ +struct slList *item; +int y; +struct linkedFeatures *lfStart = (struct linkedFeatures *)tg->items; +struct linkedFeatures *lf; +//int lineHeight = tg->lineHeight; +double scale = scaleForWindow(width, seqStart, seqEnd); + +//printf("snakeDraw "); +for(lf = lfStart; lf; lf = lf->next) + { + struct simpleFeature *sf; + + lf->score = 0; + for (sf = lf->components; sf != NULL; sf = sf->next) + { + lf->score += sf->end - sf->start; + } + } + +slSort(&tg->items, linkedFeaturesCmpScore); + + +y = yOff; +for (item = tg->items; item != NULL; item = item->next) + { + if(tg->itemColor != NULL) + color = tg->itemColor(tg, item, hvg); + tg->drawItemAt(tg, item, hvg, xOff, y, scale, font, color, vis); + y += tg->itemHeight(tg, item); +// break; + } +} + +void snakeLeftLabels(struct track *tg, int seqStart, int seqEnd, + struct hvGfx *hvg, int xOff, int yOff, int width, int height, + boolean withCenterLabels, MgFont *font, Color color, + enum trackVisibility vis) +{ +} + +void snakeDrawAt(struct track *tg, void *item, + struct hvGfx *hvg, int xOff, int y, double scale, + MgFont *font, Color color, enum trackVisibility vis) +/* Draw a single simple bed item at position. */ +{ +//printf("snakeDrawAt %d %d %g \n",xOff, y, scale); +//return; +struct linkedFeatures *lf = (struct linkedFeatures *)item; +struct simpleFeature *sf, *prevSf; +int s, e; +int heightPer = tg->heightPer; +int lineHeight = tg->lineHeight ; +int oldOrient = 0; +int tStart, tEnd, qStart; +int lastQEnd = 0; +int midY; +int qs, qe; +//int prevStart; +//int count = 0; +qStart = 0; +tStart = xOff; +tEnd = winEnd; +prevSf = NULL; + +//printf("snakeDrawAt\n"); +//prevStart = 0; +//for (sf = lf->components; sf != NULL; prevStart = sf->qStart,prevSf = sf, sf = sf->next) + //printf("%d \n",sf->qStart - prevStart); +qe = lastQEnd = 0; +for (sf = lf->components; sf != NULL; lastQEnd = qe, prevSf = sf, sf = sf->next) + { + int orient = sf->grayIx; + midY = y + heightPer/2; + + qs = sf->qStart; + s = sf->start; e = sf->end; + if (qs < lastQEnd ) + continue; + + qe = sf->qEnd; + if ((e < winStart) || (s > winEnd)) + continue; + + if (s < winStart) s = winStart; + //printf("bounds %d %d\n",winStart, winEnd); + + if (((oldOrient) && (oldOrient != orient)) + || ((oldOrient == 1) && (tEnd) && (s < tEnd)) + || ((oldOrient == -1) && (tStart) && (e > tStart))) + { + //printf("one\n"); + if ((qStart) && (sf->qStart - qStart) < 500000) + { + //printf("three\n"); + if (oldOrient == 1) + { + //printf("four\n"); + if ((orient == -1) && (tEnd < sf->start)) + { + int x1, x2, x3, w; + + //printf("five\n"); + x1 = round((double)((int)tEnd-winStart)*scale) + xOff; + x2 = round((double)((int)e-winStart)*scale) + xOff + 8; + x3 = round((double)((int)sf->end-winStart)*scale) + xOff; + w = x2-x1; + hvGfxLine(hvg, x1, y, x2, y, color); + hvGfxLine(hvg, x1, midY, x2, midY, color); + hvGfxLine(hvg, x2, lineHeight + midY, x2, midY, color); + hvGfxLine(hvg, x2, lineHeight+midY, x3, lineHeight+midY, color); + //innerLine(vg, x2, midY, 1, color); + clippedBarbs(hvg, x1, midY, w, tl.barbHeight, tl.barbSpacing, + oldOrient, color, FALSE); + clippedBarbs(hvg, x3, midY + lineHeight, x2-x3, tl.barbHeight, tl.barbSpacing, + orient, color, FALSE); + } + else if ((orient == -1) && (tEnd > sf->start)) + { + int x1, x2, x3, w; + + //printf("siz\n"); + x1 = round((double)((int)tEnd-winStart)*scale) + xOff; + x2 = round((double)((int)tEnd-winStart)*scale) + xOff + 8; + x3 = round((double)((int)sf->end-winStart)*scale) + xOff; + w = x2-x1; + hvGfxLine(hvg, x1, midY, x2, midY, color); + hvGfxLine(hvg, x2, lineHeight + midY, x2, midY, color); + hvGfxLine(hvg, x2, lineHeight+midY, x3, lineHeight+midY, color); + //innerLine(vg, x2, midY, 1, color); + clippedBarbs(hvg, x1, midY, w+1, tl.barbHeight, tl.barbSpacing, + oldOrient, color, FALSE); + clippedBarbs(hvg, x3, midY + lineHeight, x2-x3+1, tl.barbHeight, tl.barbSpacing, + orient, color, FALSE); + } + else if ((orient == 1) && (s < tEnd)) + { + int x1, x2, x3,x4, w; + + //printf("seven\n"); + x1 = round((double)((int)tEnd-winStart)*scale) + xOff; + x2 = round((double)((int)tEnd-winStart)*scale) + xOff + 8; + x3 = round((double)((int)s-winStart)*scale) + xOff - 8; + x4 = round((double)((int)s-winStart)*scale) + xOff; + w = x2-x1; + hvGfxLine(hvg, x1, midY, x2, midY, color); + hvGfxBox(hvg, x2, midY-2, 4, 4, color); + //hvGfxLine(vg, x2, lineHeight + midY, x2, midY, color); + //hvGfxLine(vg, x2, lineHeight + midY, x3, lineHeight+midY, color); + //hvGfxLine(vg, x3, lineHeight + midY, x3, 2*lineHeight+midY, color); + //hvGfxLine(vg, x2, midY, x3, lineHeight+midY, color); + //hvGfxLine(vg, x3, 2*lineHeight + midY, x4, 2*lineHeight+midY, color); + hvGfxBox(hvg, x3 - 4, midY-2 + lineHeight, 4, 4, color); + hvGfxLine(hvg, x3, lineHeight + midY, x4, lineHeight+midY, color); + //y += lineHeight; + //innerLine(vg, x2, midY, 1, color); + clippedBarbs(hvg, x1, midY, w+1, tl.barbHeight, tl.barbSpacing, + oldOrient, color, FALSE); + //clippedBarbs(vg, x3, midY + lineHeight, x2-x3+1, tl.barbHeight, tl.barbSpacing, + //-1 , color, FALSE); + if (x3 > x4) + printf("oops\n"); + clippedBarbs(hvg, x3, midY + lineHeight, x4-x3+1, tl.barbHeight, tl.barbSpacing, + orient , color, FALSE); + //clippedBarbs(vg, x3, midY + 2* lineHeight, x4-x3+1, tl.barbHeight, tl.barbSpacing, + //orient , color, FALSE); + } + } + else if (oldOrient == -1) + { + if ((orient == 1) && (tStart >= sf->start)) + { + int x1, x2, x3, w; + + //printf("gook\n"); + x1 = round((double)((int)tStart-winStart)*scale) + xOff; + x2 = round((double)((int)sf->start-winStart)*scale) + xOff - 8; + x3 = round((double)((int)sf->start-winStart)*scale) + xOff; + w = x1 - x2; + hvGfxLine(hvg, x1, midY, x2, midY, color); + hvGfxLine(hvg, x2, lineHeight + midY, x2, midY, color); + hvGfxLine(hvg, x2, lineHeight+midY, x3, lineHeight+midY, color); + //innerLine(vg, x2, midY, 1, color); + clippedBarbs(hvg, x2, midY, w, tl.barbHeight, tl.barbSpacing, + oldOrient, color, FALSE); + clippedBarbs(hvg, x2, lineHeight+midY, x3-x2+1, tl.barbHeight, tl.barbSpacing, + orient, color, FALSE); + } + else if ((orient == 1) && (tStart < sf->start)) + { + int x1, x2, x3, w; + + //printf("grook\n"); + x1 = round((double)((int)tStart-winStart)*scale) + xOff; + x2 = round((double)((int)tStart-winStart)*scale) + xOff - 8; + x3 = round((double)((int)sf->start-winStart)*scale) + xOff; + w = x1-x2; + hvGfxLine(hvg, x1, midY, x2, midY, color); + hvGfxLine(hvg, x2, lineHeight + midY, x2, midY, color); + hvGfxLine(hvg, x2, lineHeight+midY, x3, lineHeight+midY, color); + //innerLine(vg, x2, midY, 1, color); + clippedBarbs(hvg, x2, midY, w, tl.barbHeight, tl.barbSpacing, + oldOrient, color, FALSE); + if (x3 < x2) + printf("oops\n"); + clippedBarbs(hvg, x2, midY + lineHeight, x3-x2, tl.barbHeight, tl.barbSpacing, + orient, color, FALSE); + } + else if ((orient == -1) && (e > sf->start)) + { + int x1, x2, x3,x4, w; + + //printf("tStart %d e %d sf %d %d\n",tStart,e,sf->start,sf->end); + //printf("loop\n"); + x1 = round((double)((int)tStart-winStart)*scale) + xOff; + x2 = round((double)((int)tStart-winStart)*scale) + xOff - 8; + x3 = round((double)((int)e-winStart)*scale) + xOff + 8; + x4 = round((double)((int)e-winStart)*scale) + xOff; + w = x1-x2; + hvGfxLine(hvg, x1, midY, x2, midY, color); + hvGfxBox(hvg, x2, midY-2, 4, 4, color); + //hvGfxLine(vg, x2, lineHeight + midY, x2, midY, color); + //hvGfxLine(vg, x2, lineHeight + midY, x3, lineHeight+midY, color); + //hvGfxLine(vg, x3, lineHeight + midY, x3, 2*lineHeight+midY, color); + hvGfxLine(hvg, x3, lineHeight + midY, x4, lineHeight+midY, color); + hvGfxBox(hvg, x3, lineHeight + midY-2, 4, 4, color); + //y += lineHeight; + //innerLine(vg, x2, midY, 1, color); + clippedBarbs(hvg, x2, midY, w+1, tl.barbHeight, tl.barbSpacing, + oldOrient, color, FALSE); + //clippedBarbs(vg, x2, midY + lineHeight, x3-x2+1, tl.barbHeight, tl.barbSpacing, + //1 , color, FALSE); + if (x4 > x3) + printf("oops\n"); + clippedBarbs(hvg, x4, midY + lineHeight, x3-x4+1, tl.barbHeight, tl.barbSpacing, + oldOrient , color, FALSE); + } + } + else + printf("eat me\n"); + } + //else + //printf("sf %d qStart %d \n",sf->qStart,qStart); + + y += lineHeight; + } + else if ((oldOrient) && ((qStart) && (sf->qStart - qStart) < 500000)) + { + //printf("two\n"); + int x1, x2, w; + + x1 = round((double)((int)tEnd-winStart)*scale) + xOff; + x2 = round((double)((int)sf->start -winStart)*scale) + xOff; + hvGfxLine(hvg, x1, midY, x2, midY, color); + if (x2 > x1) + { + w = x2-x1; + clippedBarbs(hvg, x1, midY, w+1, tl.barbHeight, tl.barbSpacing, + oldOrient, color, FALSE); + } + else + { + w = x1-x2; + clippedBarbs(hvg, x2, midY, w+1, tl.barbHeight, tl.barbSpacing, + oldOrient, color, FALSE); + } + } + //printf("sf %d %d\n",s - tStart,e -tStart); + //printf("sfq %d %d\n",sf->qStart, sf->qEnd); + //if(tg->itemColor != NULL) + color = lfChromColor(tg, item, hvg); + + drawScaledBoxSample(hvg, s, e, scale, xOff, y, heightPer, + color, lf->score ); + tEnd = e; + tStart = s; + qStart = sf->qStart; + oldOrient = orient; + //if (++count == 5) + //break; + } +//linkedFeaturesDrawAt(tg, item, vg, xOff, y, scale, font, color, vis); +} + +static int simpleFeatureCmpQStart(const void *va, const void *vb) +{ +const struct simpleFeature *a = *((struct simpleFeature **)va); +const struct simpleFeature *b = *((struct simpleFeature **)vb); +int diff = a->qStart - b->qStart; + +if (diff == 0) + { + diff = a->start - b->start; + } + +return diff; +} + +static int linkedFeaturesCmpChrom(const void *va, const void *vb) +/* Help sort linkedFeatures by starting pos. */ +{ +const struct linkedFeatures *a = *((struct linkedFeatures **)va); +const struct linkedFeatures *b = *((struct linkedFeatures **)vb); +return strcmp(a->name, b->name); +} + +int snakeHeight(struct track *tg, enum trackVisibility vis) +/* set up size of sequence logo */ +{ +//printf("snakeHeight\n"); +//return 50; +int height = 0; +struct slList *item = tg->items, *nextItem; +struct linkedFeatures *firstLf, *lf = (struct linkedFeatures *)tg->items; +struct simpleFeature *sf, *nextSf; + +//tg->drawItems = snakeDraw; + + +slSort(&tg->items, linkedFeaturesCmpChrom); + +item = tg->items; + +lf = (struct linkedFeatures *)tg->items; +//item = NULL; +if (item) +{ +firstLf = lf; +//printf("orient %d %c |\n",lf->orientation,lf->orientation); +for (;item; item = nextItem) + { + struct linkedFeatures *lf = (struct linkedFeatures *)item; +// slAddTail(&firstSf, lf->components); + nextItem = item->next; + //printf("orient %d %c |\n",lf->orientation,lf->orientation); + if (!sameString(firstLf->name, lf->name)) + { + //printf("name %s %s\n",firstLf->name, lf->name); + slSort(&firstLf->components, simpleFeatureCmpQStart); + firstLf = lf; + } + for (sf = lf->components; sf != NULL; sf = nextSf) + { + sf->grayIx = lf->orientation; + nextSf = sf->next; + if (firstLf != lf) + { + + lf->components = NULL; + slAddHead(&firstLf->components, sf); + } + } + height += tg->itemHeight(tg, item); + } + +slSort(&firstLf->components, simpleFeatureCmpQStart); + +/* +for (item=tg->items;item; item = item->next) + { + struct linkedFeatures *lf = (struct linkedFeatures *)item; + int lastQ = 0; + printf("begin\n"); + slSort(&lf->components, simpleFeatureCmpQStart); + for (sf = lf->components; sf != NULL; sf = sf->next) + { + if (sf == lf->components) + printf("%d ",sf->qStart); + else + printf("%d ",sf->qStart - lastQ) ; + lastQ = sf->qStart; + } + printf("end\n"); + } + */ +} +return 1800; +} + +static void chainDraw(struct track *tg, int seqStart, int seqEnd, + struct hvGfx *hvg, int xOff, int yOff, int width, + MgFont *font, Color color, enum trackVisibility vis) +/* Draw chained features. This loads up the simple features from + * the chainLink table, calls linkedFeaturesDraw, and then + * frees the simple features again. */ +{ +struct linkedFeatures *lf; +struct simpleFeature *sf; +struct lm *lm; +struct hash *hash; /* Hash of chain ids. */ +struct sqlConnection *conn; +//double scale = ((double)(winEnd - winStart))/width; +char fullName[64]; +int start, end, extra; +struct simpleFeature *lastSf = NULL; +int maxOverLeft = 0, maxOverRight = 0; +int overLeft, overRight; + +if (tg->items == NULL) /*Exit Early if nothing to do */ + return; + +lm = lmInit(1024*4); +hash = newHash(0); +conn = hAllocConn(database); + +/* Make up a hash of all linked features keyed by + * id, which is held in the extras field. To + * avoid burning memory on full chromosome views + * we'll just make a single simple feature and + * exclude from hash chains less than three pixels wide, + * since these would always appear solid. */ +for (lf = tg->items; lf != NULL; lf = lf->next) + { + //double pixelWidth = (lf->end - lf->start) / scale; + if (1)//pixelWidth >= 2.5) + { + char buf[256]; + struct chain *pChain = lf->extra; + safef(buf, sizeof(buf), "%d", pChain->id); + //hashAdd(hash, lf->extra, lf); + hashAdd(hash, buf, lf); + overRight = lf->end - seqEnd; + if (overRight > maxOverRight) + maxOverRight = overRight; + overLeft = seqStart - lf->start ; + if (overLeft > maxOverLeft) + maxOverLeft = overLeft; + } + else + { + lmAllocVar(lm, sf); + sf->start = lf->start; + sf->end = lf->end; + sf->grayIx = lf->grayIx; + lf->components = sf; + } + } + +/* if some chains are bigger than 3 pixels */ +if (hash->size) + { + boolean isSplit = TRUE; + /* Make up range query. */ + sprintf(fullName, "%s_%s", chromName, tg->table); + if (!hTableExists(database, fullName)) + { + strcpy(fullName, tg->table); + isSplit = FALSE; + } + + /* in dense mode we don't draw the lines + * so we don't need items off the screen + */ + if (vis == tvDense) + doQuery(conn, fullName, lm, hash, seqStart, seqEnd, isSplit, -1); + else + { + /* if chains extend beyond edge of window we need to get + * elements that are off the screen + * in both directions so we know whether to draw + * one or two lines to the edge of the screen. + */ +#define STARTSLOP 10000 +#define MULTIPLIER 10 +#define MAXLOOK 100000 + extra = (STARTSLOP < maxOverLeft) ? STARTSLOP : maxOverLeft; + start = seqStart - extra; + extra = (STARTSLOP < maxOverRight) ? STARTSLOP : maxOverRight; + end = seqEnd + extra; + doQuery(conn, fullName, lm, hash, start, end, isSplit, -1); + + for (lf = tg->items; lf != NULL; lf = lf->next) + { + struct chain *pChain = lf->extra; + int chainId = pChain->id; + + if (lf->components == NULL) + continue; + slSort(&lf->components, linkedFeaturesCmpStart); + extra = (STARTSLOP < maxOverRight)?STARTSLOP:maxOverRight; + end = seqEnd + extra; + lastSf = NULL; + while (lf->end > end ) + { + for(lastSf=sf=lf->components;sf;lastSf=sf,sf=sf->next) + ; + + /* get out if we have an element off right side */ + if (( (lastSf != NULL) &&(lastSf->end > seqEnd)) || (extra > MAXLOOK)) + break; + + extra *= MULTIPLIER; + start = end; + end = start + extra; + doQuery(conn, fullName, lm, hash, start, end, isSplit, chainId); + slSort(&lf->components, linkedFeaturesCmpStart); + } + + /* if we didn't find an element off to the right , add one */ + if ((lf->end > seqEnd) && ((lastSf == NULL) ||(lastSf->end < seqEnd))) + { + lmAllocVar(lm, sf); + sf->start = seqEnd; + sf->end = seqEnd+1; + sf->grayIx = lf->grayIx; + sf->qStart = 0; + sf->qEnd = sf->qStart + (sf->end - sf->start); + sf->next = lf->components; + lf->components = sf; + slSort(&lf->components, linkedFeaturesCmpStart); + } + + /* we know we have a least one component off right + * now look for one off left + */ + extra = (STARTSLOP < maxOverLeft) ? STARTSLOP:maxOverLeft; + start = seqStart - extra; + while((extra < MAXLOOK) && (lf->start < seqStart) && + (lf->components->start > seqStart)) + { + extra *= MULTIPLIER; + end = start; + start = end - extra; + if (start < 0) + start = 0; + doQuery(conn, fullName, lm, hash, start, end, isSplit, chainId); + slSort(&lf->components, linkedFeaturesCmpStart); + } + if ((lf->components->start > seqStart) && (lf->start < lf->components->start)) + { + lmAllocVar(lm, sf); + sf->start = 0; + sf->end = 1; + sf->grayIx = lf->grayIx; + sf->qStart = lf->components->qStart; + sf->qEnd = sf->qStart + (sf->end - sf->start); + sf->next = lf->components; + lf->components = sf; + slSort(&lf->components, linkedFeaturesCmpStart); + } + } + } + } +if (1) +{ +snakeHeight(tg, vis); +snakeDraw(tg, seqStart, seqEnd, hvg, xOff, yOff, width, + font, color, vis); + } + else + { +linkedFeaturesDraw(tg, seqStart, seqEnd, hvg, xOff, yOff, width, + font, color, vis); + } +/* Cleanup time. */ +for (lf = tg->items; lf != NULL; lf = lf->next) + lf->components = NULL; + +lmCleanup(&lm); +freeHash(&hash); +hFreeConn(&conn); +} + +void snakeLoadItems(struct track *tg) +/* Load up all of the chains from correct table into tg->items + * item list. At this stage to conserve memory for other tracks + * we don't load the links into the components list until draw time. */ +{ +char *track = tg->table; +struct chain chain; +int rowOffset; +char **row; +struct sqlConnection *conn = hAllocConn(database); +struct sqlResult *sr = NULL; +struct linkedFeatures *list = NULL, *lf; +int qs; +char optionChr[128]; /* Option - chromosome filter */ +char *optionChrStr; +char extraWhere[128] ; +struct cartOptions *chainCart; +struct chain *pChain; + +chainCart = (struct cartOptions *) tg->extraUiData; + +snprintf( optionChr, sizeof(optionChr), "%s.chromFilter", tg->table); +optionChrStr = cartUsualString(cart, optionChr, "All"); +if (startsWith("chr",optionChrStr)) + { + snprintf(extraWhere, sizeof(extraWhere), + "qName = \"%s\" and score > %d",optionChrStr, + chainCart->scoreFilter); + sr = hRangeQuery(conn, track, chromName, winStart, winEnd, + extraWhere, &rowOffset); + } +else + { + if (chainCart->scoreFilter > 0) + { + snprintf(extraWhere, sizeof(extraWhere), + "score > \"%d\"",chainCart->scoreFilter); + sr = hRangeQuery(conn, track, chromName, winStart, winEnd, + extraWhere, &rowOffset); + } + else + { + snprintf(extraWhere, sizeof(extraWhere), " "); + sr = hRangeQuery(conn, track, chromName, winStart, winEnd, + NULL, &rowOffset); + } + } +while ((row = sqlNextRow(sr)) != NULL) + { + //char buf[16]; + chainHeadStaticLoad(row + rowOffset, &chain); + AllocVar(pChain); + *pChain = chain; + AllocVar(lf); + lf->start = lf->tallStart = chain.tStart; + lf->end = lf->tallEnd = chain.tEnd; + lf->grayIx = maxShade; + if (chainCart->chainColor == chainColorScoreColors) + { + float normScore = sqlFloat((row+rowOffset)[11]); + lf->grayIx = (int) ((float)maxShade * (normScore/100.0)); + if (lf->grayIx > (maxShade+1)) lf->grayIx = maxShade+1; + lf->score = normScore; + } + else + lf->score = chain.score; + + lf->filterColor = -1; + + if (chain.qStrand == '-') + { + lf->orientation = -1; + qs = chain.qSize - chain.qEnd; + } + else + { + lf->orientation = 1; + qs = chain.qStart; + } + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "%s %c %dk", + chain.qName, chain.qStrand, qs/1000); + lf->name = cloneString(buffer); + //snprintf(lf->name, sizeof(lf->name), "%s %c %dk", + // chain.qName, chain.qStrand, qs/1000); + //snprintf(lf->name, sizeof(lf->name), "%s", + // chain.qName); + //snprintf(lf->popUp, sizeof(lf->name), "%s %c start %d size %d", + // chain.qName, chain.qStrand, qs, chain.qEnd - chain.qStart); + //snprintf(buf, sizeof(buf), "%d", chain.id); + //lf->extra = cloneString(buf); + lf->extra = pChain; + //printf("setting extra to %llu\n",(long long) pChain); + slAddHead(&list, lf); + } + +/* Make sure this is sorted if in full mode. Sort by score when + * coloring by score and in dense */ +if (tg->visibility != tvDense) + slSort(&list, linkedFeaturesCmpStart); +else if ((tg->visibility == tvDense) && + (chainCart->chainColor == chainColorScoreColors)) + slSort(&list, chainCmpScore); +else + slReverse(&list); +tg->items = list; + + +/* Clean up. */ +sqlFreeResult(&sr); +hFreeConn(&conn); +} /* chainLoadItems() */ + +static Color chainScoreColor(struct track *tg, void *item, struct hvGfx *hvg) +{ +struct linkedFeatures *lf = (struct linkedFeatures *)item; + +return(tg->colorShades[lf->grayIx]); +} + +static Color chainNoColor(struct track *tg, void *item, struct hvGfx *hvg) +{ +return(tg->ixColor); +} + +static void setNoColor(struct track *tg) +{ +tg->itemColor = chainNoColor; +tg->color.r = 0; +tg->color.g = 0; +tg->color.b = 0; +tg->altColor.r = 127; +tg->altColor.g = 127; +tg->altColor.b = 127; +tg->ixColor = MG_BLACK; +tg->ixAltColor = MG_GRAY; +} + +void snakeMethods(struct track *tg, struct trackDb *tdb, + int wordCount, char *words[]) +/* Fill in custom parts of alignment chains. */ +{ + +//boolean normScoreAvailable = FALSE; +struct cartOptions *chainCart; +//char scoreOption[256]; + +AllocVar(chainCart); + +boolean normScoreAvailable = chainDbNormScoreAvailable(tdb); +//normScoreAvailable = chainDbNormScoreAvailable(chromName, tg->table, NULL); + +/* what does the cart say about coloring option */ +chainCart->chainColor = chainFetchColorOption(cart, tdb, FALSE); + +//snprintf( scoreOption, sizeof(scoreOption), "%s.scoreFilter", tdb->tableName); +chainCart->scoreFilter = cartUsualIntClosestToHome(cart, tdb, + FALSE, SCORE_FILTER, 0); +//chainCart->scoreFilter = cartUsualInt(cart, scoreOption, 0); + + +linkedFeaturesMethods(tg); +tg->itemColor = lfChromColor; /* default coloring option */ + +/* if normScore column is available, then allow coloring */ +if (normScoreAvailable) + { + switch (chainCart->chainColor) + { + case (chainColorScoreColors): + tg->itemColor = chainScoreColor; + tg->colorShades = shadesOfGray; + break; + case (chainColorNoColors): + setNoColor(tg); + break; + default: + case (chainColorChromColors): + break; + } + } +else + { + char option[128]; /* Option - rainbow chromosome color */ + char *optionStr; /* this old option was broken before */ + + snprintf(option, sizeof(option), "%s.color", tg->table); + optionStr = cartUsualString(cart, option, "on"); + if (differentWord("on",optionStr)) + { + setNoColor(tg); + chainCart->chainColor = chainColorNoColors; + } + else + chainCart->chainColor = chainColorChromColors; + } + +tg->loadItems = snakeLoadItems; +tg->drawItems = chainDraw; +tg->mapItemName = lfMapNameFromExtra; +tg->subType = lfSubChain; +tg->extraUiData = (void *) chainCart; +// tg->drawItems = snakeDraw; + tg->drawItemAt = snakeDrawAt; + tg->totalHeight = snakeHeight; + tg->itemHeight = snakeItemHeight; +}