cee60adf868375933ac0eb26e1b84048639e804f
braney
  Fri Feb 24 11:07:54 2023 -0800
ongoing work on snakes

diff --git src/hg/hgTracks/snake.c src/hg/hgTracks/snake.c
index 065a6ca..3e0ba5a 100644
--- src/hg/hgTracks/snake.c
+++ src/hg/hgTracks/snake.c
@@ -16,35 +16,30 @@
 #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 "bigPsl.h"
 #include "snake.h"
 
-// this is the number of pixels used by the target self-align bar
-#define DUP_LINE_HEIGHT	0
-// this is the number of pixels used when displaying the insertion lengths
-#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;
 }
 
@@ -521,36 +516,36 @@
 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
 
+// order the blocks so lowest start position is first
+slReverse(&proposedList);
 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;
@@ -619,41 +614,37 @@
 {
 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;
+int height = 0;
+struct linkedFeatures *item = tg->items;
 
-for (item=tg->items;item; item = item->next)
+for (;item; item = item->next)
     {
     height += tg->itemHeight(tg, item);
     }
-if (height < DUP_LINE_HEIGHT + tg->lineHeight)
-    height = DUP_LINE_HEIGHT + tg->lineHeight;
 return height;
 }
 
 
 //  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 Color hashColor(char *name)
 {
 bits32 hashVal = hashString(name);
@@ -675,30 +666,72 @@
     {
     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 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 snake 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);
+    } 
+}
+
 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);
 
@@ -1095,30 +1128,31 @@
 
 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->next = lf;
 	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);
 	    }
 	}
     }
 
@@ -1135,51 +1169,42 @@
 }
 
 static void makeSnakeFeatures(struct linkedFeatures *lf)
 {
 for(; lf; lf = lf->next)
     {
     struct simpleFeature *sf = lf->components;
     struct snakeFeature *sfList = NULL;
 
     for(;sf; sf = sf->next)
         {
         struct snakeFeature *this;
 
         AllocVar(this);
         *(struct simpleFeature *)this = *sf;
-        /*
-	if ((lf) && lf->orientation == -1)
-	    {
-	    int temp;
-
-	    temp = this->qStart;
-	    this->qStart = lf->qSize - this->qEnd;
-	    this->qEnd = lf->qSize - temp;
-	    }
-            */
 	this->orientation = lf->orientation;
         slAddHead(&sfList, this);
         }
     lf->components = (struct simpleFeature *)sfList;
     }
 }
 
 void maybeLoadSnake(struct track *track)
 /* check to see if we're doing snakes and if so load the correct methods. */
 {
 boolean doSnake = cartOrTdbBoolean(cart, track->tdb, "doSnake", FALSE);
 if (doSnake)
     {
     track->drawLeftLabels = snakeDrawLeftLabels;
     track->itemHeight = snakeItemHeight;
     track->totalHeight = snakeHeight;
     track->drawItemAt = snakeDrawAt;
+    track->drawItems = snakeDraw;
 
-    slSort(track->items, linkedFeaturesCmpStart);
+    slSort(&track->items, linkedFeaturesCmpName);
     makeSnakeFeatures(track->items);
     fixItems(track->items);
     track->visibility = track->limitedVis = tvFull;
     track->canPack = FALSE;
     }
 }