staden-lg/src/staden/tman_traceDisplay.c

440 lines
10 KiB
C

/*
Title: traceDisplay
File: traceDisplay.c
Purpose: Display the trace of a sequence on a graph widget
Last update: Monday 20 January 1992
*/
/*
`plotEdgeOffset' indicates the pixel position at which point 0
occurs. The characters for bases are printed with their centres
corresponding to their locations on the plot.
The cutoffs are actually drawn between the positions of the
bases on either side.
*/
/* ---- Includes ---- */
#include "tman_traceDisplay.h"
#include "tman_display.h" /* IMPORT: userEvent */
#include "Graph.h"
#include "seq.h" /* IMPORT: Seq, NULLSeq, getNPoints */
#include "values.h" /* IMPORT: M_SQRT2 */
#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Form.h>
/* ---- Statics ---- */
static GC Agc, Cgc, Ggc, Tgc;
static Pixel normBackground, dimBackground;
/* ---- Position translation ---- */
/*
Convert a value from the `point-in-the-sequence' to the
`x-pixel-on-the-graph' scale, and vice-versa, given that
`plotWidth' holds the current pixel width of the graph which
starts `plotEdgeOffset' from either edge of the graph and
`NPoints' gives the current point width.
Fractional results are truncated - for pixelToPoint this may
mean a point one too low is indicated, but a point too high is
never indicated.
*/
static int pointToPixel(DisplayContext *dc, int point)
{ return(((point * dc->plotWidth) / (dc->NPoints-1)) + dc->plotEdgeOffset);
}
static int pixelToPoint(DisplayContext *dc, int pixel)
{ return(((pixel-dc->plotEdgeOffset) * (dc->NPoints-1)) / dc->plotWidth);
}
static int scaleTrace(DisplayContext *dc, int y)
{
return(dc->traceHeight -
(int)(dc->scaleFactor * (float)y * (float)dc->traceHeight / dc->maxTraceVal)
);
}
static int leftCutoffPoint(DisplayContext *dc, int baseNum)
/*
Return the point corresponding to a left cutoff at `baseNum'.
*/
{ int pL, pR;
pL = (baseNum == 0) ? 0 : baseNumToPoint(dc->seq, OrigBases, baseNum-1);
pR = (baseNum == 0) ? 0 : baseNumToPoint(dc->seq, OrigBases, baseNum);
return((pR==NULLPoint)?pL:(pL+pR)/2);
}
static int rightCutoffPoint(DisplayContext *dc, int baseNum)
/*
Return the point corresponding to a right cutoff at `baseNum'.
*/
{ int NorigBases = getNBases(dc->seq, OrigBases);
int pL, pR;
pL = (baseNum == 0)
? dc->NPoints-1
: baseNumToPoint(dc->seq, OrigBases, NorigBases-baseNum);
pR = (baseNum == 0)
? dc->NPoints-1
: baseNumToPoint(dc->seq, OrigBases, NorigBases-baseNum-1);
return((pL+pR)/2);
}
/* ---- Internal routines ---- */
static void drawTrace(DisplayContext *dc, Widget wid, char base, int p0, int pN)
/*
Draw the `base' trace between points p0..pN (inclusive)
*/
{ GC gc;
int pSeg, pSeg0, pSegN;
#define NSegs 500
int traces[NSegs];
XPoint xPoint[NSegs];
switch (base)
{ case 'A': gc=Agc; break;
case 'C': gc=Cgc; break;
case 'G': gc=Ggc; break;
case 'T': gc=Tgc; break;
}
/*
The range (p0..pN) is drawn as a series of overlapping
segments (pSeg0..pSegN).
*/
pSegN = p0;
do
{ int i;
/*
This segment carries on from and including the last point
of the last segment.
*/
pSeg0 = pSegN;
pSegN = ((pSeg0+NSegs-1)<=pN) ? pSeg0+NSegs-1 : pN;
/* Get the traces for this segment */
getTraces(dc->seq, base, pSeg0, pSegN, traces);
/* Translate to pixel coords and place in an XPoint array */
pSeg = pSeg0;
i = 0;
while (pSeg<=pSegN)
{ xPoint[i].x = pointToPixel(dc,pSeg);
xPoint[i].y = scaleTrace(dc,traces[i]);
pSeg++;
i++;
}
/* Draw the segments in the XPoint array */
XDrawLines(XtDisplay(wid),
XtWindow(wid),
gc,
xPoint,
pSegN-pSeg0+1,
CoordModeOrigin);
} while (pSegN < pN);
}
/* ---- Callbacks ---- */
static void exposeCallback(Widget wid,
XtPointer client_data, XtPointer call_data)
{ Region region = (Region) call_data;
XRectangle rect;
int x0, xN; /* Affected region: pixels */
int p0, pN; /* Affected region: points */
int leftCutoffP, rightCutoffP;
DisplayContext *dc = widgetToDisplayContext(XtParent(XtParent(XtParent(wid))));
if ((dc->seq == NULLSeq) || isBasesOnly(dc->seq)) return;
/*
`region' gives us the exposed graph region.
XClipBox will return a bounding rectangle, in pixels.
*/
XClipBox(region, &rect);
x0 = rect.x;
xN = rect.x+rect.width;
/* Trim it so we only consider the plot proper */
if ((x0>dc->plotWidth+dc->plotEdgeOffset) || (xN<dc->plotEdgeOffset)) return;
x0 = (x0<dc->plotEdgeOffset) ? dc->plotEdgeOffset : x0;
xN = (xN>dc->plotWidth+dc->plotEdgeOffset) ? dc->plotWidth+dc->plotEdgeOffset : xN;
/* Convert to affected points */
p0 = pixelToPoint(dc,x0);
pN = pixelToPoint(dc,xN);
if (pN<dc->NPoints-1) pN++;
leftCutoffP = leftCutoffPoint(dc,dc->leftCutoff);
rightCutoffP = rightCutoffPoint(dc,dc->rightCutoff);
if (p0<leftCutoffP)
/*
Some of the exposed region is in the left cutoff area.
Repaint it with dimmed background.
*/
{ int firstP = p0;
int lastP = (pN<leftCutoffP) ? pN : leftCutoffP;
int pix0 = pointToPixel(dc,firstP);
int pixN = pointToPixel(dc,lastP);
XSetWindowBackground(XtDisplay(dc->traceWid), XtWindow(dc->traceWid),
dimBackground);
XClearArea(XtDisplay(dc->traceWid), XtWindow(dc->traceWid),
pix0, 0,
pixN-pix0, dc->traceHeight,
False);
XSetWindowBackground(XtDisplay(dc->traceWid), XtWindow(dc->traceWid),
normBackground);
}
if (pN>rightCutoffP)
/*
Some of the exposed region is in the right cutoff area.
Repaint it with dimmed background.
*/
{ int firstP = (p0>rightCutoffP) ? p0 : rightCutoffP;
int lastP = pN;
int pix0 = pointToPixel(dc,firstP);
int pixN = pointToPixel(dc,lastP);
XSetWindowBackground(XtDisplay(dc->traceWid), XtWindow(dc->traceWid),
dimBackground);
XClearArea(XtDisplay(dc->traceWid), XtWindow(dc->traceWid),
pix0, 0,
pixN-pix0, dc->traceHeight,
False);
XSetWindowBackground(XtDisplay(dc->traceWid), XtWindow(dc->traceWid),
normBackground);
}
/*
Now draw the traces.
The GC background is unused when drawing lines, so we do
not need to change it depending on whether we are in the
cutoff region or not.
*/
drawTrace(dc,wid, 'A', p0, pN);
drawTrace(dc,wid, 'C', p0, pN);
drawTrace(dc,wid, 'G', p0, pN);
drawTrace(dc,wid, 'T', p0, pN);
}
static void resizeCallback(Widget wid,
XtPointer client_data, XtPointer call_data)
{ Arg args[10];
int nargs;
DisplayContext *dc = widgetToDisplayContext(XtParent(XtParent(XtParent(wid))));
/*
This routine can be called in two ways.
(a) as a callback when the trace is resized by the user
(b) indirectly when setGraphWidth alters the graph width
*/
nargs = 0;
XtSetArg(args[nargs], XtNheight, &dc->traceHeight); nargs++;
XtSetArg(args[nargs], XtNwidth, &dc->traceWidth); nargs++;
XtGetValues(wid, args, nargs);
if (XtIsRealized(wid)) XClearWindow(XtDisplay(wid), XtWindow(wid));
}
/* ---- Exports ---- */
static void redisplayTraces(DisplayContext *dc)
{
/*
** Clear the area and generate an expose.
*/
XClearArea(XtDisplay(dc->traceWid), XtWindow(dc->traceWid),
0, 0,
0, 0,
True);
}
void incScaleFactor(DisplayContext *dc)
{
dc->scaleFactor *= M_SQRT2;
redisplayTraces(dc);
}
void decScaleFactor(DisplayContext *dc)
{
dc->scaleFactor /= M_SQRT2;
redisplayTraces(dc);
}
void setScaleFactor(DisplayContext *dc, float sf)
{
dc->scaleFactor = sf;
redisplayTraces(dc);
}
void createTraceDisplay(DisplayContext *dc, Widget parentWid, Widget fromVertWid,
Dimension width, Dimension offset)
/*
Create the trace display within the Form widget `parent',
with the XtNfromVert constraint `fromVertWid'. The initial
width is `width' and the plot is drawn `offset' from
the left and right hand edges.
No trace is initially displayed.
*/
{ Arg args[10];
int nargs;
nargs = 0;
XtSetArg(args[nargs], XtNfromVert, fromVertWid); nargs++;
XtSetArg(args[nargs], XtNwidth, width); nargs++;
dc->traceWid = XtCreateManagedWidget("trace", graphWidgetClass,
parentWid, args, nargs);
XtAddCallback(dc->traceWid, XtNexposeCallback, exposeCallback, NULL);
XtAddCallback(dc->traceWid, XtNresizeCallback, resizeCallback, NULL);
nargs = 0;
XtSetArg(args[nargs], XtNheight, &dc->traceHeight); nargs++;
XtGetValues(dc->traceWid, args, nargs);
dc->traceWidth = width;
dc->plotWidth = dc->traceWidth-(2*dc->plotEdgeOffset);
dc->plotEdgeOffset = offset;
dc->seq = NULLSeq;
dc->scaleFactor = 1.0;
/*
Get the GCs
*/
Agc = GraphGC1(dc->traceWid);
Cgc = GraphGC2(dc->traceWid);
Ggc = GraphGC3(dc->traceWid);
Tgc = GraphGC4(dc->traceWid);
/*
Get the backgrounds
*/
nargs = 0;
XtSetArg(args[nargs], XtNbackground, &normBackground); nargs++;
XtSetArg(args[nargs], XtNdimBackground, &dimBackground); nargs++;
XtGetValues(dc->traceWid, args, nargs);
}
void initTraceDisplay(Seq seq)
/*
Initialise the trace display of sequence `seq'.
*/
{
DisplayContext *dc = seqToDisplayContext(seq);
if (seq == NULLSeq) return;
dc->seq = seq;
/*
Get static information about the current sequence.
*/
dc->NPoints = getNPoints(dc->seq);
dc->maxTraceVal = getMaxTraceVal(dc->seq);
getCutoffs(dc->seq, &dc->leftCutoff, &dc->rightCutoff);
}
void setTraceWidth(DisplayContext *dc, Dimension width)
/*
Set the width of the current sequence trace display.
*/
{ Arg args[10];
int nargs;
nargs = 0;
XtSetArg(args[nargs], XtNwidth, width); nargs++;
XtSetValues(dc->traceWid, args, nargs);
dc->traceWidth = width;
dc->plotWidth = dc->traceWidth-(2*dc->plotEdgeOffset);
/*
Clear the graph.
*/
if (XtIsRealized(dc->traceWid))
XClearWindow(XtDisplay(dc->traceWid), XtWindow(dc->traceWid));
}