747d414a3053db1454d223d0db7e74a4765e7c98 braney Tue Jan 24 17:00:18 2023 -0800 re-introducing chainSnakes into the browser diff --git src/hg/hgTracks/snakeTrack.c src/hg/hgTracks/snakeTrack.c deleted file mode 100644 index 7825910..0000000 --- src/hg/hgTracks/snakeTrack.c +++ /dev/null @@ -1,1945 +0,0 @@ -/* Copyright (C) 2014 The Regents of the University of California - * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ - -#ifdef USE_HAL -/* snakeTrack - stuff to load and display snake type tracks in browser. */ - -#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" -#include "errCatch.h" -#include "twoBit.h" -#include "bigWarn.h" -#include <pthread.h> -#include "trackHub.h" -#include "limits.h" -#include "snakeUi.h" -#include "bits.h" -#include "trix.h" -#include "chromAlias.h" - -#include "halBlockViz.h" -#include "bigPsl.h" - -// this is the number of pixels used by the target self-align bar -#define DUP_LINE_HEIGHT 4 -// this is the number of pixels used when displaying the insertion lengths -#define INSERT_TEXT_HEIGHT 10 - -struct snakeFeature - { - struct snakeFeature *next; - int start, end; /* Start/end in browser coordinates. */ - int qStart, qEnd; /* query start/end */ - int level; /* level in snake */ - int orientation; /* strand... -1 is '-', 1 is '+' */ - boolean drawn; /* did we draw this feature? */ - char *qSequence; /* may have sequence, or NULL */ - char *tSequence; /* may have sequence, or NULL */ - char *qName; /* chrom name on other species */ - unsigned pixX1, pixX2; /* pixel coordinates within window */ - }; - -static int snakeFeatureCmpTStart(const void *va, const void *vb) -/* sort by start position on the target sequence */ -{ -const struct snakeFeature *a = *((struct snakeFeature **)va); -const struct snakeFeature *b = *((struct snakeFeature **)vb); -int diff = a->start - b->start; - -return diff; -} - -static int snakeFeatureCmpQStart(const void *va, const void *vb) -/* sort by start position on the query sequence */ -{ -const struct snakeFeature *a = *((struct snakeFeature **)va); -const struct snakeFeature *b = *((struct snakeFeature **)vb); -int diff = a->qStart - b->qStart; - -if (diff == 0) - { - diff = a->start - b->start; - } - -return diff; -} - -// static machinery to calculate full and pack snake - -#define NUM_LEVELS 1000 - -struct level -{ -boolean init; /* has this level been initialized */ -int orientation; /* strand.. see above */ -unsigned long edge; /* the leading edge of this level */ -int adjustLevel; /* used to compress out the unused levels */ -boolean hasBlock; /* are there any blocks in this level */ - -// these fields are used to compact full snakes -unsigned *connectsToLevel; /* what levels does this level connect to */ -Bits *pixels; /* keep track of what pixels are used */ -struct snakeFeature *blocks; /* the ungapped blocks attached to this level */ -}; - -static struct level Levels[NUM_LEVELS]; /* for packing the snake, not re-entrant! */ -static int maxLevel = 0; /* deepest level */ - -/* blocks that make it through the min size filter */ -static struct snakeFeature *newList = NULL; - -static void clearLevels() -/* clear out the data structure that we use to calculate snakes */ -{ -int ii; - -for(ii=0; ii < sizeof(Levels) / sizeof(Levels[0]); ii++) - Levels[ii].init = FALSE; -maxLevel = 0; -} - -static void calcFullSnakeHelper(struct snakeFeature *list, int level) -// calculate a full snake -// updates global newList with unsorted blocks that pass the min -// size filter. -{ -struct snakeFeature *cb = list; -struct snakeFeature *proposedList = NULL; - -if (level > maxLevel) - maxLevel = level; -if (level > ArraySize(Levels)) - errAbort("too many levels"); - -if (Levels[level].init == FALSE) - { - // initialize the level if this is the first time we've seen it - Levels[level].init = TRUE; - Levels[level].orientation = list->orientation; - if (list->orientation == -1) - Levels[level].edge = LONG_MAX; // bigger than the biggest chrom - else - Levels[level].edge = 0; - } - -// now we step through the blocks and assign them to levels -struct snakeFeature *next; -struct snakeFeature *insertHead = NULL; -for(; cb; cb = next) - { - // we're going to add this block to a different list - // so keep track of the next pointer - next = cb->next; - - // if this block can't fit on this level add to the insert - // list and move on to the next block - if ((Levels[level].orientation != cb->orientation) || - ((cb->orientation == 1) && (Levels[level].edge > cb->start)) || - ((cb->orientation == -1) && (Levels[level].edge < cb->end))) - { - // add this to the list of an insert - slAddHead(&insertHead, cb); - continue; - } - - // the current block will fit on this level - // go ahead and deal with the blocks that wouldn't - if (insertHead) - { - // we had an insert, go ahead and calculate where that goes - slReverse(&insertHead); - calcFullSnakeHelper(insertHead, level + 1); - insertHead = NULL; - } - - // assign the current block to this level - cb->level = level; - - if (cb->orientation == 1) - Levels[level].edge = cb->end; - else - Levels[level].edge = cb->start; - - // add this block to the list of proposed blocks for this level - slAddHead(&proposedList, cb); - } - -// we're at the end of the list. Deal with any blocks -// that didn't fit on this level -if (insertHead) - { - slReverse(&insertHead); - int nextLevel = level + 1; - calcFullSnakeHelper(insertHead, nextLevel); - insertHead = NULL; - } - -// do we have any proposed blocks -if (proposedList == NULL) - return; - -// we parsed all the blocks in the list to see if they fit in our level -// now let's see if the list of blocks for this level is big enough -// to actually add - -struct snakeFeature *temp; -double scale = scaleForWindow(insideWidth, winStart, winEnd); -int start, end; - -// order the blocks so lowest start position is first -if (Levels[level].orientation == 1) - slReverse(&proposedList); - -start=proposedList->start; -for(temp=proposedList; temp->next; temp = temp->next) - ; -end=temp->end; - -// calculate how big the string of blocks is in screen coordinates -double apparentSize = scale * (end - start); - -if (apparentSize < 0) - errAbort("size of a list of blocks should not be less than zero"); - -// check to see if the apparent size is big enough -if (apparentSize < 1) - return; - -// transfer proposedList to new block list -for(temp=proposedList; temp; temp = next) - { - next = temp->next; - temp->next = NULL; - slAddHead(&newList, temp); - } -} - -struct snakeInfo -{ -int maxLevel; -} snakeInfo; - -static void freeFullLevels() -// free the connection levels and bitmaps for each level -{ -int ii; - -for(ii=0; ii <= maxLevel; ii++) - { - freez(&Levels[ii].connectsToLevel); - bitFree(&Levels[ii].pixels); - } -} - -static void initializeFullLevels(struct snakeFeature *sfList) -/* initialize levels for compact snakes */ -{ -int ii; - -for(ii=0; ii <= maxLevel; ii++) - { - Levels[ii].connectsToLevel = needMem((maxLevel+1) * sizeof(unsigned)); - Levels[ii].pixels = bitAlloc(insideWidth); - Levels[ii].blocks = NULL; - } - -struct snakeFeature *sf, *next; -int prevLevel = -1; -double scale = scaleForWindow(insideWidth, winStart, winEnd); - -for(sf=sfList; sf; sf = next) - { - next = sf->next; - - if (positiveRangeIntersection(sf->start, sf->end, winStart, winEnd)) - { - int sClp = (sf->start < winStart) ? winStart : sf->start; - sf->pixX1 = round((sClp - winStart)*scale); - int eClp = (sf->end > winEnd) ? winEnd : sf->end; - sf->pixX2 = round((eClp - winStart)*scale); - } - else - { - sf->pixX1 = sf->pixX2 = 0; - } - - bitSetRange(Levels[sf->level].pixels, sf->pixX1, sf->pixX2 - sf->pixX1); - - if (prevLevel != -1) - Levels[sf->level].connectsToLevel[prevLevel] = 1; - - if(next != NULL) - Levels[sf->level].connectsToLevel[next->level] = 1; - - prevLevel = sf->level; - - slAddHead(&Levels[sf->level].blocks, sf); - } -} - -static int highestLevelBelowUs(int level) -// is there a level below us that doesn't connect to us -{ -int newLevel; - -// find the highest level below us that we connect to -for(newLevel = level - 1; newLevel >= 0; newLevel--) - if (Levels[level].connectsToLevel[newLevel]) - break; - -// if the next level is more than one below us, we may -// be able to push our blocks to it. -if ((newLevel < 0) || (newLevel + 1 == level)) - return -1; - -return newLevel + 1; -} - -// the number of pixels we need clear on either side of the blocks we push -#define EXTRASPACE 10 - -static boolean checkBlocksOnLevel(int level, struct snakeFeature *sfList) -// is there enough pixels on this level to hold our blocks? -{ -struct snakeFeature *sf; - -for(sf=sfList; sf; sf = sf->next) - { - if (bitCountRange(Levels[level].pixels, sf->pixX1 - EXTRASPACE, (sf->pixX2 - sf->pixX1) + 2*EXTRASPACE)) - return FALSE; - } -return TRUE; -} - -static void collapseLevel(int oldLevel, int newLevel) -// push level up to higher level -{ -struct snakeFeature *sf; -struct snakeFeature *next; - -for(sf=Levels[oldLevel].blocks; sf; sf = next) - { - next = sf->next; - sf->level = newLevel; - slAddHead(&Levels[newLevel].blocks, sf); - - bitSetRange(Levels[sf->level].pixels, sf->pixX1, sf->pixX2 - sf->pixX1); - } -Levels[oldLevel].blocks = NULL; -Levels[oldLevel].pixels = bitAlloc(insideWidth); -} - -static void remapConnections(int oldLevel, int newLevel) -// if we've moved a level, we need to remap all the connections -{ -int ii, jj; - -for(ii=0; ii <= maxLevel; ii++) - { - for(jj=0; jj <= maxLevel; jj++) - { - if (Levels[ii].connectsToLevel[oldLevel]) - { - Levels[ii].connectsToLevel[oldLevel] = 0; - Levels[ii].connectsToLevel[newLevel] = 1; - } - } - } -} - -static struct snakeFeature *compactSnakes(struct snakeFeature *sfList) -// collapse levels that will fit on a higer level -{ -int ii; - -initializeFullLevels(sfList); - -// start with third level to see what can be compacted -for(ii=2; ii <= maxLevel; ii++) - { - int newLevel; - // is there a level below us that doesn't connect to us - if ((newLevel = highestLevelBelowUs(ii)) > 0) - { - int jj; - for (jj=newLevel; jj < ii; jj++) - { - if (checkBlocksOnLevel(jj, Levels[ii].blocks)) - { - collapseLevel(ii, jj); - remapConnections(ii, jj); - break; - } - } - } - } - -// reattach blocks in the levels to linkedFeature -struct snakeFeature *newList = NULL; -for(ii=0; ii <= maxLevel; ii++) - { - newList = slCat(Levels[ii].blocks, newList); - } -slSort(&newList, snakeFeatureCmpQStart); - -// figure out the new max -int newMax = 0; -for(ii=0; ii <= maxLevel; ii++) - if (Levels[ii].blocks != NULL) - newMax = ii; - -freeFullLevels(); -maxLevel = newMax; - -return newList; -} - -static void calcFullSnake(struct track *tg, void *item) -// calculate a full snake -{ -struct linkedFeatures *lf = (struct linkedFeatures *)item; - -// if there aren't any blocks, don't bother -if (lf->components == NULL) - return; - -// we use the codons field to keep track of whether we already -// calculated the height of this snake -if (lf->codons == NULL) - { - clearLevels(); - struct snakeFeature *sf; - - // this will destroy lf->components, and add to newList - calcFullSnakeHelper((struct snakeFeature *)lf->components, 0); - lf->components = (struct simpleFeature *)newList; - newList = NULL; - slSort(&lf->components, snakeFeatureCmpQStart); - - // now we're going to compress the levels that aren't used - // to do that, we need to see which blocks are on the screen, - // or connected to something on the screen - int oldMax = maxLevel; - clearLevels(); - struct snakeFeature *prev = NULL; - for(sf=(struct snakeFeature *)lf->components; sf; prev = sf, sf = sf->next) - { - if (Levels[sf->level].init == FALSE) - { - Levels[sf->level].init = TRUE; - Levels[sf->level].orientation = sf->orientation; - Levels[sf->level].hasBlock = FALSE; - } - else - { - if (Levels[sf->level].orientation != sf->orientation) - errAbort("found snakeFeature with wrong orientation"); - if ((sf->orientation == 1) && (Levels[sf->level].edge > sf->start)) - errAbort("found snakeFeature that violates edge"); - if ((sf->orientation == -1) && (Levels[sf->level].edge < sf->end)) - errAbort("found snakeFeature that violates edge"); - } - if (sf->orientation == 1) - Levels[sf->level].edge = sf->end; - else - Levels[sf->level].edge = sf->start; - if (sf->level > maxLevel) - maxLevel = sf->level; - if(positiveRangeIntersection(winStart, winEnd, sf->start, sf->end)) - { - Levels[sf->level].hasBlock = TRUE; - if (sf->next != NULL) - Levels[sf->next->level].hasBlock = TRUE; - if (prev != NULL) - Levels[prev->level].hasBlock = TRUE; - - } - } - - // now figure out how to remap the blocks - int ii; - int count = 0; - for(ii=0; ii < oldMax + 1; ii++) - { - Levels[ii].adjustLevel = count; - if ((Levels[ii].init) && (Levels[ii].hasBlock)) - count++; - } - maxLevel = count; - - // remap blocks - for(sf=(struct snakeFeature *)lf->components; sf; sf = sf->next) - sf->level = Levels[sf->level].adjustLevel; - - // now compact the snakes - lf->components = (void *)compactSnakes((struct snakeFeature *)lf->components); - struct snakeInfo *si; - AllocVar(si); - si->maxLevel = maxLevel; - lf->codons = (struct simpleFeature *)si; - } -} - -static void calcPackSnakeHelper(struct snakeFeature *list, int level) -// calculate a packed snake -// updates global newList with unsorted blocks that pass the min -// size filter. -{ -struct snakeFeature *cb = list; -struct snakeFeature *proposedList = NULL; - -if (level > maxLevel) - maxLevel = level; -if (level > ArraySize(Levels)) - errAbort("too many levels"); - -if (Levels[level].init == FALSE) - { - // initialize the level if this is the first time we've seen it - Levels[level].init = TRUE; - Levels[level].edge = 0; - } - -// now we step through the blocks and assign them to levels -struct snakeFeature *next; -struct snakeFeature *insertHead = NULL; -for(; cb; cb = next) - { - // we're going to add this block to a different list - // so keep track of the next pointer - next = cb->next; - - // if this block can't fit on this level add to the insert - // list and move on to the next block - if ( Levels[level].edge > cb->start) - { - // add this to the list of an insert - slAddHead(&insertHead, cb); - continue; - } - - // the current block will fit on this level - // go ahead and deal with the blocks that wouldn't - if (insertHead) - { - // we had an insert, go ahead and calculate where that goes - slReverse(&insertHead); - calcPackSnakeHelper(insertHead, level + 1); - insertHead = NULL; - } - - // assign the current block to this level - cb->level = level; - - Levels[level].edge = cb->end; - - // add this block to the list of proposed blocks for this level - slAddHead(&proposedList, cb); - } - -// we're at the end of the list. Deal with any blocks -// that didn't fit on this level -if (insertHead) - { - slReverse(&insertHead); - calcPackSnakeHelper(insertHead, level + 1); - insertHead = NULL; - } - -// do we have any proposed blocks -if (proposedList == NULL) - return; - -// we parsed all the blocks in the list to see if they fit in our level -// now let's see if the list of blocks for this level is big enough -// to actually add - -struct snakeFeature *temp; -double scale = scaleForWindow(insideWidth, winStart, winEnd); -int start, end; - -// order the blocks so lowest start position is first -slReverse(&proposedList); - -start=proposedList->start; -for(temp=proposedList; temp->next; temp = temp->next) - ; -end=temp->end; - -// calculate how big the string of blocks is in screen coordinates -double apparentSize = scale * (end - start); - -if (apparentSize < 0) - errAbort("size of a list of blocks should not be less than zero"); - -// check to see if the apparent size is big enough -if (apparentSize < 1) - return; - -// transfer proposedList to new block list -for(temp=proposedList; temp; temp = next) - { - next = temp->next; - temp->next = NULL; - slAddHead(&newList, temp); - } -} - -static void calcPackSnake(struct track *tg, void *item) -{ -struct linkedFeatures *lf = (struct linkedFeatures *)item; -if (lf->components == NULL) - return; - -// we use the codons field to keep track of whether we already -// calculated the height of this snake -if (lf->codons == NULL) - { - clearLevels(); - - // this will destroy lf->components, and add to newList - calcPackSnakeHelper((struct snakeFeature *)lf->components, 0); - lf->components = (struct simpleFeature *)newList; - newList = NULL; - - //slSort(&lf->components, snakeFeatureCmpQStart); - - struct snakeInfo *si; - AllocVar(si); - si->maxLevel = maxLevel; - lf->codons = (struct simpleFeature *)si; - } -} - -static int snakeItemHeight(struct track *tg, void *item) -// return height of a single packed snake -{ -if ((item == NULL) || (tg->visibility == tvSquish) || (tg->visibility == tvDense)) - return 0; - -struct linkedFeatures *lf = (struct linkedFeatures *)item; -if (lf->components == NULL) - return 0; - -if (tg->visibility == tvFull) - calcFullSnake(tg, item); -else if (tg->visibility == tvPack) - calcPackSnake(tg, item); - -struct snakeInfo *si = (struct snakeInfo *)lf->codons; -int lineHeight = tg->lineHeight ; -int multiplier = 1; - -if (tg->visibility == tvFull) - multiplier = 2; -return (si->maxLevel + 1) * (multiplier * lineHeight); -} - -static int linkedFeaturesCmpScore(const void *va, const void *vb) -/* Help sort linkedFeatures by score */ -{ -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; -} - -static int snakeHeight(struct track *tg, enum trackVisibility vis) -/* calculate height of all the snakes being displayed */ -{ -if (tg->networkErrMsg != NULL) - { - // we had a parallel load failure - tg->drawItems = bigDrawWarning; - tg->totalHeight = bigWarnTotalHeight; - return bigWarnTotalHeight(tg, vis); - } - -if (vis == tvDense) - return tg->lineHeight; - -if (vis == tvSquish) - return tg->lineHeight/2; - -int height = DUP_LINE_HEIGHT + INSERT_TEXT_HEIGHT; -struct slList *item = tg->items; - -item = tg->items; - -for (item=tg->items;item; item = item->next) - { - height += tg->itemHeight(tg, item); - } -if (height < DUP_LINE_HEIGHT + tg->lineHeight) - height = DUP_LINE_HEIGHT + tg->lineHeight; -return height; -} - -static 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 *lf; -double scale = scaleForWindow(width, seqStart, seqEnd); -int height = snakeHeight(tg, vis); - -hvGfxSetClip(hvg, xOff, yOff, width, height); - -if ((tg->visibility == tvFull) || (tg->visibility == tvPack)) - { - // score snakes by how many bases they cover - for (item = tg->items; item != NULL; item = item->next) - { - lf = (struct linkedFeatures *)item; - struct snakeFeature *sf; - - lf->score = 0; - for (sf = (struct snakeFeature *)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); - if (vis == tvFull) - y += tg->itemHeight(tg, item); - } -} - -// this is a 16 color palette with every other color being a lighter version of -// the color before it -static int snakePalette2[] = -{ -0x1f77b4, 0xaec7e8, 0xff7f0e, 0xffbb78, 0x2ca02c, 0x98df8a, 0xd62728, 0xff9896, 0x9467bd, 0xc5b0d5, 0x8c564b, 0xc49c94, 0xe377c2, 0xf7b6d2, 0x7f7f7f, 0xc7c7c7, 0xbcbd22, 0xdbdb8d, 0x17becf, 0x9edae5 -}; - -static int snakePalette[] = -{ -0x1f77b4, 0xff7f0e, 0x2ca02c, 0xd62728, 0x9467bd, 0x8c564b, 0xe377c2, 0x7f7f7f, 0xbcbd22, 0x17becf -}; - -static Color hashColor(char *name) -{ -bits32 hashVal = hashString(name); -unsigned int colorInt = snakePalette2[hashVal % (sizeof(snakePalette2)/sizeof(Color))]; - -return MAKECOLOR_32(((colorInt >> 16) & 0xff),((colorInt >> 8) & 0xff),((colorInt >> 0) & 0xff)); -} - -static void boundMapBox(struct hvGfx *hvg, int start, int end, int x, int y, int width, int height, - char *track, char *item, char *statusLine, char *directUrl, boolean withHgsid, - char *extra) -// make sure start x and end x position are on the screen -// otherwise the tracking box code gets confused -{ -if (x > insideWidth) - return; - -if (x < 0) - { - width -= -x; - x = 0; - } - -if (x + width > insideWidth) - { - width -= x + width - insideWidth; - } - -mapBoxHgcOrHgGene(hvg, start, end, x, y, width, height, - track, item, statusLine, directUrl, withHgsid, - extra); -} - -static 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. */ -{ -unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, - SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH); -struct linkedFeatures *lf = (struct linkedFeatures *)item; - - -if (tg->visibility == tvFull) - calcFullSnake(tg, item); -else if (tg->visibility == tvPack) - calcPackSnake(tg, item); - -if (lf->components == NULL) - return; - -boolean isHalSnake = lf->isHalSnake; - -struct snakeFeature *sf = (struct snakeFeature *)lf->components, *prevSf = NULL; -int s = tg->itemStart(tg, item); -int sClp = (s < winStart) ? winStart : s; -int x1 = round((sClp - winStart)*scale) + xOff; -int textX = x1; -int yOff = y; -boolean withLabels = (withLeftLabels && (vis == tvFull) && !tg->drawName); -unsigned labelColor = MG_BLACK; - -// draw the labels -if (withLabels) - { - char *name = tg->itemName(tg, item); - int nameWidth = mgFontStringWidth(font, name); - int dotWidth = tl.nWidth/2; - boolean snapLeft = FALSE; - boolean drawNameInverted = FALSE; - textX -= nameWidth + dotWidth; - snapLeft = (textX < fullInsideX); - /* Special tweak for expRatio in pack mode: force all labels - * left to prevent only a subset from being placed right: */ - snapLeft |= (startsWith("expRatio", tg->tdb->type)); -#ifdef IMAGEv2_NO_LEFTLABEL_ON_FULL - if (theImgBox == NULL && snapLeft) -#else///ifndef IMAGEv2_NO_LEFTLABEL_ON_FULL - if (snapLeft) /* Snap label to the left. */ -#endif ///ndef IMAGEv2_NO_LEFTLABEL_ON_FULL - { - textX = leftLabelX; - assert(hvgSide != NULL); - hvGfxUnclip(hvgSide); - hvGfxSetClip(hvgSide, leftLabelX, yOff, fullInsideX - leftLabelX, tg->height); - if(drawNameInverted) - { - int boxStart = leftLabelX + leftLabelWidth - 2 - nameWidth; - hvGfxBox(hvgSide, boxStart, y, nameWidth+1, tg->heightPer - 1, color); - hvGfxTextRight(hvgSide, leftLabelX, y, leftLabelWidth-1, tg->heightPer, - MG_WHITE, font, name); - } - else - hvGfxTextRight(hvgSide, leftLabelX, y, leftLabelWidth-1, tg->heightPer, - labelColor, font, name); - hvGfxUnclip(hvgSide); - hvGfxSetClip(hvgSide, insideX, yOff, insideWidth, tg->height); - } - else - { - int pdfSlop=nameWidth/5; - hvGfxUnclip(hvg); - hvGfxSetClip(hvg, textX-1-pdfSlop, y, nameWidth+1+pdfSlop, tg->heightPer); - if(drawNameInverted) - { - hvGfxBox(hvg, textX - 1, y, nameWidth+1, tg->heightPer-1, color); - hvGfxTextRight(hvg, textX, y, nameWidth, tg->heightPer, MG_WHITE, font, name); - } - else - hvGfxTextRight(hvg, textX, y, nameWidth, tg->heightPer, labelColor, font, name); - hvGfxUnclip(hvg); - hvGfxSetClip(hvg, insideX, yOff, insideWidth, tg->height); - } - } - -// let's draw some blue bars for the duplications -struct hal_target_dupe_list_t* dupeList = lf->dupeList; - -int count = 0; -if ((tg->visibility == tvFull) || (tg->visibility == tvPack)) - { - for(; dupeList ; dupeList = dupeList->next, count++) - { - struct hal_target_range_t *range = dupeList->tRange; - - unsigned int colorInt = snakePalette[count % (sizeof(snakePalette)/sizeof(Color))]; - Color color = MAKECOLOR_32(((colorInt >> 16) & 0xff),((colorInt >> 8) & 0xff),((colorInt >> 0) & 0xff)); - - for(; range; range = range->next) - { - int s = range->tStart; - int e = range->tStart + range->size; - int sClp = (s < winStart) ? winStart : s; - int eClp = (e > winEnd) ? winEnd : e; - int x1 = round((sClp - winStart)*scale) + xOff; - int x2 = round((eClp - winStart)*scale) + xOff; - hvGfxBox(hvg, x1, y , x2-x1, DUP_LINE_HEIGHT - 1 , color); - } - } - y+=DUP_LINE_HEIGHT; - } - -// now we're going to draw the boxes - -s = sf->start; -int lastE = -1; -int lastS = -1; -int offY = y; -int lineHeight = tg->lineHeight ; -int qs, qe; -int heightPer = tg->heightPer; -int lastX = -1; -int lastQEnd = 0; -int lastLevel = -1; -int e; -qe = lastQEnd = 0; -for (sf = (struct snakeFeature *)lf->components; sf != NULL; lastQEnd = qe, prevSf = sf, sf = sf->next) - { - qs = sf->qStart; - qe = sf->qEnd; - if (vis == tvDense) - y = offY; - else if ((vis == tvPack) || (vis == tvSquish)) - y = offY + (sf->level * 1) * lineHeight; - else if (vis == tvFull) - y = offY + (sf->level * 2) * lineHeight; - s = sf->start; e = sf->end; - - int sx, ex; - if (!positiveRangeIntersection(winStart, winEnd, s, e)) - continue; - sx = round((double)((int)s-winStart)*scale) + xOff; - ex = round((double)((int)e-winStart)*scale) + xOff; - - // color by strand - static Color darkBlueColor = 0; - static Color darkRedColor = 0; - if (darkRedColor == 0) - { - //the light blue: rgb(149, 204, 252) - //the light red: rgb(232, 156, 156) - darkRedColor = hvGfxFindColorIx(hvg, 232,156,156); - darkBlueColor = hvGfxFindColorIx(hvg, 149,204,252); - } - - char *colorBy = cartOrTdbString(cart, tg->tdb, - SNAKE_COLOR_BY, SNAKE_DEFAULT_COLOR_BY); - - extern Color getChromColor(char *name, struct hvGfx *hvg); - if (sameString(colorBy, SNAKE_COLOR_BY_STRAND_VALUE)) - color = (sf->orientation == -1) ? darkRedColor : darkBlueColor; - else if (sameString(colorBy, SNAKE_COLOR_BY_CHROM_VALUE)) - color = hashColor(sf->qName); - else - color = darkBlueColor; - - int w = ex - sx; - if (w == 0) - w = 1; - assert(w > 0); - char buffer[1024]; - - if (vis == tvFull) - safef(buffer, sizeof buffer, "%d-%d",sf->qStart,sf->qEnd); - else - safef(buffer, sizeof buffer, "%s:%d-%d",sf->qName,sf->qStart,sf->qEnd); - if (sx < insideX) - { - int olap = insideX - sx; - sx = insideX; - w -= olap; - } - char qAddress[4096]; - if ((vis == tvFull) || (vis == tvPack) ) - { - safef(qAddress, sizeof qAddress, "qName=%s&qs=%d&qe=%d&qWidth=%d",sf->qName, qs, qe, winEnd - winStart); - boundMapBox(hvg, s, e, sx+1, y, w-2, heightPer, tg->track, - buffer, buffer, NULL, TRUE, qAddress); - } - hvGfxBox(hvg, sx, y, w, heightPer, color); - - // now draw the mismatches if we're at high enough resolution - if ((isHalSnake && sf->qSequence != NULL) && (winBaseCount < showSnpWidth) && ((vis == tvFull) || (vis == tvPack))) - { - char *twoBitString = trackDbSetting(tg->tdb, "twoBit"); - static struct twoBitFile *tbf = NULL; - static char *lastTwoBitString = NULL; - static struct dnaSeq *seq = NULL; - static char *lastQName = NULL; - - // sequence for chain snakes is in 2bit files which we cache - if (!isHalSnake) - { - if (twoBitString == NULL) - twoBitString = "/gbdb/hg19/hg19.2bit"; - - if ((lastTwoBitString == NULL) || - differentString(lastTwoBitString, twoBitString)) - { - if (tbf != NULL) - { - lastQName = NULL; - twoBitClose(&tbf); - } - tbf = twoBitOpen(twoBitString); - } - - // we're reading in the whole chrom - if ((lastQName == NULL) || differentString(sf->qName, lastQName)) - seq = twoBitReadSeqFrag(tbf, sf->qName, 0, 0); - lastQName = sf->qName; - lastTwoBitString = twoBitString; - } - - char *ourDna; - if (isHalSnake) - ourDna = sf->qSequence; - else - ourDna = &seq->dna[sf->qStart]; - - int seqLen = sf->qEnd - sf->qStart; - toUpperN(ourDna, seqLen); - if (!isHalSnake && (sf->orientation == -1)) - reverseComplement(ourDna,seqLen); - - // get the reference sequence - char *refDna; - if (isHalSnake && differentString(tg->tdb->type, "pslSnake")) - { - refDna = sf->tSequence; - } - else - { - struct dnaSeq *extraSeq = hDnaFromSeq(database, chromName, sf->start, sf->end, dnaUpper); - refDna = extraSeq->dna; - } - int si = s; - char *ptr1 = refDna; - char *ptr2 = ourDna; - for(; si < e; si++,ptr1++,ptr2++) - { - // if mismatch! If reference is N ignore, if query is N, paint yellow - if ( (*ptr1 != *ptr2) && !((*ptr1 == 'N') || (*ptr1 == 'n'))) - { - int misX1 = round((double)((int)si-winStart)*scale) + xOff; - int misX2 = round((double)((int)(si+1)-winStart)*scale) + xOff; - int w1 = misX2 - misX1; - if (w1 < 1) - w1 = 1; - - Color boxColor = MG_RED; - if ((*ptr2 == 'N') || (*ptr2 == 'n')) - boxColor = hvGfxFindRgb(hvg, &undefinedYellowColor); - hvGfxBox(hvg, misX1, y, w1, heightPer, boxColor); - } - } - - // if we're zoomed to base level, draw sequence of mismatch - if (zoomedToBaseLevel) - { - int mysx = round((double)((int)s-winStart)*scale) + xOff; - int myex = round((double)((int)e-winStart)*scale) + xOff; - int myw = myex - mysx; - spreadAlignString(hvg, mysx, y, myw, heightPer, MG_WHITE, font, ourDna, - refDna, seqLen, TRUE, FALSE); - } - - } - sf->drawn = TRUE; - lastLevel = sf->level; - //lastX = x; - } - -if (vis != tvFull) - return; - -// now we're going to draw the lines between the blocks - -lastX = -1; -lastQEnd = 0; -lastLevel = 0; -qe = lastQEnd = 0; -prevSf = NULL; -for (sf = (struct snakeFeature *)lf->components; sf != NULL; lastQEnd = qe, prevSf = sf, sf = sf->next) - { - int y1, y2; - int sx, ex; - qs = sf->qStart; - qe = sf->qEnd; - if (lastLevel == sf->level) - { - y1 = offY + (lastLevel * 2) * lineHeight + lineHeight/2; - y2 = offY + (sf->level * 2) * lineHeight + lineHeight/2; - } - else if (lastLevel > sf->level) - { - y1 = offY + (lastLevel * 2 ) * lineHeight; - y2 = offY + (sf->level * 2 + 1) * lineHeight + lineHeight/3; - } - else - { - y1 = offY + (lastLevel * 2 + 1) * lineHeight - 1; - y2 = offY + (sf->level * 2 ) * lineHeight - lineHeight/3;; - } - s = sf->start; e = sf->end; - - sx = round((double)((int)s-winStart)*scale) + xOff; - ex = round((double)((int)e-winStart)*scale) + xOff; - color = (sf->orientation == -1) ? MG_RED : MG_BLUE; - - if (lastX != -1) - { - char buffer[1024]; -#define MG_ORANGE 0xff0082E6 - int color = MG_GRAY; - - if (lastQEnd != qs) { - long long queryInsertSize = llabs(lastQEnd - qs); - long long targetInsertSize; - if (sf->orientation == 1) - targetInsertSize = s - lastE; - else - targetInsertSize = lastS - e; - int blue = 0; - int red = 0; - int green = 0; - if (queryInsertSize > targetInsertSize) { - double frac = ((double) queryInsertSize - targetInsertSize) / targetInsertSize; - if (frac > 1.0) - frac = 1.0; - red = 255 - 255 * frac; - blue = 255 * frac; - } else { - double frac = ((double) targetInsertSize - queryInsertSize) / targetInsertSize; - if (frac > 1.0) - frac = 1.0; - red = 255 - 255 * frac; - green = 255 * frac; - } - color = hvGfxFindColorIx(hvg, red, green, blue); - } - double queryGapNFrac = 0.0; - double queryGapMaskedFrac = 0.0; - if ((qs > lastQEnd) && qs - lastQEnd < 1000000) { - // sketchy - char *fileName = trackDbSetting(tg->tdb, "bigDataUrl"); - char *otherSpecies = trackDbSetting(tg->tdb, "otherSpecies"); - int handle = halOpenLOD(fileName, NULL); - char *queryGapDna = halGetDna(handle, otherSpecies, sf->qName, lastQEnd, qs, NULL); - long long numNs = 0; - long long numMasked = 0; - char *i = queryGapDna; - while (*i != '\0') { - if (*i == 'N' || *i == 'n') { - numNs++; - numMasked++; - } - if (*i == 'a' || *i == 't' || *i == 'g' || *i == 'c') { - numMasked++; - } - i++; - } - free(queryGapDna); - queryGapMaskedFrac = ((double) numMasked) / (qs - lastQEnd); - queryGapNFrac = ((double) numNs) / (qs - lastQEnd); - } - - // draw the vertical orange bars if there is an insert in the other sequence - if ((winBaseCount < showSnpWidth) ) - { - if ((sf->orientation == 1) && (qs != lastQEnd) && (lastE == s)) - { - hvGfxLine(hvg, sx, y2 - lineHeight/2 , sx, y2 + lineHeight/2, MG_ORANGE); - safef(buffer, sizeof buffer, "%dbp (%.1lf%% N, %.1lf%% masked)", qs - lastQEnd, queryGapNFrac*100, queryGapMaskedFrac*100); - boundMapBox(hvg, s, e, sx, y2 - lineHeight/2, 1, lineHeight, tg->track, - "foo", buffer, NULL, TRUE, NULL); - safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd); - hvGfxTextCentered(hvg, sx - 10, y2 + lineHeight/2, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer); - } - else if ((sf->orientation == -1) && (qs != lastQEnd) && (lastS == e)) - { - hvGfxLine(hvg, ex, y2 - lineHeight/2 , ex, y2 + lineHeight/2, MG_ORANGE); - safef(buffer, sizeof buffer, "%dbp (%.1lf%% N, %.1lf%% masked)", qs - lastQEnd, queryGapNFrac*100, queryGapMaskedFrac*100); - boundMapBox(hvg, s, e, ex, y2 - lineHeight/2, 1, lineHeight, tg->track, - "foo", buffer, NULL, TRUE, NULL); - safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd); - hvGfxTextCentered(hvg, ex - 10, y2 + lineHeight/2, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer); - } - } - - // now draw the lines between blocks - if ((!((lastX == sx) && (y1 == y2))) && - (sf->drawn || ((prevSf != NULL) && (prevSf->drawn))) && - (((lastE >= winStart) && (lastE <= winEnd)) || - ((s > winStart) && (s < winEnd)))) - { - if (lastLevel == sf->level) - { - if (sf->orientation == 1) - safef(buffer, sizeof buffer, "%dbp (%dbp in ref) (%.1lf%% N, %.1lf%% masked)", qs - lastQEnd, s - lastE, queryGapNFrac*100, queryGapMaskedFrac*100); - else - safef(buffer, sizeof buffer, "%dbp (%dbp in ref) (%.1lf%% N, %.1lf%% masked)", qs - lastQEnd, lastS - e, queryGapNFrac*100, queryGapMaskedFrac*100); - if (sf->orientation == -1) - { - if (lastX != ex) - { - hvGfxLine(hvg, ex, y1, lastX, y2, color); - boundMapBox(hvg, s, e, ex, y1, lastX-ex, 1, tg->track, - "", buffer, NULL, TRUE, NULL); - if (lastQEnd != qs) { - safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd); - hvGfxTextCentered(hvg, ex, y2 + lineHeight/2, lastX-ex, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer); - } - } - } - else - { - if (lastX != sx) - { - hvGfxLine(hvg, lastX, y1, sx, y2, color); - boundMapBox(hvg, s, e, lastX, y1, sx-lastX, 1, tg->track, - "", buffer, NULL, TRUE, NULL); - if (lastQEnd != qs) { - safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd); - hvGfxTextCentered(hvg, lastX, y2 + lineHeight/2, sx-lastX, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer); - } - } - } - } - else if (lastLevel > sf->level) - { - hvGfxLine(hvg, lastX, y1, sx, y2, color); - hvGfxLine(hvg, sx, y2, sx, y2 - lineHeight - lineHeight/3, color); - char buffer[1024]; - safef(buffer, sizeof buffer, "%d-%d %dbp gap (%.1lf%% N, %.1lf%% masked)",prevSf->qStart,prevSf->qEnd, qs - lastQEnd, queryGapNFrac*100, queryGapMaskedFrac*100); - boundMapBox(hvg, s, e, sx, y2 - lineHeight - lineHeight/3, 2, lineHeight + lineHeight/3, tg->track, - "", buffer, NULL, TRUE, NULL); - safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd); - if (lastQEnd != qs) - hvGfxTextCentered(hvg, sx - 10, y2 + lineHeight/2, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer); - - } - else - { - char buffer[1024]; - safef(buffer, sizeof buffer, "%d-%d %dbp gap (%.1lf%% N, %.1lf%% masked)",prevSf->qStart,prevSf->qEnd, qs - lastQEnd, queryGapNFrac*100, queryGapMaskedFrac*100); - if (sf->orientation == -1) - { - hvGfxLine(hvg, lastX-1, y1, ex, y2, color); - hvGfxLine(hvg, ex, y2, ex, y2 + lineHeight , color); - boundMapBox(hvg, s, e, ex-1, y2, 2, lineHeight , tg->track, - "", buffer, NULL, TRUE, NULL); - safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd); - if (lastQEnd != qs) - hvGfxTextCentered(hvg, ex - 10, y2 + lineHeight, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer); - } - else - { - hvGfxLine(hvg, lastX-1, y1, sx, y2, color); - hvGfxLine(hvg, sx, y2, sx, y2 + lineHeight , color); - boundMapBox(hvg, s, e, sx-1, y2, 2, lineHeight , tg->track, - "", buffer, NULL, TRUE, NULL); - - safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd); - if (lastQEnd != qs) - hvGfxTextCentered(hvg, sx - 10, y2 + lineHeight, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer); - } - } - } - } - if (sf->orientation == -1) - lastX = sx; - else - lastX = ex; - lastS = s; - lastE = e; - lastLevel = sf->level; - lastQEnd = qe; - } -} - -static char *doChromIxSearch(char *trixFile, char *searchName) -/* search ixFile for the searchName, return name if found */ -{ -struct trix *trix = trixOpen(trixFile); -char *trixWords[1]; -int trixWordCount = 1; -trixWords[0] = strLower(searchName); -char *name = NULL; // assume NOT found - -struct trixSearchResult *tsList = trixSearch(trix, trixWordCount, trixWords, tsmExact); -if (tsList) - name = tsList->itemId; // FOUND -return name; -} - -static struct hal_block_results_t *pslSnakeBlocks(char *fileName, struct track *track, char *chrom, unsigned start, unsigned end, unsigned int maxItems) -/* create HAL-like blocks from a bigPsl file. */ -{ -struct hal_block_results_t *head; - -AllocVar(head); - -struct lm *lm = lmInit(0); -//struct bigBedInterval *bb, *bbList = bigBedSelectRangeExt(track, chrom, start, end, lm, maxItems); -struct bigBedInterval *bb, *bbList = bigBedSelectRangeExt(track, chrom, 0, hChromSize(database,chromName), lm, maxItems); - -struct bbiFile *bbi = fetchBbiForTrack(track); -int seqTypeField = 0; -if (sameString(track->tdb->type, "bigPsl")) - { - seqTypeField = bbExtraFieldIndex(bbi, "seqType"); - } -bbiFileClose(&bbi); -for (bb = bbList; bb != NULL; bb = bb->next) - { - char *seq, *cds; - struct psl *psl = pslFromBigPsl(chromName, bb, seqTypeField, &seq, &cds); - unsigned *targetStart = psl->tStarts; - unsigned *queryStart = psl->qStarts; - unsigned *size = psl->blockSizes; - int ii; - - if ((seq != NULL) && (psl->strand[0] == '-')) - reverseComplement(seq, strlen(seq)); - for(ii = 0; ii < psl->blockCount; ii++) - { - struct hal_block_t *block; - AllocVar(block); - slAddHead(&head->mappedBlocks, block); - - block->qChrom = psl->qName; - block->tStart = *targetStart++; - block->qStart = *queryStart++; - block->size = *size++; - block->strand = psl->strand[0]; - block->qSequence = &seq[block->qStart]; - - if (block->strand == '-') - block->qStart = psl->qSize - block->qStart; - } - } - -return head; -} - -void halSnakeLoadItems(struct track *tg) -// load up a snake from a HAL file. This code is called in threads -// so *no* use of globals please. All but full snakes are read into a single -// linked feature. -{ -unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, - SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH); - -char * chromAlias = NULL; // create later when needed -char * chromAliasFile = trackDbSetting(tg->tdb, "searchTrix"); -if (chromAliasFile) - chromAlias = doChromIxSearch(chromAliasFile, chromName); - -char *aliasName = chromName; -if (chromAlias) - { - if (differentWord(chromAlias, aliasName)) - aliasName = chromAlias; - } - -boolean isPsl = sameString(tg->tdb->type, "pslSnake"); - -// if we have a network error we want to put out a message about it -struct errCatch *errCatch = errCatchNew(); -if (errCatchStart(errCatch)) - { - char *fileName = trackDbSetting(tg->tdb, "bigDataUrl"); - char *otherSpecies = trackDbSetting(tg->tdb, "otherSpecies"); - char *errString = "<HAL error message not set>"; - int handle = -1; - if (!isPsl) - { - handle = halOpenLOD(fileName, &errString); - if (handle < 0) - { - errAbort("HAL open error: %s\n", errString); - goto out; - } - } - boolean isPackOrFull = (tg->visibility == tvFull) || - (tg->visibility == tvPack); - hal_dup_type_t dupMode = (isPackOrFull) ? HAL_QUERY_AND_TARGET_DUPS : - HAL_QUERY_DUPS; - hal_seqmode_type_t needSeq = isPackOrFull && (winBaseCount < showSnpWidth) ? HAL_LOD0_SEQUENCE : HAL_NO_SEQUENCE; - int mapBackAdjacencies = (tg->visibility == tvFull); - char codeVarName[1024]; - safef(codeVarName, sizeof codeVarName, "%s.coalescent", tg->tdb->track); - char *coalescent = cartOptionalString(cart, codeVarName); - char *otherDbName = trackHubSkipHubName(database); - struct hal_block_results_t *head = NULL; - if (isPsl) - { - head = pslSnakeBlocks(fileName, tg, chromName, winStart, winEnd, 10000000); - } - else - { - struct slName *aliasList = chromAliasFindAliases(chromName); - struct slName *nativeName = newSlName(aliasName); - slAddHead(&aliasList, nativeName); - for (; aliasList; aliasList = aliasList->next) - { - head = halGetBlocksInTargetRange(handle, otherSpecies, otherDbName, aliasList->name, winStart, winEnd, 0, needSeq, dupMode,mapBackAdjacencies, coalescent, &errString); - if (head != NULL) - break; - } - } - - // did we get any blocks from HAL - if (head == NULL) - { - errAbort("HAL get blocks error: %s\n", errString); - goto out; - } - struct hal_block_t* cur = head->mappedBlocks; - struct linkedFeatures *lf = NULL; - struct hash *qChromHash = newHash(5); - struct linkedFeatures *lfList = NULL; - char buffer[4096]; - -#ifdef NOTNOW - struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks; - - for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next) - { - printf("<br>id: %d qChrom %s\n", targetDupeBlocks->id, targetDupeBlocks->qChrom); - struct hal_target_range_t *range = targetDupeBlocks->tRange; - for(; range; range = range->next) - { - printf("<br> %ld : %ld\n", range->tStart, range->size); - } - } -#endif - - while (cur) - { - struct hashEl* hel; - - if (tg->visibility == tvFull) - safef(buffer, sizeof buffer, "%s", cur->qChrom); - else - { - // make sure the block is on the screen - if (!positiveRangeIntersection(winStart, winEnd, cur->tStart, cur->tStart + cur->size)) - { - cur = cur->next; - continue; - } - safef(buffer, sizeof buffer, "allInOne"); - } - - if ((hel = hashLookup(qChromHash, buffer)) == NULL) - { - AllocVar(lf); - lf->isHalSnake = TRUE; - slAddHead(&lfList, lf); - lf->start = 0; - lf->end = 1000000000; - lf->grayIx = maxShade; - lf->name = cloneString(buffer); - lf->extra = cloneString(buffer); - lf->orientation = (cur->strand == '+') ? 1 : -1; - hashAdd(qChromHash, lf->name, lf); - - // now figure out where the duplication bars go - struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks; - - if ((tg->visibility == tvPack) || (tg->visibility == tvFull)) - for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next) - { - if ((tg->visibility == tvPack) || - ((tg->visibility == tvFull) && - (sameString(targetDupeBlocks->qChrom, cur->qChrom)))) - { - struct hal_target_dupe_list_t* dupeList; - AllocVar(dupeList); - *dupeList = *targetDupeBlocks; - slAddHead(&lf->dupeList, dupeList); - // TODO: should clone the target_range structures - // rather than copying them - } - } - } - else - { - lf = hel->val; - } - - struct snakeFeature *sf; - AllocVar(sf); - slAddHead(&lf->components, sf); - - sf->start = cur->tStart; - sf->end = cur->tStart + cur->size; - sf->qStart = cur->qStart; - sf->qEnd = cur->qStart + cur->size; - sf->orientation = (cur->strand == '+') ? 1 : -1; - sf->tSequence = cloneString(cur->tSequence); - sf->qSequence = cloneString(cur->qSequence); - if (sf->tSequence != NULL) - toUpperN(sf->tSequence, strlen(sf->tSequence)); - if (sf->qSequence != NULL) - toUpperN(sf->qSequence, strlen(sf->qSequence)); - sf->qName = cur->qChrom; - - cur = cur->next; - } - if (tg->visibility == tvFull) - { - for(lf=lfList; lf ; lf = lf->next) - { - slSort(&lf->components, snakeFeatureCmpQStart); - } - } - else if ((tg->visibility == tvPack) && (lfList != NULL)) - { - assert(lfList->next == NULL); - slSort(&lfList->components, snakeFeatureCmpTStart); - } - - //halFreeBlocks(head); - //halClose(handle, myThread); - - tg->items = lfList; - } - -out: -errCatchEnd(errCatch); -if (errCatch->gotError) - { - tg->networkErrMsg = cloneString(errCatch->message->string); - tg->drawItems = bigDrawWarning; - tg->totalHeight = bigWarnTotalHeight; - } -errCatchFree(&errCatch); -} - -void halSnakeDrawLeftLabels(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) -/* Draw left label (shortLabel) in pack and dense modes. */ -{ -if ((vis == tvDense) || (vis == tvPack)) - { - hvGfxSetClip(hvgSide, leftLabelX, yOff + tg->lineHeight, insideWidth, tg->height); - hvGfxTextRight(hvgSide, leftLabelX, yOff + tg->lineHeight, leftLabelWidth-1, tg->lineHeight, - color, font, tg->shortLabel); - hvGfxUnclip(hvgSide); - } -} - -void halSnakeMethods(struct track *tg, struct trackDb *tdb, - int wordCount, char *words[]) -{ -linkedFeaturesMethods(tg); -tg->canPack = tdb->canPack = TRUE; -tg->loadItems = halSnakeLoadItems; -tg->drawItems = snakeDraw; -tg->mapItemName = lfMapNameFromExtra; -tg->subType = lfSubChain; -//tg->extraUiData = (void *) chainCart; -tg->totalHeight = snakeHeight; -tg->drawLeftLabels = halSnakeDrawLeftLabels; - -tg->drawItemAt = snakeDrawAt; -tg->itemHeight = snakeItemHeight; -tg->nextItemButtonable = FALSE; -} -#endif // USE_HAL - -#ifdef NOTNOW - -// from here down are routines to support the visualization of chains as snakes -// this code is currently BROKEN, and may be removed completely in the future - -struct cartOptions - { - enum chainColorEnum chainColor; /* ChromColors, ScoreColors, NoColors */ - int scoreFilter ; /* filter chains by score if > 0 */ - }; - -// mySQL code to read in chains - -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 snakeFeature *sf; -struct dyString *query = dyStringNew(1024); - -if (chainId == -1) - { - sqlDyStringPrintf(query, - "select chainId,tStart,tEnd,qStart from %sLink ", fullName); - if (isSplit) - sqlDyStringPrintf(query,"force index (bin) "); - sqlDyStringPrintf(query, "where ", - } -else - sqlDyStringPrintf(query, - "select chainId, tStart,tEnd,qStart from %sLink where chainId=%d and ", - fullName, chainId); -if (!isSplit) - sqlDyStringPrintf(query, "tName='%s' and ", chromName); -hAddBinToQuery(start, end, query); -sqlDyStringPrintf(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. */ -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; - } - sf->orientation = lf->orientation; - slAddHead(&lf->components, sf); - } - } -sqlFreeResult(&sr); -dyStringFree(&query); -} - -static void fixItems(struct linkedFeatures *lf) -// put all chain blocks from a single query chromosome into one -// linkedFeatures structure -{ -struct linkedFeatures *firstLf, *next; -struct snakeFeature *sf, *nextSf; - -firstLf = lf; -for (;lf; lf = next) - { - next = lf->next; - if (!sameString(firstLf->name, lf->name) && (lf->components != NULL)) - { - slSort(&firstLf->components, snakeFeatureCmpQStart); - firstLf = lf; - } - for (sf = (struct snakeFeature *)lf->components; sf != NULL; sf = nextSf) - { - sf->qName = lf->name; - sf->orientation = lf->orientation; - nextSf = sf->next; - if (firstLf != lf) - { - lf->components = NULL; - slAddHead(&firstLf->components, sf); - } - } - } - -if (firstLf != NULL) - { - slSort(&firstLf->components, snakeFeatureCmpQStart); - firstLf->next = 0; - } -} - - -static void loadLinks(struct track *tg, int seqStart, int seqEnd, - enum trackVisibility vis) -// load up the chain elements into linkedFeatures -{ -int start, end, extra; -char fullName[64]; -int maxOverLeft = 0, maxOverRight = 0; -int overLeft, overRight; -struct linkedFeatures *lf; -struct lm *lm; -struct hash *hash; /* Hash of chain ids. */ -struct sqlConnection *conn; -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. */ -for (lf = tg->items; lf != NULL; lf = lf->next) - { - char buf[256]; - struct chain *pChain = lf->extra; - safef(buf, sizeof(buf), "%d", pChain->id); - hashAdd(hash, buf, lf); - overRight = lf->end - seqEnd; - if (overRight > maxOverRight) - maxOverRight = overRight; - overLeft = seqStart - lf->start ; - if (overLeft > maxOverLeft) - maxOverLeft = overLeft; - } - -if (hash->size) - { - boolean isSplit = TRUE; - /* Make up range query. */ - safef(fullName, sizeof 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 0 -#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); - } - } -hFreeConn(&conn); -} - -void snakeLoadItems(struct track *tg) -// Load chains from a mySQL database -{ -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; - -safef( optionChr, sizeof(optionChr), "%s.chromFilter", tg->table); -optionChrStr = cartUsualString(cart, optionChr, "All"); -int ourStart = winStart; -int ourEnd = winEnd; - -// we're grabbing everything now.. we really should be -// doing this as a preprocessing stage, rather than at run-time -ourStart = 0; -ourEnd = 500000000; -//ourStart = winStart; -//ourEnd = winEnd; -if (startsWith("chr",optionChrStr)) - { - sqlSafef(extraWhere, sizeof(extraWhere), - "qName = \"%s\" and score > %d",optionChrStr, - chainCart->scoreFilter); - sr = hRangeQuery(conn, track, chromName, ourStart, ourEnd, - extraWhere, &rowOffset); - } -else - { - if (chainCart->scoreFilter > 0) - { - sqlSafef(extraWhere, sizeof(extraWhere), - "score > \"%d\"",chainCart->scoreFilter); - sr = hRangeQuery(conn, track, chromName, ourStart, ourEnd, - extraWhere, &rowOffset); - } - else - { - sqlSafef(extraWhere, sizeof(extraWhere), " "); - sr = hRangeQuery(conn, track, chromName, ourStart, ourEnd, - NULL, &rowOffset); - } - } -while ((row = sqlNextRow(sr)) != NULL) - { - 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]; - safef(buffer, sizeof(buffer), "%s", chain.qName); - lf->name = cloneString(buffer); - lf->extra = 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); - -/* now load the items */ -loadLinks(tg, ourStart, ourEnd, tg->visibility); -lf=tg->items; -fixItems(lf); -} /* chainLoadItems() */ - -void snakeMethods(struct track *tg, struct trackDb *tdb, - int wordCount, char *words[]) -/* Fill in custom parts of alignment chains. */ -{ - -struct cartOptions *chainCart; - -AllocVar(chainCart); - -boolean normScoreAvailable = chainDbNormScoreAvailable(tdb); - -/* what does the cart say about coloring option */ -chainCart->chainColor = chainFetchColorOption(cart, tdb, FALSE); - -chainCart->scoreFilter = cartUsualIntClosestToHome(cart, tdb, - FALSE, SCORE_FILTER, 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 */ - - safef(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->canPack = FALSE; -tg->loadItems = snakeLoadItems; -tg->drawItems = snakeDraw; -tg->mapItemName = lfMapNameFromExtra; -tg->subType = lfSubChain; -tg->extraUiData = (void *) chainCart; -tg->totalHeight = snakeHeight; - -tg->drawItemAt = snakeDrawAt; -tg->itemHeight = snakeItemHeight; -} - -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; -} -#endif