Files
pcas/src/util/sydPlot.c
1994-06-22 15:48:30 +00:00

4082 lines
116 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* base/src/util $Id$
* Author: Roger A. Cole
* Date: 12-04-90
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991-93, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* .01 12-04-90 rac initial version
* .02 06-30-91 rac installed in SCCS
* .03 09-06-91 rac change pprAreaErase to pprRegionErase; add
* documentation
* .04 10-01-91 rac properly handle channels which aren't connected yet
* .05 10-20-91 rac avoid an abort on printing a plot to
* PostScript; for non-user-window plotting,
* defer the pprWinIsMono call until after
* the window is mapped
* .06 12-03-91 rac add some intelligence to auto ranging
* .07 01-23-92 rac don't take log10 of zero value
* .08 03-31-92 rac fix plotting of filled channels; set time axis
* scaling based on firstData to lastData rather
* than 0 to sampleCount; handle plotting mean and
* standard deviation; handle plotting restricted set
* of data; better annotate time axes; support a time
* cursor on a plot; add sydPlotChan_event to determine
* which channel a mouse event applies to;
* .09 08-27-92 rac add user-specified range for AutoRange; add more
* smarts to AutoRange; have only one X-axis annotation;
* add strip chart; discontinue use of special malloc;
* .10 10-01-92 rac continued work on strip chart; use pprWave routines;
* .11 01-12-93 rac get StripYY routines in sync with StripY routines
* .12 05-04-94 pg HPUX port changes.
*
* make options
* -DXWINDOWS makes a version for X11
* -DNDEBUG don't compile assert() checking
* -DDEBUG compile various debug code
*/
/*+/mod***********************************************************************
* TITLE sydPlot.c - plotting for synchronous data
*
* DESCRIPTION
* These routines provide high-level plotting capability in conjunction
* with the sydSubr.c routines. The data acquired by the sydSubr
* routines are accepted directly by these plotting routines.
*
* These routines support plotting in either batch or incremental mode.
* In batch mode, all the samples exist at the time of plotting; for
* incremental mode, only part (or none) of the samples exist when
* plotting starts, and additional samples are to be plotted as they
* arrive.
*
* Some windowing events, such as expose and resize, are transparently
* handled by these routines. Hard copy of plots to a PostScript
* printer is easily available.
*
* QUICK REFERENCE
*
* #include <sydDefs.h>
* #include <sydPlotDefs.h>
*
* void sydPlotAxisAutoRange(pSlave, minVal, maxVal)
* long sydPlotAxisSetAttr(pSlave, attr, value, pArg)
* attr = SYD_PLATTR_{GC}
* SYD_PL_SLAVE *sydPlotChanAdd(pMstr, pSChan)
* SYD_PL_SLAVE *sydPlotChan_event(pMstr, x, y)
* long sydPlotDone(pMstr, quitFlag)
* long sydPlotEraseSamples(pMstr)
* long sydPlotInit(pMstr, pSspec, winType, dispName, winTitle,
* fullInit)
* long sydPlotInitUW(pMstr, pSspec, pDisp, window, gc)
* long sydPlotSamples(pMstr, begin, end, incrFlag)
* long sydPlotSetAttr(pMstr, attr, value, pArg)
* attr = SYD_PLATTR_{FG1,FG2,INCR,LINE,MARK,MONO,POINT,SHOW,
* UNDER,WRAP}
* long sydPlotSetTitles(pMstr, top, left, bottom, right)
* long sydPlotTimeCursor(pMstr, pStamp, pSlave)
* long sydPlotWinLoop(pMstr)
* long sydPlotWinReplot(pMstr)
*
* DESCRIPTION, continued
* These routines generally work with the concepts of `plot master'
* and `plot slave'. The plot master structure roughly corresponds
* to a plotting surface (i.e., X11 window or PostScript sheet) and
* contains most of the information necessary to perform plotting.
* The plot master contains a list of plot slave structures, each of
* which is analogous to a data channel. A plot slave structure
* contains channel specific information, including data. Time
* stamp information is provided via the plot master, through the
* use of its connection to synchronous sample structures.
*
* BUGS
* o sydPlotInitUW doesn't support SunView; some other routines have
* questionable support
* o there is no counterpart for sydTimeCursor for other than time-based
* plots
* o knows and uses many intimate details of the ppr structures
*
*-***************************************************************************/
#include <genDefs.h>
#include <sydDefs.h>
#include <tsDefs.h>
#ifdef XWINDOWS
# include <X11/Xlib.h>
# include <X11/Xutil.h>
#endif
#define SYD_PLOT_PRIVATE
#include <sydPlotDefs.h>
#ifdef vxWorks
/*----------------------------------------------------------------------------
* includes and defines for VxWorks compile
*---------------------------------------------------------------------------*/
# include <vxWorks.h>
# include <stdioLib.h>
# include <strLib.h>
# include <ctype.h>
#else
/*----------------------------------------------------------------------------
* includes and defines for Sun compile
*---------------------------------------------------------------------------*/
# include <stdio.h>
# include <string.h>
# include <strings.h>
# include <ctype.h>
# include <math.h>
#endif
# ifdef _HPUX_SOURCE
# ifndef nint
# define nint(value) (value>=0 ? (int)((value)+.5) : (int)((value)-.5))
# endif
# ifndef exp10
# define exp10(value) (exp(value * log(10.)))
# endif
# endif
/*-----------------------------------------------------------------------------
* prototypes
*----------------------------------------------------------------------------*/
void sydPlot_SmithPlot();
void sydPlot_SmithGrid();
void sydPlot_SmithSamples();
void sydPlot_SmithStats();
void sydPlot_StripYPlot();
void sydPlot_StripYGrid();
void sydPlot_StripYRedisplay();
void sydPlot_StripYSamples();
void sydPlot_StripYYPlot();
void sydPlot_StripYYGrid();
void sydPlot_StripYYRedisplay();
void sydPlot_StripYYSamples();
void sydPlot_TYPlot();
void sydPlot_TYGrid();
void sydPlot_TYSamples();
void sydPlot_TYStats();
void sydPlot_TYYPlot();
void sydPlot_TYYGrid();
void sydPlot_XYPlot();
void sydPlot_XYGrid();
void sydPlot_XYSamples();
void sydPlot_XYStats();
void sydPlot_XYarray();
void sydPlot_XYYPlot();
void sydPlot_XYYGrid();
void sydPlot_YPlot();
void sydPlot_YGrid();
void sydPlot_YSamples();
void sydPlot_YStats();
void sydPlot_Yarray();
void sydPlot_YYPlot();
void sydPlot_YYGrid();
/*+/internal******************************************************************
* NAME sydAnnotVal - generate an array of value axis annotations
*
*-*/
static void
sydAnnotVal(pSlave, pAnnot, annot)
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
char *pAnnot[];
char annot[20][28];
{
int i;
double val, tick;
assert(pSlave->nInt < 20);
tick = (pSlave->extentVal - pSlave->originVal) / pSlave->nInt;
for (i=0, val=pSlave->originVal; i<=pSlave->nInt; i++, val+=tick) {
if (i == pSlave->nInt)
val = pSlave->extentVal;
cvtDblToTxt(annot[i], 6, val, pSlave->decPl);
pAnnot[i] = annot[i];
}
}
/*+/internal******************************************************************
* NAME logGetOK - get log of minimum allowable tick size
*
* DESCRIPTION
* Find the minimum tick size based on a field width of 6 using
* cvtDblToTxt using for printing.
*
*-*/
static int logGetOK(val)
double val;
{
int logVal, logTickVal;
logVal = val != 0. ? nint(floor(log10(fabs(val)))) : -10;
if (val >= 0.) {
if (1 <= logVal && logVal <= 4) logTickVal = logVal - 4;
else if (logVal == 5) logTickVal = 0;
else if (logVal == -1) logTickVal = -4;
else logTickVal = logVal - 2;
}
else {
if (1 <= logVal && logVal <= 3) logTickVal = logVal - 3;
else if (logVal == 4) logTickVal = 0;
else if (logVal == 0) logTickVal = -3;
else if (logVal == -1) logTickVal = -4;
else logTickVal = logVal - 1;
}
return logTickVal;
}
/*+/internal******************************************************************
* NAME moveVal - move a value to it's tick mark
*
*-*/
static double moveVal(val, tick, minFlag)
double val, tick;
int minFlag;
{
double moved;
int awayFrom=0;
double temp;
if (val < 0 && minFlag) awayFrom = 1;
else if (val > 0 && !minFlag) awayFrom = 1;
if (val > -1. * tick && val < tick && awayFrom == 0)
return 0.;
temp = fmod(val, tick);
moved = val - temp;
if (awayFrom && temp != 0.) {
if (val <= 0.) { if (moved > val) moved -= tick; }
else { if (moved < val) moved += tick; }
}
return moved;
}
/*+/internal******************************************************************
* NAME autoRange - compute auto range for an axis
*
*-*/
static void
autoRange(pOrigin, pExtent, pNTicks, pTick, pDecPl)
double *pOrigin, *pExtent, *pTick;
int *pNTicks, *pDecPl;
{
double origin, extent;
double min, min1, max, max1, logD, tick;
int logTick, logTickMin, logTickMax, logTickOK;
double maxVal;
int nTicks, decPl;
#define MIN(a,b) (a<=b?a:b)
#define MAX(a,b) (a<=b?b:a)
min = MIN(*pOrigin, *pExtent);
max = MAX(*pOrigin, *pExtent);
if (min == max)
min -= .001, max += .001;
min1 = min; max1 = max;
/*-----------------------------------------------------------------------------
* First, determine tick size and number of intervals without regard
* to the number of divisions which would result. Round the min
* and max to tick boundaries.
*----------------------------------------------------------------------------*/
logD = floor(log10(max-min));
tick = exp10(logD);
min = moveVal(min, tick, 1);
max = moveVal(max, tick, 0);
nTicks = nint((max - min) / tick);
if (nTicks == 10) nTicks = 5, tick *= 2.;
else if (nTicks == 1) nTicks = 5, tick /= 5.;
else if (nTicks == 2) nTicks = 4, tick /= 2.;
else if (nTicks == 8) nTicks = 4, tick *= 2.;
else if (nTicks == 9) nTicks = 3, tick *= 3.;
/*-----------------------------------------------------------------------------
* Next, make sure the tick size is consistent with printing in a
* six character field with 3 significant digits. For example, if the
* max is 1000000, it will print as 100E4, allowing a minimum tick
* size of 10000.
*----------------------------------------------------------------------------*/
logTick = nint(floor(log10(tick)));
logTickMax = logGetOK(max);
logTickMin = logGetOK(min);
logTickOK = MAX(logTickMin, logTickMax);
if (logTickOK > logTick) {
tick = exp10((double)logTickOK);
min = moveVal(min1, tick, 1);
max = moveVal(max1, tick, 0);
nTicks = 1;
}
/*-----------------------------------------------------------------------------
* Now, figure how many decimal places can be printed, based on the
* biggest endpoint, assuming a field width of 6 characters.
*----------------------------------------------------------------------------*/
maxVal = fabs(max) > fabs(min) ? max : min;
if (maxVal >= 10000. || maxVal <= -1000.) decPl = 0;
else if (maxVal >= 1000. || maxVal <= -100.) decPl = 1;
else if (maxVal >= 100. || maxVal <= -10.) decPl = 2;
else if (maxVal >= 10. || maxVal <= -1.) decPl = 3;
else decPl = 4;
if (*pOrigin <= *pExtent) {
*pTick = tick;
*pOrigin = min;
*pExtent = max;
}
else {
*pOrigin = max;
*pExtent = min;
*pTick = 0. - tick;
}
*pNTicks = nTicks;
*pDecPl = decPl;
}
/*+/subr**********************************************************************
* NAME sydPlotAxisAutoRange - set axis ends to min and max data values
*
* DESCRIPTION
* Sets the endpoints of the axis for the plot slave structure to
* `nice' values based on the minimum and maximum of the data for the
* slave. The number of intervals to divide the axis is also set.
*
* If the minimum and maximum values specified in the call aren't equal,
* they are used for scaling, rather than the min and max of the data.
*
* RETURNS
* void
*
* SEE ALSO
*
* EXAMPLE
*
*
*-*/
void
sydPlotAxisAutoRange(pSlave, minVal, maxVal)
SYD_PL_SLAVE *pSlave; /* I pointer to plot slave structure */
double minVal; /* I minimum value, for setting scaling */
double maxVal; /* I maximum value, for setting scaling */
{
SYD_CHAN *pSChan=pSlave->pSChan;
double origin=pSlave->pSChan->restrictMinDataVal;
double extent=pSlave->pSChan->restrictMaxDataVal;
int nInt, decPl;
double tick;
if (pSChan->dbrType == DBR_TIME_ENUM)
return;
if (minVal != maxVal) {
origin = minVal;
extent = maxVal;
}
autoRange(&origin, &extent, &nInt, &tick, &decPl);
pSlave->originVal = origin;
pSlave->extentVal = extent;
pSlave->nInt = nInt;
pSlave->decPl = decPl;
}
/*+/subr**********************************************************************
* NAME sydPlotAxisSetAttr - set plot axis attributes
*
* DESCRIPTION
* Setting an attribute doesn't automatically reset other related
* attributes.
*
* Declare a slave to be used as the x-axis channel when x vs. y
* plotting is done:
* sydPlotAxisSetAttr(pSlave, SYD_PLATTR_XCHAN, {0,1}, NULL)
*
* Set the background and/or foreground pixel values for X11 for
* a slave:
* sydPlotAxisSetAttr(pSlave, SYD_PLATTR_BG, 0, pBgPixelValue)
* sydPlotAxisSetAttr(pSlave, SYD_PLATTR_FG, 0, pFgPixelValue)
*
* RETURNS
* S_syd_OK
*
* BUGS
* o text
*
* SEE ALSO
*
* EXAMPLE
*
*-*/
long
sydPlotAxisSetAttr(pSlave, attr, value, pArg)
SYD_PL_SLAVE *pSlave; /* I pointer to plot slave structure */
SYD_PLATTR attr; /* I attribute selector--one of SYD_PLATTR_xxx */
int value; /* I value for attribute */
void *pArg; /* I pointer for value for attribute */
{
if (attr == SYD_PLATTR_XCHAN) pSlave->xChan = value;
#ifdef XWINDOWS
else if (attr == SYD_PLATTR_BG)
pSlave->bg = *(unsigned long *)pArg;
else if (attr == SYD_PLATTR_FG)
pSlave->fg = *(unsigned long *)pArg;
#endif
else assertAlways(0);
return S_syd_OK;
}
/*+/internal******************************************************************
* NAME sydPlotAxisSetup - set up axis information for a channel
*
* DESCRIPTION
* Set up axis information.
* o the axis endpoints are set to LOPR and HOPR. If LOPR==HOPR,
* then minimum and maximum data values are used for endpoints.
* If min==max, then arbitrary values are used.
* o number of major intervals is set to 5
*
* RETURNS
* void
*
* BUGS
* o in pathological cases, the setup is overly arbitrary
* o number of intervals is fixed at 5
*
* SEE ALSO
*
* EXAMPLE
*
*-*/
void
sydPlotAxisSetup(pSlave)
SYD_PL_SLAVE *pSlave; /* I pointer to plot slave structure */
{
SYD_CHAN *pSChan=pSlave->pSChan;
double originVal, extentVal;
int nInt=5;
if (pSChan->dbrType == DBR_TIME_FLOAT) {
originVal = pSChan->grBuf.gfltval.lower_disp_limit;
extentVal = pSChan->grBuf.gfltval.upper_disp_limit;
}
else if (pSChan->dbrType == DBR_TIME_SHORT) {
originVal = pSChan->grBuf.gshrtval.lower_disp_limit;
extentVal = pSChan->grBuf.gshrtval.upper_disp_limit;
}
else if (pSChan->dbrType == DBR_TIME_DOUBLE) {
originVal = pSChan->grBuf.gdblval.lower_disp_limit;
extentVal = pSChan->grBuf.gdblval.upper_disp_limit;
}
else if (pSChan->dbrType == DBR_TIME_LONG) {
originVal = pSChan->grBuf.glngval.lower_disp_limit;
extentVal = pSChan->grBuf.glngval.upper_disp_limit;
}
else if (pSChan->dbrType == DBR_TIME_CHAR) {
originVal = pSChan->grBuf.gchrval.lower_disp_limit;
extentVal = pSChan->grBuf.gchrval.upper_disp_limit;
}
else if (pSChan->dbrType == DBR_TIME_ENUM) {
nInt = pSChan->grBuf.genmval.no_str-1;
originVal = 0;
extentVal = nInt;
if (originVal >= extentVal) {
if (nInt < 0)
(void)strcpy(pSChan->grBuf.genmval.strs[0], " ");
extentVal = nInt = 1;
pSChan->grBuf.genmval.no_str = 2;
(void)strcpy(pSChan->grBuf.genmval.strs[1], " ");
}
}
if (originVal == extentVal) {
originVal = pSlave->pSChan->minDataVal;
extentVal = pSlave->pSChan->maxDataVal;
}
if (originVal == extentVal) {
if (originVal == 0.)
extentVal = 10.;
else if (originVal < 0.)
extentVal = 0;
else
originVal = 0.;
}
pSlave->originVal = originVal;
pSlave->extentVal = extentVal;
pSlave->nInt = nInt;
pSlave->nSubInt = 0;
pSlave->decPl = 3;
}
/*+/subr**********************************************************************
* NAME sydPlotChanAdd - add a plot slave
*
* DESCRIPTION
* Adds a slave to a master plot structure. Some of the items needed
* for actual plotting are set up by this routine:
*
* o endpoints for plotting. If HOPR and LOPR are present for the
* channel, they are used as the plotting endpoints. If they
* aren't present (or if they are equal), then some relatively
* arbitrary endpoints are picked. For DBF_ENUM channels, the
* endpoints are determined by the states.
* o number of major tick intervals. For DBF_ENUM channels, the
* number of states determines the number of intervals.
* o a default plot mark to be used for mark plotting
* o a default line key to be used for monochrome plotting. This
* line key also establishes a default color to be used for
* color plotting; the default color can be overridden using
* sydPlotAxisSetAttr.
*
* RETURNS
* SYD_PL_SLAVE *, or
* NULL
*
* BUGS
* o the scheme for establishing mark and key numbers won't work if
* deleting and re-adding plot channels is allowed
*
*-*/
SYD_PL_SLAVE *
sydPlotChanAdd(pMstr, pSChan)
SYD_PL_MSTR *pMstr; /* I pointer to plot master */
SYD_CHAN *pSChan; /* I pointer to synchronous data channel structure,
as from sydChanOpen */
{
SYD_PL_SLAVE *pSlave; /* pointer to slave structure */
int i;
assert(pMstr != NULL);
if (dbr_type_is_STRING(pSChan->dbrType)) {
(void)printf("sydPlotChanAdd: can't plot DBF_STRING values\n");
return NULL;
}
if ((pSlave = (SYD_PL_SLAVE *)malloc(sizeof(SYD_PL_SLAVE))) == NULL) {
(void)printf("sydPlotChanAdd: can't get memory\n");
return NULL;
}
pSlave->pSChan = pSChan;
pMstr->nSlaves++;
pSlave->markNum = pMstr->nSlaves - 1;
pSlave->lineKey = pMstr->nSlaves;
pSlave->xChan = 0;
pSlave->pArea = NULL;
pSlave->fg = pSlave->bg = 0;
pSlave->first = 1;
pSlave->xFracLeft = pSlave->xFracRight = 0.;
pSlave->yFracBot = pSlave->yFracTop = 0.;
pSlave->annotXFL = pSlave->annotXFR = 0.;
pSlave->annotYFB = pSlave->annotYFT = 0.;
DoubleListAppend(pSlave, pMstr->pHead, pMstr->pTail);
sydPlotAxisSetup(pSlave);
if (dbr_type_is_ENUM(pSChan->dbrType)) {
for (i=0; i<=pSlave->extentVal; i++)
pSlave->pAnnot[i] = pSChan->grBuf.genmval.strs[i];
pSlave->ppAnnot = pSlave->pAnnot;
}
else
pSlave->ppAnnot = NULL;
return pSlave;
}
/*+/subr**********************************************************************
* NAME sydPlotChan_event - find the plot slave corresponding to an event
*
* DESCRIPTION
* The x and y position for the event are used to find the corresponding
* plot slave. This search examines the bounding box for the grid and
* the annotation area.
*
* For a shared grid plot, the result will be ambiguous.
*
* RETURNS
* SYD_PL_SLAVE *, or
* NULL
*
*-*/
SYD_PL_SLAVE *
sydPlotChan_event(pMstr, x, y)
SYD_PL_MSTR *pMstr; /* I pointer to plot master */
int x, y; /* I the x and y position from the event */
{
SYD_PL_SLAVE *pSlave; /* pointer to slave structure */
int i;
double xFrac, yFrac;
assert(pMstr != NULL);
xFrac = PprPixXToXFrac(pMstr->pWin, x);
yFrac = PprPixYToYFrac(pMstr->pWin, y);
for (pSlave=pMstr->pHead; pSlave!=NULL; pSlave=pSlave->pNext) {
if (xFrac >= pSlave->xFracLeft && xFrac <= pSlave->xFracRight &&
yFrac >= pSlave->yFracBot && yFrac <= pSlave->yFracTop)
return pSlave;
if (xFrac >= pSlave->annotXFL && xFrac <= pSlave->annotXFR &&
yFrac >= pSlave->annotYFB && yFrac <= pSlave->annotYFT)
return pSlave;
}
return NULL;
}
/*+/subr**********************************************************************
* NAME sydPlotDone - plotting rundown
*
* DESCRIPTION
* Wrap up processing for a plot. Each slave is closed. The present
* size and position of the plot window are saved in the plot master
* structure.
*
* RETURNS
* S_syd_OK
*
* SEE ALSO
*
* EXAMPLE
*
*-*/
long
sydPlotDone(pMstr, quitFlag)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int quitFlag; /* I use 0 for replot, 1 for total rundown */
{
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
SYD_PL_SLAVE *pSlave1; /* pointer to individual slave struct */
assert(pMstr != NULL);
if (quitFlag) {
pSlave = pMstr->pHead;
while (pSlave != NULL) {
pMstr->nSlaves--;
DoubleListRemove(pSlave, pMstr->pHead, pMstr->pTail);
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pSlave1 = pSlave;
pSlave = pSlave->pNext;
free((char *)pSlave1);
}
pprWinInfo(pMstr->pWin, &pMstr->x, &pMstr->y,
&pMstr->width, &pMstr->height);
pprWinClose(pMstr->pWin);
}
return S_syd_OK;
}
/*+/subr**********************************************************************
* NAME sydPlotEraseSamples - erase samples from the screen
*
* DESCRIPTION
* Erase the plot areas for the plot master.
*
* RETURNS
* S_syd_OK
*
* SEE ALSO
*
* EXAMPLE
*
*-*/
long
sydPlotEraseSamples(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
assert(pMstr != NULL);
pSlave = pMstr->pHead;
while (pSlave != NULL) {
pSlave->first = 1;
if (pSlave->pArea != NULL) {
pprRegionErase(pSlave->pArea, 1., 1., -1., -1.);
}
pSlave = pSlave->pNext;
}
return S_syd_OK;
}
static void sydPlotInit_common();
/*+/subr**********************************************************************
* NAME sydPlotInit - plotting initialization
*
* DESCRIPTION
* Initialize for plotting, using an automatically created window:
* o the window is created
* o if full initialization is requested, then the default window
* size and position are used; otherwise, the size and position
* in the plot master (as saved by sydPlotDone) are used.
*
* This routine doesn't perform any plotting--sydPlotWinLoop must
* be called to do the actual plotting.
*
* The type of plotting which is done depends both on the window type
* specified in the call to this routine and on the way that the plot
* master is set up at the time of the call to sydPlotWinLoop.
*
* RETURNS
* S_syd_OK, or
* S_syd_ERROR if initialization can't be completed
*
* BUGS
* o need an sdrXxx call to initialize a master with caller-supplied
* or default size and position
*
* SEE ALSO
* sydPlotInitUW, sydPlotDone, sydPlotWinLoop
* sydPlotSetAttr
*
* EXAMPLE
*
*-*/
long
sydPlotInit(pMstr, pSspec, winType, dispName, winTitle, fullInit)
SYD_PL_MSTR *pMstr; /* I pointer to plot master structure */
SYD_SPEC *pSspec; /* I pointer to synchronous set spec */
PPR_WIN_TY winType; /* I type of "plot window": PPR_WIN_xxx
PPR_WIN_SCREEN for an X11 window
PPR_WIN_POSTSCRIPT for a PostScript file
PPR_WIN_EPS for an Encapsulated PostScript file
char *dispName; /* I name of "plot window"--display, PostScript
file, EPS file, or NULL */
char *winTitle; /* I title for window title bar and icon */
int fullInit; /* I 0 or 1 to do partial or full initialization */
{
if (fullInit) {
pMstr->pWin = pprWinOpen(winType, dispName, winTitle, 0,0,0,0);
if (pMstr->pWin == NULL)
return S_syd_ERROR;
pprWinInfo(pMstr->pWin, &pMstr->x, &pMstr->y, &pMstr->width,
&pMstr->height);
}
else {
pMstr->pWin = pprWinOpen(winType, dispName, winTitle,
pMstr->x, pMstr->y, pMstr->width, pMstr->height);
if (pMstr->pWin == NULL)
return S_syd_ERROR;
}
pMstr->winType = winType;
pMstr->plotAxis = SYD_PLAX_UNDEF;
pMstr->pSspec = pSspec;
sydPlotInit_common(pMstr);
return S_syd_OK;
}
/*+/internal******************************************************************
* NAME sydPlotInit_common
*
*-*/
static void
sydPlotInit_common(pMstr)
SYD_PL_MSTR *pMstr;
{
pMstr->linePlot = 1;
pMstr->pointPlot = 0;
pMstr->markPlot = 0;
pMstr->showStat = 0;
pMstr->fillUnder = 0;
pMstr->noColor = 0;
pMstr->errBar = 0;
#ifdef XWINDOWS
pMstr->pDisp = NULL;
pMstr->window = NULL;
pMstr->bg = 0;
pMstr->fg = 0;
pMstr->altPixel1 = 0;
pMstr->altPixel2 = 0;
#endif
pMstr->label[0] = '\0';
pMstr->title[0] = '\0';
pMstr->lTitle[0] = '\0';
pMstr->bTitle[0] = '\0';
pMstr->rTitle[0] = '\0';
pMstr->pHead = NULL;
pMstr->pTail = NULL;
pMstr->nSlaves = 0;
pMstr->originVal = 0.;
pMstr->extentVal = 0.;
pMstr->nInt = 1;
pMstr->nSubInt = 0;
pMstr->stripIncr = .2;
pMstr->wrapX = 0;
if (pMstr->pSspec->sampleCount >= 1) {
pMstr->originVal =
pMstr->pSspec->pDeltaSec[pMstr->pSspec->restrictFirstData] -
pMstr->pSspec->restrictDeltaSecSubtract;
pMstr->extentVal =
pMstr->pSspec->pDeltaSec[pMstr->pSspec->restrictLastData] -
pMstr->pSspec->restrictDeltaSecSubtract;
}
}
#ifdef XWINDOWS
/*+/subr**********************************************************************
* NAME sydPlotInitUW - plotting initialization, using User Window
*
* DESCRIPTION
* Initialize for plotting, using a user-supplied window.
*
* This routine doesn't perform any actual plotting. When an expose
* or resize event occurs (or when additional samples are received
* when plotting in incremental mode), one of the following routines
* must be called to perform plotting:
*
* sydPlotWinReplot--plots all the samples in the synchronous data
* set.
*
* sydPlotSamples--plots the indicated subset of the samples in the
* synchronous data set.
*
* RETURNS
* S_syd_OK
*
* BUGS
* o available only for X11
*
* SEE ALSO
* sydPlotInit, sydPlotDone, sydPlotWinReplot, sydPlotSamples
* sydPlotSetAttr
*
* EXAMPLE
*
*-*/
long
sydPlotInitUW(pMstr, pSspec, pDisp, window, gc)
SYD_PL_MSTR *pMstr; /* I pointer to plot master structure */
SYD_SPEC *pSspec; /* I pointer to synchronous set spec */
Display *pDisp; /* I X11 display pointer */
Window window; /* I X11 window handle */
GC gc; /* I X11 gc handle */
{
long stat;
pMstr->pWin = pprWinOpenUW(&pDisp, &window, &gc, NULL);
assertAlways(pMstr->pWin != NULL);
pMstr->winType = PPR_WIN_SCREEN;
pMstr->plotAxis = SYD_PLAX_UNDEF;
pMstr->pSspec = pSspec;
sydPlotInit_common(pMstr);
if (pprWinIsMono(pMstr->pWin))
pMstr->noColor = 1;
else
pMstr->noColor = 0;
pMstr->pDisp = pDisp;
pMstr->window = window;
return S_syd_OK;
}
#endif XWINDOWS
/*+/subr**********************************************************************
* NAME sydPlotSamples - plot one or more sync samples
*
* DESCRIPTION
* Plot one or more samples in the synchronous sample set (whose
* handle is held by the plot master). The sample range is specified
* as sample numbers within the sync sample set.
*
* This routine is for use only with sydPlotInitUW. When this routine
* is called, the sydPlot_xxx routine indicated by the .plotAxis
* member of the plot master structure is called.
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
* sydPlotInitUW, sydPlotSetAttr, sydPlot_xxx
*
* NOTES
* 1. The `incrFlag' argument allows plotting in either batch or
* incremental mode. If incrFlag is 1, then this set of samples will
* be treated as a continuation of a prior set of samples. This is
* important primarily for line plots. Both sydPlotChanAdd and
* sydPlotEraseSamples set the flag (for one or all slaves, respectively)
* indicating there was no prior set of samples; this might be used
* to avoid having to change incrFlag back and forth.
*
*-*/
void
sydPlotSamples(pMstr, begin, end, incrFlag)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin sample to plot */
int end; /* I number of end sample to plot */
int incrFlag; /* I 0,1 for batch,incremental plotting */
{
if (pMstr->plotAxis == SYD_PLAX_TY)
sydPlot_TYSamples(pMstr, begin, end, incrFlag);
else if (pMstr->plotAxis == SYD_PLAX_TYY)
sydPlot_TYSamples(pMstr, begin, end, incrFlag);
else if (pMstr->plotAxis == SYD_PLAX_XY)
sydPlot_XYSamples(pMstr, begin, end, incrFlag);
else if (pMstr->plotAxis == SYD_PLAX_XYY)
sydPlot_XYSamples(pMstr, begin, end, incrFlag);
else if (pMstr->plotAxis == SYD_PLAX_Y)
sydPlot_YSamples(pMstr, begin, end, incrFlag);
else if (pMstr->plotAxis == SYD_PLAX_YY)
sydPlot_YSamples(pMstr, begin, end, incrFlag);
else if (pMstr->plotAxis == SYD_PLAX_STRIP_Y)
sydPlot_StripYSamples(pMstr, begin, end, incrFlag);
else if (pMstr->plotAxis == SYD_PLAX_STRIP_YY)
sydPlot_StripYSamples(pMstr, begin, end, incrFlag);
else if (pMstr->plotAxis == SYD_PLAX_SMITH_IMP ||
pMstr->plotAxis == SYD_PLAX_SMITH_ADM ||
pMstr->plotAxis == SYD_PLAX_SMITH_IMM)
sydPlot_SmithSamples(pMstr, begin, end, incrFlag);
else
assertAlways(0);
}
/*+/subr**********************************************************************
* NAME sydPlotSetAttr - set plot attributes
*
* DESCRIPTION
* Setting an attribute doesn't automatically reset other related
* attributes.
*
* sydPlotSetAttr(pMstr, SYD_PLATTR_FG1, 0, &fgPixVal)
* sydPlotSetAttr(pMstr, SYD_PLATTR_FG2, 0, &fgPixVal)
* sydPlotSetAttr(pMstr, SYD_PLATTR_INCR, 0, &stripIncr_sec)
* sydPlotSetAttr(pMstr, SYD_PLATTR_LINE, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_MARK, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_MONO, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_POINT, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_SHOW, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_STDDEV, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_UNDER, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_WRAP, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_XLAB, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_XANN, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_YLAB, {0,1}, NULL)
* sydPlotSetAttr(pMstr, SYD_PLATTR_YANN, {0,1}, NULL)
*
* RETURNS
* S_syd_OK
*
* BUGS
* o there should be a SYD_PLATTR_AXIS_TYPE, rather than having to
* explicitly set the .plotAxis member of the plot master structure
*
* SEE ALSO
* sydPlotSetTitles, sydPlotInit, sydPlotInitUW
*
* EXAMPLE
*
*-*/
long
sydPlotSetAttr(pMstr, attr, value, pArg)
SYD_PL_MSTR *pMstr; /* I pointer to plot master structure */
SYD_PLATTR attr; /* I attribute selector--one of SYD_PLATTR_xxx */
int value; /* I value for attribute */
void *pArg; /* I pointer for value for attribute */
{
#ifdef XWINDOWS
if (attr == SYD_PLATTR_FG1) pMstr->altPixel1 = *(unsigned long *)pArg;
else if (attr == SYD_PLATTR_FG2) pMstr->altPixel2 = *(unsigned long *)pArg;
else
#endif
if (attr == SYD_PLATTR_LINE) pMstr->linePlot = value;
else if (attr == SYD_PLATTR_MARK) pMstr->markPlot = value;
else if (attr == SYD_PLATTR_POINT) pMstr->pointPlot = value;
else if (attr == SYD_PLATTR_SHOW) pMstr->showStat = value;
else if (attr == SYD_PLATTR_UNDER) pMstr->fillUnder = value;
else if (attr == SYD_PLATTR_WRAP) pMstr->wrapX = value;
else if (attr == SYD_PLATTR_XLAB) pMstr->useXlabel = value;
else if (attr == SYD_PLATTR_XANN) pMstr->useXannot = value;
else if (attr == SYD_PLATTR_YLAB) pMstr->useYlabel = value;
else if (attr == SYD_PLATTR_YANN) pMstr->useYannot = value;
else if (attr == SYD_PLATTR_MONO) pMstr->noColor = value;
else if (attr == SYD_PLATTR_STDDEV) {
if (value == 1)
pMstr->errBar = SYD_PLATTR_STDDEV;
else
pMstr->errBar = 0;
}
else if (attr == SYD_PLATTR_INCR) pMstr->stripIncr = *(float *)pArg;
else assertAlways(0);
return S_syd_OK;
}
/*+/subr**********************************************************************
* NAME sydPlotSetTitles - establish or change titles for a plot
*
* DESCRIPTION
* Set the titles for a plot.
*
* By default, there are no titles for a plot. If the argument
* for a particular title isn't NULL, then that title is changed.
*
* RETURNS
* S_syd_OK
*
* BUGS
* o text
*
* SEE ALSO
* sydPlot_setup, sydPlotSetAttr
*
* EXAMPLE
*
*-*/
long
sydPlotSetTitles(pMstr, top, left, bottom, right)
SYD_PL_MSTR *pMstr; /* I pointer to plot master structure */
char *top; /* I title for top of plot, or NULL */
char *left; /* I title for left of plot, or NULL */
char *bottom; /* I title for bottom of plot, or NULL */
char *right; /* I title for right of plot, or NULL */
{
if (top != NULL) {
assert(strlen(top) < sizeof(pMstr->title));
strcpy(pMstr->title, top);
}
if (left != NULL) {
assert(strlen(left) < sizeof(pMstr->lTitle));
strcpy(pMstr->lTitle, left);
}
if (bottom != NULL) {
assert(strlen(bottom) < sizeof(pMstr->bTitle));
strcpy(pMstr->bTitle, bottom);
}
if (right != NULL) {
assert(strlen(right) < sizeof(pMstr->rTitle));
strcpy(pMstr->rTitle, right);
}
return S_syd_OK;
}
/*+/subr**********************************************************************
* NAME sydPlotTimeCursor - plot a time `cursor'
*
* DESCRIPTION
* Draws or erases a vertical line corresponding to the specified
* time stamp. If a plot slave is specified, its annotation area
* is outlined (or the outline is erased).
*
* The drawing is done using the X GXxor function, so that the first
* call for a time stamp draws a line and the next call for the
* same time stamp erases the line.
*
* RETURNS
* S_syd_OK
*
* NOTES
* 1. Since alternate calls to this routine draw and erase, speciall
* handling is needed by the caller who wants to draw several time
* cursors and also outline the annotation area for a plot slave.
* For this case, the pointer to the plot slave should be used in only
* _one_ of the calls to this routine.
*
*-*/
long
sydPlotTimeCursor(pMstr, pStamp, pSlave)
SYD_PL_MSTR *pMstr; /* I pointer to plot master structure */
TS_STAMP *pStamp; /* I time stamp to position cursor */
SYD_PL_SLAVE *pSlave; /* I pointer to plot slave structure, or NULL */
{
SYD_SPEC *pSspec = pMstr->pSspec;
double diff; /* offset of stamp from reference stamp */
PPR_AREA *pArea;
if (pMstr->plotAxis != SYD_PLAX_TY && pMstr->plotAxis != SYD_PLAX_TYY)
return S_syd_OK;
TsDiffAsDouble(&diff, pStamp, &pSspec->restrictRefTs);
if (diff < pMstr->originVal || diff > pMstr->extentVal)
return S_syd_OK;
pArea = pprAreaOpen(pMstr->pWin,
pMstr->originFrac, 0., pMstr->extentFrac, 1.,
pMstr->originVal, 0., pMstr->extentVal, 1.,
1, 1, 0.);
assertAlways(pArea != NULL);
XSetFunction(pArea->pWin->pDisp, pArea->attr.gc, GXinvert);
XSetPlaneMask(pArea->pWin->pDisp, pArea->attr.gc, 1);
pprLineSegD(pArea, diff, 0., diff, 1.);
pprAreaClose(pArea);
pArea = pprAreaOpen(pMstr->pWin, 0.,0.,1.,1., 0.,0.,1.,1., 1, 1, 0.);
assertAlways(pArea != NULL);
XSetFunction(pArea->pWin->pDisp, pArea->attr.gc, GXinvert);
XSetPlaneMask(pArea->pWin->pDisp, pArea->attr.gc, 1);
if (pSlave != NULL) {
double inX, inY; /* insets into the annot area */
inX = (pSlave->annotXFR - pSlave->annotXFL) * .05;
inY = (pSlave->annotYFT - pSlave->annotYFB) * .05;
pprMoveD(pArea, pSlave->annotXFL+inX, pSlave->annotYFB+inY, 0);
pprMoveD(pArea, pSlave->annotXFL+inX, pSlave->annotYFT-inY, 1);
pprMoveD(pArea, pSlave->annotXFR-inX, pSlave->annotYFT-inY, 1);
pprMoveD(pArea, pSlave->annotXFR-inX, pSlave->annotYFB+inY, 1);
pprMoveD(pArea, pSlave->annotXFL+inX, pSlave->annotYFB+inY, 1);
}
pprAreaClose(pArea);
return S_syd_OK;
}
/*+/subr**********************************************************************
* NAME sydPlotWinLoop - do the actual plotting
*
* DESCRIPTION
* Perform the actual plotting for a plot master which was set up
* using sydPlotInit.
*
* This routine is for use only with sydPlotInit. When this routine
* is called, the sydPlot_xxx routine indicated by the .plotAxis
* member of the plot master structure is called.
*
* This routine creates and maps a window and draws the plot. This
* routine retains control (for processing expose and resize events)
* until the mouse pointer is placed in the plot window and the right
* button is clicked.
*
* RETURNS
* S_syd_OK
*
* BUGS
* o text
*
* SEE ALSO
* sydPlotInit, sydPlotSetAttr, sydPlot_xxx
*
* EXAMPLE
*
*-*/
long
sydPlotWinLoop(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to plot master structure */
{
SYD_PLAX pltTy = pMstr->plotAxis; /* type of plot desired */
long stat;
int npts, beg, end;
SYD_SPEC *pSspec = pMstr->pSspec;
npts = pSspec->sampleCount;
beg = pSspec->restrictFirstData;
end = pSspec->restrictLastData;
if (npts <= 1 || pMstr->originVal == pMstr->extentVal) {
pMstr->originVal = 0.;
pMstr->extentVal = 100.;
strcpy(pMstr->label, "elapsed seconds");
pMstr->nInt = 5;
}
if (pprWinMap(pMstr->pWin) != 0)
return S_syd_ERROR;
if (pprWinIsMono(pMstr->pWin))
pMstr->noColor = 1;
else
pMstr->noColor = 0;
stat = pprWinLoop(pMstr->pWin, sydPlot, pMstr);
if (stat != OK)
return S_syd_ERROR;
pprWinInfo(pMstr->pWin, &pMstr->x, &pMstr->y,&pMstr->width,&pMstr->height);
return S_syd_OK;
}
/*+/subr**********************************************************************
* NAME sydPlotWinReplot - do the actual plotting
*
* DESCRIPTION
* Perform the actual plotting for a plot master which was set up
* using sydPlotInitUW. This routine calls the sydPlot_xxx routine
* indicated by the .plotAxis member of the plot master structure.
*
* RETURNS
* S_syd_OK
*
* BUGS
* o text
*
* SEE ALSO
* sydPlotInitUW, sydPlotSamples, sydPlot_xxx
*
* EXAMPLE
*
*-*/
long
sydPlotWinReplot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to plot master structure */
{
int npts, beg, end;
SYD_SPEC *pSspec = pMstr->pSspec;
npts = pSspec->sampleCount;
beg = pSspec->restrictFirstData;
end = pSspec->restrictLastData;
if (npts <= 1 || pMstr->originVal == pMstr->extentVal) {
pMstr->originVal = 0.;
pMstr->extentVal = 100.;
strcpy(pMstr->label, "elapsed seconds");
pMstr->nInt = 5;
}
pprWinErase(pMstr->pWin);
pprWinReplot(pMstr->pWin, sydPlot, pMstr);
return S_syd_OK;
}
/*+/subr**********************************************************************
* NAME sydPlot - call the plot routine appropriate for plot type
*
* DESCRIPTION
* Provides a generic interface for doing the actual plotting. This
* routine calls the specific plotting routine as dictated by the
* set up for the plot master. That routine will draw the grid(s)
* and plot the data.
*
* Prior to calling this routine, the caller must set several values
* in the plot master structure to control how plotting is done. Except
* for the .plotAxis member, the preferred method for setting the
* values is with the sydPlotSetAttr routine.
*
* .plotAxis--the type of axis used in plotting:
* SYD_PLAX_TY value vs time, separate grids
* SYD_PLAX_TYY value vs time, shared grid
* SYD_PLAX_XY value vs value, separate grids
* SYD_PLAX_XYY value vs value, shared grid
* SYD_PLAX_Y value vs bin number, separate grids
* SYD_PLAX_YY value vs bin number, shared grid
* SYD_PLAX_STRIP_Y value vs delta time, separate grids
* SYD_PLAX_STRIP_YY value vs delta time, shared grid
* SYD_PLAX_SMITH_IMP value vs value, with Smith impedance overlay
* SYD_PLAX_SMITH_ADM value vs value, with Smith admittance overlay
* SYD_PLAX_SMITH_IMM value vs value, with Smith immitance overlay
*
* .linePlot--1 to connect data points with lines, else 0
* .markPlot--1 to plot a mark at each data point, else 0
* .pointPlot--1 to plot a point at each data point, else 0
* .showStat--1 to plot a status indicator at each data point, else 0
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
* sydPlotSetAttr, specific sydPlot_xxx routines
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot(pWin, pMstr)
PPR_WIN *pWin; /* I pointer to plot window structure */
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
pprWinInfo(pWin, &pMstr->x, &pMstr->y, &pMstr->width, &pMstr->height);
if (pMstr->plotAxis == SYD_PLAX_TY)
sydPlot_TYPlot(pMstr);
else if (pMstr->plotAxis == SYD_PLAX_TYY)
sydPlot_TYYPlot(pMstr);
else if (pMstr->plotAxis == SYD_PLAX_XY)
sydPlot_XYPlot(pMstr);
else if (pMstr->plotAxis == SYD_PLAX_XYY)
sydPlot_XYYPlot(pMstr);
else if (pMstr->plotAxis == SYD_PLAX_Y)
sydPlot_YPlot(pMstr);
else if (pMstr->plotAxis == SYD_PLAX_YY)
sydPlot_YYPlot(pMstr);
else if (pMstr->plotAxis == SYD_PLAX_STRIP_Y)
sydPlot_StripYPlot(pMstr);
else if (pMstr->plotAxis == SYD_PLAX_STRIP_YY)
sydPlot_StripYYPlot(pMstr);
else if (pMstr->plotAxis == SYD_PLAX_SMITH_IMP ||
pMstr->plotAxis == SYD_PLAX_SMITH_ADM ||
pMstr->plotAxis == SYD_PLAX_SMITH_IMM)
sydPlot_SmithPlot(pMstr);
else
assertAlways(0);
}
/*/macro-----------------------------------------------------------------------
* NAME FetchIthValInto - space saver for getting value as a double
*
*----------------------------------------------------------------------------*/
#define FetchIthValInto(pSChan, dbl) \
if (dbr_type_is_FLOAT(pSChan->dbrType)) \
dbl = (double)((float *)pSChan->pData)[i]; \
else if (dbr_type_is_SHORT(pSChan->dbrType)) { \
if (pSChan->isRVAL) \
dbl = (double)((unsigned short *)pSChan->pData)[i]; \
else \
dbl = (double)((short *)pSChan->pData)[i]; \
} \
else if (dbr_type_is_DOUBLE(pSChan->dbrType)) \
dbl = (double)((double *)pSChan->pData)[i]; \
else if (dbr_type_is_LONG(pSChan->dbrType)) { \
if (pSChan->isRVAL) \
dbl = (double)((unsigned long *)pSChan->pData)[i]; \
else \
dbl = (double)((long *)pSChan->pData)[i]; \
} \
else if (dbr_type_is_CHAR(pSChan->dbrType)) \
dbl = (double)((char *)pSChan->pData)[i]; \
else if (dbr_type_is_ENUM(pSChan->dbrType)) \
dbl = (double)((short *)pSChan->pData)[i]; \
else \
assertAlways(0);
#if 0
dbl = (double)((short *)pSChan->pData)[i];
#endif
/*+/internal******************************************************************
* NAME sydPlot_setup - set up titles and margins for a plot window
*
* DESCRIPTION
* Plots whatever titles are present in the plot master, reserving
* an appropriate margin when necessary.
*
* All slaves can be plotted in a shared grid, or separate grids
* can be used. This is controlled by the `nGrids' argument.
*
* This routine returns information to allow easily intermixing calls
* to the pprPlot routines with calls to sydPlot routines.
*
* If plotting is for PostScript, date and time are plotted in the
* upper right corner of the window.
*
* RETURNS
* void
*
* BUGS
* o handles only vertical subdividing of the plot window (i.e., into
* long horizontal strips)
*
*-*/
static void
sydPlot_setup(pMstr, nGrids, pXlo,pYlo,pXhi,pYhi, pYpart, pCh,pChX,pChTY,pChTX)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int nGrids; /* I number of grids */
double *pXlo; /* O pointer to X position of lower left corner of
first grid, as fraction of window width */
double *pYlo; /* O pointer to Y position of lower left corner of
first grid, as fraction of window height */
double *pXhi; /* O pointer to X position of upper right corner of
first grid, as fraction of window width */
double *pYhi; /* O pointer to Y position of upper right corner of
first grid, as fraction of window height */
double *pYpart; /* O pointer to fraction of window height occupied
by a single grid (all grids are equal) */
double *pCh; /* O pointer to character height, as fraction
of window height */
double *pChX; /* O pointer to character height for rotated text,
as fraction of window width */
double *pChTY; /* O pointer to title character height, as fraction
of window height */
double *pChTX; /* O pointer to title character height for rotated
text, as fraction of window width */
{
PPR_WIN *pWin; /* pointer to plot window structure */
double xlo, ylo, xhi, yhi, yPart, charHtTY, charHtTX, charHt, charHtX;
PPR_AREA *pArea;
TS_STAMP now;
char nowText[32];
pWin = pMstr->pWin;
xlo = 0.;
xhi = .98;
ylo = 0.;
yhi = .98;
charHtTY = .012;
charHtTX = pprYFracToXFrac(pWin, charHtTY);
/*-----------------------------------------------------------------------------
* initialize a plot area covering the whole window, with diagonal corners
* of 0,0 1,1 for plotting the titles
*
* for PostScript, plot current date and time
* plot the titles which aren't empty
*----------------------------------------------------------------------------*/
pArea = pprAreaOpen(pWin, 0.,0., 1.,1., 0.,0., 1.,1., 1, 1, 0.);
assertAlways(pArea != NULL);
if (pMstr->winType == PPR_WIN_POSTSCRIPT) {
(void)tsLocalTime(&now);
(void)tsStampToText(&now, TS_TEXT_MONDDYYYY, nowText);
pprText(pArea, .98, .995, nowText, PPR_TXT_RJ, .008, 0.);
}
if (strlen(pMstr->title) > 0) {
yhi = 1. - charHtTY;
pprText(pArea, .5, yhi, pMstr->title, PPR_TXT_CEN, charHtTY, 0.);
yhi -= 2. * charHtTY;
}
if (strlen(pMstr->lTitle) > 0) {
xlo = 2. * charHtTX;
pprText(pArea, xlo, .5, pMstr->lTitle, PPR_TXT_CEN, charHtTX, 90.);
xlo += 2. * charHtTX;
}
if (strlen(pMstr->bTitle) > 0) {
ylo = 2. * charHtTY;
pprText(pArea, .5, ylo, pMstr->bTitle, PPR_TXT_CEN, charHtTY, 0.);
ylo += 2. * charHtTY;
}
if (strlen(pMstr->rTitle) > 0) {
xhi = 1. - 2. * charHtTX;
pprText(pArea, xhi, .5, pMstr->rTitle, PPR_TXT_CEN, charHtTX, 90.);
xhi -= 2. * charHtTX;
}
pprAreaClose(pArea);
ylo += 4. * charHtTY; /* allow for x axis label and annotation */
yPart = (yhi - ylo)/(double)nGrids;
yhi = yPart + ylo;
charHt = PprDfltCharHt(ylo, yhi);
charHtX = pprYFracToXFrac(pWin, charHt);
*pXlo = xlo;
*pXhi = xhi;
*pYlo = ylo;
*pYhi = yhi;
*pYpart = yPart;
*pCh = charHt;
*pChX = charHtX;
*pChTY = charHtTY;
*pChTX = charHtTX;
}
/*-----------------------------------------------------------------------------
* structure for annotating time axis
*----------------------------------------------------------------------------*/
static struct {
unsigned long threshold; /* seconds for start of partition */
unsigned long modForEnds; /* rounding interval for axis ends */
short firstForEnds; /* index in mm/dd/yy hh:mm:ss.msec */
short nCharForEnds; /* # char from mm/dd/... for end label */
unsigned long modForTicks; /* rounding interval for axis tick marks */
short nSubInt; /* number of subintervals */
short firstForTicks; /* index in mm/dd/yy hh:mm:ss.msec */
short nCharForTicks; /* # char from mm/dd/... for tick label */
} timeCal[]={
7*86400+1, 86400, 0, 5, 86400, 24, 0, 5, /* more than 7 days */
43201, 86400, 0, 5, 43200, 12, 9, 5, /* more than 12 hours */
3601, 3600, 9, 5, 3600, 6, 9, 5, /* more than 1 hour */
601, 600, 9, 5, 600, 10, 9, 5, /* more than 10 minutes */
61, 60, 12, 5, 60, 6, 12, 5, /* more than 60 seconds */
11, 10, 12, 5, 10, 10, 12, 5, /* more than 10 seconds */
0, 1, 15, 6, 1, 0, 15, 6 /* <= 10 seconds */
};
/*+/internal******************************************************************
* NAME sydPlot_setupTime - handle time axis
*
*-*/
sydPlot_setupTime(pMstr, pAnnot, annot)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
char *pAnnot[20], annot[20][28];
{
SYD_SPEC *pSspec = pMstr->pSspec;
unsigned long xminUL, xmaxUL, elapsedUL, xTickDeltaUL;
TS_STAMP stamp, refStamp, xminTs, xmaxTs, elapsedTs;
char xminText[28], xmaxText[28], stampText[28];
int xNint;
double xtemp, xdelta, xmin, xmax, ymin, ymax;
int i, calNum;
/*-----------------------------------------------------------------------------
* get start and end times (as set by sydPlotInit) referenced to the
* restrictRefTs. Round them to something `sane' based on the total
* time range, then build the table of annotation labels. The rounding
* is based on local time, rather than UTC.
*----------------------------------------------------------------------------*/
if (pSspec->restrictRefTs.secPastEpoch > 0) {
tsAddDouble(&xminTs, &pSspec->restrictRefTs, pMstr->originVal);
xminTs.nsec = 0;
tsAddDouble(&xmaxTs, &pSspec->restrictRefTs, pMstr->extentVal);
if (xmaxTs.nsec > 0) {
xmaxTs.secPastEpoch++;
xmaxTs.nsec = 0;
}
TsDiffAsStamp(&elapsedTs, &xmaxTs, &xminTs);
for (calNum=0; ; calNum++) {
if (timeCal[calNum].threshold <= elapsedTs.secPastEpoch)
break;
}
tsRoundDownLocal(&xminTs, timeCal[calNum].modForEnds);
tsRoundUpLocal(&xmaxTs, timeCal[calNum].modForEnds);
if (xminTs.secPastEpoch == xmaxTs.secPastEpoch)
xmaxTs.secPastEpoch += timeCal[calNum].modForEnds;
refStamp = xminTs;
xminUL = xminTs.secPastEpoch;
xmaxUL = xmaxTs.secPastEpoch;
elapsedUL = xmaxUL - xminUL;
xTickDeltaUL = timeCal[calNum].modForTicks;
xNint = (xmaxUL - xminUL) / xTickDeltaUL;
if (xNint >= 20) {
xNint = 5;
xTickDeltaUL = elapsedUL / xNint;
}
pMstr->nInt = xNint;
pMstr->nSubInt = timeCal[calNum].nSubInt;
for (i=0; i<=xNint; i++) {
tsStampToText(&refStamp, TS_TEXT_MMDDYY, stampText);
if (i == 0 || i == xNint) {
strcpy(annot[i], &stampText[timeCal[calNum].firstForEnds]);
annot[i][timeCal[calNum].nCharForEnds] = '\0';
if (i == 0)
TsDiffAsDouble(&xmin, &refStamp, &pSspec->restrictRefTs);
else
TsDiffAsDouble(&xmax, &refStamp, &pSspec->restrictRefTs);
}
else {
strcpy(annot[i], &stampText[timeCal[calNum].firstForTicks]);
annot[i][timeCal[calNum].nCharForTicks] = '\0';
}
pAnnot[i] = annot[i];
refStamp.secPastEpoch += xTickDeltaUL;
}
(void)tsStampToText(&xminTs, TS_TEXT_MMDDYY, xminText);
(void)tsStampToText(&xmaxTs, TS_TEXT_MMDDYY, xmaxText);
(void)sprintf(pMstr->label, "%s to %s", xminText, xmaxText);
}
else {
xmin = pMstr->originVal;
xmax = pMstr->extentVal;
if (xmin == xmax)
xmax += 10.;
pprAutoEnds(xmin, xmax, &xmin, &xmax);
pprAutoInterval(xmin, xmax, &xNint);
if (xNint > 19)
xNint = 19;
xdelta = (xmax - xmin) / xNint;
for (i=0, xtemp=xmin; i<=xNint; i++,xtemp+=xdelta) {
if (i == xNint)
xtemp=xmax;
pprCvtDblToTxt(annot[i], 8, xtemp, 2);
pAnnot[i] = annot[i];
}
(void)sprintf(pMstr->label, "delta seconds");
}
pMstr->originVal = xmin;
pMstr->extentVal = xmax;
pMstr->nInt = xNint;
}
/*+/subr**********************************************************************
* NAME sydPlot_SmithPlot - handle Smith Chart plots
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
* sydPlot_SmithGrid, sydPlot_SmithSamples
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_SmithPlot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_SPEC *pSspec;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
sydPlot_SmithGrid(pMstr);
if (pSspec->useStats == 0) {
sydPlot_SmithSamples(pMstr,
pSspec->restrictFirstData, pSspec->restrictLastData, 0);
}
else
sydPlot_SmithStats(pMstr, 0, pSspec->statCount-1);
}
/*+/subr**********************************************************************
* NAME sydPlot_SmithGrid - draw a Smith chart overlay
*
* DESCRIPTION
* Draws a Smith chart overlay, to be used in plotting X vs Y data.
* Three overlays are available, with axis type controlling which is
* drawn:
*
* SYD_PLAX_SMITH_IMP results in an impedance overlay, with
* circles tangent on the right. If SYD_PLATTR_FG1 has been
* used to set an alternate foreground pixel value, then, on
* color displays, the overlay is drawn using that pixel value.
* SYD_PLAX_SMITH_ADM results in an admittance overlay, with
* circles tangent on the left. If SYD_PLATTR_FG2 has been
* used to set an alternate foreground pixel value, then, on
* color displays, the overlay is drawn using that pixel value.
* SYD_PLAX_SMITH_IMM results in an "immittance" overlay, which is
* a combination of the impedance overlay on top of the
* admittance overlay. On color displays when alternate
* foreground pixel values have been specified, the overlays
* are drawn as described above. On monochrome displays, or
* when no alternate foreground pixel values are specified,
* the impedance overlay is drawn with a solid line and the
* admittance overlay is drawn with a dashed line.
*
* On color displays, if no alternate foreground pixel values have been
* set, then the overlays are drawn using the color of the plot window.
*
* RETURNS
* void
*
* BUGS
* o channel names aren't displayed
* o colors are done only under X11
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
*-*/
void
sydPlot_SmithGrid(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
PPR_WIN *pWin;
PPR_AREA *pArea;
double incr=5.; /* use 5 degree increments */
double x, y, rad;
int r;
static char *xTxt[]={"5","2","1","0.5","0.2","0"};
double xlo, ylo, xhi, yhi;
double xmin, ymin, xmax, ymax;
double yPart;
double charHt, charHtX, charHtTY, charHtTX;
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
SYD_PL_SLAVE *pSlaveX; /* pointer to X axis slave struct */
pWin = pMstr->pWin;
sydPlot_setup(pMstr, 1, &xlo, &ylo, &xhi, &yhi, &yPart,
&charHt, &charHtX, &charHtTY, &charHtTX);
xlo += 3. * charHtX;
ylo += 2. * charHt;
xhi -= charHt;
yhi -= 2. * charHt;
pSlaveX = pMstr->pHead;
while (1) {
if (pSlaveX->xChan)
break;
pSlaveX = pSlaveX->pNext;
if (pSlaveX == NULL) {
pSlaveX = pMstr->pHead;
break;
}
}
if (pSlaveX == pMstr->pHead)
pSlave = pSlaveX->pNext;
else
pSlave = pMstr->pHead;
pArea = pprAreaOpen(pWin, xlo,ylo, xhi,yhi, 0.,0., 1.,1., 1, 1, 0.);
if (pMstr->plotAxis == SYD_PLAX_SMITH_ADM ||
pMstr->plotAxis == SYD_PLAX_SMITH_IMM) {
/*-----------------------------------------------------------------------------
* admittance overlay, with circles tangent at x=0,y=.5
*
* For immitance plots, with this as a secondary overlay, a dashed
* line pattern is used if the screen is monochrome. The outer
* circle isn't drawn and annotations aren't drawn.
*----------------------------------------------------------------------------*/
#ifdef XWINDOWS
if (pMstr->noColor == 0 && pMstr->altPixel2 != 0)
pprAreaSetAttr(pArea, PPR_ATTR_FG, 0, &pMstr->altPixel2);
else {
#else
if (1) {
#endif
if (pMstr->plotAxis == SYD_PLAX_SMITH_IMM || pMstr->noColor == 0)
pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, 1, NULL);
}
if (pMstr->plotAxis == SYD_PLAX_SMITH_ADM)
pprLineSegD(pArea, 0.,.5, 1.,.5);
y = .5;
for (r=6; r>0; r--) {
rad = (double)r / 12.;
x = rad;
if (r != 6 || pMstr->plotAxis == SYD_PLAX_SMITH_ADM)
pprArcD(pArea, x, y, rad, 0., 360., incr);
if (pMstr->plotAxis == SYD_PLAX_SMITH_ADM)
pprText(pArea, x+rad+.015, y, xTxt[r-1], PPR_TXT_LJ, 0., 0.);
}
x = 0.;
rad = .25, y = .5 + rad;
pprArcD(pArea, x, y, rad, 270., 37., incr);
if (pMstr->plotAxis == SYD_PLAX_SMITH_ADM)
pprText(pArea, .19, .92, "2", PPR_TXT_RJ, 0., 0.);
y = .5 - rad;
pprArcD(pArea, x, y, rad, 323., 90., incr);
if (pMstr->plotAxis == SYD_PLAX_SMITH_ADM)
pprText(pArea, .19, .08, "2", PPR_TXT_RJ, 0., 0.);
rad = .5, y = .5 + rad;
pprArcD(pArea, x, y, rad, 270., 0., incr);
if (pMstr->plotAxis == SYD_PLAX_SMITH_ADM)
pprText(pArea, .5, 1.02, "1", PPR_TXT_CEN, 0., 0.);
y = .5 - rad;
pprArcD(pArea, x, y, rad, 0., 90., incr);
if (pMstr->plotAxis == SYD_PLAX_SMITH_ADM)
pprText(pArea, .5, -.02, "1", PPR_TXT_CEN, 0., 0.);
rad = 1., y = .5 + rad;
pprArcD(pArea, x, y, rad, 270., 323., incr);
if (pMstr->plotAxis == SYD_PLAX_SMITH_ADM)
pprText(pArea, .81, .92, "0.5", PPR_TXT_LJ, 0., 0.);
y = .5 - rad;
pprArcD(pArea, x, y, rad, 37., 90., incr);
if (pMstr->plotAxis == SYD_PLAX_SMITH_ADM)
pprText(pArea, .81, .08, "0.5", PPR_TXT_LJ, 0., 0.);
}
if (pMstr->plotAxis == SYD_PLAX_SMITH_IMP ||
pMstr->plotAxis == SYD_PLAX_SMITH_IMM) {
/*-----------------------------------------------------------------------------
* impedance overlay, with circles tangent at x=1,y=.5
*----------------------------------------------------------------------------*/
#ifdef XWINDOWS
if (pMstr->noColor == 0 && pMstr->altPixel1 != 0)
pprAreaSetAttr(pArea, PPR_ATTR_FG, 0, &pMstr->altPixel1);
else {
#else
if (1) {
#endif
pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, 0, NULL);
}
pprLineSegD(pArea, 0.,.5, 1.,.5);
y = .5;
for (r=6; r>0; r--) {
rad = (double)r / 12.;
x = 1. - rad;
pprArcD(pArea, x, y, rad, 0., 360., incr);
pprText(pArea, x-rad-.015, y, xTxt[r-1], PPR_TXT_RJ, 0., 0.);
}
x = 1.;
rad = .25, y = .5 + rad;
pprArcD(pArea, x, y, rad, 143., 270., incr);
pprText(pArea, .81, .92, "2", PPR_TXT_LJ, 0., 0.);
y = .5 - rad;
pprArcD(pArea, x, y, rad, 90., 217., incr);
pprText(pArea, .81, .08, "2", PPR_TXT_LJ, 0., 0.);
rad = .5, y = .5 + rad;
pprArcD(pArea, x, y, rad, 180., 270., incr);
pprText(pArea, .5, 1.02, "1", PPR_TXT_CEN, 0., 0.);
y = .5 - rad;
pprArcD(pArea, x, y, rad, 90., 180., incr);
pprText(pArea, .5, -.02, "1", PPR_TXT_CEN, 0., 0.);
rad = 1., y = .5 + rad;
pprArcD(pArea, x, y, rad, 217., 270., incr);
pprText(pArea, .19, .92, "0.5", PPR_TXT_RJ, 0., 0.);
y = .5 - rad;
pprArcD(pArea, x, y, rad, 90., 143., incr);
pprText(pArea, .19, .08, "0.5", PPR_TXT_RJ, 0., 0.);
}
pprAreaClose(pArea);
pSlaveX->pArea = NULL;
xmin = pSlaveX->originVal;
xmax = pSlaveX->extentVal;
while (pSlave != NULL) {
ymin = pSlave->originVal;
ymax = pSlave->extentVal;
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pArea = pSlave->pArea = pprAreaOpen(pWin,
xlo,ylo, xhi,yhi, xmin, ymin, xmax, ymax, 1, 1, 0.);
assertAlways(pArea != NULL);
pSlave->xFracLeft = xlo + 12. * charHtX;
pSlave->xFracRight = xhi;
pSlave->yFracBot = ylo + 6. * charHt;
pSlave->yFracTop = yhi;
pSlave->annotXFL = xlo;
pSlave->annotXFR = pSlave->xFracLeft;
pSlave->annotYFB = pSlave->yFracBot;
pSlave->annotYFT = yhi;
if (pSlave->fg != 0 && pMstr->noColor == 0)
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_FG, 0, &pSlave->fg);
pSlave = pSlave->pNext;
if (pSlave == pSlaveX)
pSlave = pSlave->pNext;
}
}
/*+/subr**********************************************************************
* NAME sydPlot_SmithSamples - plot one or more samples for a Smith Chart plot
*
* DESCRIPTION
* the first channel in the plot spec is used for the X axis
*
* RETURNS
* void
*
* BUGS
* o this isn't a true Smith chart plot--the caller must have transformed
* the data into simple X vs Y data
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_SmithSamples(pMstr, begin, end, incr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin sample to plot */
int end; /* I number of end sample to plot */
int incr; /* I 0,1 for batch,incremental plotting */
{
sydPlot_XYSamples(pMstr, begin, end, incr);
}
/*+/subr**********************************************************************
* NAME sydPlot_SmithStats - plot one or more snapshots for a Smith Chart plot
*
* DESCRIPTION
* the first channel in the plot spec is used for the X axis
*
* RETURNS
* void
*
* BUGS
* o this isn't a true Smith chart plot--the caller must have transformed
* the data into simple X vs Y data
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_SmithStats(pMstr, begin, end)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin snapshot to plot */
int end; /* I number of end snapshot to plot */
{
sydPlot_XYStats(pMstr, begin, end);
}
/*+/subr**********************************************************************
* NAME sydPlot_StripYPlot - handle strip chart, Y plots
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_StripYPlot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_SPEC *pSspec;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
sydPlot_StripYGrid(pMstr);
sydPlot_StripYSamples(pMstr,
pSspec->restrictFirstData, pSspec->restrictLastData, 0);
}
/*+/subr**********************************************************************
* NAME sydPlot_StripYGrid - draw a grid for a strip chart, Y plot
*
* DESCRIPTION
*
* RETURNS
* void
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_StripYGrid(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
double xlo, ylo, xhi, yhi;
double yPart;
PPR_AREA *pArea;
double xmin, xmax, ymin, ymax;
char **ppAnnotVal, *pAnnotVal[20], annotVal[20][28];
double charHt, charHtX, charHtTY, charHtTX;
SYD_SPEC *pSspec = pMstr->pSspec;
SYD_CHAN *pSChan;
int thick=3;
int nGrids;
int i;
pWin = pMstr->pWin;
nGrids = pMstr->nSlaves;
sydPlot_setup(pMstr, nGrids, &xlo, &ylo, &xhi, &yhi, &yPart,
&charHt, &charHtX, &charHtTY, &charHtTX);
if (pMstr->pSspec->sampleCount > 0) {
xmax = pMstr->pSspec->pDeltaSec[pMstr->pSspec->lastData];
xmin = xmax - pMstr->stripIncr * pMstr->pSspec->reqCount;
}
else if (pMstr->winType == PPR_WIN_SCREEN) {
xmin = -1. * (pMstr->stripIncr * pMstr->pSspec->reqCount);
xmax = 0.;
}
else {
xmin = 0.;
xmax = pMstr->stripIncr * pMstr->pSspec->reqCount;
}
pSlave = pMstr->pHead;
while (pSlave != NULL) {
/*-----------------------------------------------------------------------------
* for each channel, initialize a plot area.
*
* plot a perimeter with grid lines
*----------------------------------------------------------------------------*/
pSChan = pSlave->pSChan;
ymin = pSlave->originVal;
ymax = pSlave->extentVal;
if (pSlave->ppAnnot == NULL) {
sydAnnotVal(pSlave, pAnnotVal, annotVal);
ppAnnotVal = pAnnotVal;
}
else
ppAnnotVal = pSlave->ppAnnot;
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pArea = pSlave->pArea = pprAreaOpen(pWin,
xlo+12.*charHtX, ylo+2.*charHt, xhi, yhi,
xmin, ymin, xmax, ymax, 1, pSlave->nInt, charHt);
assertAlways(pArea != NULL);
pSlave->xFracLeft = xlo + 12. * charHtX;
pSlave->xFracRight = xhi;
pSlave->yFracBot = ylo + 2.*charHt;
pSlave->yFracTop = yhi;
pSlave->annotXFL = xlo;
pSlave->annotXFR = pSlave->xFracLeft;
pSlave->annotYFB = pSlave->yFracBot;
pSlave->annotYFT = yhi;
if (pSlave->fg != 0 && pMstr->noColor == 0)
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_FG, 0, &pSlave->fg);
else if (pMstr->linePlot) {
if (dbr_type_is_ENUM(pSChan->dbrType))
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
}
pprAnnotY(pArea, 0, ymin, ymax, pSlave->nInt, 0,
pSlave->pSChan->label, ppAnnotVal, 0.);
if (pSlave == pMstr->pHead) {
pArea->charHt = charHtTY * pWin->height;
pprAnnotX(pArea, 0, xmin, xmax, 1, 0, "delta seconds", NULL, 0.);
pArea->charHt = charHt * pWin->height;
}
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_STRIP, 1, NULL);
pprGrid(pArea);
ylo += yPart;
yhi += yPart;
pSlave = pSlave->pNext;
}
pSlave = pMstr->pHead;
pMstr->originFrac = pSlave->xFracLeft;
pMstr->extentFrac = pSlave->xFracRight;
}
/*+/subr**********************************************************************
* NAME sydPlot_StripYSamples - plot samples for a strip chart, Y plot
*
* DESCRIPTION
*
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_StripYSamples(pMstr, begin, end, incr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin sample to plot */
int end; /* I number of end sample to plot */
int incr; /* I 0,1 for batch,incremental plotting */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
PPR_AREA *pArea;
int i, j;
SYD_SPEC *pSspec;
SYD_CHAN *pSChan;
double oldX, oldY, newX, newY;
int skip;
int showStat; /* 1 to show status code on plot */
int pointPlot; /* 1 for point plot */
int linePlot; /* 1 to connect points with lines */
int markPlot; /* 1 to draw marks at points */
int markNum; /* number of mark to use */
int nEl; /* number of array elements */
int first; /* ==1 if this is the first sample */
float shift; /* amount to shift the strip chart(s) */
int pixEnd; /* pixel coordinate for end time */
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
pWin = pMstr->pWin;
linePlot = pMstr->linePlot;
pointPlot = pMstr->pointPlot;
markPlot = pMstr->markPlot;
showStat = pMstr->showStat;
pArea = pMstr->pHead->pArea;
pixEnd = pArea->xPixRight +
.5 + (pSspec->pDeltaSec[end] - pArea->xRight) * pArea->xScale;
if (pixEnd >= pArea->xPixRight) {
shift = pSspec->pDeltaSec[end] - pMstr->pHead->pArea->xRight;
if (shift < pMstr->stripIncr)
shift = pMstr->stripIncr;
}
else
shift = 0.;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
pArea = pSlave->pArea;
pSChan = pSlave->pSChan;
markNum = pSlave->markNum;
if (pSChan->pData == NULL || pSChan->dataChan == 0)
; /* no action if never connected or not data channel */
else {
if (shift > 0.) {
pprAreaShiftLeft(pArea, shift);
if (pArea == pMstr->pHead->pArea) {
pMstr->originVal = pArea->xLeft;
pMstr->extentVal = pArea->xRight;
}
}
nEl = pSChan->elCount;
i = begin;
if (!incr)
first = 1;
else {
first = pSlave->first;
oldX = pSlave->oldX;
oldY = pSlave->oldY;
skip = pSlave->skip;
}
while (i >= 0) {
int restart, restart1;
restart = restart1 = 0;
if (pSChan->pFlags[i].restart) {
if (!pSChan->pFlags[i].snapstart)
restart = 1;
else if (!pSChan->pFlags[i].snapend)
restart = 1;
}
if (i != end && pSChan->pFlags[i+1].restart) {
if (!pSChan->pFlags[i+1].snapstart)
restart1 = 1;
else if (!pSChan->pFlags[i+1].snapend)
restart1 = 1;
}
if (pSChan->pFlags[i].missing)
skip = 1;
else if (first || skip || restart) {
oldX = pSspec->pDeltaSec[i] -
pMstr->pSspec->restrictDeltaSecSubtract;
if (oldX >= pArea->xLeft) {
FetchIthValInto(pSChan, oldY)
if (markPlot)
pprMarkD(pArea, oldX, oldY, markNum);
if (showStat && pSChan->pDataCodeR[i] != ' ') {
pprChar(pArea, oldX, oldY,
pSChan->pDataCodeR[i], 0., 0.);
}
else if (pointPlot)
pprPointD(pArea, oldX, oldY);
skip = 0;
}
}
else if (pSChan->pFlags[i].filled && restart1 == 0 && i != end)
; /* no action */
else {
newX = pSspec->pDeltaSec[i] -
pMstr->pSspec->restrictDeltaSecSubtract;
if (linePlot && dbr_type_is_ENUM(pSChan->dbrType)) {
if (oldX >= pArea->xLeft)
pprLineSegD(pArea, oldX, oldY, newX, oldY);
oldX = newX;
}
FetchIthValInto(pSChan, newY)
if (oldX >= pArea->xLeft) {
if (linePlot)
pprLineSegD(pArea, oldX, oldY, newX, newY);
if (markPlot)
pprMarkD(pArea, newX, newY, markNum);
if (showStat && pSChan->pDataCodeR[i] != ' ') {
pprChar(pArea, newX, newY,
pSChan->pDataCodeR[i], 0., 0.);
}
else if (pointPlot)
pprPointD(pArea, newX, newY);
}
oldX = newX;
oldY = newY;
}
if (i == end)
i = -1;
else if (++i >= pSspec->dataDim)
i = 0;
first = 0;
}
}
pSlave->first = first;
pSlave->oldX = oldX;
pSlave->oldY = oldY;
pSlave->skip = skip;
pSlave = pSlave->pNext;
}
}
/*+/subr**********************************************************************
* NAME sydPlot_StripYYPlot - handle strip chart, multiple Y plots
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o labeling of x axis is un-esthetic. It should be time based, with
* some intelligent adaptation, based on time interval for X
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_StripYYPlot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_SPEC *pSspec;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
sydPlot_StripYYGrid(pMstr);
sydPlot_StripYSamples(pMstr,
pSspec->restrictFirstData, pSspec->restrictLastData, 0);
}
/*+/subr**********************************************************************
* NAME sydPlot_StripYYGrid - draw a grid for a strip chart, multiple Y plot
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_StripYYGrid(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
double xlo, ylo, xhi, yhi;
double yPart;
PPR_AREA *pArea;
double xmin, xmax, ymin, ymax;
double charHt, charHtX, charHtTY, charHtTX;
char **ppAnnotVal, *pAnnotVal[20], annotVal[20][28];
SYD_SPEC *pSspec = pMstr->pSspec;
SYD_CHAN *pSChan;
int thick=3;
int nGrids;
int i, calNum;
int offsetAnnotY=0;
int drawAxis=0;
pWin = pMstr->pWin;
nGrids = 1;
sydPlot_setup(pMstr, nGrids, &xlo, &ylo, &xhi, &yhi, &yPart,
&charHt, &charHtX, &charHtTY, &charHtTX);
if (pMstr->pSspec->sampleCount > 0) {
xmax = pMstr->pSspec->pDeltaSec[pMstr->pSspec->lastData];
xmin = xmax - pMstr->stripIncr * pMstr->pSspec->reqCount;
}
else if (pMstr->winType == PPR_WIN_SCREEN) {
xmin = -1. * (pMstr->stripIncr * pMstr->pSspec->reqCount);
xmax = 0.;
}
else {
xmin = 0.;
xmax = pMstr->stripIncr * pMstr->pSspec->reqCount;
}
xlo += 6. * charHtX * (double)pMstr->nSlaves;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
/*-----------------------------------------------------------------------------
* for the first channel:
* initialize a plot area; its fractional size depends on how many
* "sub-plots" there are
* plot a perimeter with grid lines
* for the other channels:
* initialize an overlapping plot area
* set a dashed line pattern (unless this is a mark or point plot)
* draw a "floating" Y axis
*----------------------------------------------------------------------------*/
pSChan = pSlave->pSChan;
ymin = pSlave->originVal;
ymax = pSlave->extentVal;
if (pSlave->ppAnnot == NULL) {
sydAnnotVal(pSlave, pAnnotVal, annotVal);
ppAnnotVal = pAnnotVal;
}
else
ppAnnotVal = pSlave->ppAnnot;
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pArea = pSlave->pArea = pprAreaOpen(pWin, xlo, ylo+2.*charHt, xhi, yhi,
xmin, ymin, xmax, ymax, pMstr->nInt, pSlave->nInt, charHt);
assertAlways(pArea != NULL);
pSlave->xFracLeft = xlo;
pSlave->xFracRight = xhi;
pSlave->yFracBot = ylo;
pSlave->yFracTop = yhi;
if (pSlave->fg != 0 && pMstr->noColor == 0)
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_FG, 0, &pSlave->fg);
else if (pMstr->linePlot) {
if (dbr_type_is_ENUM(pSChan->dbrType))
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
if (pSlave->lineKey > 1 || pMstr->noColor == 0)
pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, pSlave->lineKey, NULL);
}
else if (pMstr->noColor == 0)
pprAreaSetAttr(pArea, PPR_ATTR_COLORNUM, pSlave->lineKey, NULL);
pprAnnotY(pArea, offsetAnnotY, pSlave->originVal, pSlave->extentVal,
pSlave->nInt, drawAxis,
pSlave->pSChan->label, ppAnnotVal, 90.);
if (drawAxis == 0) {
if (pSlave == pMstr->pHead) {
pArea->charHt = charHtTY * pWin->height;
pprAnnotX(pArea, 0, xmin,xmax,1,0,"delta seconds",NULL,0.);
pArea->charHt = charHt * pWin->height;
}
pprAreaSetAttr(pArea, PPR_ATTR_STRIP, 1, NULL);
pprGrid(pArea);
}
else
pprAreaSetAttr(pArea, PPR_ATTR_STRIP, 1, pMstr->pHead->pArea);
if (pMstr->markPlot)
pprAnnotYMark(pArea, offsetAnnotY, pSlave->markNum);
offsetAnnotY += 6;
drawAxis = 1; /* draw an "auxiliary" axis next time */
pSlave->annotXFL = xlo - offsetAnnotY * charHtX;
pSlave->annotXFR = pSlave->annotXFL + 6. * charHtX;
pSlave->annotYFB = ylo;
pSlave->annotYFT = yhi;
pSlave = pSlave->pNext;
}
pSlave = pMstr->pHead;
pMstr->originFrac = pSlave->xFracLeft;
pMstr->extentFrac = pSlave->xFracRight;
}
/*+/subr**********************************************************************
* NAME sydPlot_TYPlot - handle time vs Y plots
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_TYPlot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_SPEC *pSspec;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
sydPlot_TYGrid(pMstr);
if (pSspec->useStats == 0) {
sydPlot_TYSamples(pMstr,
pSspec->restrictFirstData, pSspec->restrictLastData, 0);
}
else
sydPlot_TYStats(pMstr, 0, pSspec->statCount-1);
}
/*+/subr**********************************************************************
* NAME sydPlot_TYGrid - draw a grid for a time vs Y plot
*
* DESCRIPTION
*
* RETURNS
* void
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_TYGrid(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
double xlo, ylo, xhi, yhi;
double yPart;
PPR_AREA *pArea;
double xmin, xmax, ymin, ymax;
char *pAnnot[20], annot[20][28]; /* annot for time axis */
char **ppAnnotVal, *pAnnotVal[20], annotVal[20][28];
double charHt, charHtX, charHtTY, charHtTX;
SYD_SPEC *pSspec = pMstr->pSspec;
SYD_CHAN *pSChan;
int thick=3;
int nGrids;
int i;
pWin = pMstr->pWin;
nGrids = pMstr->nSlaves;
sydPlot_setup(pMstr, nGrids, &xlo, &ylo, &xhi, &yhi, &yPart,
&charHt, &charHtX, &charHtTY, &charHtTX);
sydPlot_setupTime(pMstr, pAnnot, annot);
xmin = pMstr->originVal;
xmax = pMstr->extentVal;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
/*-----------------------------------------------------------------------------
* for each channel, initialize a plot area.
*
* plot a perimeter with grid lines
*----------------------------------------------------------------------------*/
pSChan = pSlave->pSChan;
ymin = pSlave->originVal;
ymax = pSlave->extentVal;
if (pSlave->ppAnnot == NULL) {
sydAnnotVal(pSlave, pAnnotVal, annotVal);
ppAnnotVal = pAnnotVal;
}
else
ppAnnotVal = pSlave->ppAnnot;
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pArea = pSlave->pArea = pprAreaOpen(pWin,
xlo+12.*charHtX, ylo+2.*charHt, xhi, yhi,
xmin, ymin, xmax, ymax, pMstr->nInt, pSlave->nInt, charHt);
assertAlways(pArea != NULL);
pSlave->xFracLeft = xlo + 12. * charHtX;
pSlave->xFracRight = xhi;
pSlave->yFracBot = ylo + 2.*charHt;
pSlave->yFracTop = yhi;
pSlave->annotXFL = xlo;
pSlave->annotXFR = pSlave->xFracLeft;
pSlave->annotYFB = pSlave->yFracBot;
pSlave->annotYFT = yhi;
if (pSlave->fg != 0 && pMstr->noColor == 0)
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_FG, 0, &pSlave->fg);
else if (pMstr->linePlot) {
if (dbr_type_is_ENUM(pSChan->dbrType))
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
}
pprGrid(pArea);
pprAnnotY(pArea, 0, ymin, ymax, pSlave->nInt, 0,
pSlave->pSChan->label, ppAnnotVal, 0.);
if (pSlave == pMstr->pHead) {
pArea->charHt = charHtTY * pWin->height;
pArea->xNsubint = pMstr->nSubInt;
pprAnnotX(pArea, 0, xmin, xmax, pMstr->nInt, 0,
pMstr->label, pAnnot, 0.);
pArea->charHt = charHt * pWin->height;
}
ylo += yPart;
yhi += yPart;
pSlave = pSlave->pNext;
}
pSlave = pMstr->pHead;
pMstr->originFrac = pSlave->xFracLeft;
pMstr->extentFrac = pSlave->xFracRight;
}
/*+/subr**********************************************************************
* NAME sydPlot_TYSamples - plot one or more samples for a time vs Y plot
*
* DESCRIPTION
*
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_TYSamples(pMstr, begin, end, incr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin sample to plot */
int end; /* I number of end sample to plot */
int incr; /* I 0,1 for batch,incremental plotting */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
PPR_AREA *pArea;
int i, j;
SYD_SPEC *pSspec;
SYD_CHAN *pSChan;
double oldX, oldY, newX, newY;
int skip;
int showStat; /* 1 to show status code on plot */
int pointPlot; /* 1 for point plot */
int linePlot; /* 1 to connect points with lines */
int markPlot; /* 1 to draw marks at points */
int markNum; /* number of mark to use */
int nEl; /* number of array elements */
int first; /* ==1 if this is the first sample */
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
pWin = pMstr->pWin;
linePlot = pMstr->linePlot;
pointPlot = pMstr->pointPlot;
markPlot = pMstr->markPlot;
showStat = pMstr->showStat;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
pArea = pSlave->pArea;
pSChan = pSlave->pSChan;
markNum = pSlave->markNum;
if (pSChan->pData == NULL || pSChan->dataChan == 0)
; /* no action if never connected or not data channel */
else {
nEl = pSChan->elCount;
i = begin;
if (!incr)
first = 1;
else {
first = pSlave->first;
oldX = pSlave->oldX;
oldY = pSlave->oldY;
skip = pSlave->skip;
}
while (i >= 0) {
int restart, restart1;
restart = restart1 = 0;
if (pSChan->pFlags[i].restart) {
if (!pSChan->pFlags[i].snapstart)
restart = 1;
else if (!pSChan->pFlags[i].snapend)
restart = 1;
}
if (i != end && pSChan->pFlags[i+1].restart) {
if (!pSChan->pFlags[i+1].snapstart)
restart1 = 1;
else if (!pSChan->pFlags[i+1].snapend)
restart1 = 1;
}
if (pSChan->pFlags[i].missing)
skip = 1;
else if (first || skip || restart) {
oldX = pSspec->pDeltaSec[i] -
pMstr->pSspec->restrictDeltaSecSubtract;
if (pMstr->wrapX) {
while (oldX > pMstr->extentVal)
oldX -= pMstr->extentVal;
}
FetchIthValInto(pSChan, oldY)
if (markPlot)
pprMarkD(pArea, oldX, oldY, markNum);
if (showStat && pSChan->pDataCodeR[i] != ' ') {
pprChar(pArea, oldX,oldY, pSChan->pDataCodeR[i],0.,0.);
}
else if (pointPlot)
pprPointD(pArea, oldX, oldY);
skip = 0;
}
else if (pSChan->pFlags[i].filled && restart1 == 0 && i != end)
; /* no action */
else {
newX = pSspec->pDeltaSec[i] -
pMstr->pSspec->restrictDeltaSecSubtract;
if (pMstr->wrapX) {
while (newX > pMstr->extentVal)
newX -= pMstr->extentVal;
}
if (linePlot && dbr_type_is_ENUM(pSChan->dbrType)) {
pprLineSegD(pArea, oldX, oldY, newX, oldY);
oldX = newX;
}
FetchIthValInto(pSChan, newY)
if (linePlot)
pprLineSegD(pArea, oldX, oldY, newX, newY);
if (markPlot)
pprMarkD(pArea, newX, newY, markNum);
if (showStat && pSChan->pDataCodeR[i] != ' ') {
pprChar(pArea, newX,newY, pSChan->pDataCodeR[i],0.,0.);
}
else if (pointPlot)
pprPointD(pArea, newX, newY);
oldX = newX;
oldY = newY;
}
if (i == end)
i = -1;
else if (++i >= pSspec->dataDim)
i = 0;
first = 0;
}
}
pSlave->first = first;
pSlave->oldX = oldX;
pSlave->oldY = oldY;
pSlave->skip = skip;
pSlave = pSlave->pNext;
}
}
/*+/subr**********************************************************************
* NAME sydPlot_TYStats - plot one or more snapshots for a time vs Y plot
*
* DESCRIPTION
*
*
* RETURNS
* void
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
*-*/
void
sydPlot_TYStats(pMstr, begin, end)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin snapshot to plot */
int end; /* I number of end snapshot to plot */
{
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
PPR_AREA *pArea;
int i;
SYD_SPEC *pSspec;
SYD_CHAN *pSChan;
double oldX, oldY, newX, newY, err;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
for (pSlave=pMstr->pHead; pSlave!=NULL; pSlave=pSlave->pNext) {
pArea = pSlave->pArea;
pSChan = pSlave->pSChan;
for (i=begin; i<=end; i++) {
if (i == begin) {
oldX = pSspec->pStatDeltaSec[i] -
pMstr->pSspec->restrictDeltaSecSubtract;
if (pMstr->wrapX) {
while (oldX > pMstr->extentVal)
oldX -= pMstr->extentVal;
}
oldY = pSChan->pStats[i].mean;
}
else {
newX = pSspec->pStatDeltaSec[i] -
pMstr->pSspec->restrictDeltaSecSubtract;
if (pMstr->wrapX) {
while (newX > pMstr->extentVal)
newX -= pMstr->extentVal;
}
newY = pSChan->pStats[i].mean;
if (pMstr->linePlot)
pprLineSegD(pArea, oldX, oldY, newX, newY);
oldX = newX;
oldY = newY;
}
if (pMstr->markPlot)
pprMarkD(pArea, oldX, oldY, pSlave->markNum);
else
pprPointD(pArea, oldX, oldY);
if (pMstr->errBar == SYD_PLATTR_STDDEV) {
err = pSChan->pStats[i].stdDev;
pprErrorBar(pArea, oldX, oldY-err, oldX, oldY+err);
}
}
}
}
/*+/subr**********************************************************************
* NAME sydPlot_TYYPlot - handle time vs multiple Y plots
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o labeling of x axis is un-esthetic. It should be time based, with
* some intelligent adaptation, based on time interval for X
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_TYYPlot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_SPEC *pSspec;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
sydPlot_TYYGrid(pMstr);
if (pSspec->useStats == 0) {
sydPlot_TYSamples(pMstr,
pSspec->restrictFirstData, pSspec->restrictLastData, 0);
}
else
sydPlot_TYStats(pMstr, 0, pSspec->statCount-1);
}
/*+/subr**********************************************************************
* NAME sydPlot_TYYGrid - draw a grid for a time vs multiple Y plot
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_TYYGrid(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
double xlo, ylo, xhi, yhi;
double yPart;
PPR_AREA *pArea;
double xmin, xmax, ymin, ymax;
char *pAnnot[20], annot[20][28]; /* annot for time axis */
double charHt, charHtX, charHtTY, charHtTX;
SYD_SPEC *pSspec = pMstr->pSspec;
SYD_CHAN *pSChan;
int thick=3;
int nGrids;
int i, calNum;
int offsetAnnotY=0;
int drawAxis=0;
char **ppAnnotVal, *pAnnotVal[20], annotVal[20][28];
pWin = pMstr->pWin;
nGrids = 1;
sydPlot_setup(pMstr, nGrids, &xlo, &ylo, &xhi, &yhi, &yPart,
&charHt, &charHtX, &charHtTY, &charHtTX);
sydPlot_setupTime(pMstr, pAnnot, annot);
xmin = pMstr->originVal;
xmax = pMstr->extentVal;
xlo += 6. * charHtX * (double)pMstr->nSlaves;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
/*-----------------------------------------------------------------------------
* for the first channel:
* initialize a plot area; its fractional size depends on how many
* "sub-plots" there are
* plot a perimeter with grid lines
* for the other channels:
* initialize an overlapping plot area
* set a dashed line pattern (unless this is a mark or point plot)
* draw a "floating" Y axis
*----------------------------------------------------------------------------*/
pSChan = pSlave->pSChan;
ymin = pSlave->originVal;
ymax = pSlave->extentVal;
if (pSlave->ppAnnot == NULL) {
sydAnnotVal(pSlave, pAnnotVal, annotVal);
ppAnnotVal = pAnnotVal;
}
else
ppAnnotVal = pSlave->ppAnnot;
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pArea = pSlave->pArea = pprAreaOpen(pWin, xlo, ylo+2.*charHt, xhi, yhi,
xmin, ymin, xmax, ymax, pMstr->nInt, pSlave->nInt, charHt);
assertAlways(pArea != NULL);
pSlave->xFracLeft = xlo;
pSlave->xFracRight = xhi;
pSlave->yFracBot = ylo;
pSlave->yFracTop = yhi;
if (pSlave->fg != 0 && pMstr->noColor == 0)
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_FG, 0, &pSlave->fg);
else if (pMstr->linePlot) {
if (dbr_type_is_ENUM(pSChan->dbrType))
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
if (pSlave->lineKey > 1 || pMstr->noColor == 0)
pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, pSlave->lineKey, NULL);
}
else if (pMstr->noColor == 0)
pprAreaSetAttr(pArea, PPR_ATTR_COLORNUM, pSlave->lineKey, NULL);
if (drawAxis == 0) {
pprGrid(pArea);
if (pSlave == pMstr->pHead) {
pArea->charHt = charHtTY * pWin->height;
pArea->xNsubint = pMstr->nSubInt;
pprAnnotX_wc(pArea, 0,
xmin, xmax, pMstr->nInt, 0, pMstr->label, pAnnot, 0.);
pArea->charHt = charHt * pWin->height;
}
}
pprAnnotY(pArea, offsetAnnotY, pSlave->originVal, pSlave->extentVal,
pSlave->nInt, drawAxis,
pSlave->pSChan->label, ppAnnotVal, 90.);
if (pMstr->markPlot)
pprAnnotYMark(pArea, offsetAnnotY, pSlave->markNum);
offsetAnnotY += 6;
drawAxis = 1; /* draw an "auxiliary" axis next time */
pSlave->annotXFL = xlo - offsetAnnotY * charHtX;
pSlave->annotXFR = pSlave->annotXFL + 6. * charHtX;
pSlave->annotYFB = ylo;
pSlave->annotYFT = yhi;
pSlave = pSlave->pNext;
}
pSlave = pMstr->pHead;
pMstr->originFrac = pSlave->xFracLeft;
pMstr->extentFrac = pSlave->xFracRight;
}
/*+/subr**********************************************************************
* NAME sydPlot_XYPlot - handle X vs Y plots
*
* DESCRIPTION
* the first channel in the plot spec is used for the X axis
*
* alarm state of the "X" channel is not displayed
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_XYPlot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_SPEC *pSspec;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
sydPlot_XYGrid(pMstr);
if (pSspec->useStats == 0) {
sydPlot_XYSamples(pMstr,
pSspec->restrictFirstData, pSspec->restrictLastData, 0);
}
else
sydPlot_XYStats(pMstr, 0, pSspec->statCount-1);
}
/*+/subr**********************************************************************
* NAME sydPlot_XYGrid - draw a grid for an X vs Y plot
*
* DESCRIPTION
* the first channel in the plot spec is used for the X axis
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_XYGrid(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
SYD_PL_SLAVE *pSlaveX; /* pointer to X axis slave struct */
double xlo, ylo, xhi, yhi;
double yPart;
PPR_AREA *pArea;
double xmin, xmax, ymin, ymax;
double charHt, charHtX, charHtTY, charHtTX;
SYD_CHAN *pSChan;
SYD_CHAN *pSChanX;
int nGrids;
char **ppAnnotVal, *pAnnotVal[20], annotVal[20][28];
char **ppAnnotXVal, *pAnnotXVal[20], annotXVal[20][28];
int first=1;
pWin = pMstr->pWin;
pSlaveX = pMstr->pHead;
while (1) {
if (pSlaveX->xChan)
break;
pSlaveX = pSlaveX->pNext;
if (pSlaveX == NULL) {
pSlaveX = pMstr->pHead;
break;
}
}
if (pSlaveX == pMstr->pHead)
pSlave = pSlaveX->pNext;
else
pSlave = pMstr->pHead;
nGrids = pMstr->nSlaves - 1;
sydPlot_setup(pMstr, nGrids, &xlo, &ylo, &xhi, &yhi, &yPart,
&charHt, &charHtX, &charHtTY, &charHtTX);
pSlaveX->pArea = NULL;
pSChanX = pSlaveX->pSChan;
if (pSlaveX->ppAnnot == NULL) {
sydAnnotVal(pSlaveX, pAnnotXVal, annotXVal);
ppAnnotXVal = pAnnotXVal;
}
else
ppAnnotVal = pSlave->ppAnnot;
xmin = pSlaveX->originVal;
xmax = pSlaveX->extentVal;
while (pSlave != NULL) {
/*-----------------------------------------------------------------------------
* for each Y channel, plot a perimeter with grid lines
*----------------------------------------------------------------------------*/
pSChan = pSlave->pSChan;
ymin = pSlave->originVal;
ymax = pSlave->extentVal;
if (pSlave->ppAnnot == NULL) {
sydAnnotVal(pSlave, pAnnotVal, annotVal);
ppAnnotVal = pAnnotVal;
}
else
ppAnnotVal = pSlave->ppAnnot;
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pArea = pSlave->pArea = pprAreaOpen(pWin,
xlo+12.*charHtX, ylo+2.*charHt, xhi, yhi,
xmin, ymin, xmax, ymax, pSlaveX->nInt, pSlave->nInt, charHt);
assertAlways(pArea != NULL);
pSlave->xFracLeft = xlo + 12. * charHtX;
pSlave->xFracRight = xhi;
pSlave->yFracBot = ylo + 2. * charHt;
pSlave->yFracTop = yhi;
pSlave->annotXFL = xlo;
pSlave->annotXFR = pSlave->xFracLeft;
pSlave->annotYFB = pSlave->yFracBot;
pSlave->annotYFT = yhi;
if (pSlave->fg != 0 && pMstr->noColor == 0)
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_FG, 0, &pSlave->fg);
pprGrid(pArea);
pprAnnotY(pArea, 0, ymin, ymax, pSlave->nInt, 0,
pSlave->pSChan->label, ppAnnotVal, 0.);
if (first) {
pArea->charHt = charHtTY * pWin->height;
pprAnnotX(pArea, 0, xmin, xmax, pSlaveX->nInt, 0,
pSlaveX->pSChan->label, ppAnnotXVal, 0.);
pArea->charHt = charHt * pWin->height;
first = 0;
}
ylo += yPart;
yhi += yPart;
pSlave = pSlave->pNext;
if (pSlave == pSlaveX)
pSlave = pSlave->pNext;
}
}
/*+/subr**********************************************************************
* NAME sydPlot_XYSamples - plot one or more samples for an X vs Y plot
*
* DESCRIPTION
* the first channel in the plot spec is used for the X axis
*
* alarm state of the "X" channel is not displayed
*
* RETURNS
* void
*
* BUGS
* o line plot isn't handled
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_XYSamples(pMstr, begin, end, incr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin sample to plot */
int end; /* I number of end sample to plot */
int incr; /* I 0,1 for batch,incremental plotting */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
SYD_PL_SLAVE *pSlaveX; /* pointer to X axis slave struct */
PPR_AREA *pArea;
int i, j;
SYD_SPEC *pSspec;
SYD_CHAN *pSChan;
SYD_CHAN *pSChanX;
double oldX, oldY, newX, newY;
int skip;
int showStat; /* 1 to show status code on plot */
int pointPlot; /* 1 for point plot */
int linePlot; /* 1 to connect points with lines */
int markPlot; /* 1 to draw marks at points */
int markNum; /* number of mark to use */
int nEl; /* number of array elements */
int first; /* ==1 if this is the first sample */
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
pWin = pMstr->pWin;
linePlot = pMstr->linePlot;
pointPlot = pMstr->pointPlot;
markPlot = pMstr->markPlot;
showStat = pMstr->showStat;
pSlaveX = pMstr->pHead;
while (1) {
if (pSlaveX->xChan)
break;
pSlaveX = pSlaveX->pNext;
if (pSlaveX == NULL) {
pSlaveX = pMstr->pHead;
break;
}
}
if (pSlaveX == pMstr->pHead)
pSlave = pSlaveX->pNext;
else
pSlave = pMstr->pHead;
pSChanX = pSlaveX->pSChan;
while (pSlave != NULL) {
pArea = pSlave->pArea;
pSChan = pSlave->pSChan;
if (pSChan->pData == NULL || pSChan->dataChan == 0)
; /* no action if never connected or not data channel */
else {
markNum = pSlave->markNum;
nEl = pSChanX->elCount;
if (nEl > pSChan->elCount)
nEl = pSChan->elCount;
i = begin;
if (!incr)
first = 1;
else {
first = pSlave->first;
oldX = pSlave->oldX;
oldY = pSlave->oldY;
skip = pSlave->skip;
}
while (i >= 0) {
int restart, restart1;
restart = restart1 = 0;
if (pSChan->pFlags[i].restart) {
if (!pSChan->pFlags[i].snapstart)
restart = 1;
else if (!pSChan->pFlags[i].snapend)
restart = 1;
}
if (i != end && pSChan->pFlags[i+1].restart) {
if (!pSChan->pFlags[i+1].snapstart)
restart1 = 1;
else if (!pSChan->pFlags[i+1].snapend)
restart1 = 1;
}
if (pSChan->pFlags[i].missing || pSChanX->pFlags[i].missing)
skip = 1;
else if (first || skip || restart ||
pSChanX->pFlags[i].restart) {
if (nEl == 1) {
FetchIthValInto(pSChanX, oldX)
FetchIthValInto(pSChan, oldY)
if (markPlot)
pprMarkD(pArea, oldX, oldY, markNum);
if (showStat && pSChan->pDataCodeR[i] != ' ') {
pprChar(pArea,
oldX, oldY, pSChan->pDataCodeR[i], 0., 0.);
}
else if (pointPlot)
pprPointD(pArea, oldX, oldY);
}
else {
sydPlot_XYarray(pArea, pSChanX, pSChan, i);
}
skip = 0;
}
#if 0 /* don't "optimize" filled--show each x,y */
else if (pSChan->pFlags[i].filled && i != end &&
pSChan->pFlags[i+1].restart == 0)
; /* no action */
#endif
else {
if (nEl == 1) {
FetchIthValInto(pSChanX, newX)
FetchIthValInto(pSChan, newY)
if (linePlot)
pprLineSegD(pArea, oldX, oldY, newX, newY);
if (markPlot)
pprMarkD(pArea, newX, newY, markNum);
if (showStat && pSChan->pDataCodeR[i] != ' ') {
pprChar(pArea,
newX, newY, pSChan->pDataCodeR[i], 0., 0.);
}
else if (pointPlot)
pprPointD(pArea, newX, newY);
oldX = newX;
oldY = newY;
}
else {
sydPlot_XYarray(pArea, pSChanX, pSChan, i);
}
}
if (i == end)
i = -1;
else if (++i >= pSspec->dataDim)
i = 0;
first = 0;
}
}
pSlave->first = first;
pSlave->oldX = oldX;
pSlave->oldY = oldY;
pSlave->skip = skip;
pSlave = pSlave->pNext;
if (pSlave == pSlaveX)
pSlave = pSlave->pNext;
}
}
/*+/subr**********************************************************************
* NAME sydPlot_XYStats - plot one or more snapshots for an X vs Y plot
*
* DESCRIPTION
* the first channel in the plot spec is used for the X axis
*
* alarm state of the "X" channel is not displayed
*
* RETURNS
* void
*
* BUGS
* o line plot isn't handled
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_XYStats(pMstr, begin, end)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin snapshots to plot */
int end; /* I number of end snapshots to plot */
{
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
SYD_PL_SLAVE *pSlaveX; /* pointer to X axis slave struct */
PPR_AREA *pArea;
int i;
SYD_SPEC *pSspec;
SYD_CHAN *pSChan;
SYD_CHAN *pSChanX;
double oldX, oldY, newX, newY, err;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
pSlaveX = pMstr->pHead;
while (1) {
if (pSlaveX->xChan)
break;
pSlaveX = pSlaveX->pNext;
if (pSlaveX == NULL) {
pSlaveX = pMstr->pHead;
break;
}
}
if (pSlaveX == pMstr->pHead)
pSlave = pSlaveX->pNext;
else
pSlave = pMstr->pHead;
pSChanX = pSlaveX->pSChan;
while (pSlave != NULL) {
pArea = pSlave->pArea;
pSChan = pSlave->pSChan;
for (i=begin; i<=end; i++) {
if (i == begin) {
oldX = pSChanX->pStats[i].mean;
oldY = pSChan->pStats[i].mean;
}
else {
newX = pSChanX->pStats[i].mean;
newY = pSChan->pStats[i].mean;
if (pMstr->linePlot)
pprLineSegD(pArea, oldX, oldY, newX, newY);
oldX = newX;
oldY = newY;
}
if (pMstr->markPlot)
pprMarkD(pArea, oldX, oldY, pSlave->markNum);
else
pprPointD(pArea, oldX, oldY);
if (pMstr->errBar == SYD_PLATTR_STDDEV) {
err = pSChan->pStats[i].stdDev;
pprErrorBar(pArea, oldX, oldY-err, oldX, oldY+err);
err = pSChanX->pStats[i].stdDev;
pprErrorBar(pArea, oldX-err, oldY, oldX+err, oldY);
}
}
pSlave = pSlave->pNext;
if (pSlave == pSlaveX)
pSlave = pSlave->pNext;
}
}
/*+/internal******************************************************************
* NAME sydPlot_XYarray - plot array vs array
*
* DESCRIPTION
*
* RETURNS
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
static void
sydPlot_XYarray(pArea, pSChanX, pSChan, sub)
PPR_AREA *pArea;
SYD_CHAN *pSChan;
SYD_CHAN *pSChanX;
int sub;
{
int nEl, nElX, nElY, i;
char *pSrcX, *pSrcY;
double newX, newY, oldX, oldY;
int nByteX, nByteY;
nEl = nElX = pSChanX->elCount;
nElY = pSChan->elCount;
if (nElX > nElY)
nEl = nElY;
nByteX = dbr_value_size[pSChanX->dbrType];
pSrcX = (char *)pSChanX->pData + sub * nByteX * nElX;
nByteY = dbr_value_size[pSChan->dbrType];
pSrcY = (char *)pSChan->pData + sub * nByteY * nElY;
for (i=0; i<nEl; i++) {
if (dbr_type_is_FLOAT(pSChanX->dbrType))
newX = *(float *)pSrcX;
else if (dbr_type_is_SHORT(pSChanX->dbrType))
newX = *(short *)pSrcX;
else if (dbr_type_is_DOUBLE(pSChanX->dbrType))
newX = *(double *)pSrcX;
else if (dbr_type_is_LONG(pSChanX->dbrType))
newX = *(long *)pSrcX;
else if (dbr_type_is_CHAR(pSChanX->dbrType))
newX = *(unsigned char *)pSrcX;
else if (dbr_type_is_ENUM(pSChanX->dbrType))
newX = *(short *)pSrcX;
if (dbr_type_is_FLOAT(pSChan->dbrType))
newY = *(float *)pSrcY;
else if (dbr_type_is_SHORT(pSChan->dbrType))
newY = *(short *)pSrcY;
else if (dbr_type_is_DOUBLE(pSChan->dbrType))
newY = *(double *)pSrcY;
else if (dbr_type_is_LONG(pSChan->dbrType))
newY = *(long *)pSrcY;
else if (dbr_type_is_CHAR(pSChan->dbrType))
newY = *(unsigned char *)pSrcY;
else if (dbr_type_is_ENUM(pSChan->dbrType))
newY = *(short *)pSrcY;
if (i > 0)
pprLineSegD(pArea, oldX, oldY, newX, newY);
oldX = newX;
oldY = newY;
pSrcX += nByteX;
pSrcY += nByteY;
}
}
/*+/subr**********************************************************************
* NAME sydPlot_XYYPlot - handle X vs multiple Y plots
*
* DESCRIPTION
* the first channel in the plot spec is used for the X axis
*
* alarm state of the "X" channel is not displayed
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_XYYPlot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_SPEC *pSspec;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
sydPlot_XYYGrid(pMstr);
if (pSspec->useStats == 0) {
sydPlot_XYSamples(pMstr,
pSspec->restrictFirstData, pSspec->restrictLastData, 0);
}
else
sydPlot_XYStats(pMstr, 0, pSspec->statCount-1);
}
/*+/subr**********************************************************************
* NAME sydPlot_XYYGrid - draw a grid for an X vs multiple Y plot
*
* DESCRIPTION
* the first channel in the plot spec is used for the X axis
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_XYYGrid(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
SYD_PL_SLAVE *pSlaveX; /* pointer to X axis slave struct */
double xlo, ylo, xhi, yhi, yPart;
PPR_AREA *pArea;
double xmin, xmax, ymin, ymax;
double charHt, charHtX, charHtTY, charHtTX;
SYD_CHAN *pSChan;
SYD_CHAN *pSChanX;
int offsetAnnotY=0;
int drawAxis=0;
int nGrids;
char **ppAnnotVal, *pAnnotVal[20], annotVal[20][28];
char **ppAnnotXVal, *pAnnotXVal[20], annotXVal[20][28];
pWin = pMstr->pWin;
pSlaveX = pMstr->pHead;
while (1) {
if (pSlaveX->xChan)
break;
pSlaveX = pSlaveX->pNext;
if (pSlaveX == NULL) {
pSlaveX = pMstr->pHead;
break;
}
}
if (pSlaveX == pMstr->pHead)
pSlave = pSlaveX->pNext;
else
pSlave = pMstr->pHead;
pSChanX = pSlaveX->pSChan;
nGrids = 1;
sydPlot_setup(pMstr, nGrids, &xlo, &ylo, &xhi, &yhi, &yPart,
&charHt, &charHtX, &charHtTY, &charHtTX);
xlo += 6. * charHtX * (double)(pMstr->nSlaves - 1);
pSlaveX->pArea = NULL;
xmin = pSlaveX->originVal;
xmax = pSlaveX->extentVal;
if (pSlaveX->ppAnnot == NULL) {
sydAnnotVal(pSlaveX, pAnnotXVal, annotXVal);
ppAnnotXVal = pAnnotXVal;
}
else
ppAnnotXVal = pSlaveX->ppAnnot;
pSlaveX->yFracBot = pSlaveX->yFracTop = 0.;
while (pSlave != NULL) {
/*-----------------------------------------------------------------------------
* for the first Y channel:
* initialize a plot area; its fractional size depends on how many
* "sub-plots" there are
* plot a perimeter with grid lines
* set for solid line
* for the other channels:
* initialize an overlapping plot area
* set a dashed line pattern (unless this is a mark or point plot)
* draw a "floating" Y axis
*----------------------------------------------------------------------------*/
pSChan = pSlave->pSChan;
ymin = pSlave->originVal;
ymax = pSlave->extentVal;
if (pSlave->ppAnnot == NULL) {
sydAnnotVal(pSlave, pAnnotVal, annotVal);
ppAnnotVal = pAnnotVal;
}
else
ppAnnotVal = pSlave->ppAnnot;
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pArea = pSlave->pArea = pprAreaOpen(pWin, xlo, ylo+2.*charHt, xhi, yhi,
xmin, ymin, xmax, ymax, pSlaveX->nInt, pSlave->nInt, charHt);
assertAlways(pArea != NULL);
pSlave->xFracLeft = xlo;
pSlave->xFracRight = xhi;
pSlave->yFracBot = ylo;
pSlave->yFracTop = yhi;
if (pSlave->fg != 0 && pMstr->noColor == 0)
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_FG, 0, &pSlave->fg);
else if (pMstr->linePlot) {
/* set keynum if color is being used or if this is auxiliary axis */
if (drawAxis || pMstr->noColor == 0)
pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, pSlave->lineKey, NULL);
}
else if (pMstr->noColor == 0)
pprAreaSetAttr(pArea, PPR_ATTR_COLORNUM, pSlave->lineKey, NULL);
if (drawAxis == 0) {
pprGrid(pArea);
pArea->charHt = charHtTY * pWin->height;
pprAnnotX_wc(pArea, 0, pSlaveX->originVal, pSlaveX->extentVal,
pSlaveX->nInt, 0, pSlaveX->pSChan->label, ppAnnotXVal, 0.);
pArea->charHt = charHt * pWin->height;
}
pprAnnotY(pArea, offsetAnnotY, pSlave->originVal, pSlave->extentVal,
pSlave->nInt, drawAxis, pSlave->pSChan->label, ppAnnotVal, 90.);
if (pMstr->markPlot)
pprAnnotYMark(pArea, offsetAnnotY, pSlave->markNum);
offsetAnnotY += 6;
drawAxis = 1; /* draw an "auxiliary" axis next time */
pSlave->annotXFL = xlo - offsetAnnotY * charHtX;
pSlave->annotXFR = pSlave->annotXFL + 6. * charHtX;
pSlave->annotYFB = ylo;
pSlave->annotYFT = yhi;
pSlave = pSlave->pNext;
if (pSlave == pSlaveX)
pSlave = pSlave->pNext;
}
return;
}
/*+/subr**********************************************************************
* NAME sydPlot_YPlot - handle Y plots
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_YPlot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_SPEC *pSspec;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
sydPlot_YGrid(pMstr);
if (pSspec->useStats == 0) {
sydPlot_YSamples(pMstr,
pSspec->restrictFirstData, pSspec->restrictLastData, 0);
}
else
sydPlot_YStats(pMstr, 0, pSspec->statCount-1);
}
/*+/subr**********************************************************************
* NAME sydPlot_YGrid - draw a grid for a Y plot
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_YGrid(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
double xlo, ylo, xhi, yhi;
double yPart;
PPR_AREA *pArea;
double xmin, xmax, ymin, ymax;
int xNint;
double charHt, charHtX, charHtTY, charHtTX;
SYD_CHAN *pSChan;
int thick=3;
int nGrids;
char **ppAnnotVal, *pAnnotVal[20], annotVal[20][28];
pWin = pMstr->pWin;
nGrids = pMstr->nSlaves;
sydPlot_setup(pMstr, nGrids, &xlo, &ylo, &xhi, &yhi, &yPart,
&charHt, &charHtX, &charHtTY, &charHtTX);
xmin = xmax = 0.;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
if (pSlave->pSChan->elCount > xmax)
xmax = pSlave->pSChan->elCount;
pSlave = pSlave->pNext;
}
xNint = 1;
if (xmax == 1.)
xmax = pMstr->pSspec->reqCount - 1;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
/*-----------------------------------------------------------------------------
* for each channel, initialize a plot area.
*
* plot a perimeter with grid lines
*----------------------------------------------------------------------------*/
pSChan = pSlave->pSChan;
ymin = pSlave->originVal;
ymax = pSlave->extentVal;
charHt = PprDfltCharHt(ylo, yhi);
charHtX = pprYFracToXFrac(pWin, charHt);
if (pSlave->ppAnnot == NULL) {
sydAnnotVal(pSlave, pAnnotVal, annotVal);
ppAnnotVal = pAnnotVal;
}
else
ppAnnotVal = pSlave->ppAnnot;
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pArea = pSlave->pArea = pprAreaOpen(pWin,
xlo+12.*charHtX, ylo+2.*charHt, xhi, yhi,
xmin, ymin, xmax, ymax, xNint, pSlave->nInt, charHt);
assertAlways(pArea != NULL);
pSlave->xFracLeft = xlo + 12. * charHtX;
pSlave->xFracRight = xhi;
pSlave->yFracBot = ylo + 6. * charHt;
pSlave->yFracTop = yhi;
pSlave->annotXFL = xlo;
pSlave->annotXFR = pSlave->xFracLeft;
pSlave->annotYFB = pSlave->yFracBot;
pSlave->annotYFT = yhi;
if (pSlave->fg != 0 && pMstr->noColor == 0)
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_FG, 0, &pSlave->fg);
else if (pMstr->linePlot) {
if (dbr_type_is_ENUM(pSChan->dbrType))
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
}
pprGrid(pArea);
pprAnnotY(pArea, 0, ymin, ymax, pSlave->nInt, 0,
pSlave->pSChan->label, ppAnnotVal, 0.);
if (pSlave == pMstr->pHead) {
pArea->charHt = charHtTY * pWin->height;
pprAnnotX(pArea, 0, xmin, xmax, xNint, 0, "bin number", NULL, 0.);
pArea->charHt = charHt * pWin->height;
}
ylo += yPart;
yhi += yPart;
pSlave = pSlave->pNext;
}
}
/*+/subr**********************************************************************
* NAME sydPlot_YSamples - plot one or more samples for a Y plot
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_YSamples(pMstr, begin, end, incr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin sample to plot */
int end; /* I number of end sample to plot */
int incr; /* I 0,1 for batch,incremental plotting */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
PPR_AREA *pArea;
int i, j;
SYD_SPEC *pSspec;
SYD_CHAN *pSChan;
double oldX, oldY, newX, newY;
int skip;
int showStat; /* 1 to show status code on plot */
int pointPlot; /* 1 for point plot */
int linePlot; /* 1 to connect points with lines */
int markPlot; /* 1 to draw marks at points */
int markNum; /* number of mark to use */
int nEl; /* number of array elements */
int first; /* ==1 if this is the first sample */
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
pWin = pMstr->pWin;
linePlot = pMstr->linePlot;
pointPlot = pMstr->pointPlot;
markPlot = pMstr->markPlot;
showStat = pMstr->showStat;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
pArea = pSlave->pArea;
pSChan = pSlave->pSChan;
if (pSChan->pData == NULL || pSChan->dataChan == 0)
; /* no action if never connected or not data channel */
else {
markNum = pSlave->markNum;
nEl = pSChan->elCount;
i = begin;
if (!incr)
first = 1;
else {
first = pSlave->first;
oldX = pSlave->oldX;
oldY = pSlave->oldY;
skip = pSlave->skip;
}
while (i >= 0) {
int restart, restart1;
restart = restart1 = 0;
if (pSChan->pFlags[i].restart) {
if (!pSChan->pFlags[i].snapstart)
restart = 1;
else if (!pSChan->pFlags[i].snapend)
restart = 1;
}
if (i != end && pSChan->pFlags[i+1].restart) {
if (!pSChan->pFlags[i+1].snapstart)
restart1 = 1;
else if (!pSChan->pFlags[i+1].snapend)
restart1 = 1;
}
if (pSChan->pFlags[i].missing)
skip = 1;
else if (first || skip || restart) {
if (nEl == 1) {
oldX = i;
FetchIthValInto(pSChan, oldY)
if (markPlot)
pprMarkD(pArea, oldX, oldY, markNum);
if (showStat && pSChan->pDataCodeR[i] != ' ') {
pprChar(pArea, oldX, oldY,
pSChan->pDataCodeR[i], 0., 0.);
}
else if (pointPlot)
pprPointD(pArea, oldX, oldY);
}
else {
sydPlot_Yarray(pArea, pSChan, i);
}
skip = 0;
}
else if (pSChan->pFlags[i].filled && restart1 == 0 && i != end)
; /* no action */
else {
if (nEl == 1) {
newX = i;
if (linePlot && dbr_type_is_ENUM(pSChan->dbrType)) {
pprLineSegD(pArea, oldX, oldY, newX, oldY);
oldX = newX;
}
FetchIthValInto(pSChan, newY)
if (linePlot)
pprLineSegD(pArea, oldX, oldY, newX, newY);
if (markPlot)
pprMarkD(pArea, newX, newY, markNum);
if (showStat && pSChan->pDataCodeR[i] != ' ') {
pprChar(pArea, newX, newY,
pSChan->pDataCodeR[i], 0., 0.);
}
else if (pointPlot)
pprPointD(pArea, newX, newY);
oldX = newX;
oldY = newY;
}
else {
sydPlot_Yarray(pArea, pSChan, i);
}
}
if (i == end)
i = -1;
else if (++i >= pSspec->dataDim)
i = 0;
first = 0;
}
}
pSlave->first = first;
pSlave->oldX = oldX;
pSlave->oldY = oldY;
pSlave->skip = skip;
pSlave = pSlave->pNext;
}
}
/*+/subr**********************************************************************
* NAME sydPlot_YStats - plot one or more snapshots for a Y plot
*
* DESCRIPTION
*
* RETURNS
* void
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
*-*/
void
sydPlot_YStats(pMstr, begin, end)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
int begin; /* I number of begin snapshots to plot */
int end; /* I number of end snapshots to plot */
{
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
PPR_AREA *pArea;
int i;
SYD_SPEC *pSspec;
SYD_CHAN *pSChan;
double oldX, oldY, newX, newY, err;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
for (pSlave=pMstr->pHead; pSlave!=NULL; pSlave=pSlave->pNext) {
pArea = pSlave->pArea; pSChan = pSlave->pSChan;
for (i=begin; i<=end; i++) {
if (i == begin) {
oldX = i; oldY = pSChan->pStats[i].mean;
}
else {
newX = i; newY = pSChan->pStats[i].mean;
if (pMstr->linePlot)
pprLineSegD(pArea, oldX, oldY, newX, newY);
oldX = newX; oldY = newY;
}
if (pMstr->markPlot)
pprMarkD(pArea, oldX, oldY, pSlave->markNum);
else
pprPointD(pArea, oldX, oldY);
if (pMstr->errBar == SYD_PLATTR_STDDEV) {
err = pSChan->pStats[i].stdDev;
pprErrorBar(pArea, oldX, oldY-err, oldX, oldY+err);
}
}
}
}
/*+/internal******************************************************************
* NAME sydPlot_Yarray - plot array vs array
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
static void
sydPlot_Yarray(pArea, pSChan, sub)
PPR_AREA *pArea;
SYD_CHAN *pSChan;
int sub;
{
int nEl, nElY, i;
char *pSrcY;
double newX, newY, oldX, oldY;
int nByteY;
nEl = nElY = pSChan->elCount;
nByteY = dbr_value_size[pSChan->dbrType];
pSrcY = (char *)pSChan->pData + sub * nByteY * nElY;
if (dbr_type_is_FLOAT(pSChan->dbrType))
pprWaveF(pArea, 1., (float *)pSrcY, nEl);
else if (dbr_type_is_SHORT(pSChan->dbrType))
pprWaveS(pArea, 1, (short *)pSrcY, nEl);
else if (dbr_type_is_DOUBLE(pSChan->dbrType))
pprWaveD(pArea, 1., (double *)pSrcY, nEl);
else if (dbr_type_is_LONG(pSChan->dbrType))
pprWaveL(pArea, 1, (long *)pSrcY, nEl);
else if (dbr_type_is_ENUM(pSChan->dbrType))
pprWaveS(pArea, 1, (short *)pSrcY, nEl);
else if (dbr_type_is_CHAR(pSChan->dbrType)) {
for (i=0; i<nEl; i++) {
newX = i;
newY = *(unsigned char *)pSrcY;
if (i > 0)
pprLineSegD(pArea, oldX, oldY, newX, newY);
oldX = newX;
oldY = newY;
pSrcY += nByteY;
}
}
}
/*+/subr**********************************************************************
* NAME sydPlot_YYPlot - handle multiple Y plots
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_YYPlot(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
SYD_SPEC *pSspec;
assert(pMstr != NULL);
pSspec = pMstr->pSspec;
assert(pSspec != NULL);
sydPlot_YYGrid(pMstr);
if (pSspec->useStats == 0) {
sydPlot_YSamples(pMstr,
pSspec->restrictFirstData, pSspec->restrictLastData, 0);
}
else
sydPlot_YStats(pMstr, 0, pSspec->statCount-1);
}
/*+/subr**********************************************************************
* NAME sydPlot_YYGrid - draw a grid for a multiple Y plot
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* NOTES
* 1. This routine isn't intended to be called directly.
*
* EXAMPLE
*
*-*/
void
sydPlot_YYGrid(pMstr)
SYD_PL_MSTR *pMstr; /* I pointer to master plot structure */
{
PPR_WIN *pWin; /* pointer to plot window structure */
SYD_PL_SLAVE *pSlave; /* pointer to individual slave struct */
double xlo, ylo, xhi, yhi, yPart;
PPR_AREA *pArea;
double xmin, xmax, ymin, ymax;
int xNint;
double charHt, charHtX, charHtTY, charHtTX;
SYD_CHAN *pSChan;
int offsetAnnotY=0;
int drawAxis=0;
int thick=3;
int nGrids;
pWin = pMstr->pWin;
nGrids = 1;
sydPlot_setup(pMstr, nGrids, &xlo, &ylo, &xhi, &yhi, &yPart,
&charHt, &charHtX, &charHtTY, &charHtTX);
xlo += 6. * charHtX * (double)pMstr->nSlaves;
xmin = xmax = 0.;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
if (pSlave->pSChan->elCount > xmax)
xmax = pSlave->pSChan->elCount;
pSlave = pSlave->pNext;
}
xNint = 1;
if (xmax == 1.)
xmax = pMstr->pSspec->reqCount - 1;
pSlave = pMstr->pHead;
while (pSlave != NULL) {
/*-----------------------------------------------------------------------------
* for the first channel:
* initialize a plot area; its fractional size depends on how many
* "sub-plots" there are
* plot a perimeter with grid lines
* for the other channels:
* initialize an overlapping plot area
* set a dashed line pattern (unless this is a mark or point plot)
* draw a "floating" Y axis
*----------------------------------------------------------------------------*/
pSChan = pSlave->pSChan;
ymin = pSlave->originVal;
ymax = pSlave->extentVal;
if (pSlave->pArea != NULL)
pprAreaClose(pSlave->pArea);
pArea = pSlave->pArea = pprAreaOpen(pWin, xlo, ylo+2.*charHt, xhi, yhi,
xmin, ymin, xmax, ymax, xNint, pSlave->nInt, charHt);
assertAlways(pArea != NULL);
pSlave->xFracLeft = xlo;
pSlave->xFracRight = xhi;
pSlave->yFracBot = ylo;
pSlave->yFracTop = yhi;
if (pSlave->fg != 0 && pMstr->noColor == 0)
pprAreaSetAttr(pSlave->pArea, PPR_ATTR_FG, 0, &pSlave->fg);
else if (pMstr->linePlot) {
if (dbr_type_is_ENUM(pSChan->dbrType))
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
if (pSlave->lineKey > 1 || pMstr->noColor == 0)
pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, pSlave->lineKey, NULL);
}
else if (pMstr->noColor == 0)
pprAreaSetAttr(pArea, PPR_ATTR_COLORNUM, pSlave->lineKey, NULL);
if (drawAxis == 0) {
pprGrid(pArea);
pArea->charHt = charHtTY * pWin->height;
pprAnnotX_wc(pArea, 0, xmin, xmax, xNint, 0, "bin number", NULL,0.);
pArea->charHt = charHt * pWin->height;
}
pprAnnotY(pArea, offsetAnnotY, pSlave->originVal, pSlave->extentVal,
pSlave->nInt, drawAxis,
pSlave->pSChan->label, pSlave->ppAnnot, 90.);
if (pMstr->markPlot)
pprAnnotYMark(pArea, offsetAnnotY, pSlave->markNum);
offsetAnnotY += 6;
drawAxis = 1; /* draw an "auxiliary" axis next time */
pSlave->annotXFL = xlo - offsetAnnotY * charHtX;
pSlave->annotXFR = pSlave->annotXFL + 6. * charHtX;
pSlave->annotYFB = ylo;
pSlave->annotYFT = yhi;
pSlave = pSlave->pNext;
}
}