2a99d78cddf4b7de673435f911262ee25b36c238
braney
  Sun Feb 12 14:14:18 2023 -0800
ongoing work on snake display for chains and psls

diff --git src/hg/hgTracks/chainSnakeTrack.c src/hg/hgTracks/chainSnakeTrack.c
index acd36e2..065a6ca 100644
--- src/hg/hgTracks/chainSnakeTrack.c
+++ src/hg/hgTracks/chainSnakeTrack.c
@@ -17,67 +17,33 @@
 #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 "bigPsl.h"
 #include "snake.h"
 
 // this is the number of pixels used by the target self-align bar
-#define DUP_LINE_HEIGHT	4
+#define DUP_LINE_HEIGHT	0
 // 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 */
-    };
-
-#ifdef NOTNOW
-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;
-}
-#endif
-static int snakeFeatureCmpQSequence(const void *va, const void *vb)
-/* sort by sequence name of the query sequence */
-{
-const struct snakeFeature *a = *((struct snakeFeature **)va);
-const struct snakeFeature *b = *((struct snakeFeature **)vb);
-
-return strcmp(a->qSequence, b->qSequence);
-}
+#define INSERT_TEXT_HEIGHT 0
 
 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;
 }
@@ -404,33 +370,33 @@
 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
+// we use the snakeInfo field to keep track of whether we already
 // calculated the height of this snake
-if (lf->codons == NULL)
+if (lf->snakeInfo == 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();
@@ -477,31 +443,31 @@
 	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;
+    lf->snakeInfo = 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");
@@ -592,86 +558,74 @@
 // 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
+// we use the snakeIfno field to keep track of whether we already
 // calculated the height of this snake
-if (lf->codons == NULL)
+if (lf->snakeInfo == 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;
+    lf->snakeInfo = 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;
+struct snakeInfo *si = (struct snakeInfo *)lf->snakeInfo;
 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)
@@ -679,85 +633,38 @@
 
 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
 };
 
-#ifdef NOTNOW
-static int snakePalette[] =
-{
-0x1f77b4, 0xff7f0e, 0x2ca02c, 0xd62728, 0x9467bd, 0x8c564b, 0xe377c2, 0x7f7f7f, 0xbcbd22, 0x17becf
-};
-#endif
 
 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
 {
@@ -848,59 +755,30 @@
         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);
         }
     }
 
-#ifdef NOTNOW
-// 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;
-    }
-#endif
-
 // 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)
@@ -1079,82 +957,33 @@
 
     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);
         if (queryInsertSize > 100)
             color = MG_ORANGE;
-#ifdef NOTNOW
-            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);
-#endif
         }
         double queryGapNFrac = 0.0;
         double queryGapMaskedFrac = 0.0;
-        #ifdef NOTNOW
-        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);
-        }
-        #endif
 
 	// 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))
 		{
@@ -1246,176 +1075,36 @@
 		    }
 		}
 	    }
 	}
     if (sf->orientation == -1)
 	lastX = sx;
     else
 	lastX = ex;
     lastS = s;
     lastE = e;
     lastLevel = sf->level;
     lastQEnd = qe;
     }
 }
 
-#ifdef NOTNOW
-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;
-}
-#endif
-
-
-
-
-
-// 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 ",
-    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;
@@ -1429,291 +1118,68 @@
 	    {
 	    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
+void snakeDrawLeftLabels()
 {
-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)
+static void makeSnakeFeatures(struct linkedFeatures *lf)
 {
-    boolean isSplit = TRUE;
-    /* Make up range query. */
-    safef(fullName, sizeof fullName, "%s_%s", chromName, tg->table);
-    if (!hTableExists(database, fullName))
+for(; lf; lf = lf->next)
     {
-	strcpy(fullName, tg->table);
-	isSplit = FALSE;
-	}
+    struct simpleFeature *sf = lf->components;
+    struct snakeFeature *sfList = NULL;
 
-    /* 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
+    for(;sf; sf = sf->next)
         {
-	/* 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);
-}
+        struct snakeFeature *this;
 
-static Color chainScoreColor(struct track *tg, void *item, struct hvGfx *hvg)
+        AllocVar(this);
+        *(struct simpleFeature *)this = *sf;
+        /*
+	if ((lf) && lf->orientation == -1)
 	    {
-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 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;
+	    int temp;
 
-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);
+	    temp = this->qStart;
+	    this->qStart = lf->qSize - this->qEnd;
+	    this->qEnd = lf->qSize - temp;
 	    }
+            */
+	this->orientation = lf->orientation;
+        slAddHead(&sfList, this);
         }
-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;
+    lf->components = (struct simpleFeature *)sfList;
     }
-    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);
-
-/* we need to sort by query chrom so they'll bunch up together */
-slSort(&tg->items, snakeFeatureCmpQSequence);
-lf=tg->items;
-fixItems(lf);
-}	/*	chainLoadItems()	*/
-
-static void snakeDrawLeftLabels()
-{
 }
 
-void snakeMethods(struct track *tg, struct trackDb *tdb, 
-	int wordCount, char *words[])
-/* Fill in custom parts of alignment chains. */
+void maybeLoadSnake(struct track *track)
+/* check to see if we're doing snakes and if so load the correct methods. */
 {
-
-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)
+boolean doSnake = cartOrTdbBoolean(cart, track->tdb, "doSnake", FALSE);
+if (doSnake)
     {
-	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 */
+    track->drawLeftLabels = snakeDrawLeftLabels;
+    track->itemHeight = snakeItemHeight;
+    track->totalHeight = snakeHeight;
+    track->drawItemAt = snakeDrawAt;
 
-    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;
+    slSort(track->items, linkedFeaturesCmpStart);
+    makeSnakeFeatures(track->items);
+    fixItems(track->items);
+    track->visibility = track->limitedVis = tvFull;
+    track->canPack = FALSE;
     }
-
-tg->canPack = FALSE;
-tg->loadItems = snakeLoadItems;
-tg->drawItems = snakeDraw;
-tg->mapItemName = lfMapNameFromExtra;
-tg->subType = lfSubChain;
-tg->extraUiData = (void *) chainCart;
-tg->totalHeight = snakeHeight; 
-tg->drawLeftLabels = snakeDrawLeftLabels;
-
-tg->drawItemAt = snakeDrawAt;
-tg->itemHeight = snakeItemHeight;
 }