db44b993ec6123985aaae9aade94f329b0db49ec
kate
  Sun Sep 23 21:03:19 2018 -0700
Add option to merge interactions for a single target, in pack and squish modes.  Initial version for demo. refs #21917

diff --git src/hg/hgTracks/interactTrack.c src/hg/hgTracks/interactTrack.c
index 14e1c14..0aa1f03 100644
--- src/hg/hgTracks/interactTrack.c
+++ src/hg/hgTracks/interactTrack.c
@@ -120,54 +120,113 @@
 {
 }
 
 void interactFreeItems(struct track *tg)
 /* Free up interact items track */
 {
 interactFreeList((struct interact **)(&tg->items));
 }
 
 static boolean isBedMode(struct track *tg)
 /* Pack and squish modes display using BED linked features code */
 {
 return tg->visibility == tvPack || tg->visibility == tvSquish;
 }
 
+static struct linkedFeatures *interactToLf(struct interact *inter, boolean doColor)
+/* Convert interact BED to linkedFeatures */
+{
+struct bed *bed = interactToBed(inter);
+struct linkedFeatures *lf = lfFromBed(bed);
+if (doColor)
+    {
+    lf->extra = (void *)USE_ITEM_RGB;   /* signal for coloring */
+    lf->filterColor = bed->itemRgb;
+    }
+bedFree(&bed);
+// TODO: use lfFromBedExtra with scoreMin, scoreMax ?
+return lf;
+}
+
 void interactLoadItems(struct track *tg)
 /* Load interact items in interact format */
 {
 loadAndFilterItems(tg);
 if (isBedMode(tg))
     {
-    /* convert to BEDs for linked feature display */
+    // convert to BEDs for linked feature display
     struct interact *inters = tg->items, *inter;
     struct linkedFeatures *lfs = NULL, *lf;
+    struct hash *intersMerge = hashNew(0);
+    boolean doMerge = cartVarExists(cart, "interactTargetMerge");
+    boolean doColor = !tg->colorShades;
     for (inter = inters; inter; inter = inter->next)
         {
-        struct bed *bed = interactToBed(inter);
-        lf = lfFromBed(bed);
-        if (!tg->colorShades)
+        if (doMerge)
             {
-            lf->extra = (void *)USE_ITEM_RGB;   /* signal for coloring */
-            lf->filterColor = bed->itemRgb;
+            lf = (struct linkedFeatures *) hashFindVal(intersMerge, inter->targetName);
+            if (lf)
+                {
+                // add a simple feature for this source to the linked feature
+                struct simpleFeature *sf = NULL;
+                AllocVar(sf);
+                sf->start = inter->sourceStart;
+                sf->end = inter->sourceEnd;
+                struct simpleFeature *sfs = lf->components;
+                slAddHead(&sfs, sf);
+                lf->components = sfs;
+                // TODO: consider averaging score
+
+                // FIXME: just for demo
+                struct bed *tempBed = interactToBed(inter);
+                if (orientFromChar(tempBed->strand[0]) != lf->orientation)
+                    lf->orientation = 0;
+                bedFree(&tempBed);
                 }
-        bedFree(&bed);
-        // TODO: use lfFromBedExtra with scoreMin, scoreMax
+            else
+                {
+                lf = interactToLf(inter, doColor);
+                lf->name = inter->targetName;
+                lf->tallStart = inter->targetStart;
+                lf->tallEnd = inter->targetEnd;
+                hashAdd(intersMerge, lf->name, lf);
+                }
+            }
+        else 
+            {
+            lf = interactToLf(inter, doColor);
             slAddHead(&lfs, lf);
             }
+        }
+    if (doMerge)
+        {
+        // sort simplefeatures and adjust bounds of merged features
+        struct hashEl *el, *els = hashElListHash(intersMerge);
+        for (el = els; el; el = el->next)
+            {
+            lf = (struct linkedFeatures *)el->val;
+            linkedFeaturesSortAndBound(lf);
+            slAddHead(&lfs, lf);
+            }
+        slSort(&lfs, linkedFeaturesCmp);
+        }
+    else
+        {
         slReverse(&lfs);
+        }
     tg->items = lfs;
+    // TODO: consider freeing interact items
     }
 else
     {
     tg->mapsSelf = TRUE;
     tg->totalHeight = interactTotalHeight;
     tg->drawLeftLabels = interactDrawLeftLabels;
     tg->freeItems = interactFreeItems;
     }
 }
 
 char *interactMouseover(struct interact *inter, char *otherChrom)
 /* Make mouseover text for an interaction */
 {
 struct dyString *ds = dyStringNew(0);
 if (isEmptyTextField(inter->name))