f8d4a7651a5843d1c0bfa90cdb7da7582615c263
kate
  Thu Aug 9 13:47:29 2018 -0700
Add filter to hide interactions lacking one or both ends in the window. Helpful for busy/noisy datasets.  refs #21109

diff --git src/hg/hgTracks/interactTrack.c src/hg/hgTracks/interactTrack.c
index f770776..b19dba2 100644
--- src/hg/hgTracks/interactTrack.c
+++ src/hg/hgTracks/interactTrack.c
@@ -33,58 +33,93 @@
     return tg->colorShades[grayInRange(inter->score, 0, 1000)];
     }
 /*
  There must be a better way..., e.g.:
 
 unsigned red = COLOR_32_RED(inter->color);
 unsigned green = COLOR_32_GREEN(inter->color);
 unsigned blue = COLOR_32_BLUE(inter->color);
 */
 unsigned red = (inter->color & 0xff0000) >> 16;
 unsigned green = (inter->color & 0xff00) >> 8;
 unsigned blue = inter->color & 0xff;
 return hvGfxFindColorIx(hvg, red, green, blue);
 }
 
+boolean interactSourceInWindow(struct interact *inter)
+/* True if midpoint of source is on screen */
+{
+unsigned s = interactRegionCenter(inter->sourceStart, inter->sourceEnd);
+return (s >= winStart) && (s < winEnd);
+}
+
+boolean interactTargetInWindow(struct interact *inter)
+/* True if midpoint of target is on screen */
+{
+unsigned t = interactRegionCenter(inter->targetStart, inter->targetEnd);
+return (t >= winStart) && (t < winEnd);
+}
+
 void interactLoadItems(struct track *tg)
 /* Load all interact items in region */
 {
 loadSimpleBedWithLoader(tg, (bedItemLoader)interactLoadAndValidate);
 
 if (slCount(tg->items) == 0 && tg->limitedVisSet)
     {
     // too many items to display
     // borrowed behaviors in bamTrack and vcfTrack
     // TODO BRANEY: make this behavior generic for bigBeds
     // (bigBedSelectRange)
     tg->drawItems = bigDrawWarning;
     tg->networkErrMsg = "Too many items in display (zoom in)"; 
     tg->totalHeight = bigWarnTotalHeight;
     return;
 }
 
-// filter on score
+// filters
+
+// score filter
 char buf[1024];
 safef(buf, sizeof buf, "%s.%s", tg->tdb->track, INTERACT_MINSCORE);
 int minScore = cartUsualInt(cart, buf, 0);
 struct interact *inter, *next, *filteredItems = NULL;
 int count = slCount(tg->items);
+
+// exclude if missing endpoint(s) in window
+char *endsVisible = cartUsualStringClosestToHome(cart, tg->tdb, FALSE,
+                            INTERACT_ENDS_VISIBLE, INTERACT_ENDS_VISIBLE_DEFAULT);
 for (inter = tg->items; inter; inter = next)
     {
     next = inter->next;
     if (inter->score < minScore)
         continue;
+    if (differentString(endsVisible, INTERACT_ENDS_VISIBLE_ANY))
+        {
+        boolean sOnScreen = interactSourceInWindow(inter);
+        boolean tOnScreen = interactTargetInWindow(inter);
+        if (sameString(endsVisible, INTERACT_ENDS_VISIBLE_TWO))
+            {
+            if (!(sOnScreen && tOnScreen))
+                continue;
+            }
+        if (sameString(endsVisible, INTERACT_ENDS_VISIBLE_ONE))
+            {
+            if (!(sOnScreen || tOnScreen))
+                continue;
+            }
+        }
     slAddHead(&filteredItems, inter);
     }
 
 slReverse(&filteredItems);
 // consider sorting by score/value so highest scored items draw last (on top)
 if (slCount(filteredItems) != count)
     labelTrackAsFiltered(tg);
 tg->items = filteredItems;
 }
 
 char *interactMouseover(struct interact *inter, char *otherChrom)
 /* Make mouseover text for an interaction */
 {
 struct dyString *ds = dyStringNew(0);
 if (isEmptyTextField(inter->name))