40a345b04f483a7e67494e62afc8528675eb587e
braney
  Mon Mar 6 12:06:43 2023 -0800
make sure alignment blockse are single coverage over the query.

diff --git src/hg/hgTracks/snake.c src/hg/hgTracks/snake.c
index 61e8425..215f29e 100644
--- src/hg/hgTracks/snake.c
+++ src/hg/hgTracks/snake.c
@@ -16,30 +16,40 @@
 #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"
 
+static int snakeFeatureCmpScore(const void *va, const void *vb)
+/* sort by score of the alignment. */
+{
+const struct snakeFeature *a = *((struct snakeFeature **)va);
+const struct snakeFeature *b = *((struct snakeFeature **)vb);
+int diff = b->score - a->score;
+
+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;
 }
 
@@ -1135,76 +1145,112 @@
 
 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;
+        sf->score = lf->score;
 	nextSf = sf->next;
 	if (firstLf != lf)
 	    {
 	    lf->components = NULL;
 	    slAddHead(&firstLf->components, sf);
 	    }
 	}
     }
 
 if (firstLf != NULL)
     {
     slSort(&firstLf->components, snakeFeatureCmpQStart);
     firstLf->next = 0;
     }
 }
 
 
 void snakeDrawLeftLabels()
 {
 }
 
 static void makeSnakeFeatures(struct linkedFeatures *lf)
+/* allocate an info structure for every block in the alignment. */
 {
 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;
 	this->orientation = lf->orientation;
         slAddHead(&sfList, this);
         }
     lf->components = (struct simpleFeature *)sfList;
     }
 }
 
+static void makeSingleCoverage(struct linkedFeatures *lf)
+/* Because snakes are a display of O+O of the query sequence projected onto the reference sequence, 
+ * we need to only have one copy of each piece of the query sequence. */
+{
+for(; lf; lf = lf->next)   // for each query sequence
+    {
+    slSort(&lf->components, snakeFeatureCmpScore); // we want to choose the higher scoring alignements
+    Bits *qBits = bitAlloc(lf->qSize); // the bit array we use to keep track if we've seen this query sequence
+    struct simpleFeature *sf = lf->components;
+    struct simpleFeature *prevSf = NULL;
+
+    for(; sf ; sf = sf->next)
+        {
+        // have we seen this query range?
+        if (bitCountRange(qBits, sf->qStart, sf->qEnd - sf->qStart))
+            {
+            // if we've seen this query sequence, then delete it
+            if (prevSf == NULL)
+                lf->components = sf->next;
+            else
+                prevSf->next = sf->next;
+            }
+        else
+            {
+            bitSetRange(qBits, sf->qStart, sf->qEnd - sf->qStart);
+            prevSf = sf;
+            }
+        }
+
+    slSort(&lf->components, snakeFeatureCmpQStart);
+    }
+}
+
 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, linkedFeaturesCmpName);
     makeSnakeFeatures(track->items);
     fixItems(track->items);
+    makeSingleCoverage(track->items);
     track->visibility = track->limitedVis = tvFull;
     track->canPack = FALSE;
     }
 }