e7f02d37914178e82c5f2b481cf6f294c6687d39
jcasper
  Mon Nov 28 16:35:16 2022 -0800
Allow users to invert Hi-C plots, refs #30330, #30343

diff --git src/hg/hgTracks/hicTrack.c src/hg/hgTracks/hicTrack.c
index 322cc02..684482d 100644
--- src/hg/hgTracks/hicTrack.c
+++ src/hg/hgTracks/hicTrack.c
@@ -276,146 +276,166 @@
     *rightEnd = winEnd-winStart;
 }
 
 
 static void drawHicTriangle(struct track *tg, int seqStart, int seqEnd,
         struct hvGfx *hvg, int xOff, int yOff, int width, 
         MgFont *font, Color color, enum trackVisibility vis)
 /* Draw a list of Hi-C interactions in a triangle */
 {
 double xScale = scaleForWindow(width, seqStart, seqEnd);
 double yScale = xScale;
 int maxHeight = tg->height;
 struct interact *hicItem = NULL;
 struct hicMeta *hicFileInfo = (struct hicMeta*)tg->customPt;
 int binSize = hicUiFetchResolutionAsInt(cart, tg->tdb, hicFileInfo, winEnd-winStart);
+boolean invert = hicUiFetchInverted(cart, tg->tdb);
 
 yScale *= hicSqueezeFactor(vis);
 
 double maxScore = getHicMaxScore(tg);
 Color *colorIxs = colorSetForHic(hvg, tg, HIC_SCORE_BINS+1);
 if (colorIxs == NULL)
     return; // something went wrong with colors
 
 for (hicItem = (struct interact *)tg->items; hicItem; hicItem = hicItem->next)
     {
     int leftStart, leftEnd, rightStart, rightEnd;
     calcItemLeftRightBoundaries(&leftStart, &leftEnd, &rightStart, &rightEnd, binSize, hicItem);
     int colorIx;
     if (hicItem->value > maxScore)
         colorIx = colorIxs[HIC_SCORE_BINS];
     else
         colorIx = colorIxs[(int)(HIC_SCORE_BINS * hicItem->value/maxScore)];
     // adding four polygon points for a diamond, based on the starts and ends of the source and target coordinate ranges.
     struct gfxPoly *diamond = gfxPolyNew();
 
     // left point of the diamond
     double x = xScale * (leftStart+rightStart)/2.0;
     double y = yScale * (rightStart-leftStart)/2.0;
-    gfxPolyAddPoint(diamond, (int)x+xOff, maxHeight-(int)y+yOff);
+    if (!invert)
+        y = maxHeight-(int)y;
+    gfxPolyAddPoint(diamond, (int)x+xOff, (int)y+yOff);
 
     // top point of the diamond
     x = xScale * (leftStart+rightEnd)/2.0;
     y = yScale * (rightEnd-leftStart)/2.0;
-    gfxPolyAddPoint(diamond, (int)x+xOff, maxHeight-(int)y+yOff);
+    if (!invert)
+        y = maxHeight-(int)y;
+    gfxPolyAddPoint(diamond, (int)x+xOff, (int)y+yOff);
 
     // right point of the diamond
     x = xScale * ((leftEnd + rightEnd)/2.0);
     y = yScale * (rightEnd-leftEnd)/2.0;
-    gfxPolyAddPoint(diamond, (int)x+xOff, maxHeight-(int)y+yOff);
+    if (!invert)
+        y = maxHeight-(int)y;
+    gfxPolyAddPoint(diamond, (int)x+xOff, (int)y+yOff);
 
     // bottom point of the diamond
     x = xScale * (leftEnd+rightStart)/2.0;
     y = yScale * (rightStart-leftEnd)/2.0;
-    gfxPolyAddPoint(diamond, (int)x+xOff, maxHeight-(int)y+yOff);
+    if (!invert)
+        y = maxHeight-(int)y;
+    gfxPolyAddPoint(diamond, (int)x+xOff, (int)y+yOff);
     hvGfxDrawPoly(hvg, diamond, colorIx, TRUE);
     gfxPolyFree(&diamond);
     }
 }
 
 
 
 static void drawHicSquare(struct track *tg, int seqStart, int seqEnd,
         struct hvGfx *hvg, int xOff, int yOff, int width, 
         MgFont *font, Color color, enum trackVisibility vis)
 /* Draw a Hi-C heatmap as a square */
 {
 double xScale = scaleForWindow(width, seqStart, seqEnd);
 double yScale = xScale;
 int maxHeight = tg->height;
 struct interact *hicItem = NULL;
 struct hicMeta *hicFileInfo = (struct hicMeta*)tg->customPt;
 int binSize = hicUiFetchResolutionAsInt(cart, tg->tdb, hicFileInfo, winEnd-winStart);
+boolean invert = hicUiFetchInverted(cart, tg->tdb);
 if (binSize == 0)
     return;
 
 yScale *= hicSqueezeFactor(vis);
 
 double maxScore = getHicMaxScore(tg);
 Color *colorIxs = colorSetForHic(hvg, tg, HIC_SCORE_BINS+1);
 if (colorIxs == NULL)
     return; // something went wrong with colors
 
 for (hicItem = (struct interact *)tg->items; hicItem; hicItem = hicItem->next)
     {
     int leftStart, leftEnd, rightStart, rightEnd;
     calcItemLeftRightBoundaries(&leftStart, &leftEnd, &rightStart, &rightEnd, binSize, hicItem);
 
     int colorIx;
     if (hicItem->value > maxScore)
         colorIx = colorIxs[HIC_SCORE_BINS];
     else
         colorIx = colorIxs[(int)(HIC_SCORE_BINS * hicItem->value/maxScore)];
     double x = xScale * leftStart;
     double y = yScale * ((winEnd-winStart)-rightStart);
-    hvGfxBox(hvg, (int)x+xOff, maxHeight-(int)y+yOff, (int)(xScale*(leftEnd-leftStart))+1, (int)(yScale*(rightEnd-rightStart))+1, colorIx);
+    y = maxHeight-(int)y;
+    if (invert)  // when inverted, the top left of the box corresponds to rightEnd instead of rightStart
+        y = yScale * ((winEnd-winStart)-rightEnd);
+    hvGfxBox(hvg, (int)x+xOff, (int)y+yOff, (int)(xScale*(leftEnd-leftStart))+1, (int)(yScale*(rightEnd-rightStart))+1, colorIx);
     if (leftStart != rightStart)
         {
         x = xScale * rightStart;
         y = yScale * ((winEnd-winStart)-leftStart);
-        hvGfxBox(hvg, (int)x+xOff, maxHeight-(int)y+yOff, (int)(xScale*(rightEnd-rightStart))+1, (int)(yScale*(leftEnd-leftStart))+1, colorIx);
+        y = maxHeight-(int)y;
+        if (invert)
+            y = yScale * ((winEnd-winStart)-leftEnd);
+        hvGfxBox(hvg, (int)x+xOff, (int)y+yOff, (int)(xScale*(rightEnd-rightStart))+1, (int)(yScale*(leftEnd-leftStart))+1, colorIx);
         }
     }
     // Draw top-left to bottom-right diagonal axis line in black
     int colorIx = hvGfxFindColorIx(hvg, 0, 0, 0);
+    if (invert)  // Draw bottom-left to top-right instead
+        hvGfxLine(hvg, xOff, maxHeight+yOff, ((winEnd-winStart)*xScale)+xOff, yOff, colorIx);
+    else
         hvGfxLine(hvg, xOff, yOff, ((winEnd-winStart)*xScale)+xOff, maxHeight+yOff, colorIx);
 }
 
 
 int cmpHicItems(const void *elem1, const void *elem2)
 /* Comparison function for sorting Hi-C interactions by score */
 {
 struct interact *item1 = *((struct interact**)elem1);
 struct interact *item2 = *((struct interact**)elem2);
 if (item1->value > item2->value)
     return 1;
 if (item1->value < item2->value)
     return -1;
 return 0;
 }
 
 static void drawHicArc(struct track *tg, int seqStart, int seqEnd,
         struct hvGfx *hvg, int xOff, int yOff, int width, 
         MgFont *font, Color color, enum trackVisibility vis)
 /* Draw Hi-C interactions in arc mode */
 {
 double xScale = scaleForWindow(width, seqStart, seqEnd);
 double yScale = xScale;
 int maxHeight = tg->height;
 struct interact *hicItem = NULL;
 struct hicMeta *hicFileInfo = (struct hicMeta*)tg->customPt;
 int binSize = hicUiFetchResolutionAsInt(cart, tg->tdb, hicFileInfo, winEnd-winStart);
+boolean invert = hicUiFetchInverted(cart, tg->tdb);
 if (binSize == 0)
     return;
 
 yScale *= hicSqueezeFactor(vis);
 
 double maxScore = getHicMaxScore(tg);
 Color *colorIxs = colorSetForHic(hvg, tg, HIC_SCORE_BINS+1);
 if (colorIxs == NULL)
     return; // something went wrong with colors
 
 slSort(&tg->items, cmpHicItems); // So that the darkest arcs are drawn on top and not lost
 for (hicItem = (struct interact *)tg->items; hicItem; hicItem = hicItem->next)
     {
     int leftStart = hicItem->sourceStart - winStart;
     int leftMidpoint = leftStart + binSize/2;
@@ -424,33 +444,38 @@
     if ((leftMidpoint < 0) || (leftMidpoint > winEnd-winStart))
         continue;  // skip this item - we'd be drawing to a point off the screen
     if ((rightMidpoint < 0) || (rightMidpoint > winEnd-winStart))
         continue;  // skip this item - we'd be drawing to a point off the screen
 
     int colorIx;
     if (hicItem->value > maxScore)
         colorIx = colorIxs[HIC_SCORE_BINS];
     else
         colorIx = colorIxs[(int)(HIC_SCORE_BINS * hicItem->value/maxScore)];
 
     double leftx = xScale * leftMidpoint;
     double rightx = xScale * rightMidpoint;
     double midx = xScale * (rightMidpoint+leftMidpoint)/2.0;
     double midy = yScale * (rightMidpoint-leftMidpoint)/2.0;
+    if (!invert)
+        midy = maxHeight-(int)midy;
     midy *= 1.5; // Heuristic scaling for better use of vertical space
-    hvGfxCurve(hvg, (int)leftx+xOff, maxHeight+yOff, (int)midx+xOff, maxHeight-(int)midy+yOff,
-            (int)rightx+xOff, maxHeight+yOff, colorIx, FALSE);
+    int lefty = maxHeight, righty = maxHeight; // the height of the endpoints
+    if (invert)
+        lefty = righty = 0;
+    hvGfxCurve(hvg, (int)leftx+xOff, lefty+yOff, (int)midx+xOff, midy+yOff,
+            (int)rightx+xOff, righty+yOff, colorIx, FALSE);
     }
 }
 
 void hicDrawItems(struct track *tg, int seqStart, int seqEnd,
         struct hvGfx *hvg, int xOff, int yOff, int width, 
         MgFont *font, Color color, enum trackVisibility vis)
 /* Draw a set of Hi-C interactions with the current user settings. */
 {
 char *drawMode = hicUiFetchDrawMode(cart, tg->tdb);
 if (sameString(drawMode,HIC_DRAW_MODE_SQUARE))
     drawHicSquare(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis);
 else if (sameString(drawMode,HIC_DRAW_MODE_TRIANGLE))
     drawHicTriangle(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis);
 else if (sameString(drawMode,HIC_DRAW_MODE_ARC))
     drawHicArc(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis);