eb5c9cd277c2bcd521aa461d06e9d8a32509c1d3
braney
  Thu Oct 9 12:17:30 2025 -0700
make it possible to use a cart variable in addition to an hg.conf
variable to turn on quickLift

diff --git src/hg/hgConvert/hgConvert.c src/hg/hgConvert/hgConvert.c
index 1ee630cb9c7..dc35cb6c0e7 100644
--- src/hg/hgConvert/hgConvert.c
+++ src/hg/hgConvert/hgConvert.c
@@ -14,30 +14,35 @@
 #include "htmshell.h"
 #include "hdb.h"
 #include "hui.h"
 #include "cart.h"
 #include "web.h"
 #include "chain.h"
 #include "liftOver.h"
 #include "liftOverChain.h"
 #include "chromInfo.h"
 #include "net.h"
 #include "genark.h"
 #include "trackHub.h"
 #include "hubConnect.h"
 #include "quickLift.h"
 #include "chromAlias.h"
+#ifdef NOTNOW
+#include "jsHelper.h"
+#include "bigChain.h"
+#include "bigLink.h"
+#endif
 
 
 /* CGI Variables */
 #define HGLFT_TOORG_VAR   "hglft_toOrg"           /* TO organism */
 #define HGLFT_TODB_VAR   "hglft_toDb"           /* TO assembly */
 #define HGLFT_DO_CONVERT "hglft_doConvert"	/* Do the actual conversion */
 
 /* Global Variables */
 static struct cart *cart;	        /* CGI and other variables */
 static struct hash *oldVars = NULL;
 static char *organism = NULL;
 static char *database = NULL;
 
 /* Javascript to support New Assembly pulldown when New Genome changes. */
 /* Copies selected values to a hidden form */
@@ -55,31 +60,31 @@
 
 struct dbDb *toDb =  genarkLiftOverDb(name);
 if (toDb == NULL)
     errAbort("Can't find %s in matchingDb", name);
 return toDb;
 }
 
 static void askForDestination(struct liftOverChain *liftOver, char *fromPos,
 	struct dbDb *fromDb, struct dbDb *toDb)
 /* set up page for entering data */
 {
 struct dbDb *dbList;
 boolean askAboutQuickLift = FALSE;
 //boolean quickLiftChainExists =  (quickLiftGetChain(fromDb->name, toDb->name) != 0);
 
-if (quickLiftEnabled())
+if (quickLiftEnabled(cart))
     askAboutQuickLift = TRUE;
 
 cartWebStart(cart, database, "Convert %s to New Assembly", fromPos);
 
 /* create HMTL form */
 puts("<FORM ACTION=\"../cgi-bin/hgConvert\" NAME=\"mainForm\">\n");
 cartSaveSession(cart);
 
 /* create HTML table for layout purposes */
 puts("\n<TABLE WIDTH=\"100%%\">\n");
 
 /* top row -- labels */
 cgiSimpleTableRowStart();
 cgiTableField("Old genome: ");
 cgiTableField("Old assembly: ");
@@ -274,34 +279,190 @@
 rawList = chainLoadIntersecting(fileName, chrom, start, end);
 for (chain = rawList; chain != NULL; chain = next)
     {
     struct chain *subChain, *chainToFree;
     next = chain->next;
     chainSubsetOnT(chain, start, end, &subChain, &chainToFree);
     if (subChain != NULL)
 	slAddHead(&chainList, subChain);
     if (chainToFree != NULL)
         chainFree(&chain);
     }
 slSort(&chainList, chainCmpScore);
 return chainList;
 }
 
+#ifdef NOTNOW
+struct segment
+{
+struct segment *next;
+unsigned start, end;
+char strand;
+};
+
+void compressSegs(struct segment *segs)
+{
+struct segment *nextSeg = NULL;
+struct segment *growSeg = NULL;
+
+for(; segs; segs = nextSeg)
+    {
+    nextSeg = segs->next;
+    if (nextSeg == NULL)
+        break;
+
+    if (growSeg == NULL)
+        growSeg = segs;
+
+    if ((nextSeg->start < growSeg->end + 10000) || (nextSeg->strand != growSeg->strand))
+        {
+        growSeg->end = nextSeg->end;
+        //nextSeg = nextSeg->next;
+        }
+    else
+        {
+        growSeg->next = segs;
+        growSeg = NULL;
+        }
+    }
+}
+
+static void getSegs(char *fromDb, char *toDb, struct segment **fromSegs, struct segment **toSegs, char *chrom, unsigned seqStart, unsigned seqEnd)
+{
+char *quickLiftFile = quickLiftGetChainPath(cart, fromDb, toDb);
+struct lm *lm = lmInit(0);
+//struct bigBedInterval *bbChain, *bbChainList =  bigBedIntervalQuery(bbiChain, chrom, seqStart, seqEnd, 0, lm);
+struct bbiFile *bbiChain = bigBedFileOpenAlias(quickLiftFile, chromAliasFindAliases);
+struct bigBedInterval *bbChain, *bbChainList =  bigBedIntervalQuery(bbiChain, chrom, seqStart, seqEnd, 0, lm);
+
+char *links = bigChainGetLinkFile(quickLiftFile);
+struct bbiFile *bbiLink = bigBedFileOpenAlias(links, chromAliasFindAliases);
+struct bigBedInterval  *bbLink, *bbLinkList =  bigBedIntervalQuery(bbiLink, chrom, seqStart, seqEnd, 0, lm);
+
+char *chainRow[1024];
+char *linkRow[1024];
+char startBuf[16], endBuf[16];
+
+bigBedIntervalToRow(bbChainList, chrom, startBuf, endBuf, chainRow, ArraySize(chainRow));
+struct bigChain *fbc = bigChainLoad(chainRow);
+
+for (bbChain = bbChainList; bbChain != NULL; bbChain = bbChain->next)
+    {
+    bigBedIntervalToRow(bbChain, chrom, startBuf, endBuf, chainRow, ArraySize(chainRow));
+    struct bigChain *bc = bigChainLoad(chainRow);
+    if (differentString(bc->chrom, fbc->chrom))
+        continue;
+
+   for (bbLink = bbLinkList; bbLink != NULL; bbLink = bbLink->next)
+        {
+        bigBedIntervalToRow(bbLink, chrom, startBuf, endBuf, linkRow, ArraySize(linkRow));
+        struct bigLink *bl = bigLinkLoad(linkRow);
+
+        if (!sameString(bl->name, bc->name))
+            continue;
+
+        boolean isFlipped = fbc->strand[0] != bc->strand[0];
+        struct segment *seg;
+        AllocVar(seg);
+        seg->start = bl->chromStart;
+        seg->end = bl->chromEnd;
+        seg->strand = 0;
+        slAddHead(fromSegs, seg);
+
+        unsigned width = bl->chromEnd - bl->chromStart;
+        unsigned qStart = bl->qStart;
+        unsigned qEnd = bl->qStart + width;
+        if (bc->strand[0] == '-')
+            {
+            qStart = bc->qSize - qStart;
+            qEnd = bc->qSize - qEnd;
+            }
+
+        AllocVar(seg);
+        seg->start = qStart;
+        seg->end = qEnd;
+        seg->strand = isFlipped;
+        slAddHead(toSegs, seg);
+        }
+    }
+slReverse(toSegs);
+//compressSegs(*toSegs);
+slReverse(fromSegs);
+//compressSegs(*fromSegs);
+
+}
+
+static void printSegs(struct segment *segs)
+{
+unsigned segNum = 0;
+
+jsInline("segments: [\n");
+for(; segs; segs = segs->next)
+    jsInlineF("{ name: '%d', start: %d, end: %d },\n", segNum++, segs->start, segs->end);
+jsInline("]\n");
+}
+
+static void drawSegments(char *fromDb, char *toDb, struct chain *chain)
+{
+struct segment *fromSegs = NULL;
+struct segment *toSegs = NULL;
+/*
+unsigned seqStart = chain->tStart;
+unsigned seqEnd = chain->tEnd;
+char *chrom = chain->tName;
+*/
+
+unsigned qStart = chain->qStart;
+unsigned qEnd = chain->qEnd;
+if (chain->qStrand == '-')
+    {
+    unsigned saveQStart = qStart;
+    qStart = chain->qSize - qEnd;
+    qEnd = chain->qSize - saveQStart;
+    }
+
+getSegs(fromDb, toDb, &fromSegs, &toSegs, chain->qName, chain->qStart, chain->qEnd);
+
+printf("<canvas id='canvas' width='900' height='500'></canvas>");
+jsIncludeFile("parallelSegments.js", NULL);
+
+jsInline("function drawCustom() {\n");
+jsInline("const line1Data = {\n");
+jsInlineF("range: { start: %d, end: %d },\n", chain->tStart, chain->tEnd);
+jsInlineF("label: \"%s %s:%d-%d\",\n", fromDb, chain->tName, chain->tStart, chain->tEnd);
+printSegs(toSegs);
+jsInline("}\n");
+
+jsInline("const line2Data = {\n");
+jsInlineF("range: { start: %d, end: %d },\n", qStart, qEnd);
+jsInlineF("label: \"%s %s:%d-%d\",\n", fromDb, chain->qName, qStart, qEnd);
+printSegs(fromSegs);
+jsInline("}\n");
+
+jsInline("ParallelSegments.drawCoordinateBasedSegments(line1Data, line2Data);\n");
+jsInline("}\n");
+jsInline("drawCustom();\n");
+}
+#endif
+
 static void doConvert(char *fromPos)
 /* Actually do the conversion */
 {
 struct dbDb *fromDb = hDbDb(trackHubSkipHubName(database)), *toDb = hDbDb(cartString(cart, HGLFT_TODB_VAR));
+#ifdef NOTNOW
+boolean doSegments = TRUE;
+#endif
 
 if (fromDb == NULL)
     {
     char buffer[4096];
     safef(buffer, sizeof buffer, "'%s'", trackHubSkipHubName(database));
     fromDb =  genarkLiftOverDbs(buffer);
     }
 if (toDb == NULL)
     toDb =  genarkLiftOverDb(cartString(cart, HGLFT_TODB_VAR));
 
 if (!fromDb || !toDb)
     errAbort("Early error - unable to find matching database records in dbDb - please contact support");
 
 chromAliasSetup(database);
 cartWebStart(cart, database, "%s %s %s to %s %s", fromDb->organism, fromDb->description,
@@ -319,31 +480,31 @@
 struct dyString *visDy = NULL;
 
 if (!hgParseChromRange(database, fromPos, &chrom, &start, &end))
     errAbort("position %s is not in chrom:start-end format", fromPos);
 origSize = end - start;
 
 boolean doQuickLift = cartUsualBoolean(cart, "doQuickLift", FALSE);
 cartRemove(cart, "doQuickLift");
 
 unsigned quickChain = 0;
 unsigned quickHub = 0;
 struct trackDb *badList = NULL;
 
 if (doQuickLift)
     {
-    quickChain = quickLiftGetChain(trackHubSkipHubName(fromDb->name), trackHubSkipHubName(toDb->name));
+    quickChain = quickLiftGetChainId(cart, trackHubSkipHubName(fromDb->name), trackHubSkipHubName(toDb->name));
 
     if (quickChain == 0)
         errAbort("can't find quickChain from %s to %s", fromDb->name, toDb->name);
 
     visDy = newDyString(1024);
     char *newHub = trackHubBuild(fromDb->name, cart, visDy, &badList);
     char *error = NULL;
     quickHub = hubFindOrAddUrlInStatusTable(cart, newHub, &error);
     if (error != NULL)
         errAbort("can't add quickLift hub (error %s)",error);
     }
 
 chainList = chainLoadAndTrimIntersecting(fileName, chrom, start, end);
 if (chainList == NULL)
     printf("Sorry this position couldn't be found in new assembly");
@@ -380,30 +541,35 @@
             {
             if (quickChain)
                 printf("<A HREF=\"%s?db=%s&position=%s:%d-%d&quickLift.%d.%s=%d\">",
                    hgTracksName(),  toDb->name,  chain->qName, qStart+1, qEnd, quickHub, toDb->name, quickChain);
             else
                 printf("<A HREF=\"%s?db=%s&position=%s:%d-%d\">",
 		   hgTracksName(), toDb->name, chain->qName, qStart+1, qEnd);
             startedAnchor = TRUE;
             }
 	printf("%s:%d-%d",  chain->qName, qStart+1, qEnd);
         if (startedAnchor)
 	    printf("</A>");
 	printf(" (%3.1f%% of bases, %3.1f%% of span)<BR>\n",
 	    100.0 * blockSize/origSize,
 	    100.0 * (chain->tEnd - chain->tStart) / origSize);
+#ifdef NTONOW
+        if (doSegments)
+            drawSegments(fromDb->name, toDb->name, chain);
+        break;
+#endif
 	}
     }
 if (badList)
     {
     printf("<BR>Some of your tracks failed to lift because the type is not supported by quickLift.<BR><BR>");
     printf("<TABLE><TR><TD><B>Short label<TD><B>Type</TD></TR>");
     for(; badList; badList = badList->next)
         {
         printf("<TR><TD>%s</TD><TD>%s</TD></TR>", badList->shortLabel, badList->type);
         }
     printf("</TABLE>");
     }
 cartWebEnd();
 }