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

6061 lines
196 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-92, 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 07-20-91 rac installed in SCCS; finalized "how to access"
* .03 08-09-91 rac fix a problem with pprMark when clipping
* .04 09-04-91 rac change pprAreaErase to pprRegionErase; add
* pprAreaErase; update documentation; add pprPixXToXFrac
* and pprPixYToYFrac; add various Line and Point erase
* functions
* .05 05-15-92 rac add pprErrorBar; add line caps as special marks for
* pprMark
* .06 09-07-92 rac handle sub-intervals; change pixel coordinates to
* short integers
* .07 10-09-92 rac do some optimizing to reduce CPU time and X traffic;
* provide support for strip charts; add a special
* waveform plotting call
* .08 11-13-92 rac handle annotations a little better; replace pprCvt
* with a copy of cvtXxx
* .09 05-04-94 pg HPUX port changes.
*
* make options
* -DvxWorks makes a version for VxWorks
* -DSUNVIEW to use SunView window system
* -DXWINDOWS to use X window system
* -DNDEBUG don't compile assert() checking
* -DPPR_TEST compile the embedded main program for testing
*
* UW is an "edit time" switch which sets the test program
* to use pprWinOpenUW and play like a user program which
* does all its own windowing operations.
*/
/*+/mod***********************************************************************
* TITLE pprSubr.c - portable plotting routines
*
* DESCRIPTION
* These routines support simple 2-D plotting in a "window". The
* window can be either an actual display window, a PostScript
* printer page, or an EPS file for Encapsulated PostScript.
*
* QUICK REFERENCE
* PPR_AREA *pArea; pointer to a plot area
* PPR_WIN *pWin; pointer to a plot "window"
*
* void pprAnnotX( pArea, offset, dataL, dataR, nDiv,
* drawLine, xLabel, xAnnot, angle )
* void pprAnnotY( pArea, offset, dataB, dataT, nDiv,
* drawLine, yLabel, yAnnot, angle )
* void pprAnnotYMark( pArea, offset, markNum )
* void pprAreaClose( pArea )
* void pprAreaErase( pArea xDblLft, yDblBot, xDblRt, yDblTop)
* PPR_AREA *pprAreaOpen( pWin, fracL, fracB, fracR, fracT,
* dataL, dataB, dataR, dataT,
* nXint, nYint, charHt )
* PPR_AREA *pprAreaOpenDflt( pWin, fracL, fracB, fracR, fracT,
* dataL, dataB, dataR, dataT )
* void pprAreaRescale( pArea, dataL, dataB, dataR, dataT )
* long pprAreaSetAttr( pArea, code, attrVal, pAttr )
* code: PPR_ATTR_{CLIP,COLORNUM,BG,FG,KEYNUM,LINE_THICK,NOCLIP,
* PATT_ARRAY,STRIP}
* void pprAutoEnds( dbl1, dbl2, >pNewDbl1, >pNewDbl2 )
* void pprAutoInterval( dbl1, dbl2, >pNint )
* void pprAutoRangeD( dblAry, nPts, >minDbl, >maxDbl )
* void pprAutoRangeF( fltAry, nPts, >minDbl, >maxDbl )
* void pprAutoRangeL( lngAry, nPts, >minDbl, >maxDbl )
* void pprAutoRangeS( shtAry, nPts, >minDbl, >maxDbl )
* void pprChar( pArea, xDbl, yDbl, char, charHt, angle )
* double pprCos_deg( angle )
* void pprErrorBar( pArea, xDbl1, yDbl1, xDbl2, yDbl2 )
* void pprCvtDblToTxt( >text, width, dblVal, nSigDigits )
* void pprGrid( pArea )
* void pprGridErase( pArea )
* void pprGridLabel( pArea, xLabel, xAnnot, yLabel, yAnnot, angle)
* void pprLineD( pArea, xDblAry, yDblAry, nPts )
* void pprLineF( pArea, xFltAry, yFltAry, nPts )
* void pprLineL( pArea, xLngAry, yLngAry, nPts )
* void pprLineS( pArea, xShtAry, yShtAry, nPts )
* void pprLineEraseD( pArea, xDblAry, yDblAry, nPts )
* void pprLineEraseF( pArea, xFltAry, yFltAry, nPts )
* void pprLineEraseL( pArea, xLngAry, yLngAry, nPts )
* void pprLineEraseS( pArea, xShtAry, yShtAry, nPts )
* void pprLineSegD( pArea, xDbl1, yDbl1, xDbl2, yDbl2 )
* void pprLineSegL( pArea, xLng1, yLng1, xLng2, yLng2 )
* void pprLineSegEraseD(pArea, xDbl1, yDbl1, xDbl2, yDbl2 )
* void pprLineSegEraseL(pArea, xLng1, yLng1, xLng2, yLng2 )
* void pprMarkD( pArea, xDbl1, yDbl1, markNum )
* void pprMarkL( pArea, xLng1, yLng1, markNum )
* void pprMarkEraseD( pArea, xDbl1, yDbl1, markNum )
* void pprMarkEraseL( pArea, xLng1, yLng1, markNum )
* void pprMoveD( pArea, xDbl1, yDbl1, penDown )
* void pprPerim( pArea )
* void pprPerimErase( pArea )
* void pprPerimLabel( pArea, xLabel, xAnnot, yLabel, yAnnot, angle)
* double pprPixXToXFrac( pWin, xPixel )
* double pprPixYToYFrac( pWin, yPixel )
* void pprPointD( pArea, xDbl1, yDbl1 )
* void pprPointL( pArea, xLng1, yLng1 )
* void pprPointEraseD( pArea, xDbl1, yDbl1 )
* void pprPointEraseL( pArea, xLng1, yLng1 )
* void pprRegionErase( pArea fracL, fracB, fracR, fracT )
* double pprSin_deg( angle )
* void pprText( pArea, xDbl, yDbl, text, just, charHt, angle)
* just: PPR_TXT_{CEN,RJ,LJ}
* void pprTextErase( pArea, xDbl, yDbl, text, just, charHt, angle)
* void pprWaveD( pArea, xDblIncr, yDblAry, nPts )
* void pprWaveF( pArea, xFltIncr, yFltAry, nPts )
* void pprWaveL( pArea, xLngIncr, yLngAry, nPts )
* void pprWaveS( pArea, xShtIncr, yShtAry, nPts )
* void pprWaveEraseD( pArea, xDblIncr, yDblAry, nPts )
* void pprWaveEraseF( pArea, xFltIncr, yFltAry, nPts )
* void pprWaveEraseL( pArea, xLngIncr, yLngAry, nPts )
* void pprWaveEraseS( pArea, xShtIncr, yShtAry, nPts )
* void pprWinClose( pWin )
* void pprWinErase( pWin )
* void pprWinInfo( pWin, >pXpos, >pYpos, >pXwid, >pYht )
* int pprWinIsMono( pWin )
* long pprWinLoop( pWin, drawFn, pDrawArg )
* void drawFn(pWin, pDrawArg)
* PPR_WIN *pprWinOpen( winType, dispName, winTitle, xPos, yPos, xWid,yHt)
* winType: PPR_WIN_{SCREEN,POSTSCRIPT,EPS}
* PPR_WIN *pprWinOpenUW( pFrame, pCanvas, NULL, NULL )
* PPR_WIN *pprWinOpenUW( ppDisp, pWindow, pGC, NULL )
* void pprWinReplot( pWin, drawFn, pDrawArg )
* double pprYFracToXFrac( pWin, yFrac )
*
* DESCRIPTION (continued)
* Plotting is done within "plot areas" which are defined within
* the window. Plot areas can be as large as the window, and they
* can overlap, if desired. Clipping service is optional, since
* plot areas are often calibrated for the "normal" range of data,
* and it is useful to see what's happening if the data are outside
* the normal range.
*
* One non-intuitive aspect of the term "plot area" is that the
* usual case ALWAYS plots outside the plot area. Generally, this
* happens when annotations and labels are added to a grid. The
* plot area itself only specified where the edges of the grid were
* to be drawn. Because of this, determining the size and placement
* of a plot area must take into account the necessary margins for
* text. (pprAreaOpenDflt automatically takes care of margins.)
*
* Most plotting is done using "data coordinates", which are the
* actual data values. In some cases, coordinates or distances are
* specified in terms of a fraction of the window height (see, for
* example, pprAreaOpen or pprText).
*
* Also provided in this package are some routines for interacting
* with the "window". In many cases, this means that a plotting
* program can totally avoid any knowledge of, or dependence on, a
* particular windowing environment. This makes easily available
* the capability for producing hard copies of plots on a PostScript
* printer.
*
* Many routines in this package require that values be
* represented with type 'double'. In some cases, however, other
* data types are directly supported, so that the caller doesn't
* need to alter the way data are stored.
*
* BUGS
* o Only linear axes are presently supported
* o The SunView version of this package won't run properly with
* programs which use the SunOs LightWeight Process library.
* o The SunView version of this package doesn't handle color.
*
* EXAMPLE
* The following program plots the first 80 points of a parabola. The
* size and position of the plot window can be freely changed; the
* window can be covered and exposed, iconified and de-iconified, etc.
* When a `click right' is done in the plot window, the window is
* closed. A PostScript file named "testPS" is produced; the size of
* the plot in this file is about the same as it was when the plot
* window was closed.
*
* The program is compiled and linked for X11 with the following
* command. (If making to run on sun3, use lib.sun3 in the command.)
*
* % cc plotTest.c -I~epics/epicsH -I$(OPENWINHOME)/include \
* -L~epics/share/bin/lib.sun4 -L$(OPENWINHOME)/lib \
* -lppr -lX -lm
*
* #include <stdio.h>
* #include <pprPlotDefs.h>
*
* #define NPTS 80
* ----------------------------------------------------------------------------
* define a structure for holding the data. This is needed because the
* replot routine (which does the actual plotting) is only given a pointer
* to the information it needs.
* ----------------------------------------------------------------------------
* typedef struct {
* int nPts;
* float x[NPTS];
* float y[NPTS];
* double xMin;
* double xMax;
* double yMin;
* double yMax;
* } MY_DATA;
*
* void replot();
*
* main()
* {
* int i;
* int x=0,y=0,width=0,height=0;
* PPR_WIN *pWin;
* MY_DATA myData;
* long stat;
*
* ----------------------------------------------------------------------------
* generate the data in the structure. Once it's generated, figure out
* the range of values and put the range into the structure using
* pprAutoRangeF. This specific routine was chosen because the data
* is in "float" arrays. Different forms of data would result in choosing
* a different routine.
*
* The routine pprAutoEnds is available to "round" the endpoints of the
* axes to "nicer" values. Depending on the application, it will be
* attractive to use this following the pprAutoRange call.
* ----------------------------------------------------------------------------
* myData.nPts = NPTS;
* for (i=0; i<NPTS; i++) {
* myData.x[i] = (float)i;
* myData.y[i] = (float)(i*i);
* }
* pprAutoRangeF(myData.x, NPTS, &myData.xMin, &myData.xMax);
* pprAutoRangeF(myData.y, NPTS, &myData.yMin, &myData.yMax);
*
* ----------------------------------------------------------------------------
* Now, do the actual plotting, in a roundabout way. First, an actual
* window on the screen is created with the pprWinOpen call. The
* size and position of the window are determined by the values
* (initialized above) of x, y, width, and height.
*
* After opening the window, pprWinLoop is called to accomplish the
* actual plotting. This routine calls the replot() routine whenever it
* is necessary to replot the data. This will happen immediately after
* pprWinLoop is called, and also any time the plot window is resized
* or re-exposed after being fully or partially covered. pprWinLoop
* doesn't return until a "click right" over the plot (or a window menu
* quit) is done.
*
* After pprWinLoop returns, pprWinInfo is called to get the most
* recent size and position of the window. If this program were going
* to put up another plot, this information would allow being polite
* and having the window for the new plot cover the same part of the
* screen. In this example program, the only use being made of the
* information is to control the size of the PostScript plot.
*
* Finally, the plot window is closed using pprWinClose. It's important
* not to skip this step.
* ----------------------------------------------------------------------------
* pWin = pprWinOpen(PPR_WIN_SCREEN, NULL, "test title",
* x, y, width, height);
* if (pWin == NULL) abort();
* stat = pprWinLoop(pWin, replot, &myData);
* if (stat != 0) abort();
* pprWinInfo(pWin, &x, &y, &width, &height);
* pprWinClose(pWin);
*
* ----------------------------------------------------------------------------
* Produce a file containing a PostScript version of the plot. Because
* of the information obtained by pprWinInfo, this will be about the
* same size as the plot last appeared on the screen.
* ----------------------------------------------------------------------------
* pWin = pprWinOpen(PPR_WIN_POSTSCRIPT, "testPS", NULL, x,y,width,height);
* if (pWin == NULL) abort();
* stat = pprWinLoop(pWin, replot, &myData);
* if (stat != 0) abort();
* pprWinClose(pWin);
*
* return;
* }
*
* ----------------------------------------------------------------------------
* D R A W F U N C T I O N
* ----------------------------------------------------------------------------
*
* void replot(pWin, pMyData)
* PPR_WIN *pWin;
* MY_DATA *pMyData;
* {
* double xlo=0., ylo=0., xhi=.95, yhi=.95;
* double charHt, charHtX;
* PPR_AREA *pArea;
* int i;
*
* ----------------------------------------------------------------------------
* First, figure out how big to make the characters for axis labels and
* annotations. The character size will be used to specify the left and
* bottom margins for the actual area used for plotting. (See pprText
* for a discussion of PprDfltCharHt.)
*
* The pprAreaOpen call establishes a plot area that will be used for
* the actual plotting. A left margin of 12 lines and a bottom margin
* of 6 lines are specified. The top margin is .05 of the window height,
* and the right margin is .05 of the window width.
*
* A perimeter with tick marks is drawn, and annotations and labels are
* applied, with the pprPerimLabel call.
*
* The actual plotting of data is done with pprLineF. This specific
* routine was chosen because the data is in "float" arrays. Different
* forms of data would result in choosing a different routine.
*
* Finally, the plot area is closed with pprAreaClose. It's important
* not to skip this step.
* ----------------------------------------------------------------------------
* charHt = PprDfltCharHt(ylo, yhi);
* charHtX = pprYFracToXFrac(pWin, charHt);
* pArea = pprAreaOpen(pWin, xlo+12.*charHtX, ylo+6.*charHt, xhi, yhi,
* pMyData->xMin, pMyData->yMin, pMyData->xMax, pMyData->yMax,
* 5, 5, charHt);
* pprPerimLabel(pArea, "x label", NULL, "y label", NULL, 0.);
*
* pprLineF(pArea, pMyData->x, pMyData->y, pMyData->nPts);
*
* pprAreaClose(pArea);
*
* return;
* }
*
*-***************************************************************************/
#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
#define PPR_PRIVATE
#include <pprPlotDefs.h>
void pprAnnotX_gen();
void pprAnnotY_gen();
void pprArcD_gen();
void pprLineSegPixD_ac(), pprLineSegPixL_ac();
void pprLineSegPixD_wc(), pprLineSegPixL_wc();
void pprLineSegDashD_wc();
void pprText_gen();
/*-----------------------------------------------------------------------------
* assert macros, so that this package can be portable without having to link
* to genLib.a
*----------------------------------------------------------------------------*/
#ifndef NDEBUG
# define PprAssert(expr) ((void)((expr) || pprAssertFail(__FILE__, __LINE__)))
#else
# define PprAssert(expr) ((void)0)
#endif
#define PprAssertAlways(expr) \
((void)((expr) || pprAssertFail(__FILE__, __LINE__)))
pprAssertFail(fileName, lineNum)
char *fileName;
int lineNum;
{
(void)fprintf(stderr, "pprAssertFail: in file %s line %d\n",
fileName, lineNum);
#ifdef vxWorks
if (kill(taskIdSelf(), SIGUSR1) == ERROR) {
int *j;
j = (int *)(-1);
j = (int *)(*j);
}
exit(1);
#else
abort();
#endif
}
/*-----------------------------------------------------------------------------
* doubly linked list macros
*----------------------------------------------------------------------------*/
#define DoubleListAppend(pItem,pHead,pTail) \
{\
pItem->pNext = NULL;\
pItem->pPrev = pTail;\
if (pTail != NULL)\
pTail->pNext = pItem; /* link previous tail to here */\
pTail = pItem;\
if (pHead == NULL)\
pHead = pItem; /* link to head if first item */\
}
#define DoubleListRemove(pItem,pHead,pTail) \
{\
if (pItem->pPrev != NULL)\
(pItem->pPrev)->pNext = pItem->pNext; /* link prev to next */\
else\
pHead = pItem->pNext; /* link list head to next */\
if (pItem->pNext != NULL)\
(pItem->pNext)->pPrev = pItem->pPrev; /* link next to prev */\
else\
pTail = pItem->pPrev; /* link list tail to prev */\
pItem->pNext = NULL;\
pItem->pPrev = NULL;\
}
/*+/internal******************************************************************
* NAME pprTest - test routine for plot library
*
*-*/
#ifdef PPR_TEST
#ifndef vxWorks
main() { pprTest(); }
#endif
#define NPTS 80
typedef struct {
double xMin;
double xMax;
double yMin;
double yMax;
int nPts;
float x[NPTS];
float y[NPTS];
} MY_DATA;
void replot();
#ifdef SUNVIEW
struct pprWinWin {
Frame frame;
PPR_WIN *pWin1;
PPR_WIN *pWin2;
void *pMyData;
};
#endif
#define UW
#undef UW
pprTest()
{
int i;
int x=0,y=0,width=0,height=0;
PPR_WIN *pWin, *pWin2;
MY_DATA myData;
long stat;
#ifdef SUNVIEW
Frame plotFrame;
Canvas plotCanvas, plotCanvas1, plotCanvas2;
struct pprWinWin winList;
void pprTestEvHandler();
#else
#if defined XWINDOWS
Display *pDisp; /* pointer to X server connection */
int screenNo; /* screen number */
Window rootWindow; /* the root window on display */
GC gc; /* graphics context */
XEvent anEvent; /* a window event structure */
Window plotWindow; /* the plot window on the display */
Window subWin1, subWin2;
XSizeHints sizeHints; /* defaults for position and size */
#endif
#endif
for (i=0; i<NPTS; i++) {
myData.x[i] = (float)i;
#if 1
myData.y[i] = (float)(i*i);
#else
myData.y[i] = 1.1 + ((float)i)/1000.;
#endif
}
pprAutoRangeF(myData.x, NPTS, &myData.xMin, &myData.xMax);
pprAutoRangeF(myData.y, NPTS, &myData.yMin, &myData.yMax);
myData.nPts = NPTS;
#if defined XWINDOWS && defined UW
/*-----------------------------------------------------------------------------
* A test program for user window in X; user program interacting with
* window manager.
*----------------------------------------------------------------------------*/
if ((pDisp = XOpenDisplay((char *)NULL)) == NULL)
abort();
screenNo = DefaultScreen(pDisp);
rootWindow = DefaultRootWindow(pDisp);
gc = DefaultGC(pDisp, screenNo);
sizeHints.x = x = 100;
sizeHints.y = y = 100;
sizeHints.width = width = 512;
sizeHints.height = height = 512;
sizeHints.flags = PSize | PPosition;
plotWindow = XCreateSimpleWindow(pDisp, rootWindow, x, y, width, height, 5,
BlackPixel(pDisp, screenNo), WhitePixel(pDisp, screenNo));
XSetStandardProperties(pDisp, plotWindow, "win title", "icon title",
None, 0, NULL, &sizeHints);
XSelectInput(pDisp, plotWindow,
ExposureMask |
ButtonPressMask | ButtonReleaseMask);
subWin1 = XCreateSimpleWindow(pDisp, plotWindow, 30, 40, 30, 40, 1,
BlackPixel(pDisp, screenNo), WhitePixel(pDisp, screenNo));
subWin2 = XCreateSimpleWindow(pDisp, plotWindow, 130, 140, 130, 140, 0,
BlackPixel(pDisp, screenNo), WhitePixel(pDisp, screenNo));
XMapSubwindows(pDisp, plotWindow);
XMapWindow(pDisp, plotWindow);
pWin = pprWinOpenUW(&pDisp, &subWin1, &gc, NULL);
PprAssertAlways(pWin != NULL);
pWin2 = pprWinOpenUW(&pDisp, &subWin2, &gc, NULL);
PprAssertAlways(pWin2 != NULL);
while (1) {
XNextEvent(pDisp, &anEvent);
if (anEvent.type == ButtonRelease &&
anEvent.xbutton.button == PPR_BTN_CLOSE) {
(void)printf("button 3 up\n");
pprWinClose(pWin);
pprWinClose(pWin2);
XCloseDisplay(pDisp);
break;
}
else if (anEvent.type == Expose && anEvent.xexpose.count == 0) {
pprWinReplot(pWin, replot, &myData);
pprWinReplot(pWin2, replot, &myData);
}
}
#else
#if defined SUNVIEW && defined UW
/*-----------------------------------------------------------------------------
* A test program for user window in SunView; user program interacting with
* window manager.
*----------------------------------------------------------------------------*/
plotFrame = window_create(NULL, FRAME,
FRAME_LABEL, "win title",
FRAME_NO_CONFIRM, 1,
WIN_X, 100, WIN_Y, 100,
WIN_WIDTH, 512,
WIN_HEIGHT, 512,
0);
winList.frame = plotFrame;
plotCanvas = window_create(plotFrame, CANVAS,
WIN_WIDTH, 512,
WIN_HEIGHT, 512,
CANVAS_AUTO_SHRINK, TRUE,
CANVAS_AUTO_EXPAND, TRUE,
CANVAS_FIXED_IMAGE, FALSE,
CANVAS_RETAINED, FALSE,
CANVAS_AUTO_CLEAR, TRUE,
0);
plotCanvas1 = window_create(plotFrame, CANVAS,
WIN_X, 30, WIN_Y, 40,
WIN_WIDTH, 30, WIN_HEIGHT, 40,
CANVAS_AUTO_SHRINK, TRUE,
CANVAS_AUTO_EXPAND, TRUE,
CANVAS_FIXED_IMAGE, FALSE,
CANVAS_RETAINED, FALSE,
CANVAS_AUTO_CLEAR, TRUE,
WIN_EVENT_PROC, pprTestEvHandler,
WIN_CLIENT_DATA, &winList,
0);
plotCanvas2 = window_create(plotFrame, CANVAS,
WIN_X, 130, WIN_Y, 140,
WIN_WIDTH, 130, WIN_HEIGHT, 140,
CANVAS_AUTO_SHRINK, TRUE,
CANVAS_AUTO_EXPAND, TRUE,
CANVAS_FIXED_IMAGE, FALSE,
CANVAS_RETAINED, FALSE,
CANVAS_AUTO_CLEAR, TRUE,
WIN_EVENT_PROC, pprTestEvHandler,
WIN_CLIENT_DATA, &winList,
0);
pWin = pprWinOpenUW(&plotFrame, &plotCanvas1, NULL, NULL);
PprAssertAlways(pWin != NULL);
pWin2 = pprWinOpenUW(&plotFrame, &plotCanvas2, NULL, NULL);
PprAssertAlways(pWin2 != NULL);
winList.pWin1 = pWin;
winList.pWin2 = pWin2;
winList.pMyData = &myData;
window_set(plotFrame, WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS,
ACTION_OPEN, ACTION_CLOSE,
ACTION_FRONT, ACTION_BACK,
WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, 0,
WIN_EVENT_PROC, pprTestEvHandler,
WIN_CLIENT_DATA, &winList,
0);
window_set(plotCanvas, WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS,
WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, 0,
WIN_EVENT_PROC, pprTestEvHandler,
WIN_CLIENT_DATA, &winList,
0);
window_fit(plotFrame);
window_set(plotFrame, WIN_SHOW, 1, 0);
window_set(plotCanvas, WIN_SHOW, 1, 0);
window_set(plotCanvas1, WIN_SHOW, 1, 0);
window_set(plotCanvas2, WIN_SHOW, 1, 0);
window_main_loop(plotFrame);
#else
/*-----------------------------------------------------------------------------
* A test for plot package created window, plot package interacting with
* window manager.
*----------------------------------------------------------------------------*/
pWin = pprWinOpen(PPR_WIN_SCREEN, NULL, "test title", x, y, width, height);
PprAssert(pWin != NULL);
stat = pprWinLoop(pWin, replot, &myData);
PprAssert(stat == 0);
pprWinInfo(pWin, &x, &y, &width, &height);
pprWinClose(pWin);
#endif
#endif
pWin = pprWinOpen(PPR_WIN_POSTSCRIPT, "testPS", NULL, x,y,width,height);
PprAssert(pWin != NULL);
stat = pprWinLoop(pWin, replot, &myData);
PprAssert(stat == 0);
pprWinClose(pWin);
(void)printf("PostScript plot stored in 'testPS'\n");
return;
}
void
replot(pWin, pMyData)
PPR_WIN *pWin; /* I pointer to plot window structure */
MY_DATA *pMyData;
{
char answer[80];
replotDraw(pWin, pMyData, 0);
#if 1
if (pWin->winType == PPR_WIN_SCREEN) {
#ifdef XWINDOWS
XFlush(pWin->pDisp);
#endif
(void)printf("eraseTest? (e or cr) ");
fflush(stdout);
if (fgets(answer, 80, stdin) == NULL || answer[0] == '\n')
; /* no action */
else {
if (answer[0] == 'e')
replotDraw(pWin, pMyData, 1);
}
}
#endif
return;
}
replotDraw(pWin, pMyData, erase)
PPR_WIN *pWin; /* I pointer to plot window structure */
MY_DATA *pMyData;
int erase;
{
double xlo=0., ylo=0., xhi=.95, yhi=.95;
double charHt, charHtX;
PPR_AREA *pArea;
PPR_AREA *pAreaClip, *pAreaClip2;
int i;
int thick=5, thin=0;
int keyNum=0;
int markNum;
double y=6000.;
double x;
char answer[80];
charHt = PprDfltCharHt(ylo, yhi);
charHtX = pprYFracToXFrac(pWin, charHt);
pArea = pprAreaOpen(pWin, xlo+12.*charHtX, ylo+6.*charHt, xhi, yhi,
pMyData->xMin, pMyData->yMin, pMyData->xMax, pMyData->yMax,
5, 5, charHt);
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thin, NULL);
if (!erase)
pprPerimLabel(pArea, "x label", NULL, "y label", NULL, 0.);
pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, 0, NULL);
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
if (!erase)
pprLineF(pArea, pMyData->x, pMyData->y, pMyData->nPts);
else
pprLineEraseF(pArea, pMyData->x, pMyData->y, pMyData->nPts);
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
for (x=1.; x<10.; x+=1.) {
if (!erase)
pprPointD(pArea, x, x*x+100.);
else
pprPointEraseD(pArea, x, x*x+100.);
}
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thin, NULL);
for (x=1.; x<10.; x+=1.) {
if (!erase)
pprPointD(pArea, x, x*x+200.);
else
pprPointEraseD(pArea, x, x*x+200.);
}
if (!erase)
pprAnnotYMark(pArea, 0, 1);
for (keyNum=0; keyNum<=PPR_NKEYS; keyNum++) {
pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, keyNum, NULL);
if (!erase)
pprLineSegD(pArea, 0., y, 50., y);
else
pprLineSegEraseD(pArea, 0., y, 50., y);
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
if (!erase)
pprLineSegD(pArea, 50., y, 70., y);
else
pprLineSegEraseD(pArea, 50., y, 70., y);
pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thin, NULL);
y -= 100.;
}
pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, 0, NULL);
for (i=0; i<=PPR_NCOLORS; i++) {
pprAreaSetAttr(pArea, PPR_ATTR_COLORNUM, i, NULL);
if (!erase)
pprLineSegD(pArea, 0., y, 50., y);
else
pprLineSegEraseD(pArea, 0., y, 50., y);
y -= 100.;
}
x = 1.;
for (i=0; i<PPR_NMARKS; i++) {
pprAreaSetAttr(pArea, PPR_ATTR_COLORNUM, i, NULL);
if (!erase)
pprMarkD(pArea, x, y, i);
else
pprMarkEraseD(pArea, x, y, i);
x += 1.5;
}
y -= 100.;
x = 20.;
if (!erase) {
pprText(pArea, x, y, "centered", PPR_TXT_CEN, 0., 0.);
y -= 100.;
pprText(pArea, x, y, "right just", PPR_TXT_RJ, 0., 0.);
y -= 100.;
pprText(pArea, x, y, "left just", PPR_TXT_LJ, 0., 0.);
y -= 100.;
}
else {
pprTextErase(pArea, x, y, "centered", PPR_TXT_CEN, 0., 0.);
y -= 100.;
pprTextErase(pArea, x, y, "right just", PPR_TXT_RJ, 0., 0.);
y -= 100.;
pprTextErase(pArea, x, y, "left just", PPR_TXT_LJ, 0., 0.);
y -= 100.;
}
y -= 200.;
x = 20.;
if (!erase) {
pprText(pArea, x, y, "centered 170", PPR_TXT_CEN, 0., 170.);
y -= 200.;
pprText(pArea, x, y, "right just 170", PPR_TXT_RJ, 0., 170.);
y -= 200.;
pprText(pArea, x, y, "left just 170", PPR_TXT_LJ, 0., 170.);
y -= 200.;
}
else {
pprTextErase(pArea, x, y, "centered 170", PPR_TXT_CEN, 0., 170.);
y -= 200.;
pprTextErase(pArea, x, y, "right just 170", PPR_TXT_RJ, 0., 170.);
y -= 200.;
pprTextErase(pArea, x, y, "left just 170", PPR_TXT_LJ, 0., 170.);
y -= 200.;
}
/*-----------------------------------------------------------------------------
* test clipping
*----------------------------------------------------------------------------*/
pAreaClip = pprAreaOpenDflt(pWin, .65, .06, .9, .26, 0., 0., 1., 1.);
PprAssert(pAreaClip != NULL);
if (!erase)
pprPerim(pAreaClip);
pprAreaSetAttr(pAreaClip, PPR_ATTR_CLIP, 0, NULL);
if (!erase) {
pprLineSegD(pAreaClip, .1,.1, .9,.9);
pprLineSegD(pAreaClip, .1,.9, .9,.1);
}
else {
pprLineSegEraseD(pAreaClip, .1,.1, .9,.9);
pprLineSegEraseD(pAreaClip, .1,.9, .9,.1);
}
#if 0
pprLineSegD(pAreaClip, -1.,.5, .5,.9);
#endif
for (y=-1.; y<=2.; y+=.5) {
if (!erase) {
pprLineSegD(pAreaClip, -1.,.5, .5,y);
pprLineSegD(pAreaClip, -1.,.5, 2.,y);
pprLineSegD(pAreaClip, 2.,.5, .5,y);
pprLineSegD(pAreaClip, 2.,.5, -1.,y);
}
else {
pprLineSegEraseD(pAreaClip, -1.,.5, .5,y);
pprLineSegEraseD(pAreaClip, -1.,.5, 2.,y);
pprLineSegEraseD(pAreaClip, 2.,.5, .5,y);
pprLineSegEraseD(pAreaClip, 2.,.5, -1.,y);
}
}
for (x=-1.; x<=2.; x+=.5) {
if (!erase) {
pprLineSegD(pAreaClip, .5,-1., x,.5);
pprLineSegD(pAreaClip, .5,-1., x,2.);
pprLineSegD(pAreaClip, .5,2., x,.5);
pprLineSegD(pAreaClip, .5,2., x,-1.);
}
else {
pprLineSegEraseD(pAreaClip, .5,-1., x,.5);
pprLineSegEraseD(pAreaClip, .5,-1., x,2.);
pprLineSegEraseD(pAreaClip, .5,2., x,.5);
pprLineSegEraseD(pAreaClip, .5,2., x,-1.);
}
}
pprAreaClose(pAreaClip);
pAreaClip2 = pprAreaOpenDflt(pWin, .65, .3, .9, .5, 0., 0., 1., 1.);
PprAssert(pAreaClip2 != NULL);
if (!erase)
pprPerim(pAreaClip2);
pprAreaSetAttr(pAreaClip2, PPR_ATTR_CLIP, 0, NULL);
if (!erase)
printf("25 marks with squares should appear; no others!\n");
for (y=-.25; y<=2.; y+=.25) {
for (x=-.25; x<=2.; x+=.25) {
if (y < -.01 || y > 2.01 || x < -.01 || x > 2.01)
markNum = 3;
else
markNum = 1;
if (!erase)
pprMarkD(pAreaClip2, x, y, markNum);
else
pprMarkEraseD(pAreaClip2, x, y, markNum);
}
}
pprAreaClose(pAreaClip2);
#if 1
if (!erase && pWin->winType == PPR_WIN_SCREEN) {
#ifdef XWINDOWS
XFlush(pWin->pDisp);
#endif
(void)printf( "erase win, area, grid, or perim? (w,a,g,p, or cr) ");
fflush(stdout);
if (fgets(answer, 80, stdin) == NULL || answer[0] == '\n')
; /* no action */
else {
if (answer[0] == 'w')
pprWinErase(pWin);
else if (answer[0] == 'a')
pprRegionErase(pArea,.3,.3,.6,.9);
else if (answer[0] == 'p')
pprPerimErase(pArea);
else if (answer[0] == 'g')
pprGridErase(pArea);
(void)printf("done erasing: ");
fflush(stdout);
}
}
#endif
pprAreaClose(pArea);
return;
}
#endif
/*+/internal******************************************************************
* NAME pprTestEvHandler - handler for SunView events
*
*-*/
#if defined SUNVIEW && defined UW
static void
pprTestEvHandler(window, pEvent, pArg)
Window window;
Event *pEvent;
void *pArg;
{
struct pprWinWin *pWinList;
pWinList = (struct pprWinWin *)window_get(window, WIN_CLIENT_DATA);
if (event_action(pEvent) == WIN_REPAINT) {
if (!window_get(window, FRAME_CLOSED)) {
if (window == pWinList->pWin1->canvas)
pprWinReplot(pWinList->pWin1, replot, pWinList->pMyData);
if (window == pWinList->pWin2->canvas)
pprWinReplot(pWinList->pWin2, replot, pWinList->pMyData);
}
}
else if (event_action(pEvent) == PPR_BTN_CLOSE) {
if (event_is_up(pEvent)) {
pprWinClose(pWinList->pWin1);
pprWinClose(pWinList->pWin2);
window_destroy(pWinList->frame);
}
}
}
#endif
/*+/subr**********************************************************************
* NAME pprAnnotX - annotate an X axis, perhaps drawing a line and tick marks
*
* DESCRIPTION
* Annotate an X axis, placing annotations at the major tick intervals.
*
* If desired, an axis line is also drawn, with tick marks at the
* major intervals. The tick marks are drawn using the "generic"
* line attributes for the plot window. The axis line is drawn with
* the line attributes of the plot area; this allows using a dashed
* line pattern or color to associate an axis with a data line.
*
* The annotations and label are drawn using the default character
* height for the plot area, in the color, if any, for the plot area.
*
* An array of text strings can be supplied for annotating the tick
* intervals. This is useful if the desired annotations are text.
* If an annotation array isn't supplied, then numeric annotations
* are generated.
*
* To allow multiple calibrations for an axis, this routine accepts
* an `offset' argument. If this argument is greater than 0, then
* the annotation and labeling activity occurs that many lines (in
* the default character height for the plot area) below the axis
* which was established by pprAreaOpen.
*
* An alternate entry point, pprAnnotX_wc, is available to use the
* plot window's color for the annotation.
*
* RETURNS
* void
*
* BUGS
* o only linear axes are handled
* o doesn't presently support offset processing
*
* NOTES
* 1. Uses a space below the axis of 5 character heights.
*
* SEE ALSO
* pprAnnotY, pprGrid, pprPerim, pprAreaOpen, pprAreaSetAttr
*
*-*/
void
pprAnnotX(pArea, offset, xLeft, xRight, xNint, drawLine, xLabel, xAnnot, angle)
PPR_AREA *pArea; /* I pointer to plotter area */
int offset; /* I offset as number of lines below yBot to annotate */
double xLeft; /* I x data value at left end of axis */
double xRight; /* I x data value at right end of axis */
int xNint; /* I number of major intervals for axis */
int drawLine; /* I 1 says to draw a line and tick marks */
char *xLabel; /* I label for x axis, or NULL; oriented horizontal */
char **xAnnot; /* I pointer to array of x annotations, or NULL */
double angle; /* I orientation angle for annotation text; 0. or 90. */
{
pprAnnotX_gen(pArea,offset,xLeft,xRight,xNint,drawLine,xLabel,xAnnot,angle,
pprLineSegD_ac, pprLineSegD, pprText);
}
void
pprAnnotX_wc(pArea,offset,xLeft,xRight,xNint,drawLine,xLabel,xAnnot,angle)
PPR_AREA *pArea; /* I pointer to plotter area */
int offset; /* I offset as number of lines below yBot to annotate */
double xLeft; /* I x data value at left end of axis */
double xRight; /* I x data value at right end of axis */
int xNint; /* I number of major intervals for axis */
int drawLine; /* I 1 says to draw a line and tick marks */
char *xLabel; /* I label for x axis, or NULL; oriented horizontal */
char **xAnnot; /* I pointer to array of x annotations, or NULL */
double angle; /* I orientation angle for annotation text; 0. or 90. */
{
pprAnnotX_gen(pArea,offset,xLeft,xRight,xNint,drawLine,xLabel,xAnnot,angle,
pprLineSegD_wc, pprLineSegD, pprText_wc);
}
static void
pprAnnotX_gen(pArea,offset,xLeft,xRight,xNint,drawLine,xLabel,xAnnot,angle,
fnTick, fnLine, fnText)
PPR_AREA *pArea; /* I pointer to plotter area */
int offset; /* I offset as number of lines below yBot to annotate */
double xLeft; /* I x data value at left end of axis */
double xRight; /* I x data value at right end of axis */
int xNint; /* I number of major intervals for axis */
int drawLine; /* I 1 says to draw a line and tick marks */
char *xLabel; /* I label for x axis, or NULL; oriented horizontal */
char **xAnnot; /* I pointer to array of x annotations, or NULL */
double angle; /* I orientation angle for annotation text; 0. or 90. */
void (*fnTick)();
void (*fnLine)();
void (*fnText)();
{
double tickHalf, tick1, tick2, tick1S, tick2S;
int i, j;
double x, x1, xInterval, xSubint, y;
double xVal, xValInterval;
char *pText, text[80];
int nCol=6; /* number of columns for annotation label */
int sigDigits; /* sig digits to print */
double maxVal, minVal; /* max and min of the end values for axis */
double logDiff; /* log of diff between max and min */
PPR_TXT_JUST just; /* justification code for annotations */
tickHalf = pArea->tickHt / pArea->yScale;
tick1S = pArea->yBot;
tick2S = tick1S - tickHalf;
tick1 = tick1S - tickHalf;
tick2 = tick1S + tickHalf;
if (drawLine == 0 && pArea->xNsubint > 0) {
drawLine = 1;
tick1 = tick1S;
tick2 = tick1S - 2.*tickHalf;
}
if (PprAbs(xLeft) >= PprAbs(xRight))
maxVal = PprAbs(xLeft), minVal = PprAbs(xRight);
else
maxVal = PprAbs(xRight), minVal = PprAbs(xLeft);
if (maxVal == minVal)
maxVal = minVal + 1.;
logDiff = (int)(log10(maxVal - minVal));
if (logDiff < 0.) sigDigits = 2 + (int)(-1. * logDiff);
else if (maxVal >= 100.) sigDigits = 0;
else if (maxVal >= 10.) sigDigits = 1;
else if (maxVal >= 1.) sigDigits = 2;
else sigDigits = 3;
x = pArea->xLeft;
xInterval = (pArea->xRight - pArea->xLeft) / xNint;
if (pArea->xNsubint > 0)
xSubint = xInterval / pArea->xNsubint;
xVal = xLeft;
xValInterval = (xRight - xLeft) / xNint;
y = pArea->yBot - 2. * pArea->charHt / pArea->yScale;
for (i=0; i<=xNint; i++) {
if (i == xNint) x = pArea->xRight, xVal = xRight;
if (drawLine) fnTick(pArea, x, tick1, x, tick2);
if (pArea->xNsubint > 0 && i != xNint) {
for (j=1, x1=x+xSubint; j<pArea->xNsubint; j++, x1+=xSubint)
fnTick(pArea, x1, tick1S, x1, tick2S);
}
if (i == 0) just = PPR_TXT_LJ;
else if (i == xNint) just = PPR_TXT_RJ;
else just = PPR_TXT_CEN;
if (xAnnot == NULL)
pprCvtDblToTxt(text, nCol, xVal, sigDigits), pText = text;
else
pText = xAnnot[i];
fnText(pArea, x, y, pText, just, 0., angle);
x += xInterval;
xVal += xValInterval;
}
if (xLabel != NULL) {
x = (pArea->xLeft + pArea->xRight) / 2.;
y = pArea->yBot - 4. * pArea->charHt / pArea->yScale;
fnText(pArea, x, y, xLabel, PPR_TXT_CEN, 0., angle);
}
}
/*+/subr**********************************************************************
* NAME pprAnnotY - annotate a Y axis, perhaps drawing line and tick marks
*
* DESCRIPTION
* Annotate a Y axis, placing annotations at the major tick intervals.
*
* If desired, an axis line is also drawn, with tick marks at the
* major intervals. The tick marks are drawn using the "generic"
* line attributes for the plot window. The axis line is drawn with
* the line attributes of the plot area; this allows using a dashed
* line pattern or color to associate an axis with a data line.
*
* The annotations and label are drawn using the default character
* height for the plot area, in the color, if any, for the plot area.
*
* An array of text strings can be supplied for annotating the tick
* intervals. This is useful if the desired annotations are text.
* If an annotation array isn't supplied, then numeric annotations
* are generated.
*
* To allow multiple calibrations for an axis, this routine accepts
* an `offset' argument. If this argument is greater than 0, then
* the annotation and labeling activity occurs that many lines (in
* the default character height for the plot area) to the left of
* the axis which was established by pprAreaOpen.
*
* An alternate entry point, pprAnnotY_wc, is available to use the
* plot window's color for the annotation.
*
* RETURNS
* void
*
* BUGS
* o only linear axes are handled
*
* NOTES
* 1. Uses a space to the left of the axis of 12 character heights if
* annotations are horizontal, and a space of 5 character heights
* if they are vertical.
*
* SEE ALSO
* pprAnnotX, pprGrid, pprPerim, pprAreaOpen, pprAreaSetAttr
*
*-*/
void
pprAnnotY(pArea, offset, yBot, yTop, yNint, drawLine, yLabel, yAnnot, angle)
PPR_AREA *pArea; /* I pointer to plot area structure */
int offset; /* I number of lines to left of axis for annotation */
double yBot; /* I y data value at bottom end of axis */
double yTop; /* I y data value at top end of axis */
int yNint; /* I number of major intervals for axis */
int drawLine; /* I 1 says to draw a line and tick marks */
char *yLabel; /* I label for y axis, or NULL; oriented vertical */
char **yAnnot; /* I pointer to array of y annotations, or NULL */
double angle; /* I orientation angle for annotation text; 0. or 90. */
{
pprAnnotY_gen(pArea,offset,yBot,yTop,yNint,drawLine,yLabel,yAnnot,angle,
pprLineSegD_ac, pprLineSegD, pprText);
}
void
pprAnnotY_wc(pArea, offset, yBot, yTop, yNint, drawLine, yLabel, yAnnot, angle)
PPR_AREA *pArea; /* I pointer to plot area structure */
int offset; /* I number of lines to left of axis for annotation */
double yBot; /* I y data value at bottom end of axis */
double yTop; /* I y data value at top end of axis */
int yNint; /* I number of major intervals for axis */
int drawLine; /* I 1 says to draw a line and tick marks */
char *yLabel; /* I label for y axis, or NULL; oriented vertical */
char **yAnnot; /* I pointer to array of y annotations, or NULL */
double angle; /* I orientation angle for annotation text; 0. or 90. */
{
pprAnnotY_gen(pArea,offset,yBot,yTop,yNint,drawLine,yLabel,yAnnot,angle,
pprLineSegD_wc, pprLineSegD, pprText_wc);
}
void
pprAnnotY_gen(pArea, offset, yBot, yTop, yNint, drawLine, yLabel, yAnnot, angle,
fnTick, fnLine, fnText)
PPR_AREA *pArea; /* I pointer to plot area structure */
int offset; /* I number of lines to left of axis for annotation */
double yBot; /* I y data value at bottom end of axis */
double yTop; /* I y data value at top end of axis */
int yNint; /* I number of major intervals for axis */
int drawLine; /* I 1 says to draw a line and tick marks */
char *yLabel; /* I label for y axis, or NULL; oriented vertical */
char **yAnnot; /* I pointer to array of y annotations, or NULL */
double angle; /* I orientation angle for annotation text; 0. or 90. */
void (*fnTick)();
void (*fnLine)();
void (*fnText)();
{
double tickHalf, tick1, tick2;
int i;
double x; /* x coord for annotations */
double xL; /* x coord for label */
double xBase; /* base x coordinate */
double y, yInterval;
double yVal, yValInterval;
char text[80];
int nCol=6; /* number of columns for annotation label */
int sigDigits; /* sig digits to print */
double maxVal, minVal; /* max and min of the end values for axis */
double logDiff; /* log of diff between max and min */
PPR_TXT_JUST just; /* justification flag for text */
xBase = pArea->xLeft - (double)offset * pArea->charHt / pArea->xScale;
if (drawLine) {
tickHalf = pArea->tickHt / pArea->xScale;
tick1 = xBase - tickHalf;
if (offset == 0)
tick2 = xBase + tickHalf;
else
tick2 = xBase;
}
if (PprAbs(yBot) >= PprAbs(yTop))
maxVal = PprAbs(yBot), minVal = PprAbs(yTop);
else
maxVal = PprAbs(yTop), minVal = PprAbs(yBot);
if (maxVal == minVal)
maxVal = minVal + 1.;
logDiff = (int)(log10(maxVal - minVal));
if (logDiff < 0.) sigDigits = 2 + (int)(-1. * logDiff);
else if (maxVal >= 100.) sigDigits = 0;
else if (maxVal >= 10.) sigDigits = 1;
else if (maxVal >= 1.) sigDigits = 2;
else sigDigits = 3;
if (angle == 0.) {
x = xBase - 2. * pArea->charHt / pArea->xScale;
xL = xBase - 10. * pArea->charHt / pArea->xScale;
}
else {
x = xBase - 2. * pArea->charHt / pArea->xScale;
xL = xBase - 4. * pArea->charHt / pArea->xScale;
}
y = pArea->yBot;
yInterval = (pArea->yTop - pArea->yBot) / yNint;
yVal = yBot;
yValInterval = (yTop - yBot) / yNint;
if (drawLine)
fnTick(pArea, tick1, y, tick2, y);
if (angle == 0.) just = PPR_TXT_RJ;
else just = PPR_TXT_LJ;
if (yAnnot == NULL) {
pprCvtDblToTxt(text, nCol, yVal, sigDigits);
fnText(pArea, x, y, text, just, 0., angle);
}
else
fnText(pArea, x, y, yAnnot[0], just, 0., angle);
if (angle == 0.) just = PPR_TXT_RJ;
else just = PPR_TXT_CEN;
for (i=1; i<yNint; i++) {
y += yInterval;
yVal += yValInterval;
if (drawLine)
fnTick(pArea, tick1, y, tick2, y);
if (yAnnot == NULL) {
pprCvtDblToTxt(text, nCol, yVal, sigDigits);
fnText(pArea, x, y, text, just, 0., angle);
}
else
fnText(pArea, x, y, yAnnot[i], just, 0., angle);
}
y = pArea->yTop;
if (angle == 0.) just = PPR_TXT_RJ;
else just = PPR_TXT_RJ;
if (yAnnot == NULL) {
pprCvtDblToTxt(text, nCol, yTop, sigDigits);
fnText(pArea, x, y, text, just, 0., angle);
}
else
fnText(pArea, x, y, yAnnot[yNint], just, 0., angle);
if (drawLine) {
fnTick(pArea, tick1, y, tick2, y);
fnLine(pArea, xBase, pArea->yBot, xBase, pArea->yTop);
}
if (yLabel != NULL) {
y = (pArea->yBot + pArea->yTop) / 2.;
fnText(pArea, xL, y, yLabel, PPR_TXT_CEN, 0., 90.);
}
}
/*+/subr**********************************************************************
* NAME pprAnnotYMark - add plot marks to a Y axis annotation
*
* DESCRIPTION
* Draw two plot marks at the foot of the Y axis annotation, to allow
* associating the axis with a particular set of data.
*
* RETURNS
* void
*
* BUGS
* o only linear axes are handled
*
* SEE ALSO
* pprMark, pprAnnotY
*
* EXAMPLE
*
*-*/
void
pprAnnotYMark(pArea, offset, markNum)
PPR_AREA *pArea; /* I pointer to plot area structure */
int offset; /* I number of lines to left of axis for annotation */
int markNum; /* I mark number */
{
double x, y;
x = pArea->xLeft - (double)(offset+3) * pArea->charHt / pArea->xScale;
y = pArea->yBot - pArea->charHt * 2. / pArea->yScale;
pprMarkD(pArea, x, y, markNum);
}
/*+/subr**********************************************************************
* NAME pprArc - draw an arc
*
* DESCRIPTION
* Draw an arc. The arc is specified by a radius and two angles. The
* angles, in degrees, specify the angle at which the arc starts and
* the angle at which it ends. An angle increment specifies both the
* direction of the arc and the size of the chords which approximate
* the arc. Angles are measured counter-clockwise from the positive
* X axis.
*
* The radius of the arc is treated as representing data values in the
* plot area. If both the X and Y axes of the plot area have the
* same data scaling, then circular arcs will be produced (assuming
* a square plot area). If the X scaling is not the same as the Y
* scaling, then elliptical arcs will be produced.
*
* The arc is drawn using the color, dashed line, and other attributes
* of the plot area. Alternate entry points are:
*
* pprArcD_ac uses the area color, but ignores other
* attributes
*
* RETURNS
* void
*
* SEE ALSO
*
*-*/
void
pprArcD(pArea, xDbl, yDbl, radDbl, angle1, angle2, angleIncr)
PPR_AREA *pArea; /* I pointer to plot area structure */
double xDbl; /* I x data coordinate for center of arc */
double yDbl; /* I y data coordinate for center of arc */
double radDbl;
double angle1; /* I angle to start arc */
double angle2; /* I angle to stop arc */
double angleIncr; /* I size of steps in drawing arc */
{
pprArcD_gen(pArea, xDbl, yDbl, radDbl, angle1, angle2, angleIncr,
pprMoveD);
}
void
pprArcD_ac(pArea, xDbl, yDbl, radDbl, angle1, angle2, angleIncr)
PPR_AREA *pArea;
double xDbl, yDbl, radDbl, angle1, angle2, angleIncr;
{
pprArcD_gen(pArea, xDbl, yDbl, radDbl, angle1, angle2, angleIncr,
pprMoveD_ac);
}
void
pprArcD_gen(pArea, xDbl, yDbl, radDbl, angle1, angle2, angleIncr, fn)
PPR_AREA *pArea;
double xDbl, yDbl, radDbl, angle1, angle2, angleIncr;
void (*fn)(); /* I line drawing function */
{
double x, y, angle;
int pen=0;
if (angle1 > angle2 && angleIncr > 0.) {
while (angle1 > angle2)
angle2 += 360.;
}
else if (angle1 < angle2 && angleIncr < 0.) {
while (angle1 < angle2)
angle1 += 360.;
}
angle = angle1;
while (1) {
x = xDbl + radDbl * pprCos_deg(angle);
y = yDbl + radDbl * pprSin_deg(angle);
fn(pArea, x, y, pen);
pen = 1;
if (angle == angle2)
break;
if ((angle += angleIncr) > angle2)
angle = angle2;
}
}
/*+/subr**********************************************************************
* NAME pprAreaClose - close a plot area
*
* DESCRIPTION
* Frees the memory associated with a plot area pointer and does other
* cleanup operations. This routine should be called prior to calling
* pprWinClose.
*
* RETURNS
* void
*
*-*/
void
pprAreaClose(pArea)
PPR_AREA *pArea; /* I pointer to plot area structure */
{
PPR_WIN *pWin;
pWin = pArea->pWin;
#ifdef XWINDOWS
if (pWin->winType == PPR_WIN_SCREEN) {
if (pArea->attr.myGC)
XFreeGC(pWin->pDisp, pArea->attr.gc);
if (pArea->attr.bgGC)
XFreeGC(pWin->pDisp, pArea->attr.gcBG);
if (pArea->linkedTo == NULL) {
if (pArea->pixMap != NULL)
XFreePixmap(pWin->pDisp, pArea->pixMap);
if (pArea->pixMapGC != NULL)
XFreeGC(pWin->pDisp, pArea->pixMapGC);
if (pArea->stipple != NULL)
XFreePixmap(pWin->pDisp, pArea->stipple);
}
}
#endif
DoubleListRemove(pArea, pWin->pAreaHead, pWin->pAreaTail);
free((char *)pArea);
}
/*+/subr**********************************************************************
* NAME pprAreaErase - erase an area within a plot window
*
* DESCRIPTION
* Erases an area within a plot window.
*
* RETURNS
* void
*
* BUGS
* 1. This doesn't erase the pixmap used for strip charts.
*
* SEE ALSO
* pprWinErase, pprGridErase, pprPerimErase, pprRegionErase
* the ppr...Erase... entry points for the various drawing routines
*
* EXAMPLES
* 1. A data area occupies the upper right quarter of the plot window,
* with data values at the lower left corner of xleft,ybot and at
* the upper right of xright,ytop. 3 annotation areas are used to
* the left of the data area, extending from the left edge of the
* plot window to the left edge of the data area; each annotation
* area occupies 1/3 of the height of the data area. Erase the
* middle annotation area.
*
* double xl,yb,xr,yt;
*
* The region to erase is expressed as data values. The y values are
* straightforward--just 1/3 and 2/3 of the range of the y axis. The
* right-hand x value is just a bit less than the x at the left end
* of the x axis; the left hand x value requires a bit of analytic
* geometry to get.
*
* xl = xleft - (xright - xleft)/(1. - .5) * (.5 - 0.);
* yb = ybot + (ytop - ybot)/3.;
* xr = xright - .001 * (xright - xleft);
* yt = ybot + 2.*(ytop - ybot)/3.;
* pprAreaErase(pArea, xl, yb, xr, yt);
*
*-*/
void
pprAreaErase(pArea, xDblLeft, yDblBot, xDblRight, yDblTop)
PPR_AREA *pArea; /* I pointer to plot area structure */
double xDblLeft; /* I x data value at left edge of area */
double yDblBot; /* I y data value at bottom edge of area */
double xDblRight; /* I x data value at right edge of area */
double yDblTop; /* I y data value at top edge of area */
{
int x,y,x1,x2,y1,y2,width,height;
if (pArea->pWin->winType != PPR_WIN_SCREEN)
return;
x1 = pArea->xPixLeft + .5 + (xDblLeft - pArea->xLeft) * pArea->xScale;
x2 = pArea->xPixLeft + .5 + (xDblRight - pArea->xLeft) * pArea->xScale;
if (x1 < x2) {
x = x1;
width = x2 - x1;
}
else {
x = x2;
width = x1 - x2;
}
y1 = pArea->yPixBot + .5 + (yDblBot - pArea->yBot) * pArea->yScale;
y2 = pArea->yPixBot + .5 + (yDblTop - pArea->yBot) * pArea->yScale;
if (y1 < y2) {
y = y1;
height = y2 - y1;
}
else {
y = y2;
height = y1 - y2;
}
#ifdef SUNVIEW
y = pArea->pWin->height - y - height;
pw_writebackground(pArea->pWin->pw, x, y, width, height, PIX_SRC);
#else
#if defined XWINDOWS
y = pArea->pWin->height - y - height;
XClearArea(pArea->pWin->pDisp, pArea->pWin->plotWindow,
x, y, width, height, False);
#endif
#endif
}
/*+/subr**********************************************************************
* NAME pprAreaOpen - initialize a plot area
*
* DESCRIPTION
* Initialize a plot area within the plot window. This initialization
* must be done before calling any of the routines which do actual
* plotting.
*
* This routine establishes a rectangular "data area" within the plot
* window. It is within the data area that data will be plotted.
* The size and position of the data area are specified in terms
* of fractions of the window size; they are expressed as
* "coordinates" of the lower left and upper right corners of the
* area. The data area specified in the call to pprAreaOpen does
* NOT include space for axis annotations and labels. (pprAreaOpenDflt
* can be used to automatically get the necessary margins.)
*
* This routine must also be told the data values at the two corners
* of the data area in order to determine scaling.
*
* In addition to establishing scaling, this routine accepts information
* about how many major divisions there are for each axis and what
* default character height is to be used for displaying text within
* the plot area (see pprText for more information). If any of these
* parameters is specified as zero, this routine chooses an appropriate
* value.
*
* The default line attributes for the plot are copied from those of
* the plot window. pprAreaSetAttr can be used to change them. Under
* X11, a gc is created for the plot area with the foreground and
* background being copied from the gc for the plot window;
* pprAreaSetAttr can be used to change the foreground and background.
*
* When plotting is complete for a plot area, pprAreaClose should
* be called.
*
* RETURNS
* pointer to plot area, or
* NULL
*
* BUGS
* o only linear calibration is handled
*
* SEE ALSO
* pprWinOpen, pprAreaOpenDflt, pprAreaSetAttr
* pprAutoEnds, pprAutoInterval, pprAutoRange
* pprText
*
* EXAMPLE
* 1. Set up an area which occupies the full width of the window, but
* which uses the middle third vertically. The range for x values
* is 0 to 100; for y, the range is -10 to 10. Both the x and y
* axes are to be divided into 5 intervals.
*
* Allow space below and to the left of the actual area for plotting
* for pprPerim to place labels and annotations. The required
* size of "margins" depends on the size of characters used, so a
* default size is determined (and put into effect as part of the
* pprAreaOpen call).
*
* PPR_AREA *pArea;
* double charHt, charHtX;
*
* charHt = PprDfltCharHt(.33, .67);
* charHtX = pprYFracToXFrac(pWin, charHt);
* pArea = pprAreaOpen(pWin, 0.+12.*charHtX, .33+6*charHt, 1., .67,
* 0., -10., 100., 10., 5, 5, charHt);
* ...
* pprAreaClose(pArea);
*
*-*/
PPR_AREA *
pprAreaOpen(pWin, wfracXleft, wfracYbot, wfracXright, wfracYtop,
xLeft, yBot, xRight, yTop, xNint, yNint, charHt)
PPR_WIN *pWin; /* I pointer to plot window structure */
double wfracXleft; /* I x window fraction of left edge of data area */
double wfracYbot; /* I y window fraction of bottom edge of data area */
double wfracXright; /* I x window fraction of right edge of data area */
double wfracYtop; /* I y window fraction of top edge of data area */
double xLeft; /* I x data value at left side of data area */
double yBot; /* I y data value at bottom side of data area */
double xRight; /* I x data value at right side of data area */
double yTop; /* I y data value at top side of data area */
int xNint; /* I x axis number of intervals; if <=0, a default
value is provided */
int yNint; /* I y axis number of intervals; if <=0, a default
value is provided */
double charHt; /* I value to use as default for character size, as
a fraction of window height; if <= 0.,
a default value is provided */
{
PPR_AREA *pArea; /* pointer to plot area structure */
if ((pArea = (PPR_AREA *)malloc(sizeof(PPR_AREA))) == NULL) {
(void)printf("pprAreaOpen: couldn't malloc plot area struct\n");
return NULL;
}
DoubleListAppend(pArea, pWin->pAreaHead, pWin->pAreaTail);
pArea->pWin = pWin;
pArea->xFracLeft = wfracXleft;
pArea->xFracRight = wfracXright;
if (xNint <= 0)
pprAutoInterval(xLeft, xRight, &xNint);
pArea->xNint = xNint;
pArea->xNsubint = 0;
pArea->yFracBot = wfracYbot;
pArea->yFracTop = wfracYtop;
if (yNint <= 0)
pprAutoInterval(yBot, yTop, &yNint);
pArea->yNint = yNint;
pArea->yNsubint = 0;
pArea->charHt = charHt * pWin->height;
pArea->oldWinHt = pWin->height;
pprAreaRescale(pArea, xLeft, yBot, xRight, yTop);
#ifdef XWINDOWS
if (pWin->winType == PPR_WIN_SCREEN) {
pArea->attr.gc = XCreateGC(pWin->pDisp, pWin->plotWindow, 0, NULL);
XCopyGC(pWin->pDisp, pWin->attr.gc, GCForeground | GCBackground,
pArea->attr.gc);
XSetGraphicsExposures(pWin->pDisp, pArea->attr.gc, False);
pArea->attr.myGC = 1;
}
pArea->usePixMap = 0;
pArea->linkedTo = NULL;
pArea->pixMap = pArea->stipple = NULL;
pArea->pixMapGC = NULL;
#else
#if
pArea->attr.myGC = 0;
#endif
#endif
pArea->attr.bgGC = 0;
pArea->attr.pPatt = NULL;
pArea->attr.lineThick = 1;
pArea->attr.ltCurr = -1;
pArea->attr.clip = 0;
return pArea;
}
/*+/subr**********************************************************************
* NAME pprAreaOpenDflt - initialize a plot area using defaults
*
* DESCRIPTION
* Initialize a plot area within the plot window. This initialization
* must be done before calling any of the routines which do actual
* plotting.
*
* This routine is a variant on pprAreaOpen. It performs the functions
* of that routine, but uses some defaults rather than making the
* caller determine specific values. In particular, this routine:
*
* o sets a default character height
*
* o determines the number of major divisions for each axis
*
* o establishes, inside the plot area specified, margins which
* will be adequate for annotating and labeling the axes.
*
* See the description for pprAreaOpen for additional details.
*
* When plotting is complete for a plot area, pprAreaClose should
* be called.
*
* RETURNS
* pointer to plot area, or
* NULL
*
* BUGS
* o only linear calibration is handled
*
* SEE ALSO
* pprWinOpen, pprAreaOpen, pprAreaSetAttr
* pprAutoEnds, pprAutoInterval, pprAutoRange
* pprText
*
*-*/
PPR_AREA *
pprAreaOpenDflt(pWin, wfracXleft, wfracYbot, wfracXright, wfracYtop,
xLeft, yBot, xRight, yTop)
PPR_WIN *pWin; /* I pointer to plot window structure */
double wfracXleft; /* I x window fraction of left edge of plot area */
double wfracYbot; /* I y window fraction of bottom edge of plot area */
double wfracXright; /* I x window fraction of right edge of plot area */
double wfracYtop; /* I y window fraction of top edge of plot area */
double xLeft; /* I x data value at left side of data area */
double yBot; /* I y data value at bottom side of data area */
double xRight; /* I x data value at right side of data area */
double yTop; /* I y data value at top side of data area */
{
int xNint; /* x axis number of intervals */
int yNint; /* y axis number of intervals */
double charHt, charHtX;/* default for character size */
pprAutoInterval(xLeft, xRight, &xNint);
pprAutoInterval(yBot, yTop, &yNint);
charHt = PprDfltCharHt(wfracYbot, wfracYtop);
charHtX = pprYFracToXFrac(pWin, charHt);
wfracXleft += 12. * charHtX;
wfracYbot += 6. * charHt;
return pprAreaOpen(pWin, wfracXleft, wfracYbot, wfracXright, wfracYtop,
xLeft, yBot, xRight, yTop, xNint, yNint, charHt);
}
/*+/subr**********************************************************************
* NAME pprAreaRescale - change scaling for existing plot area
*
* DESCRIPTION
* Changes the scaling for a plot area using new data values at the
* edges of the data area. The actual size and position of the
* data area within the plot window aren't changed.
*
* No re-drawing is done by this routine. Typically, the caller will
* erase the appropriate area, draw the grid or perimeter, set the
* area for clipping, and, finally, replot the data.
*
* Default character height for the plot area is altered proportionally
* to the rescaling of the plot area.
*
* RETURNS
* void
*
* SEE ALSO
* pprAreaSetAttr, pprAreaErase, pprRegionErase
*
*-*/
void
pprAreaRescale(pArea, xLeft, yBot, xRight, yTop)
PPR_AREA *pArea; /* I pointer to plot area structure */
double xLeft; /* I x data value at left side of data area */
double yBot; /* I y data value at bottom side of data area */
double xRight; /* I x data value at right side of data area */
double yTop; /* I y data value at top side of data area */
{
PPR_WIN *pWin;
pWin = pArea->pWin;
if (xLeft == xRight) {
(void)printf("pprAreaRescale: x left and right are equal\n");
return;
}
else if (yBot == yTop) {
(void)printf("pprAreaRescale: y bottom and top are equal\n");
return;
}
pArea->xPixLeft = .5 + ((double)pWin->width)*pArea->xFracLeft;
pArea->xPixRight = .5 + ((double)pWin->width)*pArea->xFracRight;
pArea->xLeft = xLeft;
pArea->xRight = xRight;
pArea->xInterval = (xRight - xLeft) / pArea->xNint;
pArea->xScale = ((double)pWin->width) *
(pArea->xFracRight - pArea->xFracLeft) / (xRight - xLeft);
pArea->yPixBot = .5 + ((double)pWin->height)*pArea->yFracBot;
pArea->yPixTop = .5 + ((double)pWin->height)*pArea->yFracTop;
pArea->yBot = yBot;
pArea->yTop = yTop;
pArea->yInterval = (yTop - yBot) / pArea->yNint;
pArea->yScale = ((double)pWin->height) *
(pArea->yFracTop - pArea->yFracBot) / (yTop - yBot);
pArea->tickHt = (double)pWin->height *
PprMin(PprAbs(.03 * (pArea->yFracTop - pArea->yFracBot)), .01);
if (pArea->charHt <= 0.)
pArea->charHt = pWin->height *
PprDfltCharHt(pArea->yFracBot, pArea->yFracTop);
else
pArea->charHt = pArea->charHt * pWin->height / pArea->oldWinHt;
pArea->oldWinHt = pWin->height;
}
/*+/subr**********************************************************************
* NAME pprAreaShiftLeft - shift the contents of the plot area
*
* DESCRIPTION
* Shifts the contents of the plot area to the left, as for a strip
* chart. The remembered endpoints for the plot area are changed
* to correspond to the shift.
*
* For best behavior of this routine, the PPR_ATTR_STRIP attribute
* should be set for the plot area after it is opened. If this
* attribute isn't set, the shift operation is more efficient, but
* the appearance is bogus when the data area is partially obscured
* by another window.
*
* RETURNS
* void
*
* NOTES
* 1. The amount shifted will usually be somewhat different from the
* amount requested, since shifts can only occur by a whole number
* of pixels. The .xRight and .xLeft items in the plot area structure
* will be changed by the amount actually shifted.
*
*-*/
void
pprAreaShiftLeft(pArea, dataShift)
PPR_AREA *pArea; /* I pointer to plot area structure */
double dataShift; /* I amount to shift left, as an x data value */
{
int xl, xr, yb, yt; /* pix coord of perimeter */
int width, height; /* pix size of perimeter */
int widP, wc; /* widths preserved and cleared */
PPR_WIN *pWin=pArea->pWin;
if (pWin->winType != PPR_WIN_SCREEN)
return;
#ifdef XWINDOWS
/*-----------------------------------------------------------------------------
* This diagram shows the shifting and clearing if the window is used.
* The areas shifted and cleared don't include pixels on the perimeter.
* (Pixel coordinates are referenced to the northwest corner.)
*
* BEFORE
* --dataShift-- distance to shift, as data value
* ----wc------ distance to shift, pixels (includes right edge)
* ----------widP------------ width to shift (neither
* edge included in width)
* +-----------+--------------------------+
* |*get rid * |
* | of this |*shift this area left *|
* | area | |
* +-----------+--------------------------+
* ^ xl + 1 ^ xl + wc + 1 shift by copying from here to xl + 1
*
* AFTER
* +--------------------------+-----------+
* | * cleared *|
* |*area shifted left *| area |
* | | |
* +--------------------------+-----------+
* ^ xl + widP + 1
*----------------------------------------------------------------------------*/
xl = pArea->xPixLeft;
xr = pArea->xPixRight;
width = xr - xl + 1;
yb = pWin->height - pArea->yPixBot;
yt = pWin->height - pArea->yPixTop;
height = yb - yt;
wc = 1. + dataShift * pArea->xScale;
if (wc >= width)
wc = width, widP = 0;
else
widP = width - wc - 1;
if (pArea->linkedTo == NULL) {
if (widP > 0) { /* shift the `preserved' area to the left */
if (pArea->usePixMap) {
XCopyArea(pWin->pDisp, pArea->pixMap, pArea->pixMap,
pArea->pixMapGC, wc+1, 0, widP, height, 1, 0);
}
else {
XCopyArea(pWin->pDisp, pWin->plotWindow, pWin->plotWindow,
pArea->attr.gc, xl+wc+1, yt+1, widP, height-2, xl+1, yt+1);
}
}
if (wc > 0) { /* clear out the new area on the right */
if (pArea->usePixMap) {
XFillRectangle(pWin->pDisp, pArea->pixMap, pArea->pixMapGC,
widP+1, 0, wc+1, height);
}
XClearArea(pWin->pDisp, pWin->plotWindow,
xl+widP+1, yt+1, wc-1, height-1, False);
}
if (pArea->usePixMap) {
XCopyArea(pWin->pDisp, pArea->pixMap, pWin->plotWindow,
pArea->pixMapGC, 1, 1, width-2, height-1, xl+1, yt+1);
}
}
/*-----------------------------------------------------------------------------
* Change the scaling by the amount actually shifted. (The amount
* shifted--a whole number of pixels--will usually be somewhat different
* from the amount requested.)
*----------------------------------------------------------------------------*/
dataShift = wc / pArea->xScale;
pArea->xRight += dataShift;
pArea->xLeft += dataShift;
#endif
}
/*+/subr**********************************************************************
* NAME pprAreaSetAttr - set attributes for a plot area
*
* DESCRIPTION
* Set individual attributes for a plot area. In most cases, the
* attributes affect the drawing of lines in the plot area.
*
* To use this routine, an attribute code and a corresponding value
* are supplied. The form of the value argument depends on the code.
*
* o PPR_ATTR_CLIP sets the plot area so that line segments which lie
* outside the data area won't be drawn, but will terminate at their
* intersection with the edge of the data area. Clipping can be
* disabled by setting the PPR_ATTR_NOCLIP attribute; the default when
* a plot area is created is no clipping.
*
* pprAreaSetAttr(pArea, PPR_ATTR_CLIP, 0, NULL);
* pprAreaSetAttr(pArea, PPR_ATTR_NOCLIP, 0, NULL);
*
* o PPR_ATTR_COLORNUM selects a color for use in drawing lines in a plot
* area. For monochrome screens, no action is taken. There are
* PPR_NCOLORS colors provided, numbered starting with 1. A colorNum
* of 0 selects black.
*
* int colorNum;
* colorNum = 4;
* pprAreaSetAttr(pArea, PPR_ATTR_COLORNUM, colorNum, NULL);
*
* o PPR_ATTR_BG installs a caller-supplied background pixel value in
* the gc for the plot area. (For use only with X11. Under X11,
* pprAreaOpen initially set the gc for the plot area to have the
* same foreground and background colors as the gc for the plot window.)
*
* pprAreaSetAttr(pArea, PPR_ATTR_BG, 0, &bg);
*
* o PPR_ATTR_FG installs a caller-supplied foreground pixel value in
* the gc for the plot area. (For use only with X11. Under X11,
* pprAreaOpen initially set the gc for the plot area to have the
* same foreground and background colors as the gc for the plot window.)
*
* pprAreaSetAttr(pArea, PPR_ATTR_FG, 0, &fg);
*
* o PPR_ATTR_KEYNUM selects a legend key for identifying lines drawn
* in a plot area, and thus distinguishing them from the lines drawn
* by a different plot area. This is primarily useful for overlapping
* plot areas, where several sets of data are drawn on the same axis.
* The key number, which is expected to be in the range 0 to PPR_NKEYS,
* inclusive, selects either a dashed line pattern or a color,
* depending on the nature of the device on which the plot window
* resides. There are PPR_NKEYS unique patterns and colors; a key
* number of 0 resets to a "plain", solid line.
*
* Use of the PPR_ATTR_KEYNUM option provides a way to restart a
* dashed line pattern at its beginning.
*
* int keyNum;
* keyNum = 4;
* pprAreaSetAttr(pArea, PPR_ATTR_KEYNUM, keyNum, NULL);
*
* o PPR_ATTR_LINE_THICK sets the line thickness for the plot area. The
* thickness is the integer number of thousandths of plot window height.
* The thickness is used for data drawing operations. A thickness of
* 0. results in pixel-thick lines. As an example, a thickness of 10
* represents 10/1000 (or .01) of the window height.
*
* int thick;
* thick = 3; .003 of window height
* pprAreaSetAttr(pArea, PPR_ATTR_LINE_THICK, thick, NULL);
*
* o PPR_ATTR_PATT_ARRAY installs a caller-supplied dashed line pattern
* array. This is an array of type short. The first element
* contains a number of pixels with `pen down'; the second has a
* number of pixels with `pen up'; the third with `pen down'; etc.
* Following the last element must be an element with a value of 0 .
* (pprAreaSetAttr stores only a pointer to the array, so the caller
* must preserve the array until pprAreaClose is called or until
* pprAreaSetAttr is called to `de-install' the pattern array.) An
* array pointer of NULL resets the plot area back to normal drawing.
*
* short pattern[]={16,4,2,4,0};
* pprAreaSetAttr(pArea, PPR_ATTR_PATT_ARRAY, 0, pattern);
*
* If one of the ppr...Erase routines is to be used in conjunction
* with a dashed line pattern, then the sequence of operations for
* erasing must be made the same as the sequence of operations for
* the original drawing.
*
* o PPR_ATTR_STRIP sets up the plot area so that the data area is
* a pixmap. When lines are drawn in the data area, they are
* also drawn in the pixmap. When pprAreaShiftLeft is called, the
* pixmap is shifted and then copied to the screen. (This approach
* is needed to properly handle the case where the data area is
* partially obscured by another window.)
*
* There are tradeoffs for using this attribute. Strip charts with
* a single channel work relatively well either with or without this
* attribute. Strip charts with multiple channels (i.e., those with
* overlapping plot areas) must use this attribute; the second and
* following plot areas will specify the first one as a `link'.
*
* advantages disadvantages
* o shifting always works o more X traffic is generated
* properly o more CPU time is used for
* o overlapping plot areas plotting, since plotting
* work properly goes to both screen and pixmap
*
* pprAreaSetAttr(pArea, PPR_ATTR_STRIP, 1, NULL);
* pprAreaSetAttr(pArea1, PPR_ATTR_STRIP, 1, pArea);
* pprAreaSetAttr(pArea2, PPR_ATTR_STRIP, 1, pArea);
*
*
*
* Some pprXxx routines don't use the attributes from the plot
* area, but instead use the `generic' attributes from the
* plot window structure. The pprLineSegx_wc and pprMovex_wc
* routines provide an explicit mechanism for using the plot window
* attributes.
*
* RETURNS
* 0, or
* -1 if an error is encountered
*
* BUGS
* o color is supported only for X
* o when color is used, ALL output for the plot area is colored; it's
* not clear yet whether this is a bug or a feature.
* o line thickness doesn't operate consistently under SunView
*
* SEE ALSO
* pprAreaOpen
*
*-*/
long
pprAreaSetAttr(pArea, code, arg, pArg)
PPR_AREA *pArea; /* I pointer to plot area structure */
PPR_ATTR_CODE code; /* I attribute code: one of PPR_ATTR_xxx */
int arg; /* I attribute value, or 0 */
void *pArg; /* I pointer to attribute, or NULL */
{
int keyNum, colorNum;
PPR_WIN *pWin;
#ifdef XWINDOWS
int screenNo;
Colormap cmap;
XColor color, rgbDb;
#endif
if (code == PPR_ATTR_CLIP) {
pArea->attr.clip = 1;
return 0;
}
if (code == PPR_ATTR_NOCLIP) {
pArea->attr.clip = 0;
return 0;
}
if (code == PPR_ATTR_COLORNUM) {
#ifdef XWINDOWS
pWin = pArea->pWin;
if (pWin->winType != PPR_WIN_SCREEN)
return 0;
colorNum = arg;
if (colorNum == 0)
XCopyGC(pWin->pDisp, pWin->attr.gc, GCForeground, pArea->attr.gc);
else {
screenNo = DefaultScreen(pWin->pDisp);
colorNum = (colorNum - 1) % PPR_NCOLORS;
if (!pprWinIsMono(pWin)) {
cmap = DefaultColormap(pWin->pDisp, screenNo);
if (XAllocNamedColor(pWin->pDisp, cmap, pglPprColor[colorNum],
&color, &rgbDb)) {
XSetForeground(pWin->pDisp,pArea->attr.gc,color.pixel);
}
else
return -1;
}
}
#endif
return 0;
}
if (code == PPR_ATTR_BG) {
#ifdef XWINDOWS
pWin = pArea->pWin;
if (pWin->winType != PPR_WIN_SCREEN)
return 0;
XSetBackground(pWin->pDisp, pArea->attr.gc, *(unsigned long *)pArg);
#endif
return 0;
}
if (code == PPR_ATTR_FG) {
#ifdef XWINDOWS
pWin = pArea->pWin;
if (pWin->winType != PPR_WIN_SCREEN)
return 0;
XSetForeground(pWin->pDisp, pArea->attr.gc, *(unsigned long *)pArg);
#endif
return 0;
}
if (code == PPR_ATTR_KEYNUM) {
keyNum = arg;
pWin = pArea->pWin;
if (keyNum == 0) {
pArea->attr.pPatt = NULL;
#ifdef XWINDOWS
if (pWin->winType == PPR_WIN_SCREEN)
XCopyGC(pWin->pDisp,pWin->attr.gc,GCForeground,pArea->attr.gc);
#endif
}
else {
keyNum = (keyNum - 1) % PPR_NKEYS;
#ifdef XWINDOWS
if (pWin->winType == PPR_WIN_SCREEN) {
screenNo = DefaultScreen(pWin->pDisp);
if (!pprWinIsMono(pWin)) {
cmap = DefaultColormap(pWin->pDisp, screenNo);
if (XAllocNamedColor(pWin->pDisp, cmap, pglPprColor[keyNum],
&color, &rgbDb)) {
XSetForeground(pWin->pDisp,pArea->attr.gc,color.pixel);
pArea->attr.pPatt = NULL;
return 0;
}
}
}
#endif
#if 0
if (keyNum == 0) {
pArea->attr.pPatt = NULL;
return 0;
}
#endif
pArea->attr.pPatt = pglPprPat[keyNum];
pArea->attr.sub = 0;
pArea->attr.rem = pArea->attr.pPatt[0];
pArea->attr.pen = 1;
}
return 0;
}
if (code == PPR_ATTR_LINE_THICK) {
pArea->attr.lineThick = arg;
return 0;
}
if (code == PPR_ATTR_COLORNUM) {
#ifdef XWINDOWS
pWin = pArea->pWin;
if (pWin->winType != PPR_WIN_SCREEN)
return 0;
colorNum = arg;
if (colorNum == 0)
XCopyGC(pWin->pDisp, pWin->attr.gc, GCForeground, pArea->attr.gc);
else {
colorNum = (colorNum - 1) % PPR_NCOLORS;
screenNo = DefaultScreen(pWin->pDisp);
if (!pprWinIsMono(pWin)) {
cmap = DefaultColormap(pWin->pDisp, screenNo);
if (XAllocNamedColor(pWin->pDisp, cmap, pglPprColor[colorNum],
&color, &rgbDb)) {
XSetForeground(pWin->pDisp,pArea->attr.gc,color.pixel);
}
else
return -1;
}
}
#endif
return 0;
}
if (code == PPR_ATTR_PATT_ARRAY) {
pArea->attr.pPatt = (short *)pArg;
if (pArg != NULL) {
pArea->attr.sub = 0;
pArea->attr.rem = pArea->attr.pPatt[0];
pArea->attr.pen = 1;
}
return 0;
}
if (code == PPR_ATTR_STRIP) {
#ifdef XWINDOWS
pWin = pArea->pWin;
if (pWin->winType != PPR_WIN_SCREEN)
return 0;
if (pArea->linkedTo == NULL) {
if (pArea->pixMap != NULL)
XFreePixmap(pWin->pDisp, pArea->pixMap);
if (pArea->stipple != NULL)
XFreePixmap(pWin->pDisp, pArea->stipple);
if (pArea->pixMapGC != NULL)
XFreeGC(pWin->pDisp, pArea->pixMapGC);
}
if (arg != 0) {
static char stipple[8]={0,0,0,0,0,0,0,0};
pArea->usePixMap = 1;
if (pArg != NULL) {
PPR_AREA *pArea1=(PPR_AREA *)pArg;
pArea->pixMapWidth = pArea1->pixMapWidth;
pArea->pixMapHeight = pArea1->pixMapHeight;
pArea->pixMap = pArea1->pixMap;
pArea->pixMapGC = pArea1->pixMapGC;
pArea->stipple = pArea1->stipple;
pArea->linkedTo = pArea1;
return 0;
}
pArea->pixMapWidth = pArea->xPixRight - pArea->xPixLeft + 1;
pArea->pixMapHeight = pArea->yPixTop - pArea->yPixBot + 2;
pArea->pixMap = XCreatePixmap(pWin->pDisp, pWin->plotWindow,
pArea->pixMapWidth, pArea->pixMapHeight,
DefaultDepth(pWin->pDisp, DefaultScreen(pWin->pDisp)));
PprAssertAlways(pArea->pixMap != NULL);
pArea->pixMapGC = XCreateGC(pWin->pDisp, pWin->plotWindow, 0, NULL);
PprAssertAlways(pArea->pixMapGC != NULL);
XCopyGC(pWin->pDisp, pArea->attr.gc,
GCBackground|GCForeground, pArea->pixMapGC);
XSetFunction(pWin->pDisp, pArea->pixMapGC, GXcopy);
pArea->stipple = XCreatePixmapFromBitmapData(pWin->pDisp,
pArea->pixMap, stipple, 8, 8, 1, 0, 1);
PprAssertAlways(pArea->stipple != NULL);
XSetStipple(pWin->pDisp, pArea->pixMapGC, pArea->stipple);
XSetFillStyle(pWin->pDisp, pArea->pixMapGC, FillOpaqueStippled);
XFillRectangle(pWin->pDisp, pArea->pixMap, pArea->pixMapGC,
0, 0, pArea->pixMapWidth+1, pArea->pixMapHeight+1);
}
else {
pArea->usePixMap = 0;
pArea->linkedTo = NULL;
}
#endif
return 0;
}
return -1;
}
/*+/subr**********************************************************************
* NAME pprAutoEnds - choose `clean' endpoint valuess for an axis
*
* DESCRIPTION
* For a specific numeric range, this routine calculates a possibly
* altered numeric range which will produce more tasteful axis
* calibration.
*
* RETURNS
* void
*
* BUGS
* o this routine should probably focus some attention on choice of
* number of intervals for an axis; presently, the new endpoints
* chosen by this routine may be difficult to use for choosing
* interval size
* o uses exp10(), which doesn't exist in VxWorks
* o only linear calibration is handled
*
* SEE ALSO
* pprAutoInterval, pprAutoRange, pprAreaOpen
*
*-*/
void
pprAutoEnds(left, right, pLeftNew, pRightNew)
double left; /* I leftmost value */
double right; /* I rightmost value */
double *pLeftNew; /* O new leftmost value */
double *pRightNew; /* O new rightmost value */
{
double x1, x2, x1a, x2a, exp1, exp2, new1, new2;
double pwr1, pwr2, pwr;
if (left == right) {
if (left == 0.) {
left = -1.;
right = 1.;
}
else if (left < 0.) {
left -= 1.;
right = 0.;
}
else {
left = 0.;
right += 1.;
}
}
/*-----------------------------------------------------------------------------
* if axis if "reversed", temporarily put it "normal", to make life easy
*----------------------------------------------------------------------------*/
if (left > right) { x1 = right; x2 = left; }
else { x1 = left; x2 = right; }
/*-----------------------------------------------------------------------------
* now, find a reasonable place to round each end to; the larger magnitude
* number controls to what "boundary" to round. Use absolute values in
* the sleuthing.
*----------------------------------------------------------------------------*/
x1a = x1 >= 0. ? x1 : -x1;
if (x1a == 0.)
pwr1 = x1a;
else
pwr1 = exp10((double)((int)log10(x1a)));
x2a = x2 >= 0. ? x2 : -x2;
if (x2a == 0.)
pwr2 = x2a;
else
pwr2 = exp10((double)((int)log10(x2a)));
pwr = pwr1>pwr2 ? pwr1 : pwr2;
/*-----------------------------------------------------------------------------
* actually do the rounding; and restore the values' original signs
*----------------------------------------------------------------------------*/
if (x1 < 0.) { new1 = (1+(int)(x1a/pwr-.0001)) * pwr; new1 = -new1; }
else new1 = ((int)(x1a/pwr-.0001)) * pwr;
if (x2 < 0.) { new2 = ((int)(x2a/pwr-.0001)) * pwr; new2 = -new2; }
else new2 = (1+(int)(x2a/pwr-.0001)) * pwr;
/*-----------------------------------------------------------------------------
* unscramble if input was "reversed"; and give values to caller
*----------------------------------------------------------------------------*/
if (left < right) {
*pLeftNew = new1;
*pRightNew = new2;
}
else {
*pLeftNew = new2;
*pRightNew = new1;
}
}
/*+/subr**********************************************************************
* NAME pprAutoInterval - figure out good interval size for an axis
*
* DESCRIPTION
* Determine a "good" interval size for an axis, so that axis
* annotation will be tasteful.
*
* RETURNS
* void
*
* BUGS
* o this routine always chooses to divide an axis into 5 intervals
* o only linear calibration is handled
*
* SEE ALSO
* pprAutoEnds, pprAutoRange, pprAreaOpen
*
*-*/
void
pprAutoInterval(val1, val2, pNint)
double val1; /* I value at one end of axis */
double val2; /* I value at other end of axis */
int *pNint; /* O number of intervals */
{
#define PPR_EQ(v1, v2) PprAbs((v2)-(v1)) <= slop
double vmin, vmax;
double slop; /* differences no larger mean == */
double diff, ratio, aint;
int nInt;
slop = PprAbs(val2 - val1);
vmin = PprMin(val1, val2);
vmax = PprMax(val1, val2);
if (PPR_EQ(vmin, 0.))
/* pprAutoInt(vmax, &nInt); */
;
else if (PPR_EQ(vmax, 0.))
/* pprAutoInt(vmin, &nInt); */
;
else if (vmin < 0. && vmax > 0.) {
;
}
nInt = 5.;
*pNint = nInt;
}
/*+/macro*********************************************************************
* NAME pprAutoRange - find minimum and maximum values for an array
*
* DESCRIPTION
* Finds the minimum and maximum values in an array of values.
*
* Four different routines are available, depending on the type of
* the input array. Each returns the min and max as a double:
*
* void pprAutoRangeD(doubleArray, nPoints, doubleMin, doubleMax)
* void pprAutoRangeF(floatArray, nPoints, doubleMin, doubleMax)
* void pprAutoRangeL(longArray, nPoints, doubleMin, doubleMax)
* void pprAutoRangeS(shortArray, nPoints, doubleMin, doubleMax)
*
* RETURNS
* void
*
* SEE ALSO
* pprAutoEnds, pprAutoInterval, pprAreaOpen
*
*-*/
void pprAutoRangeD(dblArray, npts, dblMin, dblMax)
double *dblArray; /* I data value array */
int npts; /* I number of data points */
double *dblMin; /* O minimum value in array */
double *dblMax; /* O maximum value in array */
{
int i;
*dblMin = *dblMax = dblArray[0];
for (i=1; i<npts; i++) {
if (*dblMin > dblArray[i]) *dblMin = dblArray[i];
if (*dblMax < dblArray[i]) *dblMax = dblArray[i];
}
}
void pprAutoRangeF(fltArray, npts, dblMin, dblMax)
float *fltArray; /* I data value array */
int npts; /* I number of data points */
double *dblMin; /* O minimum value in array */
double *dblMax; /* O maximum value in array */
{
int i;
*dblMin = *dblMax = fltArray[0];
for (i=1; i<npts; i++) {
if (*dblMin > fltArray[i]) *dblMin = fltArray[i];
if (*dblMax < fltArray[i]) *dblMax = fltArray[i];
}
}
void pprAutoRangeL(lngArray, npts, dblMin, dblMax)
long *lngArray; /* I data value array */
int npts; /* I number of data points */
double *dblMin; /* O minimum value in array */
double *dblMax; /* O maximum value in array */
{
int i;
*dblMin = *dblMax = lngArray[0];
for (i=1; i<npts; i++) {
if (*dblMin > lngArray[i]) *dblMin = lngArray[i];
if (*dblMax < lngArray[i]) *dblMax = lngArray[i];
}
}
void pprAutoRangeS(shtArray, npts, dblMin, dblMax)
short *shtArray; /* I data value array */
int npts; /* I number of data points */
double *dblMin; /* O minimum value in array */
double *dblMax; /* O maximum value in array */
{
int i;
*dblMin = *dblMax = shtArray[0];
for (i=1; i<npts; i++) {
if (*dblMin > shtArray[i]) *dblMin = shtArray[i];
if (*dblMax < shtArray[i]) *dblMax = shtArray[i];
}
}
static int pprTrigInit=0;
static double pprCos[361]; /* cos for 0-90, in .25 steps */
/*+/subr**********************************************************************
* NAME pprCos_deg - get the cosine of an angle in degrees
*
* DESCRIPTION
* Get the cosine of an angle in degrees. A table lookup technique
* is used. The angle argument is truncated to the next lower 1/4
* degree prior to lookup.
*
* RETURNS
* cosine
*
*-*/
double
pprCos_deg(angle)
double angle; /* I angle, in degrees */
{
int indx;
double cosine;
if (!pprTrigInit) {
int i;
double angle;
pprTrigInit = 1;
for (i=0; i<=360; i++) {
angle = (double)i / 4. * .017453292;
pprCos[i] = cos(angle);
}
}
indx = angle * 4.;
if (indx < 0)
indx = -indx;
if (indx >= 1440)
indx %= 1440;
if (indx <= 360)
cosine = pprCos[indx];
else if ((indx -= 360) <= 360)
cosine = -pprCos[360 - indx];
else if ((indx -= 360) <= 360)
cosine = -pprCos[indx];
else {
indx -= 360;
cosine = pprCos[360 - indx];
}
return cosine;
}
/*+/subr**********************************************************************
* NAME pprChar - plot a character
*
* DESCRIPTION
* Plots a single text character at a location. The center of the
* character is placed at the specified x,y position.
*
* The character height specification is in terms of a fraction of the
* height of the window. This results in automatic scaling of
* character sizes as the window size changes. If a height of zero
* is specified in the call, then the default height for the plot
* area is used. (The default height was established by pprAreaOpen.)
*
* A macro is available which returns the default character height
* used by this plot package. The value returned is proportional to
* the height of the plot area. This value can be used to generate
* "big" and "small" character sizes.
*
* PprDfltCharHt(lowYfrac, highYfrac)
*
* lowYfrac is the vertical fraction of the window at which
* the bottom edge of the plot area lies
* highYfrac is the vertical fraction of the window at which
* the top edge of the plot area lies
*
* RETURNS
* void
*
* BUGS
* o technique used works only with linear axes
* o ASCII character codes are assumed
* o no checks are made for illegal characters
*
* SEE ALSO
* pprText, pprAreaOpen, pprLine, pprPoint
*
*-*/
void
pprChar(pArea, x, y, chr, height, angle)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate of character */
double y; /* I y data coordinate of character */
char chr; /* I character to plot */
double height; /* I height of character, as a fraction of
the height of the window; a value of
zero results in using a default height */
double angle; /* I orientation angle of character, ccw degrees */
{
double xWin, yWin;
double scale; /* convert character units to win coord */
double cosT, sinT;
char str[2];
if (height <= 0.)
height = pArea->charHt;
else
height *= pArea->pWin->height;
xWin = pArea->xPixLeft + .5 + (x - pArea->xLeft) * pArea->xScale;
yWin = pArea->yPixBot + .5 + (y - pArea->yBot) * pArea->yScale;
if (pArea->pWin->winType == PPR_WIN_SCREEN) {
if (angle == 0.) cosT = 1., sinT = 0.;
else if (angle == 90.) cosT = 0., sinT = 1.;
else { cosT = pprCos_deg(angle);
sinT = pprSin_deg(angle);
}
scale = height / 6.;
pprText1(pArea,
xWin, yWin, chr, 0, scale, sinT, cosT, pprLineSegPixD_ac);
}
else {
height = 1.5 * height;
str[0] = chr;
str[1] = '\0';
pprTextPS(pArea->pWin->file, xWin, yWin,PPR_TXT_CEN,str,height,angle);
}
}
/*+/subr**********************************************************************
* NAME pprCvtDblToTxt - convert double to text, being STINGY with space
*
* DESCRIPTION
* Convert a double value to text. The main usefulness of this routine
* is that it maximizes the amount of information presented in a
* minimum number of characters. For example, if a 1 column width
* is specified, only the sign of the value is presented.
*
* A secondary usefulness of this routine is that for small numbers
* it uses the last argument as a number of significant digits rather
* than as the number of decimal places.
*
* When an exponent is needed to represent the value, for narrow
* column widths only the exponent appears. If there isn't room
* even for the exponent, large positive exponents will appear as E*,
* and large negative exponents will appear as E-.
*
* Negative numbers receive some special treatment. In narrow
* columns, very large negative numbers may be represented as - and
* very small negative numbers may be represented as -. or -.E- .
*
* Some example outputs follow (with 3 decimal places assumed):
*
* value printed values for column widths
* 1 2 3 4 5 6 7
*
* 0.000 0 0 0 0 0 0 0
* -1.000 - -1 -1 -1 -1 -1 -1
* 0.123 + E- .12 .123 .123 .123 .123
* -0.00123 - -. -. -.E- -1E-3 -12E-4 -123E-5
* -12.3 - - -12 -12 -12.3 -12.30 -12.300
* 123 + E2 123 123 123.0 123.00 123.000
*
*-*/
void
pprCvtDblToTxt(text, width, value, sigDig)
char *text; /* O text representation of value */
int width; /* I max width of text string (not counting '\0') */
double value; /* I value to print */
int sigDig; /* I max # of dec places to print */
{
double valAbs; /* absolute value of caller's value */
int wholeNdig; /* number of digits in "whole" part of value */
double logVal; /* log10 of value */
int decPlaces; /* number of decimal places to print */
int expI; /* exponent for frac values */
double expD;
int expWidth; /* width needed for exponent field */
int excess; /* number of low order digits which
won't fit into the field */
char tempText[100]; /* temp for fractional conversions */
int roomFor;
int minusWidth; /* amount of room for - sign--0 or 1 */
double temp;
/*-----------------------------------------------------------------------------
* special cases
*----------------------------------------------------------------------------*/
#define D1 .000000001
if (value >= 0.) {
for (temp=0.; temp<=9.; temp+=1.) {
if (value >= temp-D1 && value <= temp+D1) {
sprintf(text, "%.0f", temp);
return;
}
}
}
if (width == 1) {
if (value >= 0)
strcpy(text, "+");
else
strcpy(text, "-");
return;
}
else if (value < 0.) {
for (temp=-1.; temp>=-9.; temp-=1.) {
if (value >= temp-D1 && value <= temp+D1) {
sprintf(text, "%.0f", temp);
return;
}
}
}
else if (width == 2 && value < -1.) {
strcpy(text, "-");
return;
}
valAbs = value>0. ? value : -value;
logVal = log10(valAbs);
strcpy(tempText, " ");
if (logVal < 0.) {
/*-----------------------------------------------------------------------------
* numbers with only a fractional part
*----------------------------------------------------------------------------*/
if (width == 2) {
if (value > 0.)
strcpy(tempText, "0E-");
else
strcpy(tempText, "0-.");
}
else if (width == 3 && value < 0)
strcpy(tempText, "0-.");
else {
if (value < 0.)
minusWidth = 1;
else
minusWidth = 0;
if (logVal >= -1.)
expI = -1 * ceil(logVal);
else
expI = sigDig - ceil(logVal);
if (expI < 9) expWidth = 3; /* need E-n */
else if (expI < 99) expWidth = 4; /* need E-nn */
else if (expI < 999) expWidth = 5; /* need E-nnn */
else expWidth = 6; /* need E-nnnn */
/*-----------------------------------------------------------------------------
* figure out how many significant digits can appear. For numbers between
* .1 and .999, a . will be printed; for numbers between 0. and .0999,
* no . will be printed, and number will be normalized.
*----------------------------------------------------------------------------*/
if (logVal >= -1.)
roomFor = width - expI - 1 - minusWidth;
else
roomFor = width - expWidth - minusWidth;
if (roomFor >= 1 && logVal >= -1.) {
decPlaces = expI + sigDig;
if (decPlaces > width -1 - minusWidth)
decPlaces = roomFor + expI;
if (decPlaces > sigDig)
decPlaces = sigDig;
(void)sprintf(tempText, "%.*f", decPlaces, value);
if (value < 0.)
tempText[1] = '-';
}
else if (roomFor >= 1) {
long t;
if (roomFor < sigDig)
expI -= (sigDig - roomFor);
else
roomFor = sigDig;
t = value * exp10((double)expI);
(void)sprintf(&tempText[1], "%dE-%d", t, expI);
}
else {
expD = expI;
value *= exp10(expD);
if (value > 0.)
sprintf(tempText, "0.E-%d", expI);
else
sprintf(tempText, "--.E-%d", expI);
}
}
if (strlen(tempText) > 1)
strncpy(text, &tempText[1], width);
else
strcpy(text, tempText);
text[width] = '\0';
return;
}
/*-----------------------------------------------------------------------------
* numbers with both an integer and a fractional part
*
* find out how many columns are required to represent the integer part
* of the value. A - is counted as a column; the . isn't.
*----------------------------------------------------------------------------*/
wholeNdig = 1 + (int)logVal;
if (value < 0.)
wholeNdig++;
if (wholeNdig < width-1) {
/*-----------------------------------------------------------------------------
* the integer part fits well within the field. Find out how many
* decimal places can be printed (honoring caller's sigDig limit).
*----------------------------------------------------------------------------*/
decPlaces = width - wholeNdig - 1;
if (sigDig < decPlaces)
decPlaces = sigDig;
if (sigDig > 0)
(void)sprintf(text, "%.*f", decPlaces, value);
else
(void)sprintf(text, "%d", nint(value));
}
else if (wholeNdig == width || wholeNdig == width-1) {
/*-----------------------------------------------------------------------------
* The integer part just fits within the field. Print the value as an
* integer, without printing the superfluous decimal point.
*----------------------------------------------------------------------------*/
(void)sprintf(text, "%d", nint(value));
}
else {
/*-----------------------------------------------------------------------------
* The integer part is too large to fit within the caller's field. Print
* with an abbreviated E notation.
*----------------------------------------------------------------------------*/
expWidth = 2; /* assume that En will work */
excess = wholeNdig - (width - 2);
if (excess > 999) {
expWidth = 5; /* no! it must be Ennnn */
excess += 3;
}
else if (excess > 99) {
expWidth = 4; /* no! it must be Ennn */
excess += 2;
}
else if (excess > 9) {
expWidth = 3; /* no! it must be Enn */
excess += 1;
}
/*-----------------------------------------------------------------------------
* Four progressively worse cases, with all or part of exponent fitting
* into field, but not enough room for any of the value
* Ennn positive value; exponent fits
* -Ennn negative value; exponent fits
* +**** positive value; exponent too big
* -**** negative value; exponent too big
*----------------------------------------------------------------------------*/
if (value >= 0. && expWidth == width)
(void)sprintf(text, "E%d", nint(logVal));
else if (value < 0. && expWidth == width-1)
(void)sprintf(text, "-E%d", nint(logVal));
else if (value > 0. && expWidth > width)
(void)sprintf(text, "%.*s", width, "+*******");
else if (value < 0. && expWidth > width-1)
(void)sprintf(text, "%.*s", width, "-*******");
else {
/*-----------------------------------------------------------------------------
* The value can fit, in exponential notation
*----------------------------------------------------------------------------*/
(void)sprintf(text, "%dE%d",
nint(value/exp10((double)excess)), excess);
}
}
}
/*+/subr**********************************************************************
* NAME pprErrorBar - plot an error bar
*
* DESCRIPTION
* Plot a line between the endpoints and draw end caps, using the color
* attribute of the plot area. Other plot area attributes are ignored.
*
* RETURNS
* void
*
* BUGS
* o only linear calibration is handled
*
* SEE ALSO
* pprLine, pprMove, pprPoint, pprText
*
*-*/
void
pprErrorBar(pArea, x1, y1, x2, y2)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x1; /* I first x point */
double y1; /* I first y point */
double x2; /* I second x point */
double y2; /* I second y point */
{
pprLineSegD_ac(pArea, x1, y1, x2, y2);
if (x1 == x2) {
pprMarkD(pArea, x1, y1, -1);
pprMarkD(pArea, x2, y2, -1);
}
else {
pprMarkD(pArea, x1, y1, -2);
pprMarkD(pArea, x2, y2, -2);
}
}
/*+/subr**********************************************************************
* NAME pprGrid - draw a grid
*
* DESCRIPTION
* Draw a perimeter and grid lines. The number of intervals
* specified in the plot area structure is used for placing
* the grid lines.
*
* The color attributes for the plot window are used for drawing;
* dashed line and line thickness are ignored.
*
* RETURNS
* void
*
* BUGS
* o only linear axes are handled
*
* SEE ALSO
* pprGridLabel, pprGridErase, pprPerim, pprAnnotX, pprAnnotY, pprAreaOpen
*
*-*/
void
pprGrid(pArea)
PPR_AREA *pArea; /* I pointer to plot area structure */
{
int i;
double x, y;
static short patt[]={1, 14, 0};
/*-----------------------------------------------------------------------------
* draw the box
*----------------------------------------------------------------------------*/
pprMoveD_wc(pArea, pArea->xLeft, pArea->yBot, 0);
pprMoveD_wc(pArea, pArea->xRight, pArea->yBot, 1);
pprMoveD_wc(pArea, pArea->xRight, pArea->yTop, 1);
pprMoveD_wc(pArea, pArea->xLeft, pArea->yTop, 1);
pprMoveD_wc(pArea, pArea->xLeft, pArea->yBot, 1);
/*-----------------------------------------------------------------------------
* draw the vertical grid lines
*----------------------------------------------------------------------------*/
x = pArea->xLeft;
for (i=1; i<pArea->xNint; i++) {
x += pArea->xInterval;
pprLineSegDashD_wc(pArea, x, pArea->yBot, x, pArea->yTop, patt);
}
/*-----------------------------------------------------------------------------
* ditto for y axis
*----------------------------------------------------------------------------*/
y = pArea->yBot;
for (i=1; i<pArea->yNint; i++) {
y += pArea->yInterval;
pprLineSegDashD_wc(pArea, pArea->xLeft, y, pArea->xRight, y, patt);
}
}
/*+/subr**********************************************************************
* NAME pprGridErase - erase within a grid
*
* DESCRIPTION
* Erases the screen inside the grid for the plot area. (Actually,
* the entire data area is erased and then the grid is redrawn.)
*
* RETURNS
* void
*
* SEE ALSO
* pprPerimErase, pprAreaErase, pprWinErase, pprRegionErase
* the ppr...Erase... entry points for the various drawing routines
*
*-*/
void
pprGridErase(pArea)
PPR_AREA *pArea; /* I pointer to plot area structure */
{
int x,y,width,height;
if (pArea->pWin->winType != PPR_WIN_SCREEN)
return;
x = pArea->xPixLeft - 3;
y = pArea->yPixBot - 3;
width = (pArea->xRight - pArea->xLeft) * pArea->xScale + 6;
height = (pArea->yTop - pArea->yBot) * pArea->yScale + 6;
#ifdef SUNVIEW
y = pArea->pWin->height - y - height;
pw_writebackground(pArea->pWin->pw, x, y, width, height, PIX_SRC);
pprGrid(pArea);
#else
#if defined XWINDOWS
y = pArea->pWin->height - y - height;
XClearArea(pArea->pWin->pDisp, pArea->pWin->plotWindow,
x, y, width, height, False);
if (pArea->pixMap != NULL) {
XFillRectangle(pArea->pWin->pDisp, pArea->pixMap, pArea->pixMapGC,
0, 0, pArea->pixMapWidth+1, pArea->pixMapHeight+1);
}
pprGrid(pArea);
XFlush(pArea->pWin->pDisp);
#endif
#endif
}
/*+/subr**********************************************************************
* NAME pprGridLabel - draw and label a grid
*
* DESCRIPTION
* Draw a perimeter and grid lines. The number of intervals
* specified in the plot area structure is used for placing
* the grid lines.
*
* Axis labels and annotations are drawn using the information from
* the plot area, as specified in the pprAreaOpen call.
*
* RETURNS
* void
*
* BUGS
* o only linear axes are handled
*
* SEE ALSO
* pprGrid, pprPerim, pprAnnotX, pprAnnotY, pprAreaOpen
*
*-*/
void
pprGridLabel(pArea, xLabel, xAnnot, yLabel, yAnnot, angle)
PPR_AREA *pArea; /* I pointer to plot area structure */
char *xLabel; /* I label for x axis, or NULL */
char **xAnnot; /* I pointer to array of x annotations, or NULL */
char *yLabel; /* I label for y axis, or NULL */
char **yAnnot; /* I pointer to array of y annotations, or NULL */
double angle; /* I angle for y annotations; 0. or 90. */
{
pprGrid(pArea);
pprAnnotX(pArea, 0, pArea->xLeft, pArea->xRight, pArea->xNint,
0, xLabel, xAnnot, 0.);
pprAnnotY(pArea, 0, pArea->yBot, pArea->yTop, pArea->yNint,
0, yLabel, yAnnot, angle);
}
/*+/subr**********************************************************************
* NAME pprLine - plot a line using x and y data value vectors
*
* DESCRIPTION
* Draw a line along the path specified by two value arrays.
*
* Several entry points are available to accomodate various
* types of data:
*
* pprLineF(pArea, x, y, npts) x and y are float[]
* pprLineD(pArea, x, y, npts) x and y are double[]
* pprLineS(pArea, x, y, npts) x and y are short[]
* pprLineL(pArea, x, y, npts) x and y are long[]
*
* Several entry points are available for erasing:
*
* pprLineEraseF(pArea, x, y, npts) x and y are float[]
* pprLineEraseD(pArea, x, y, npts) x and y are double[]
* pprLineEraseS(pArea, x, y, npts) x and y are short[]
* pprLineEraseL(pArea, x, y, npts) x and y are long[]
*
* RETURNS
* void
*
* BUGS
* o only linear calibration is handled
*
* SEE ALSO
* pprLineSeg, pprMove, pprPoint, pprText
*
*-*/
void
pprLineF(pArea, x, y, npts)
PPR_AREA *pArea; /* I pointer to plot area structure */
float *x; /* I x array of data values */
float *y; /* I y array of data values */
int npts; /* I number of points to plot */
{
int i;
pprMoveD(pArea, (double)(x[0]), (double)(y[0]), 0);
for (i=1; i<npts; i++)
pprMoveD(pArea, (double)(x[i]), (double)(y[i]), 1);
}
void
pprLineD(pArea, x, y, npts)
PPR_AREA *pArea; /* I pointer to plot area structure */
double *x; /* I x array of data values */
double *y; /* I y array of data values */
int npts; /* I number of points to plot */
{
int i;
pprMoveD(pArea, x[0], y[0], 0);
for (i=1; i<npts; i++)
pprMoveD(pArea, x[i], y[i], 1);
}
void
pprLineS(pArea, x, y, npts)
PPR_AREA *pArea; /* I pointer to plot area structure */
short *x; /* I x array of data values */
short *y; /* I y array of data values */
int npts; /* I number of points to plot */
{
int i;
pprMoveD(pArea, (double)x[0], (double)y[0], 0);
for (i=1; i<npts; i++)
pprMoveD(pArea, (double)x[i], (double)y[i], 1);
}
void
pprLineL(pArea, x, y, npts)
PPR_AREA *pArea; /* I pointer to plot area structure */
long *x; /* I x array of data values */
long *y; /* I y array of data values */
int npts; /* I number of points to plot */
{
int i;
pprMoveD(pArea, (double)x[0], (double)y[0], 0);
for (i=1; i<npts; i++)
pprMoveD(pArea, (double)x[i], (double)y[i], 1);
}
void
pprLineEraseF(pArea, x, y, npts)
PPR_AREA *pArea; /* I pointer to plot area structure */
float *x; /* I x array of data values */
float *y; /* I y array of data values */
int npts; /* I number of points to plot */
{
int i;
pprMoveD(pArea, (double)(x[0]), (double)(y[0]), 0);
for (i=1; i<npts; i++)
pprMoveEraseD(pArea, (double)(x[i]), (double)(y[i]));
}
void
pprLineEraseD(pArea, x, y, npts)
PPR_AREA *pArea; /* I pointer to plot area structure */
double *x; /* I x array of data values */
double *y; /* I y array of data values */
int npts; /* I number of points to plot */
{
int i;
pprMoveD(pArea, x[0], y[0], 0);
for (i=1; i<npts; i++)
pprMoveEraseD(pArea, x[i], y[i]);
}
void
pprLineEraseS(pArea, x, y, npts)
PPR_AREA *pArea; /* I pointer to plot area structure */
short *x; /* I x array of data values */
short *y; /* I y array of data values */
int npts; /* I number of points to plot */
{
int i;
pprMoveD(pArea, (double)x[0], (double)y[0], 0);
for (i=1; i<npts; i++)
pprMoveEraseD(pArea, (double)x[i], (double)y[i]);
}
void
pprLineEraseL(pArea, x, y, npts)
PPR_AREA *pArea; /* I pointer to plot area structure */
long *x; /* I x array of data values */
long *y; /* I y array of data values */
int npts; /* I number of points to plot */
{
int i;
pprMoveD(pArea, (double)x[0], (double)y[0], 0);
for (i=1; i<npts; i++)
pprMoveEraseD(pArea, (double)x[i], (double)y[i]);
}
/*+/subr**********************************************************************
* NAME pprLineSeg - plot a line segment between a pair of points
*
* DESCRIPTION
* Move to the first point and then draw a line to the second, using
* the line attributes of the plot area. If the attributes indicate a
* dashed line, the current dashed line pattern will be used.
*
* Two entry points are available:
*
* pprLineSegD(pArea, x1, y1, x2, y2) x and y are double
* pprLineSegL(pArea, x1, y1, x2, y2) x and y are long
*
* For drawing ignoring the dashed line, line thickness, and other plot
* area attributes, but using the area color attribute, two alternate
* entry points are available:
*
* pprLineSegD_ac(pArea, x1, y1, x2, y2) x and y are double
* pprLineSegL_ac(pArea, x1, y1, x2, y2) x and y are long
*
* Two entry points are available for erasing:
*
* pprLineSegEraseD(pArea, x1, y1, x2, y2) x and y are double
* pprLineSegEraseL(pArea, x1, y1, x2, y2) x and y are long
* RETURNS
* void
*
* BUGS
* o only linear calibration is handled
*
* SEE ALSO
* pprLine, pprMove, pprPoint, pprText
*
*-*/
void
pprLineSegD(pArea, x1, y1, x2, y2)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x1; /* I first x point */
double y1; /* I first y point */
double x2; /* I second x point */
double y2; /* I second y point */
{
pprMoveD(pArea, x1, y1, 0);
pprMoveD(pArea, x2, y2, 1);
}
void
pprLineSegL(pArea, x1, y1, x2, y2)
PPR_AREA *pArea; /* I pointer to plot area structure */
long x1; /* I first x point */
long y1; /* I first y point */
long x2; /* I second x point */
long y2; /* I second y point */
{
pprMoveD(pArea, (double)x1, (double)y1, 0);
pprMoveD(pArea, (double)x2, (double)y2, 1);
}
void
pprLineSegD_ac(pArea, x1, y1, x2, y2)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x1; /* I first x point */
double y1; /* I first y point */
double x2; /* I second x point */
double y2; /* I second y point */
{
pprMoveD_ac(pArea, x1, y1, 0);
pprMoveD_ac(pArea, x2, y2, 1);
}
void
pprLineSegD_wc(pArea, x1, y1, x2, y2)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x1; /* I first x point */
double y1; /* I first y point */
double x2; /* I second x point */
double y2; /* I second y point */
{
pprMoveD_wc(pArea, x1, y1, 0);
pprMoveD_wc(pArea, x2, y2, 1);
}
void
pprLineSegL_ac(pArea, x1, y1, x2, y2)
PPR_AREA *pArea; /* I pointer to plot area structure */
long x1; /* I first x point */
long y1; /* I first y point */
long x2; /* I second x point */
long y2; /* I second y point */
{
pprMoveD_ac(pArea, (double)x1, (double)y1, 0);
pprMoveD_ac(pArea, (double)x2, (double)y2, 1);
}
void
pprLineSegEraseD(pArea, x1, y1, x2, y2)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x1; /* I first x point */
double y1; /* I first y point */
double x2; /* I second x point */
double y2; /* I second y point */
{
pprMoveD(pArea, x1, y1, 0);
pprMoveEraseD(pArea, x2, y2);
}
void
pprLineSegEraseL(pArea, x1, y1, x2, y2)
PPR_AREA *pArea; /* I pointer to plot area structure */
long x1; /* I first x point */
long y1; /* I first y point */
long x2; /* I second x point */
long y2; /* I second y point */
{
pprMoveD(pArea, (double)x1, (double)y1, 0);
pprMoveEraseD(pArea, (double)x2, (double)y2);
}
/*+/internal******************************************************************
* NAME pprLineSegPix - line segment routine private to pprPlot
*
* DESCRIPTION
* Provides `nitty-gritty' interface to the various platforms.
*
* pprLineSegPixD_ac - uses attributes for plot area: thick, color
* pprLineSegPixL_ac - uses attributes for plot area: thick, color
* pprLineSegPixD_wc - uses attributes for plot window: thick, color
* pprLineSegPixL_wc - uses attributes for plot window: thick, color
*
* RETURNS
* void
*
*-*/
#ifdef SUNVIEW
short glSvPattern[3]={100,0,0}; /* line pattern to make pw_line happy */
struct pr_texture texture;
static int initTexture=1;
static initTex()
{
bzero((char *)&texture, sizeof(texture));
texture.pattern = glSvPattern;
texture.offset = 0;
texture.options.startpoint = 1;
texture.options.endpoint = 1;
texture.options.givenpattern = 1;
initTexture = 0;
}
#endif
static void
pprLineSegPixD_ac(pArea, xp0, yp0, xp1, yp1)
PPR_AREA *pArea;
double xp0, xp1, yp0, yp1; /* y must be corrected properly by the caller */
{
pprLineSegPixL_ac(pArea, (long)(xp0+.5), (long)(yp0+.5),
(long)(xp1+.5), (long)(yp1+.5));
}
static void
pprLineSegPixL_ac(pArea, xp0, yp0, xp1, yp1)
PPR_AREA *pArea;
long xp0, xp1, yp0, yp1; /* y must be corrected properly by the caller
for the windowing system being used. I.e.,
most of the pprXxx routines assume 0,0 is
lower left, but X and SunView assume it is
upper left--the caller must have dealt with
this. */
{
#ifdef SUNVIEW
if (initTexture)
initTex();
#endif
if (pArea->pWin->winType == PPR_WIN_SCREEN) {
#ifdef SUNVIEW
if (pArea->pWin->brush.width > 1)
pw_line(pArea->pWin->pw, xp0, yp0, xp1, yp1,
&pArea->pWin->brush, &texture, (int)PIX_SRC);
else
pw_vector(pArea->pWin->pw, xp0, yp0, xp1, yp1, PIX_SRC, 1);
#else
#if defined XWINDOWS
/*-----------------------------------------------------------------------------
* !!!! NOTE WELL !!!! Various routines have these plotting statements
* for calling XDrawLine. If you modify the statements here, modify
* the other places too!!
*----------------------------------------------------------------------------*/
if (xp0 != xp1 || yp0 != yp1) {
XDrawLine(pArea->pWin->pDisp, pArea->pWin->plotWindow,
pArea->attr.gc, xp0, yp0, xp1, yp1);
if (pArea->usePixMap) {
XDrawLine(pArea->pWin->pDisp, pArea->pixMap, pArea->attr.gc,
xp0 - pArea->xPixLeft,
yp0 - (pArea->pWin->height - pArea->yPixTop),
xp1 - pArea->xPixLeft,
yp1 - (pArea->pWin->height - pArea->yPixTop));
}
}
#endif
#endif
}
else if (pArea->pWin->winType == PPR_WIN_POSTSCRIPT ||
pArea->pWin->winType == PPR_WIN_EPS) {
(void)fprintf(pArea->pWin->file, "%d %d %d %d DS\n",
xp0, yp0, xp1, yp1);
}
}
static void
pprLineSegPixD_wc(pArea, xp0, yp0, xp1, yp1)
PPR_AREA *pArea;
double xp0, xp1, yp0, yp1; /* y must be corrected properly by the caller */
{
pprLineSegPixL_wc(pArea, (long)(xp0+.5), (long)(yp0+.5),
(long)(xp1+.5), (long)(yp1+.5));
}
static void
pprLineSegPixL_wc(pArea, xp0, yp0, xp1, yp1)
PPR_AREA *pArea;
long xp0, xp1, yp0, yp1; /* y must be corrected properly by the caller
for the windowing system being used. I.e.,
most of the pprXxx routines assume 0,0 is
lower left, but X and SunView assume it is
upper left--the caller must have dealt with
this. */
{
#ifdef SUNVIEW
if (initTexture)
initTex();
#endif
if (pArea->pWin->winType == PPR_WIN_SCREEN) {
#ifdef SUNVIEW
if (pArea->pWin->brush.width > 1)
pw_line(pArea->pWin->pw, xp0, yp0, xp1, yp1,
&pArea->pWin->brush, &texture, (int)PIX_SRC);
else
pw_vector(pArea->pWin->pw, xp0, yp0, xp1, yp1, PIX_SRC, 1);
#else
#if defined XWINDOWS
if (xp0 != xp1 || yp0 != yp1)
XDrawLine(pArea->pWin->pDisp, pArea->pWin->plotWindow,
pArea->pWin->attr.gc, xp0, yp0, xp1, yp1);
#endif
#endif
}
else if (pArea->pWin->winType == PPR_WIN_POSTSCRIPT ||
pArea->pWin->winType == PPR_WIN_EPS) {
(void)fprintf(pArea->pWin->file, "%d %d %d %d DS\n",
xp0, yp0, xp1, yp1);
}
}
static void
pprLineSegPixEraseL(pArea, xp0, yp0, xp1, yp1)
PPR_AREA *pArea;
long xp0, xp1, yp0, yp1; /* y must be corrected properly by the caller
for the windowing system being used. I.e.,
most of the pprXxx routines assume 0,0 is
lower left, but X and SunView assume it is
upper left--the caller must have dealt with
this. */
{
#ifdef SUNVIEW
if (initTexture)
initTex();
#endif
if (pArea->pWin->winType != PPR_WIN_SCREEN)
return;
#ifdef SUNVIEW
if (pArea->pWin->brush.width > 1)
pw_line(pArea->pWin->pw, xp0, yp0, xp1, yp1,
&pArea->pWin->brush, &texture, (int)(PIX_NOT(PIX_SRC)&PIX_DST));
else
pw_vector(pArea->pWin->pw, xp0, yp0, xp1, yp1, PIX_SRC, 0);
#else
#if defined XWINDOWS
if (xp0 != xp1 || yp0 != yp1)
XDrawLine(pArea->pWin->pDisp, pArea->pWin->plotWindow,
pArea->pWin->attr.gcBG, xp0, yp0, xp1, yp1);
#endif
#endif
}
static void
pprLineSegPixEraseD(pArea, xp0, yp0, xp1, yp1)
PPR_AREA *pArea;
double xp0, xp1, yp0, yp1; /* y must be corrected properly by the caller */
{
pprLineSegPixEraseL(pArea, (long)(xp0+.5), (long)(yp0+.5),
(long)(xp1+.5), (long)(yp1+.5));
}
/*+/internal******************************************************************
* NAME pprLineSegDashD_wc - drawing a dashed line segment
*
* DESCRIPTION
* Draws a dashed line between the specified points. The dashed line
* starts at the beginning of the specified pattern. The dashes are
* drawn using the plot window color.
*
* (The dashed line attributes for the plot area are neither used nor
* altered.)
*
* No clipping service is provided.
*
* RETURNS
* void
*
*-*/
static void
pprLineSegDashD_wc(pArea, x0, y0, x1, y1, pPatt)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x0; /* I x data coordinate of first point */
double y0; /* I y data coordinate of first point */
double x1; /* I x data coordinate of second point */
double y1; /* I y data coordinate of second point */
short *pPatt; /* I pointer to pattern array */
{
double xp0,yp0,xp1,yp1;
double xpA,ypA,xpB;
double segLen, endLen, dashLen, xbeg, xend, ybeg, yend;
int pen=0, sub=-1, rem=0;
xbeg = xp0 = pArea->xPixLeft + .5 + (x0 - pArea->xLeft) * pArea->xScale;
ybeg = yp0 = pArea->yPixBot + .5 + (y0 - pArea->yBot) * pArea->yScale;
if (pArea->pWin->winType == PPR_WIN_SCREEN)
ybeg = yp0 = pArea->pWin->height - yp0;
xp1 = pArea->xPixLeft + .5 + (x1 - pArea->xLeft) * pArea->xScale;
yp1 = pArea->yPixBot + .5 + (y1 - pArea->yBot) * pArea->yScale;
if (pArea->pWin->winType == PPR_WIN_SCREEN)
yp1 = pArea->pWin->height - yp1;
pprLineThick(pArea, pArea->pWin->attr.lineThick);
segLen = sqrt((xp1-xp0)*(xp1-xp0) + (yp1-yp0)*(yp1-yp0));
endLen = 0.;
while (endLen < segLen) {
if (rem < 1.) {
if ((rem = pPatt[++sub]) <= 0.) {
sub = 0; rem = pPatt[0]; pen = 1;
}
else
pen ^= 1;
}
dashLen = PprMin(rem, segLen-endLen);
endLen += dashLen;
if (PprAbs(endLen-segLen) < .5)
endLen = segLen;
xend = xp0 + endLen/segLen * (xp1 - xp0);
yend = yp0 + endLen/segLen * (yp1 - yp0);
if (pen) {
if (dashLen > 1.) pprLineSegPixD_wc(pArea, xbeg, ybeg, xend, yend);
else {
if (pArea->pWin->winType == PPR_WIN_SCREEN) {
#ifdef SUNVIEW
if (pArea->pWin->attr.ltPix > 1) {
ypA = ybeg;
xpA = xbeg - pArea->pWin->attr.ltPix / 2;
xpB = xpA + pArea->pWin->attr.ltPix - 1;
#else
#if defined XWINDOWS
if (pArea->attr.ltPix > 1) {
ypA = ybeg;
xpA = xbeg - pArea->attr.ltPix / 2;
xpB = xpA + pArea->attr.ltPix - 1;
#endif
#endif
/* for thick lines, draw a square 'blob' */
pprLineSegPixD_wc(pArea, xpA, ypA, xpB, ypA);
}
else {
#ifdef SUNVIEW
pw_put(pArea->pWin->pw, (int)xbeg, (int)ybeg, 1);
#else
#if defined XWINDOWS
XDrawPoint(pArea->pWin->pDisp, pArea->pWin->plotWindow,
pArea->pWin->attr.gc, (int)xbeg, (int)ybeg);
#endif
#endif
}
}
else if (pArea->pWin->winType == PPR_WIN_POSTSCRIPT ||
pArea->pWin->winType == PPR_WIN_EPS) {
(void)fprintf(pArea->pWin->file,"%.1f %.1f DP\n",xbeg,ybeg);
}
}
}
xbeg = xend; ybeg = yend;
rem -= dashLen;
}
}
/*+/internal******************************************************************
* NAME pprLineThick - set line thickness
*
* DESCRIPTION
*
* RETURNS
*
* BUGS
* o for X, each linewidth ought to have its own gc
* o doesn't work consistently for SunView (especially after first draw)
*
* SEE ALSO
*
* EXAMPLE
*
*-*/
pprLineThick(pArea, thick)
PPR_AREA *pArea;
short thick; /* I thickness in thousandths of window height */
{
PPR_WIN *pWin;
double lt; /* line thickness */
short ltPix; /* line thickness, in pixels */
pWin = pArea->pWin;
if (pWin->winType==PPR_WIN_POSTSCRIPT || pWin->winType==PPR_WIN_EPS) {
if (thick != pWin->attr.ltCurr) {
pWin->attr.ltCurr = thick;
if (thick == 0) lt = .1;
else lt = .001 * thick * pWin->height;
(void)fprintf(pWin->file, "%.1f setlinewidth\n", lt);
}
}
else {
#ifdef SUNVIEW
if (thick != pWin->attr.ltCurr) {
pWin->attr.ltCurr = thick;
#else
#if defined XWINDOWS
if (thick != pArea->attr.ltCurr) {
pArea->attr.ltCurr = thick;
#endif
#endif
if (thick == 0)
ltPix = 1;
else {
lt = .001 * thick * pWin->height;
if (lt < 1.) ltPix = 1;
else ltPix = (int)(lt + .5);
}
#ifdef SUNVIEW
pWin->attr.ltPix = ltPix;
pWin->brush.width = ltPix;
#else
#if defined XWINDOWS
pArea->attr.ltPix = ltPix;
XSetLineAttributes(pWin->pDisp, pArea->attr.gc, ltPix, LineSolid,
CapButt, JoinRound);
if (pArea->pWin->attr.bgGC) {
XSetLineAttributes(pWin->pDisp, pArea->pWin->attr.gcBG,
ltPix, LineSolid, CapButt, JoinRound);
}
#endif
#endif
}
}
}
/*+/subr**********************************************************************
* NAME pprMarkD - draw a plotting mark
*
* DESCRIPTION
* Draw a plotting mark at the specified point. The color attribute
* (if any) of the plot area is used in drawing the mark. Line
* thickness and dashed line pattern attributes are ignored.
*
* Two entry points are available:
*
* pprMarkD(pArea, x, y, markNum) x and y are double
* pprMarkL(pArea, x, y, markNum) x and y are long
*
* Two additional entry points are available for erasing plotting marks:
*
* pprMarkEraseD(pArea, x, y, markNum) x and y are double
* pprMarkEraseL(pArea, x, y, markNum) x and y are long
*
* RETURNS
* void
*
* NOTES
* 1. Several special mark numbers are available:
* -1 draws a short horizontal line "cap"
* -2 draws a short vertical line "cap"
*
* BUGS
* o only linear calibration is handled
*
* SEE ALSO
* pprLine, pprLineSeg, pprPoint, pprText
*
*-*/
void
pprMarkD(pArea, x, y, markNum)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate */
double y; /* I y data coordinate */
int markNum; /* I mark number--0 to PPR_NMARKS-1, inclusive */
{
pprMark_gen(pArea, x, y, markNum, pprLineSegPixL_ac);
}
static
pprMark_gen(pArea, x, y, markNum, drawFn)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate */
double y; /* I y data coordinate */
int markNum; /* I mark number--0 to PPR_NMARKS-1, inclusive */
void (*drawFn)(); /* I function to draw lines, using pixel coordinates */
{
short *pMark;
int xp0, xp1, yp0, yp1;
int pen;
pprLineThick(pArea, pArea->attr.lineThick);
if (markNum >= 0) {
markNum %= PPR_NMARKS;
pMark = pglPprMarkS[markNum]; /* use small marks */
}
else if (markNum == -1)
pMark = glPprMarkS_hCap;
else if (markNum == -2)
pMark = glPprMarkS_vCap;
xp0 = pArea->xPixLeft + .5 + (x - pArea->xLeft) * pArea->xScale;
yp0 = pArea->yPixBot + .5 + (y - pArea->yBot) * pArea->yScale;
if (pArea->attr.clip) {
if (xp0 < PprMin(pArea->xPixLeft, pArea->xPixRight) ||
xp0 > PprMax(pArea->xPixLeft, pArea->xPixRight) ||
yp0 < PprMin(pArea->yPixBot, pArea->yPixTop) ||
yp0 > PprMax(pArea->yPixBot, pArea->yPixTop)) {
return;
}
}
if (pArea->pWin->winType == PPR_WIN_SCREEN)
yp0 = pArea->pWin->height - yp0;
while (1) {
xp1 = xp0 + *pMark++;
if (pArea->pWin->winType == PPR_WIN_SCREEN) yp1 = yp0 - *pMark++;
else yp1 = yp0 + *pMark++;
pen = *pMark++;
if (pen) {
drawFn(pArea, xp0, yp0, xp1, yp1);
if (pen == 2)
break;
}
xp0 = xp1;
yp0 = yp1;
}
}
void
pprMarkL(pArea, x, y, markNum)
PPR_AREA *pArea; /* I pointer to plot area structure */
long x; /* I x data coordinate */
long y; /* I y data coordinate */
int markNum; /* I mark number--0 to PPR_NMARKS-1, inclusive */
{
pprMark_gen(pArea, (double)x, (double)y, markNum, pprLineSegPixL_ac);
}
void
pprMarkEraseD(pArea, x, y, markNum)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate */
double y; /* I y data coordinate */
int markNum; /* I mark number--0 to PPR_NMARKS-1, inclusive */
{
pprMark_gen(pArea, x, y, markNum, pprLineSegPixEraseL);
}
void
pprMarkEraseL(pArea, x, y, markNum)
PPR_AREA *pArea; /* I pointer to plot area structure */
long x; /* I x data coordinate */
long y; /* I y data coordinate */
int markNum; /* I mark number--0 to PPR_NMARKS-1, inclusive */
{
pprMark_gen(pArea, (double)x, (double)y, markNum, pprLineSegPixEraseL);
}
/*+/internal******************************************************************
* NAME pprMove_clipPix - adjust line seg ends when doing clipping
*
* RETURNS
* 0 if line segment is plottable, or
* -1 if line segment is totally outside the data area
*-*/
static int
pprMove_clipPix(pArea, pXp0,pYp0, pXp1,pYp1)
PPR_AREA *pArea;
int *pXp0,*pYp0, *pXp1,*pYp1;
{
int xp0=*pXp0, xp1=*pXp1, yp0=*pYp0, yp1=*pYp1;
int xpl=pArea->xPixLeft, xpr=pArea->xPixRight;
int ypb=pArea->yPixBot, ypt=pArea->yPixTop;
int ypeb, ypet; /* "logical" top and bottom pix values */
int xpmin=PprMin(xp0,xp1), xpmax=PprMax(xp0,xp1);
int ypmin=PprMin(yp0,yp1), ypmax=PprMax(yp0,yp1);
if (pArea->pWin->winType == PPR_WIN_SCREEN) {
ypb = pArea->pWin->height - ypb;
ypt = pArea->pWin->height - ypt;
}
ypeb = PprMin(ypb, ypt);
ypet = PprMax(ypb, ypt);
if (xpmin > xpr || xpmax < xpl || ypmin > ypet || ypmax < ypeb)
return -1; /* no possible intersection with data area */
if (xpmin < xpl || xpmax > xpr || ypmin < ypeb || ypmax > ypet) {
/* part of path is outside data area; find intersections */
if (xp0 == xp1) { /* no intersection with sides */
if (yp0 < ypeb) yp0 = ypeb;
else if (yp0 > ypet) yp0 = ypet;
if (yp1 < ypeb) yp1 = ypeb;
else if (yp1 > ypet) yp1 = ypet;
}
else if (yp0 == yp1) { /* no intersection with top or bot */
if (xp0 < xpl) xp0 = xpl;
else if (xp0 > xpr) xp0 = xpr;
if (xp1 < xpl) xp1 = xpl;
else if (xp1 > xpr) xp1 = xpr;
}
else {
double S; /* slope of line to draw */
int XP0=xp0, XP1=xp1, YP0=yp0, YP1=yp1;
S = (double)(yp1 - yp0) / (double)(xp1 - xp0);
if (XP0 < xpl)
XP0 = xpl, YP0 = yp0 + .5 + (double)(xpl-xp0) * S;
else if (XP0 > xpr)
XP0 = xpr, YP0 = yp0 + .5 + (double)(xpr-xp0) * S;
if (YP0 < ypeb)
YP0 = ypeb, XP0 = xp0 + .5 + (double)(ypeb-yp0)/S;
else if (YP0 > ypet)
YP0 = ypet, XP0 = xp0 + .5 + (double)(ypet-yp0)/S;
if (XP0 < xpl || XP0 > xpr)
return -1; /* no intersection */
if (XP1 < xpl)
XP1 = xpl, YP1 = yp0 + .5 + (double)(xpl-xp0) * S;
else if (XP1 > xpr)
XP1 = xpr, YP1 = yp0 + .5 + (double)(xpr-xp0) * S;
if (YP1 < ypeb)
YP1 = ypeb, XP1 = xp0 + .5 + (double)(ypeb-yp0)/S;
else if (YP1 > ypet)
YP1 = ypet, XP1 = xp0 + .5 + (double)(ypet-yp0)/S;
if (XP1 < xpl || XP1 > xpr)
return; /* no intersection */
xp0 = XP0, xp1 = XP1, yp0 = YP0, yp1 = YP1;
}
}
*pXp0 = xp0; *pYp0 = yp0; *pXp1 = xp1; *pYp1 = yp1;
return 0;
}
/*+/subr**********************************************************************
* NAME pprMoveD - move the pen, possibly drawing a line
*
* DESCRIPTION
* Move the "pen" to the specified point. If the "pen" is "down"
* a line will be drawn. The line attributes of the plot area are
* used in drawing the line. If the attributes indicate a dashed
* line, the current dashed line pattern will be used.
*
* The "clipping" attribute for the plot area is honored only by
* pprMoveD; pprMoveD_ac and pprMoveD_wc never clip lines at the
* data area edges.
*
* Two alternate entry points are available for drawing plain lines,
* ignoring all attributes except color. One uses the color for the
* plot area (pprMoveD_ac); the other uses the plot window color
* (pprMoveD_wc). (As noted above, these routines don't clip.)
*
* pprMoveD_ac(pArea, x, y, pen) x and y are double
* pprMoveD_wc(pArea, x, y, pen) x and y are double
*
* An additional entry point is available for erasing:
*
* pprMoveEraseD(pArea, x, y) x and y are double
*
* RETURNS
* void
*
* BUGS
* o only linear calibration is handled
*
* SEE ALSO
* pprLine, pprLineSeg, pprText
*
*-*/
void
pprMoveD(pArea, x, y, pen)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate of new point */
double y; /* I y data coordinate of new point */
int pen; /* I pen indicator--non-zero draws a line */
{
pprMoveD_gen(pArea, x, y, pen, pprLineSegPixL_ac);
}
pprMoveD_gen(pArea, x, y, pen, drawFn)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate of new point */
double y; /* I y data coordinate of new point */
int pen; /* I pen indicator--non-zero draws a line */
void (*drawFn)(); /* I pointer to function to use in drawing */
{
short *pXPix=&pArea->xPix, *pYPix=&pArea->yPix;
int xp0, xp1, yp0, yp1;
double segLen, endLen, dashLen, xbeg, xend, ybeg, yend;
PPR_WIN *pWin=pArea->pWin;
xp0 = *pXPix;
yp0 = *pYPix;
xp1 = pArea->xPixLeft + .5 + (x - pArea->xLeft) * pArea->xScale;
yp1 = pArea->yPixBot + .5 + (y - pArea->yBot) * pArea->yScale;
if (pWin->winType == PPR_WIN_SCREEN)
yp1 = pWin->height - yp1;
*pXPix = xp1; /* store _real_ coord, not the _clipped_ one */
*pYPix = yp1;
if (pen) {
pprLineThick(pArea, pArea->attr.lineThick);
if (pArea->attr.clip) {
if (pprMove_clipPix(pArea, &xp0,&yp0, &xp1,&yp1) < 0)
return;
}
if (pArea->attr.pPatt == NULL) {
#if defined XWINDOWS
/*-----------------------------------------------------------------------------
* !!!! NOTE WELL !!!! Various routines have these plotting statements
* for calling XDrawLine. If you modify the statements here, modify
* the other places too!!
*----------------------------------------------------------------------------*/
if (drawFn == pprLineSegPixL_ac) {
if (pWin->winType == PPR_WIN_SCREEN) {
if (xp0 != xp1 || yp0 != yp1)
XDrawLine(pWin->pDisp, pWin->plotWindow,
pArea->attr.gc, xp0, yp0, xp1, yp1);
if (pArea->usePixMap) {
XDrawLine(pArea->pWin->pDisp,
pArea->pixMap, pArea->attr.gc,
xp0 - pArea->xPixLeft,
yp0 - (pArea->pWin->height - pArea->yPixTop),
xp1 - pArea->xPixLeft,
yp1 - (pArea->pWin->height - pArea->yPixTop));
}
}
else if (pWin->winType == PPR_WIN_POSTSCRIPT ||
pWin->winType == PPR_WIN_EPS) {
(void)fprintf(pWin->file, "%d %d %d %d DS\n",
xp0, yp0, xp1, yp1);
}
}
#else
drawFn(pArea, xp0, yp0, xp1, yp1);
#endif
}
else {
/*-----------------------------------------------------------------------------
* draw a dashed line pattern
*----------------------------------------------------------------------------*/
segLen = sqrt((double)((xp1-xp0)*(xp1-xp0) + (yp1-yp0)*(yp1-yp0)));
endLen = 0.;
xbeg = xp0;
ybeg = yp0;
while (endLen < segLen) {
if (pArea->attr.rem < 1.) {
if ((pArea->attr.rem =
pArea->attr.pPatt[++pArea->attr.sub]) <= 0.) {
pArea->attr.sub = 0;
pArea->attr.rem = pArea->attr.pPatt[0];
pArea->attr.pen = 1;
}
else
pArea->attr.pen ^= 1;
}
dashLen = PprMin(pArea->attr.rem, segLen-endLen);
endLen += dashLen;
if (PprAbs(endLen-segLen) < .5)
endLen = segLen;
xend = xp0 + endLen/segLen * (xp1 - xp0);
yend = yp0 + endLen/segLen * (yp1 - yp0);
if (pArea->attr.pen)
drawFn(pArea, (long)(.5+xbeg), (long)(.5+ybeg),
(long)(.5+xend), (long)(.5+yend));
xbeg = xend;
ybeg = yend;
pArea->attr.rem -= dashLen;
}
}
}
}
void
pprMoveD_ac(pArea, x, y, pen)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate of new point */
double y; /* I y data coordinate of new point */
int pen; /* I pen indicator--1 draws a line */
{
int xp1 = pArea->xPixLeft + .5 + (x - pArea->xLeft) * pArea->xScale;
int yp1 = pArea->yPixBot + .5 + (y - pArea->yBot) * pArea->yScale;
if (pArea->pWin->winType == PPR_WIN_SCREEN)
yp1 = pArea->pWin->height - yp1;
if (pen) {
pprLineThick(pArea, pArea->pWin->attr.lineThick);
pprLineSegPixL_ac(pArea, pArea->xPix, pArea->yPix, xp1, yp1);
}
pArea->xPix = xp1;
pArea->yPix = yp1;
}
void
pprMoveD_wc(pArea, x, y, pen)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate of new point */
double y; /* I y data coordinate of new point */
int pen; /* I pen indicator--1 draws a line */
{
int xp1 = pArea->xPixLeft + .5 + (x - pArea->xLeft) * pArea->xScale;
int yp1 = pArea->yPixBot + .5 + (y - pArea->yBot) * pArea->yScale;
if (pArea->pWin->winType == PPR_WIN_SCREEN)
yp1 = pArea->pWin->height - yp1;
if (pen) {
pprLineThick(pArea, pArea->pWin->attr.lineThick);
pprLineSegPixL_wc(pArea, pArea->xPix, pArea->yPix, xp1, yp1);
}
pArea->xPix = xp1;
pArea->yPix = yp1;
}
void
pprMoveEraseD(pArea, x, y)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate of new point */
double y; /* I y data coordinate of new point */
{
pprMoveD_gen(pArea, x, y, 1, pprLineSegPixEraseL);
}
/*+/subr**********************************************************************
* NAME pprPerim - draw a perimeter
*
* DESCRIPTION
* Draw a perimeter with tick marks. The number of intervals
* specified in the plot area structure is used for placing
* the tick marks.
*
* The color attributes for the plot window are used for drawing;
* dashed line and line thickness are ignored.
*
* RETURNS
* void
*
* BUGS
* o only linear axes are handled
*
* SEE ALSO
* pprPerimLabel, pprPerimErase, pprGrid, pprAnnotX, pprAnnotY, pprAreaOpen
*
*-*/
void
pprPerim(pArea)
PPR_AREA *pArea; /* I pointer to plot area structure */
{
double tickHalf;
int i;
double x, y;
/*-----------------------------------------------------------------------------
* draw the box
*----------------------------------------------------------------------------*/
pprMoveD_wc(pArea, pArea->xLeft, pArea->yBot, 0);
pprMoveD_wc(pArea, pArea->xRight, pArea->yBot, 1);
pprMoveD_wc(pArea, pArea->xRight, pArea->yTop, 1);
pprMoveD_wc(pArea, pArea->xLeft, pArea->yTop, 1);
pprMoveD_wc(pArea, pArea->xLeft, pArea->yBot, 1);
/*-----------------------------------------------------------------------------
* draw the x axis tick marks
*----------------------------------------------------------------------------*/
tickHalf = pArea->tickHt / pArea->yScale;
x = pArea->xLeft;
y = pArea->yBot - 3. * tickHalf;
for (i=1; i<pArea->xNint; i++) {
x += pArea->xInterval;
pprLineSegD_wc(pArea, x, pArea->yBot - tickHalf, x, pArea->yBot);
pprLineSegD_wc(pArea, x, pArea->yTop + tickHalf, x, pArea->yTop);
}
/*-----------------------------------------------------------------------------
* ditto for y axis
*----------------------------------------------------------------------------*/
tickHalf = pArea->tickHt / pArea->xScale;
x = pArea->xLeft - 1.5 * tickHalf;
y = pArea->yBot;
for (i=1; i<pArea->yNint; i++) {
y += pArea->yInterval;
pprLineSegD_wc(pArea, pArea->xLeft - tickHalf, y, pArea->xLeft, y);
pprLineSegD_wc(pArea, pArea->xRight + tickHalf, y, pArea->xRight, y);
}
}
/*+/subr**********************************************************************
* NAME pprPerimErase - erase within a perimeter
*
* DESCRIPTION
* Erases the screen inside the perimeter for the plot area. (Actually,
* the perimeter and tick marks are erased as well, since plot marks
* may have been drawn on (and thus lie partly outside of) the perimeter
* itself. The perimeter and tick marks are then redrawn.)
*
* RETURNS
* void
*
* SEE ALSO
* pprGridErase, pprAreaErase, pprWinErase, pprRegionErase
* the ppr...Erase... entry points for the various drawing routines
*
*-*/
void
pprPerimErase(pArea)
PPR_AREA *pArea; /* I pointer to plot area structure */
{
int x,y,width,height;
if (pArea->pWin->winType != PPR_WIN_SCREEN)
return;
x = pArea->xPixLeft - 3;
y = pArea->yPixBot - 3;
width = (pArea->xRight - pArea->xLeft) * pArea->xScale + 6;
height = (pArea->yTop - pArea->yBot) * pArea->yScale + 6;
#ifdef SUNVIEW
y = pArea->pWin->height - y - height;
pw_writebackground(pArea->pWin->pw, x, y, width, height, PIX_SRC);
pprPerim(pArea);
#else
#if defined XWINDOWS
y = pArea->pWin->height - y - height;
XClearArea(pArea->pWin->pDisp, pArea->pWin->plotWindow,
x, y, width, height, False);
if (pArea->pixMap != NULL) {
XFillRectangle(pArea->pWin->pDisp, pArea->pixMap, pArea->pixMapGC,
0, 0, pArea->pixMapWidth+1, pArea->pixMapHeight+1);
}
pprPerim(pArea);
XFlush(pArea->pWin->pDisp);
#endif
#endif
}
/*+/subr**********************************************************************
* NAME pprPerimLabel - draw and label a perimeter
*
* DESCRIPTION
* Draw a perimeter with tick marks. The number of intervals
* specified in the plot area structure is used for placing
* the tick marks.
*
* Axis labels and annotations are drawn using the information from
* the plot area, as specified in the pprAreaOpen call.
*
* RETURNS
* void
*
* BUGS
* o only linear axes are handled
*
* SEE ALSO
* pprPerim, pprGrid, pprAnnotX, pprAnnotY, pprAreaOpen
*
*-*/
void
pprPerimLabel(pArea, xLabel, xAnnot, yLabel, yAnnot, angle)
PPR_AREA *pArea; /* I pointer to plot area structure */
char *xLabel; /* I label for x axis, or NULL */
char **xAnnot; /* I pointer to array of x annotations, or NULL */
char *yLabel; /* I label for y axis, or NULL */
char **yAnnot; /* I pointer to array of y annotations, or NULL */
double angle; /* I angle for y annotations; 0. or 90. */
{
pprPerim(pArea);
pprAnnotX(pArea, 0, pArea->xLeft, pArea->xRight, pArea->xNint,
0, xLabel, xAnnot, 0.);
pprAnnotY(pArea, 0, pArea->yBot, pArea->yTop, pArea->yNint,
0, yLabel, yAnnot, angle);
}
/*+/macro*********************************************************************
* NAME PprPixXToXFrac - convert pixel address to window fraction
*
* DESCRIPTION
* Converts an x or y pixel address (for example, from a mouse click)
* into a fraction of the plot window's width or height.
*
* PprPixXToXFrac(pWin, xPixel)
* PprPixYToYFrac(pWin, yPixel)
*
* RETURNS
* window fraction
*
*-*/
/*+/subr**********************************************************************
* NAME pprPoint - plot a point at a coordinate
*
* DESCRIPTION
* Plot a pixel sized point using the line thickness and color
* attributes of the plot area.
*
* Two entry points are available:
*
* pprPointD(pArea, x, y) x and y are double
* pprPointL(pArea, x, y) x and y are long
*
* Two entry points are available for erasing:
*
* pprPointEraseD(pArea, x, y) x and y are double
* pprPointEraseL(pArea, x, y) x and y are long
*
* RETURNS
* void
*
* BUGS
* o only linear calibration is handled
*
* SEE ALSO
* pprMark, pprAreaOpen, pprAreaSetAttr, pprLine,
* pprMove, pprText
*
*-*/
void
pprPointD(pArea, x, y)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate */
double y; /* I y data coordinate */
{
double xPix, yPix;
double xp0,yp0,xp1;
xPix = pArea->xPixLeft + .5 + (x - pArea->xLeft) * pArea->xScale;
yPix = pArea->yPixBot + .5 + (y - pArea->yBot) * pArea->yScale;
pprLineThick(pArea, pArea->attr.lineThick);
if (pArea->pWin->winType == PPR_WIN_SCREEN) {
yPix = pArea->pWin->height - yPix;
#ifdef SUNVIEW
if (pArea->pWin->attr.ltPix > 1) {
yp0 = yPix;
xp0 = xPix - pArea->pWin->attr.ltPix / 2;
xp1 = xp0 + pArea->pWin->attr.ltPix - 1;
#else
#if defined XWINDOWS
if (pArea->attr.ltPix > 1) {
yp0 = yPix;
xp0 = xPix - pArea->attr.ltPix / 2;
xp1 = xp0 + pArea->attr.ltPix - 1;
#endif
#endif
pprLineSegPixD_ac(pArea, xp0, yp0, xp1, yp0);
}
else {
#ifdef SUNVIEW
pw_put(pArea->pWin->pw, (int)xPix, (int)yPix, 1);
#else
#if defined XWINDOWS
XDrawPoint(pArea->pWin->pDisp, pArea->pWin->plotWindow,
pArea->attr.gc, (int)xPix, (int)yPix);
#endif
#endif
}
}
else if (pArea->pWin->winType == PPR_WIN_POSTSCRIPT ||
pArea->pWin->winType == PPR_WIN_EPS) {
(void)fprintf(pArea->pWin->file, "%.1f %.1f DP\n", xPix, yPix);
}
}
void
pprPointL(pArea, x, y)
PPR_AREA *pArea; /* I pointer to plot area structure */
long x; /* I first x point */
long y; /* I first y point */
{
pprPointD(pArea, (double)x, (double)y);
}
void
pprPointEraseD(pArea, x, y)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate */
double y; /* I y data coordinate */
{
double xPix, yPix;
double xp0,yp0,xp1;
if (pArea->pWin->winType != PPR_WIN_SCREEN)
return;
xPix = pArea->xPixLeft + .5 + (x - pArea->xLeft) * pArea->xScale;
yPix = pArea->yPixBot + .5 + (y - pArea->yBot) * pArea->yScale;
pprLineThick(pArea, pArea->attr.lineThick);
yPix = pArea->pWin->height - yPix;
#ifdef SUNVIEW
if (pArea->pWin->attr.ltPix > 1) {
yp0 = yPix;
xp0 = xPix - pArea->pWin->attr.ltPix / 2;
xp1 = xp0 + pArea->pWin->attr.ltPix - 1;
#else
#if defined XWINDOWS
if (pArea->attr.ltPix > 1) {
yp0 = yPix;
xp0 = xPix - pArea->attr.ltPix / 2;
xp1 = xp0 + pArea->attr.ltPix - 1;
#endif
#endif
pprLineSegPixEraseD(pArea, xp0, yp0, xp1, yp0);
}
else {
#ifdef SUNVIEW
pw_put(pArea->pWin->pw, (int)xPix, (int)yPix, 0);
#else
#if defined XWINDOWS
XDrawPoint(pArea->pWin->pDisp, pArea->pWin->plotWindow,
pArea->pWin->attr.gcBG, (int)xPix, (int)yPix);
#endif
#endif
}
}
void
pprPointEraseL(pArea, x, y)
PPR_AREA *pArea; /* I pointer to plot area structure */
long x; /* I first x point */
long y; /* I first y point */
{
pprPointEraseD(pArea, (double)x, (double)y);
}
/*/internal -------------------------------------------------------------------
* NAME pprPSProg - PostScript routines for lines, points, text strings, etc.
*----------------------------------------------------------------------------*/
static char *pprPSProg[]={
/*-----------------------------------------------------------------------------
* DP - draw a point
* x y DP -
*----------------------------------------------------------------------------*/
"/DP {",
" newpath",
" moveto",
" currentlinewidth dup 2 div neg 0 rlineto 0 rlineto",
" stroke",
"} def",
/*-----------------------------------------------------------------------------
* DS - draw a line segment from x1,y1 to x2,y2
* x1 y1 x2 y2 DS -
*----------------------------------------------------------------------------*/
"/DS {",
" newpath",
" 4 2 roll moveto lineto",
" stroke",
"} def",
/*-----------------------------------------------------------------------------
* FSet - set size of current font; if already proper size, no action
* size FSet -
*
* BUGS
* o should keep a list of scalefont which have already been done, to
* avoid the need to do a new one
* o doesn't allow selecting font family
*----------------------------------------------------------------------------*/
"/F /Helvetica findfont def",
"/F_HT -1 def",
"/FSet {",
" /F_ht exch def",
" F_ht F_HT ne {",
" /F_HT F_ht def",
" F F_HT scalefont dup /FF exch def setfont",
" } {",
" FF setfont", /* if not changing, still must set */
" } ifelse",
"} def",
/*-----------------------------------------------------------------------------
* PT - plot a text string
* Text appears at current location with specified size and angle.
* The text can be right, left, or center justified; the "half height"
* of the characters will be at the current location.
*
* string just angle size PT -
* "just" is one of (PTC), (PTR), or (PTL)
*----------------------------------------------------------------------------*/
"/PTL { } def",
"/PTC { dup stringwidth pop -2 div 0 rmoveto } def",
"/PTR { dup stringwidth pop neg 0 rmoveto } def",
"/PT { FSet gsave",
" currentpoint translate rotate",
" cvn cvx exec", /* execute the PTx procedure */
" 0 F_HT -3 div rmoveto", /* offset to vertical center of char */
" show",
" grestore } def"
};
/*+/subr**********************************************************************
* NAME pprRegionErase - erase an area within a plot window
*
* DESCRIPTION
* Erases an area within a plot window.
*
* RETURNS
* void
*
* SEE ALSO
* pprWinErase, pprAreaErase, pprGridErase, pprPerimErase
* the ppr...Erase... entry points for the various drawing routines
*
* BUGS
* 1. This doesn't erase the pixmap used for strip charts.
*
* NOTES
* 1. Another mode of calling pprRegionErase, in which the arguments are
* pixel offsets from the data area boundaries, is invoked by
* having one or more of the arguments be greater than 1. or less
* than 0. In this case, all the "wfrac" arguments are treated as
* pixel offsets.
*
* EXAMPLES
* 1. Erase within a data area, preserving the perimeter line. This
* example uses pixel offsets from the plot area boundary--one pixel
* inside each edge of the plot area.
*
* pprRegionErase(pArea, 1., 1., -1., -1.);
*
* 2. A data area occupies the upper right quarter of the plot window.
* An annotation area (using default character height) extends from
* the left edge of the plot window to the left edge of the data area,
* centered at the vertical midpoint of the data area. Erase the
* annotation area.
*
* double yb,yt;
*
* The region to erase is expressed as fractions of window width and
* height. For x, the region is from 0. (the left edge of the plot
* window) to .49 (just a bit left of the center of the plot window).
* For y, the region is centered at .75 (the vertical midpoint of the
* plot area within the plot window), with a height of the default
* character height.
*
* yb = .75 - PprDfltCharHt(.5,1.);
* yt = yb + PprDfltCharHt(.5,1.);
* pprRegionErase(pArea, 0., yb, .49, yt);
*
*-*/
void
pprRegionErase(pArea, wfracXleft, wfracYbot, wfracXright, wfracYtop)
PPR_AREA *pArea; /* I pointer to plot area structure */
double wfracXleft; /* I x win frac of left edge of area (see Note 1) */
double wfracYbot; /* I y win frac of bottom edge of area (see Note 1) */
double wfracXright; /* I x win frac of right edge of area (see Note 1) */
double wfracYtop; /* I y win frac of top edge of area (see Note 1) */
{
int x,y,width,height;
if (pArea->pWin->winType != PPR_WIN_SCREEN)
return;
if (wfracXleft<0. || wfracXleft>1. || wfracXright<0. || wfracXright>1. ||
wfracYbot<0. || wfracYbot>1. || wfracYtop<0. || wfracYtop>1.) {
x = pArea->xPixLeft + wfracXleft;
y = pArea->yPixBot + wfracYbot;
width = pArea->xPixRight + wfracXright - x + 1;
height = pArea->yPixTop + wfracYtop - y + 1;
}
else {
x = wfracXleft * pArea->pWin->width;
y = wfracYbot * pArea->pWin->height;
width = (wfracXright - wfracXleft) * pArea->pWin->width;
height = (wfracYtop - wfracYbot) * pArea->pWin->height;
}
#ifdef SUNVIEW
y = pArea->pWin->height - y - height;
pw_writebackground(pArea->pWin->pw, x, y, width, height, PIX_SRC);
#else
#if defined XWINDOWS
y = pArea->pWin->height - y - height;
XClearArea(pArea->pWin->pDisp, pArea->pWin->plotWindow,
x, y, width, height, False);
#endif
#endif
}
/*+/subr**********************************************************************
* NAME pprSin_deg - get the sine of an angle in degrees
*
* DESCRIPTION
* Get the sine of an angle in degrees. A table lookup technique
* is used. The angle argument is truncated to the next lower 1/4
* degree prior to lookup.
*
* RETURNS
* sine
*
*-*/
double
pprSin_deg(angle)
double angle; /* I angle, in degrees */
{
return pprCos_deg(angle - 90.);
}
/*/internal -------------------------------------------------------------------
* NAME pprTextFont - character tables for drawn font
*
* ITABLE = the array defining the character set. Each character is
* defined by one 34 character string "matrix". The "matrix"
* elements consist of a series of up to 17 (IDX,IDY)'s which
* define the next stroke. The vector is positioned at (IX1,IY1)
* and drawn to (IX2,IY2) where:
* IX1 = IX + IDX1 IY1 = IY + IDY1
* IX2 = IX + IDX2 IY2 = IY + IDY2
* (IX2,IY2) becomes the next (IX1,IY1) unless the new IDX = 0
* in which case a new vector is started with the next 2
* elements after the 0 becoming (IDX,IDY) etc. (ie., an IDX
* = 0 causes a break in the character strokes.) An IDY = 0
* causes an offset to be added to IY for the remaining strokes
* in the character. This is used for characters such as g and
* y which extend below the relative 0 line. The element
* following an IDY = 0 becomes the IDY actually used. The
* (IDX,IDY) represents a position in a 6 x 9 matrix. IDX has
* a range of 0 - 6, where most characters fall within 1 - 5;
* 0 triggers a new stroke unless it is the 1st element of the
* string in which case it is really 0. IDY has a range of
* 0 - 9, where most characters fall within 1 - 7; 0 triggers
* an offset to lower the rest of the strokes. A non-numeric
* character in the string, ie. a period, is used to terminate
* the stroke matrix for the character.
*
* converted to C by Roger Cole, 12-90
*
* EFC 4/16/85: included call to UNPKST to make character string
* matrices nearly as efficient as octal matrices.
* Uses 95 microseconds more per character on average.
* EFC 4/8/85: rewritten for STRING a character variable rather than
* hollerith. Extended and rewrote character stroke array
* for nicer characters. Changed definition of INSIZE = 0
* matrix from 10 x 13 to 9 x 13.
* EFC 9/21/84: rewritten for FORTRAN 77 on DEC KL-10 to use character
* functions rather than binary masks and shifts. Changed
* matrix for tau and xsi. Changed coding to fix bug in
* "y" shifting of charcters and eliminate inconsistencies
* in described usage and actual usage.
* modified by Debby Hyman, 9-80
* Greek characters almost match QUME printer char set, now
*
*changed 16-may-76 STB CTR
*----------------------------------------------------------------------------*/
static char *glPprFont0[]={
/*-----------------------------------------------------------------------------
* blank ! " # $ % & ' ( ) * + , - . /
*----------------------------------------------------------------------------*/
".", "2737242702221313222.", "27253727057454757.", "2721047410155501353.",
"5626152444521203137.", "57110162736251604132435241.",
"511516273746451312213153.", "35473735.", "41232547.", "21434527.",
"46220422605414.", "323605414.", "31433331.", "5414.", "3242413132.",
"5711.",
/*-----------------------------------------------------------------------------
* 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
*----------------------------------------------------------------------------*/
"132141535547271513.", "51110313726.", "51111256472716.",
"44240122141524456472716.", "46410531337.", "57171425455452412112.",
"564727161221415253442413.", "315717.",
"44555647271615244453524121121324.", "5424151627475652412112.",
"454636354504342323343.", "3646453536031334331.", "521456.",
"155501353.", "125416.", "16274756553303231212232.",
/*-----------------------------------------------------------------------------
* @ A B C D E F G H I J K L M N O
*----------------------------------------------------------------------------*/
"512112162747565443344554.", "23430513711.", "4453524111174756554414.",
"5647271612214152.", "17114153554717.", "1444051111757.", "44140111757.",
"56472716122141520515434.", "51570541401117.", "51110313705717.",
"122131424705727.", "51240571301117.", "511117.", "5157331711.",
"57511711.", "271612214152564727.",
/*-----------------------------------------------------------------------------
* P Q R S T U V W X Y Z [ \ ] ^ _
*----------------------------------------------------------------------------*/
"14445556471711.", "27161221415256472703361.", "5134014445556471711.",
"564727161524445352412112.", "313705717.", "575241211217.", "573117.",
"5741352117.", "571105117.", "57340313417.", "51115717.", "41212747.",
"1751.", "21414727.", "273847.", "10252.",
/*-----------------------------------------------------------------------------
* ` a b c d e f g h i j k l m n o
*----------------------------------------------------------------------------*/
"37454737.", "14254554510524121122353.", "1545535241211201117.",
"512112142555.", "5525141221415205157.", "512112142545545313.",
"56473726210113103414.", "52412112142545540507524121.", "111701425455451.",
"214103135250373737.", "373737030747423121.", "45134101117.",
"41210313727.", "1115014253531034455551.", "111501425455451.",
"122141525445251412.",
/*-----------------------------------------------------------------------------
* p q r s t u v w x y z { | } ~
*----------------------------------------------------------------------------*/
"1425455452412112010711.", "544525141221415205075161.",
"1115014254554.", "54452514234352412112.", "2545037324151.",
"151221415205155.", "553115.", "5541352115.", "551105115.",
"15122141520507524121.", "51115515.", "47372622314101424.",
"3137.", "27374642312104454.", "16274657.",
/*-----------------------------------------------------------------------------
* box dot
*----------------------------------------------------------------------------*/
"1252561612.", "3254361432."
};
#if 0
static char *glPprFont1[]={
/*-----------------------------------------------------------------------------
* blank ! " # $ % & ' ( ) * + , - . /
*----------------------------------------------------------------------------*/
".", "115103137.", "212704147.", "15550571101353.", "52511135195958.",
"14264254462214.", "52422614224656.", "135351.", "492523401.",
"294543201.", "125601652.", "52120333705515.", "24324403236.",
"16560353101353.", "3343443433.", "2559.",
/*-----------------------------------------------------------------------------
* 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
*----------------------------------------------------------------------------*/
"253546483929181625.", "45150353928.", "45151648392918.",
"37270162535463748392918.", "38350461629.", "491917283847463515.",
"4839291816253546372716.", "194925.", "374839291827374635251627.",
"153546483929182747.", "172728181703747483837.",
"45463635450434232334302454.", "13510531557.", "1353015264556.",
"53110135517.", "12213137475601555.",
/*-----------------------------------------------------------------------------
* @ A B C D E F G H I J K L M N O
*----------------------------------------------------------------------------*/
"12213142332536273848570364433.", "1136510234303526374635.",
"17315705414.", "31370575544241517.", "11513711.", "12520541401656.",
"224253554626151322021410313702747.", "1131021270175756.",
"12214152564727161202444.", "122131475766.", "162747545241211213244453.",
"11212212110415152424103545463635.", "0121011375104161.",
"512112142555.", "114152544515.", "11415254451502353.",
/*-----------------------------------------------------------------------------
* P Q R S T U V W X Y Z [ \ ] ^ _
*----------------------------------------------------------------------------*/
"112127017570474151.", "132242535546261513.", "132147.", "52511144175756.",
"21270414705727161524.", "21410313627160364756.", "31571731.",
"0211212314162747565443415162.", "12115152043450442402325016175756.",
"111526465551.", "161221415256.", "492920141.", "33543505414.",
"294940121.", "24364403632.", "33143501454.",
/*-----------------------------------------------------------------------------
* ` a b c d e f g h i j k l m n o
*----------------------------------------------------------------------------*/
"1353031643705515.", "5141443525141221314255.",
"2141525344140445556472716101.", "1626243343545604721.",
"56473726255352412112132434.", "52412112234302314254554.",
"452514122141525445047201.", "152636454131224556.",
"5414132141535547271514.", "25353141.", "2145473726254151.",
"1511051134555.", "11340512717.", "514204542312112015101.", "25315355.",
"171524445557482817.",
/*-----------------------------------------------------------------------------
* p q r s t u v w x y z { | } ~
*----------------------------------------------------------------------------*/
"252104144055442514.", "1626415101156.", "2231415254453524101.",
"552514132232434435.", "4131350552514.", "15132141525445.",
"145404354450251423.", "25141221320333241525445.",
"17260561615244402413125251402.", "152521024354554501.",
"1736560361312215150241.", "142404939282023141.", "6859493012112.",
"445402939484023121.", "041525445465.",
/*-----------------------------------------------------------------------------
* box dot / diamond triangle
*----------------------------------------------------------------------------*/
"3434.", "13533713."
};
#endif
/*+/subr**********************************************************************
* NAME pprText - plot a text string
*
* DESCRIPTION
* Plots a text string at a location. The character "half height" is
* placed at the specified x,y position; the 'justification' option
* selects whether the left end, center, or right end of the text is
* placed at the x,y coordinate.
*
* The character height specification is in terms of a fraction of the
* height of the window. This results in automatic scaling of
* character sizes as the window size changes. If a height of zero
* is specified in the call, then the default height for the plot
* area is used. (The default height was established by pprAreaOpen.)
*
* A macro is available which returns the default character height
* used by this plot package. The value returned is proportional to
* the height of the plot area. This value can be used to generate
* "big" and "small" character sizes with simple multiplication of
* the default height by a "scale factor".
*
* PprDfltCharHt(lowYfrac, highYfrac)
*
* lowYfrac is the vertical fraction of the window at which
* the bottom edge of the plot area lies
* highYfrac is the vertical fraction of the window at which
* the top edge of the plot area lies
*
* It is also often useful to know what horizontal fraction of the
* window width corresponds to a vertical fraction of the height. The
* following routine returns the horizontal fraction:
*
* pprYFracToXFrac(pWin, yFrac)
*
* An alternate entry point, pprText_wc, is available to use the
* plot window's color for drawing the text.
*
* An additional entry point is available for erasing (which requires
* all arguments to be exactly the same as when the text was originally
* plotted):
*
* pprTextErase(pArea, x, y, text, just, height, angle)
*
* RETURNS
* void
*
* BUGS
* o technique used works only with linear axes
* o ASCII character codes are assumed
* o no checks are made for illegal characters
* o positioning and sizing are somewhat different for the various
* window types
*
* SEE ALSO
* pprChar, pprAreaOpen, pprLine, pprPoint, pprCvtDblToTxt
*
*-*/
void
pprText(pArea, x, y, text, just, height, angle)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate of text */
double y; /* I y data coordinate of text */
char *text; /* I text to plot */
PPR_TXT_JUST just; /* I text justification selector: one of
PPR_TXT_CEN, PPR_TXT_RJ, or PPR_TXT_LJ */
double height; /* I height of text characters, as a fraction of
the height of the window; a value of
zero results in using a default height */
double angle; /* I orientation angle of text string, ccw degrees */
{
pprText_gen(pArea, x, y, text, just, height, angle, pprLineSegPixD_ac);
}
void
pprText_wc(pArea, x, y, text, just, height, angle)
PPR_AREA *pArea;
double x;
double y;
char *text;
PPR_TXT_JUST just;
double height;
double angle;
{
pprText_gen(pArea, x, y, text, just, height, angle, pprLineSegPixD_wc);
}
static void
pprText_gen(pArea, x, y, text, just, height, angle, fn)
PPR_AREA *pArea;
double x;
double y;
char *text;
PPR_TXT_JUST just;
double height;
double angle;
void (*fn)();
{
double xWin, yWin;
double scale; /* convert character units to win coord */
double cosT, sinT;
if (height <= 0.)
height = pArea->charHt;
else
height *= pArea->pWin->height;
xWin = pArea->xPixLeft + .5 + (x - pArea->xLeft) * pArea->xScale;
yWin = pArea->yPixBot + .5 + (y - pArea->yBot) * pArea->yScale;
if (pArea->pWin->winType == PPR_WIN_SCREEN) {
if (angle == 0.) cosT = 1., sinT = 0.;
else if (angle == 90.) cosT = 0., sinT = 1.;
else { cosT = pprCos_deg(angle);
sinT = pprSin_deg(angle);
}
scale = height / 6.;
if (just == PPR_TXT_CEN) {
xWin -= .5 * (scale * 6. * (double)(strlen(text)-1) * cosT);
yWin -= .5 * (scale * 6. * (double)(strlen(text)-1) * sinT);
}
else if (just == PPR_TXT_RJ) {
xWin -= scale * 6. * (double)(strlen(text)-1) * cosT;
yWin -= scale * 6. * (double)(strlen(text)-1) * sinT;
}
while (*text != '\0') {
pprText1(pArea, xWin, yWin, *text, 0, scale, sinT, cosT, fn);
xWin += scale * 6. * cosT;
yWin += scale * 6. * sinT;
text++;
}
}
else {
height = 1.5 * height;
pprTextPS(pArea->pWin->file, xWin, yWin, just, text, height, angle);
}
}
void
pprTextErase(pArea, x, y, text, just, height, angle)
PPR_AREA *pArea; /* I pointer to plot area structure */
double x; /* I x data coordinate of text */
double y; /* I y data coordinate of text */
char *text; /* I text to plot */
PPR_TXT_JUST just; /* I text justification selector: one of
PPR_TXT_CEN, PPR_TXT_RJ, or PPR_TXT_LJ */
double height; /* I height of text characters, as a fraction of
the height of the window; a value of
zero results in using a default height */
double angle; /* I orientation angle of text string, ccw degrees */
{
pprText_gen(pArea, x, y, text, just, height, angle, pprLineSegPixEraseD);
}
/*+/internal******************************************************************
* NAME pprText1 - plot a "drawn" character
*
* DESCRIPTION
* Plots a character at x,y using specified scale factor and rotation.
* All sizes and coordinates use window units, rather than data units.
*
* RETURNS
* void
*
* BUGS
* o only linear calibration is handled
*
*-*/
void
pprText1(pArea, xWin, yWin, ic, nfont, scale, sinT, cosT, fn)
PPR_AREA *pArea; /* I pointer to plot area structure */
double xWin; /* IO x position, in window coordinates */
double yWin; /* IO y position, in window coordinates */
int ic; /* I character code to plot */
int nfont; /* I font selector--0 or 1 */
double scale; /* I scale factor to convert a character height of
6 to the desired height in window coord */
double sinT; /* I sine of orientation angle */
double cosT; /* I cosine of orientation angle */
void (*fn)(); /* I pointer to drawing fn: pprLineSegPixD_.. */
{
/* stolen (who knows how many times removed) from the Los Alamos National
Laboratory Plasma Physics Plotting Package */
char *font; /* font string for this character */
int nStrokes;
int mcx, mcy, indw, drawit;
double rx, ry;
int ibyt;
double xp0,xp1,yp0,yp1;
if (ic < ' ' || ic > '~')
ic = '#';
if (nfont == 0)
font = glPprFont0[ic-' '];
#if 0
else
font = glPprFont1[ic-' '];
#endif
nStrokes = (int)(index(font, '.') - font) -1;
mcx = 3;
mcy = 4;
indw = 0;
pprLineThick(pArea, pArea->pWin->attr.lineThick);
drawit = 0;
xp0 = pArea->xPix;
yp0 = pArea->yPix;
while (indw < nStrokes) {
ibyt = font[indw] - '0';
if (ibyt == 0 && indw != 0)
drawit = 0; /* there is a break in the strokes */
else {
rx = (float)(ibyt - mcx);
while ((ibyt = font[++indw] - '0') == 0)
mcy = 6; /* this char has a descender, as for y or g */
ry = (float)(ibyt - mcy);
xp1 = xWin + scale * (rx*cosT - ry*sinT);
yp1 = yWin + scale * (rx*sinT + ry*cosT);
if (pArea->pWin->winType == PPR_WIN_SCREEN)
yp1 = pArea->pWin->height - yp1;
if (drawit)
fn(pArea, xp0, yp0, xp1, yp1);
xp0 = xp1;
yp0 = yp1;
drawit = 1;
}
indw++;
}
}
/*+/internal******************************************************************
* NAME pprTextPS - send the PostScript commands to plot some text
*
* DESCRIPTION
* This routine sets up the call to the routine (unique to this
* package) in the PostScript printer. This involves:
* o moving to the desired position
* o massaging the caller's text to enclose it in ( and ) and to
* "escape" characters which are special to PostScript
* o setting the font size
* o setting the angle for the text
* o setting for right, centered, or left justification
*
* All text is printed with the font selected by the PostScript
* routine.
*
* RETURNS
* void
*
* BUGS
* o assumes that all characters in the caller's text string are printable
*
*-*/
static void
pprTextPS(psFile, x, y, just, text, height, angle)
FILE *psFile; /* I pointer to PostScript file */
double x,y; /* I x and y position, in window coordinates */
PPR_TXT_JUST just; /* I text justification selector: one of
PPR_TXT_CEN, PPR_TXT_RJ, or PPR_TXT_LJ */
char *text; /* I the text to plot */
double height; /* I the desired height of the text, in points */
double angle; /* I orientation angle of the text, + is ccw */
{
char myJust[4];
/*-----------------------------------------------------------------------------
* send out the text string, enclosed in PostScript string delimiters of ( )
* Special characters are sent out as an appropriate \ sequence
*----------------------------------------------------------------------------*/
(void)fprintf(psFile, "%d %d moveto\n", (int)(x+.5), (int)(y+.5));
fputc('(', psFile);
while (*text != '\0') {
switch (*text) {
case '\b':
fputc('\\', psFile); fputc('b', psFile);
break;
case '\f':
fputc('\\', psFile); fputc('f', psFile);
break;
case '\n':
fputc('\\', psFile); fputc('n', psFile);
break;
case '\r':
fputc('\\', psFile); fputc('r', psFile);
break;
case '\t':
fputc('\\', psFile); fputc('t', psFile);
break;
case '(':
case ')':
case '\\':
fputc('\\', psFile);
default:
fputc(*text, psFile);
}
text++;
}
fputc(')', psFile);
fputc(' ', psFile);
/*-----------------------------------------------------------------------------
* now send out the rest of the PostScript information, so that the whole
* thing from this routine will be something like the following, with
* the proper choice of PTC PTL and PTR:
*
* x y moveto (text) (PTx) angle typesize PT
*----------------------------------------------------------------------------*/
if (just == PPR_TXT_CEN)
(void)strcpy(myJust, "PTC");
else if (just == PPR_TXT_RJ)
(void)strcpy(myJust, "PTR");
else
(void)strcpy(myJust, "PTL");
(void)fprintf(psFile, "(%s) %.2f %d PT\n", myJust, angle, (int)(height+.5));
}
/*+/internal******************************************************************
* NAME QUICK_WAVE - macro for quickly plotting waveforms under X11
*
*-*/
/*-----------------------------------------------------------------------------
* !!!! NOTE WELL !!!! Various routines have these plotting statements
* for calling XDrawLine. If you modify the statements here, modify
* the other places too!!
*----------------------------------------------------------------------------*/
#if defined XWINDOWS
#define QUICK_WAVE() \
PPR_WIN *pWin=pArea->pWin; \
if (pArea->attr.pPatt == NULL && pWin->winType == PPR_WIN_SCREEN && \
!pArea->attr.clip && !pArea->usePixMap) { \
int xp0, xp1, yp0, yp1, winHt=pWin->height; \
double xPixLeft=pArea->xPixLeft, yPixBot=pArea->yPixBot; \
double xScale=pArea->xScale, yScale=pArea->yScale; \
double xLeft=pArea->xLeft, yBot=pArea->yBot; \
double xbeg, xend, ybeg, yend; \
Display *pDisp=pWin->pDisp; \
Window plotWindow=pWin->plotWindow; \
GC gc=pArea->attr.gc; \
\
pprLineThick(pArea, pArea->attr.lineThick); \
\
xp0 = xPixLeft + .5 + (xD - xLeft) * xScale; \
yp0 = winHt - (int)(yPixBot + .5 + ((double)(*++y) - yBot) * yScale); \
for (xD=x; --npts>0; xD+=x) { \
xp1 = xPixLeft + .5 + (xD - xLeft) * xScale; \
yp1 = winHt - (int)(yPixBot + .5 + ((double)(*++y)-yBot)*yScale); \
if (xp0 != xp1 || yp0 != yp1) \
XDrawLine(pDisp, plotWindow, gc, xp0, yp0, xp1, yp1); \
xp0 = xp1; \
yp0 = yp1; \
} \
pArea->xPix = xp1; \
pArea->yPix = yp1; \
return; \
}
#else
#define QUICK_WAVE()
#endif
/*+/subr**********************************************************************
* NAME pprWave - plot a waveform
*
* DESCRIPTION
* Draw a waveform using a y data value array and an x increment value.
* The first x value is assumed to be 0.
*
* Several entry points are available to accomodate various
* types of data:
*
* pprWaveF(pArea, x, y, npts) x and y are float[]
* pprWaveD(pArea, x, y, npts) x and y are double[]
* pprWaveS(pArea, x, y, npts) x and y are short[]
* pprWaveL(pArea, x, y, npts) x and y are long[]
*
* Several entry points are available for erasing:
*
* pprWaveEraseF(pArea, x, y, npts) x and y are float[]
* pprWaveEraseD(pArea, x, y, npts) x and y are double[]
* pprWaveEraseS(pArea, x, y, npts) x and y are short[]
* pprWaveEraseL(pArea, x, y, npts) x and y are long[]
*
* RETURNS
* void
*
* BUGS
* o only linear calibration is handled
*
* SEE ALSO
* pprLineSeg, pprMove, pprPoint, pprText
*
* NOTES
* 1. The waveform drawing routines are optimized for fast plotting when
* no clipping is being done and dashed line pattern isn't being used.
* This optimization is only for plotting under X11. All other cases,
* including erasing an individual waveform, are handled with the usual
* pprXxx drawing routines.
*
*-*/
void
pprWaveF(pArea, x, y, npts)
PPR_AREA *pArea; /* I pointer to plot area structure */
float x; /* I x increment for data values */
float *y; /* I y array of data values */
int npts; /* I number of points to plot */
{ double xD=0.;
QUICK_WAVE();
pprMoveD(pArea, xD, (double)(*y), 0);
for (xD=x; --npts>0; xD+=x)
pprMoveD(pArea, xD, (double)(*++y), 1);
}
void pprWaveD(pArea, x, y, npts)
PPR_AREA *pArea; double x; double *y; int npts;
{ double xD=0.;
QUICK_WAVE();
pprMoveD(pArea, xD, *y, 0);
for (xD=x; --npts>0; xD+=x)
pprMoveD(pArea, xD, *++y, 1);
}
void pprWaveS(pArea, x, y, npts)
PPR_AREA *pArea; short x; short *y; int npts;
{ double xD=0.;
QUICK_WAVE();
pprMoveD(pArea, xD, (double)(*y), 0);
for (xD=x; --npts>0; xD+=x)
pprMoveD(pArea, xD, (double)(*++y), 1);
}
void pprWaveL(pArea, x, y, npts)
PPR_AREA *pArea; long x; long *y; int npts;
{ double xD=0.;
QUICK_WAVE();
pprMoveD(pArea, xD, (double)(*y), 0);
for (xD=x; --npts>0; xD+=x)
pprMoveD(pArea, xD, (double)(*++y), 1);
}
void pprWaveEraseF(pArea, x, y, npts)
PPR_AREA *pArea; float x; float *y; int npts;
{ double xD=0.;
pprMoveD(pArea, xD, (double)(*y), 0);
for (xD=x; --npts>0; xD+=x)
pprMoveEraseD(pArea, xD, (double)(*++y), 1);
}
void pprWaveEraseD(pArea, x, y, npts)
PPR_AREA *pArea; double x; double *y; int npts;
{ double xD=0.;
pprMoveD(pArea, xD, *y, 0);
for (xD=x; --npts>0; xD+=x)
pprMoveEraseD(pArea, xD, *++y, 1);
}
void pprWaveEraseS(pArea, x, y, npts)
PPR_AREA *pArea; short x; short *y; int npts;
{ double xD=0.;
pprMoveD(pArea, xD, (double)(*y), 0);
for (xD=x; --npts>0; xD+=x)
pprMoveEraseD(pArea, xD, (double)(*++y), 1);
}
void pprWaveEraseL(pArea, x, y, npts)
PPR_AREA *pArea; long x; long *y; int npts;
{ double xD=0.;
pprMoveD(pArea, xD, (double)(*y), 0);
for (xD=x; --npts>0; xD+=x)
pprMoveEraseD(pArea, xD, (double)(*++y), 1);
}
/*+/internal******************************************************************
* NAME pprWinAttr - set window attributes
*
*-*/
static void
pprWinAttr(pWin)
PPR_WIN *pWin;
{
#ifdef SUNVIEW
pWin->width = (int)window_get(pWin->canvas, WIN_WIDTH);
pWin->height = (int)window_get(pWin->canvas, WIN_HEIGHT);
pWin->x = (int)window_get(pWin->frame, WIN_X);
pWin->y = (int)window_get(pWin->frame, WIN_Y);
#else
#if defined XWINDOWS
XWindowAttributes winAttr;
XWindowAttributes parentAttr;
long stat;
Window rootWindow, parentWindow, *pChildWindows;
unsigned int nChildren;
int actualX, actualY;
XGetWindowAttributes(pWin->pDisp, pWin->plotWindow, &winAttr);
actualX = winAttr.x;
actualY = winAttr.y;
stat = XQueryTree(pWin->pDisp, pWin->plotWindow, &rootWindow,
&parentWindow, &pChildWindows, &nChildren);
PprAssert(stat != 0);
if (pChildWindows != NULL)
XFree(pChildWindows);
if (rootWindow != parentWindow) {
XGetWindowAttributes(pWin->pDisp, parentWindow, &parentAttr);
actualX = parentAttr.x;
actualY = parentAttr.y;
}
pWin->width = winAttr.width;
pWin->height = winAttr.height;
pWin->x = actualX;
pWin->y = actualY;
#endif
#endif
}
/*+/subr**********************************************************************
* NAME pprWinClose - close a plot window
*
* DESCRIPTION
* Free the memory associated with a plot window structure and do other
* cleanup activities.
*
* This routine should be called when plotting is complete for a plot
* window. Any plot areas not previously closed are automatically
* closed by this routine.
*
* No further references to the plot window may be made.
*
* RETURNS
* void
*
* SEE ALSO
* pprAreaClose, pprWinInfo, pprWinOpen
*
*-*/
void
pprWinClose(pWin)
PPR_WIN *pWin; /* I pointer to plot window structure */
{
PPR_AREA *pArea, *pAreaNext;
#ifdef XWINDOWS
if (pWin->winType == PPR_WIN_SCREEN) {
if (pWin->attr.myGC)
XFreeGC(pWin->pDisp, pWin->attr.gc);
if (pWin->attr.bgGC)
XFreeGC(pWin->pDisp, pWin->attr.gcBG);
}
#endif
pArea = pWin->pAreaHead;
while (pArea != NULL) {
pAreaNext = pArea->pNext;
pprAreaClose(pArea);
pArea = pAreaNext;
}
#ifdef XWINDOWS
if (pWin->winType == PPR_WIN_SCREEN && pWin->userWindow == 0)
XCloseDisplay(pWin->pDisp);
#endif
free((char *)pWin);
}
/*+/subr**********************************************************************
* NAME pprWinErase - erase a plot window
*
* DESCRIPTION
* Erase the contents of the entire plot window.
*
* RETURNS
* void
*
* SEE ALSO
* pprGridErase, pprPerimErase, pprAreaErase, pprRegionErase
* the ppr...Erase... entry points for the various drawing routines
*
*-*/
void
pprWinErase(pWin)
PPR_WIN *pWin; /* I pointer to plot window structure */
{
if (pWin->winType == PPR_WIN_SCREEN) {
#ifdef SUNVIEW
pw_writebackground(pWin->pw, 0, 0, pWin->width, pWin->height, PIX_SRC);
#else
#if defined XWINDOWS
XClearArea(pWin->pDisp, pWin->plotWindow, 0, 0,
pWin->width, pWin->height, False);
XFlush(pWin->pDisp);
#endif
#endif
}
}
/*+/internal******************************************************************
* NAME pprWinEvHandler - handle events in the plotting window
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o action needs to depend on type of window
* o for SunView, a pw_lock() and pw_unlock() would make drawing more
* efficient
*
* SEE ALSO
*
* EXAMPLE
*
*-*/
#ifdef SUNVIEW
static void
pprWinEvHandler(window, pEvent, pArg)
Window window;
Event *pEvent;
void *pArg;
{
PPR_WIN *pWin;
pWin = (PPR_WIN *)window_get(window, WIN_CLIENT_DATA);
if (pWin->winType != PPR_WIN_SCREEN)
PprAssertAlways(0);
if (event_action(pEvent) == WIN_REPAINT) {
if (window == pWin->canvas && !window_get(window, FRAME_CLOSED)) {
pprWinWrapup(pWin);
pWin->attr.ltCurr = -1;
pWin->attr.lineThick = 1;
pprWinAttr(pWin);
(pWin->drawFun)(pWin, pWin->pDrawArg);
}
}
else if (event_action(pEvent) == PPR_BTN_CLOSE) {
if (event_is_up(pEvent)) {
pprWinAttr(pWin);
window_destroy(pWin->frame);
pWin->frame = NULL;
pWin->canvas = NULL;
pprWinWrapup(pWin);
}
}
}
#endif
#ifdef XWINDOWS
static void
pprWinEvHandler(pWin, pEvent)
PPR_WIN *pWin;
XEvent *pEvent; /* pointer to a window event structure */
{
if (pEvent->type == Expose && pEvent->xexpose.count == 0) {
#define PPR_DEBUG_EVENTS 0
#if PPR_DEBUG_EVENTS
(void)printf("expose event\n");
#endif
pprWinWrapup(pWin);
pprWinAttr(pWin);
(pWin->drawFun)(pWin, pWin->pDrawArg);
}
else if (pEvent->type == ButtonRelease) {
pprWinAttr(pWin);
if (pEvent->xbutton.x < 0 || pEvent->xbutton.x > pWin->width ||
pEvent->xbutton.y < 0 || pEvent->xbutton.y > pWin->height) {
#if PPR_DEBUG_EVENTS
(void)printf("button up but mouse not home\n");
(void)printf("button x,y=%d,%d win x,y width,ht=%d,%d %d,%d\n",
pEvent->xbutton.x, pEvent->xbutton.y,
pWin->x, pWin->y, pWin->width, pWin->height);
#endif
; /* no action */
}
else if (pEvent->xbutton.button == PPR_BTN_CLOSE) {
#if PPR_DEBUG_EVENTS
(void)printf("button3 event\n");
#endif
pprWinWrapup(pWin);
pWin->loopDone = 1;
}
#if PPR_DEBUG_EVENTS
else
(void)printf("other button event\n");
#endif
}
#if PPR_DEBUG_EVENTS
else
(void)printf("some other event\n");
#endif
}
#endif
/*+/subr**********************************************************************
* NAME pprWinInfo - get some information about the plot window
*
* DESCRIPTION
* Get the size of the plot window and its position on the screen.
*
* RETURNS
* void
*
* NOTES
* 1. The information returned is window system dependent. To avoid
* portability problems, this information should be used only in
* calls to pprWinXxx routines.
*
*-*/
void
pprWinInfo(pWin, pXpos, pYpos, pXwid, pYht)
PPR_WIN *pWin; /* I pointer to plot window structure */
int *pXpos; /* O pointer to place to store window x coord., in pixels */
int *pYpos; /* O pointer to place to store window y coord., in pixels */
int *pXwid; /* O pointer to place to store window width, in pixels */
int *pYht; /* O pointer to place to store window height, in pixels */
{
*pXpos = pWin->x;
*pYpos = pWin->y;
*pXwid = pWin->width;
*pYht = pWin->height;
}
/*+/subr**********************************************************************
* NAME pprWinIsMono - test to see if plot window is monochrome
*
* DESCRIPTION
*
* RETURNS
* 1 if plot window is monochrome or gray scale
* 0 if plot window is color
*
*-*/
int
pprWinIsMono(pWin)
PPR_WIN *pWin; /* I pointer to plot window structure */
{
#ifdef XWINDOWS
int screenNo;
Visual *pVisual;
#endif
#ifdef XWINDOWS
if (pWin->winType != PPR_WIN_SCREEN)
return 1;
screenNo = DefaultScreen(pWin->pDisp);
pVisual = DefaultVisual(pWin->pDisp, screenNo);
if (pVisual->class != GrayScale && pVisual->class != StaticGray)
return 0;
#endif
return 1; /* color not supported if not XWINDOWS */
}
/*+/subr**********************************************************************
* NAME pprWinLoop - loop until "quit" event received in window
*
* DESCRIPTION
* Handles the interactions with the windowing system. The specific
* actions depend on the plot window type:
*
* PPR_WIN_SCREEN
* o creates a window on the screen
* o when the window actually appears, calls the caller's draw function
* o for all subsequent resize and expose events, calls the caller's
* draw function
* o when the right mouse button is clicked on the plot, closes the
* window and returns to the caller. The current position and size
* of the window are stored (and can be retrieved with pprWinInfo).
*
* PPR_WIN_POSTSCRIPT
* o calls the caller's draw function
*
* PPR_WIN_EPS
* o calls the caller's draw function
*
* The idea when using pprWinLoop is that a program
* will do some preliminary setup for the data to be plotted.
* Then the program must turn control over to the plot "window
* manager" using pprWinLoop, which will call the caller's
* actual plot routine.
*
* When pprWinLoop exits back to the calling program, that program
* can call pprWinInfo in order to "remember" the plot window
* size and position.
*
* RETURNS
* 0, or
* -1 if an error is encountered
*
* BUGS
* o doesn't furnish information to the draw function which would allow
* a partial redraw
* o terminology is confusing and inconsistent: "draw" function, redraw,
* replot, repaint, etc.
*
* SEE ALSO
* pprWinOpen, pprWinInfo
*
* NOTES
* 1. Even though there aren't any "events" associated with plotting on
* a PostScript printer, this routine must be called even when using
* PPR_WIN_POSTSCRIPT and PPR_WIN_EPS, since this routine invokes the
* caller's "draw" function.
*
* EXAMPLE
* See pprWinOpen for an example of a replot function.
jjj
*
*-*/
long
pprWinLoop(pWin, drawFun, pDrawArg)
PPR_WIN *pWin; /* I pointer to plot window structure */
void (*drawFun)();/* I pointer to function to draw the plot */
void *pDrawArg;/* I pointer to pass to drawFun */
{
#ifdef XWINDOWS
XEvent anEvent; /* a window event structure */
#endif
pWin->drawFun = drawFun;
pWin->pDrawArg = pDrawArg;
if (pprWinMap(pWin) != 0)
return -1;
if (pWin->winType == PPR_WIN_SCREEN) {
#ifdef SUNVIEW
window_main_loop(pWin->frame);
#else
#if defined XWINDOWS
while (pWin->loopDone == 0) {
XNextEvent(pWin->pDisp, &anEvent);
pprWinEvHandler(pWin, &anEvent);
}
#endif
#endif
}
else if (pWin->winType == PPR_WIN_POSTSCRIPT ||
pWin->winType == PPR_WIN_EPS) {
(pWin->drawFun)(pWin, pWin->pDrawArg);
}
else
PprAssertAlways(0);
pprWinWrapup(pWin);
return 0;
}
/*+/internal******************************************************************
* NAME pprWinMap - create a plotting "window" and map it onto the display
*
* DESCRIPTION
* This routine actually creates a window on a display device. This
* must be done prior to drawing; the PPR_WIN structure must have
* been initialized by pprWinOpen .
*
* If the display "device" is a file for PostScript printing, then
* the "window" which is created isn't actually a window, but the
* plotting operations of the user routine don't know the difference.
*
* RETURNS
* 0, or
* -1 if an error is encountered
*
* SEE ALSO
* pprWinOpen, pprWinLoop, pprWinWrapup
*
* NOTES
* 1. This routine is called automatically by pprWinLoop, so it should
* not be called by programs that use pprWinLoop.
*
*-*/
long
pprWinMap(pWin)
PPR_WIN *pWin; /* I pointer to plot window structure */
{
#ifdef XWINDOWS
int screenNo, x, y, width, height;
XSizeHints sizeHints;
#endif
if (pWin->winType == PPR_WIN_SCREEN) {
#ifdef SUNVIEW
pWin->frame = window_create(NULL, FRAME,
FRAME_LABEL, pWin->title,
FRAME_NO_CONFIRM, 1,
WIN_EVENT_PROC, pprWinEvHandler,
WIN_CLIENT_DATA, pWin,
WIN_X, pWin->x, WIN_Y, pWin->y,
0);
window_set(pWin->frame, WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS,
ACTION_OPEN, ACTION_CLOSE,
ACTION_FRONT, ACTION_BACK,
WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, 0,
0);
pWin->canvas = window_create(pWin->frame, CANVAS,
WIN_WIDTH, pWin->width,
WIN_HEIGHT, pWin->height,
WIN_EVENT_PROC, pprWinEvHandler,
WIN_CLIENT_DATA, pWin,
CANVAS_AUTO_SHRINK, TRUE,
CANVAS_AUTO_EXPAND, TRUE,
CANVAS_FIXED_IMAGE, FALSE,
CANVAS_RETAINED, FALSE,
CANVAS_AUTO_CLEAR, TRUE,
0);
pWin->pw = canvas_pixwin(pWin->canvas);
window_set(pWin->canvas, WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS,
WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, 0,
0);
window_fit(pWin->frame);
window_set(pWin->frame, WIN_SHOW, 1, 0);
window_set(pWin->canvas, WIN_SHOW, 1, 0);
pArea->attr.myGC = 0;
pArea->attr.bgGC = 0;
#else
#if defined XWINDOWS
if (pWin->winDispName[0] == '\0')
pWin->pDisp = XOpenDisplay((char *)NULL);
else
pWin->pDisp = XOpenDisplay(pWin->winDispName);
if (pWin->pDisp == NULL) {
(void)printf("pprWinMap: XOpenDisplay to %s failed\n",
XDisplayName(pWin->winDispName));
return -1;
}
screenNo = DefaultScreen(pWin->pDisp);
pWin->attr.gc = DefaultGC(pWin->pDisp, screenNo);
pWin->attr.myGC = 0;
sizeHints.x = x = pWin->x;
sizeHints.y = y = pWin->y;
sizeHints.width = width = pWin->width;
sizeHints.height = height = pWin->height;
sizeHints.flags = PSize | PPosition;
pWin->plotWindow = XCreateSimpleWindow(pWin->pDisp,
DefaultRootWindow(pWin->pDisp),
x, y, width, height, 1,
BlackPixel(pWin->pDisp, screenNo),
WhitePixel(pWin->pDisp, screenNo));
XSetStandardProperties(pWin->pDisp, pWin->plotWindow,
pWin->title, pWin->title,
None, 0, NULL, &sizeHints);
XSelectInput(pWin->pDisp, pWin->plotWindow,
ExposureMask | ButtonPressMask | ButtonReleaseMask);
XMapWindow(pWin->pDisp, pWin->plotWindow);
pWin->attr.gcBG = XCreateGC(pWin->pDisp, pWin->plotWindow, 0, NULL);
XCopyGC(pWin->pDisp, pWin->attr.gc,
GCBackground|GCForeground, pWin->attr.gcBG);
XSetFunction(pWin->pDisp, pWin->attr.gcBG, GXclear);
pWin->attr.bgGC = 1;
#endif
#endif
}
else if (pWin->winType == PPR_WIN_POSTSCRIPT ||
pWin->winType == PPR_WIN_EPS) {
; /* no action */
}
else
PprAssertAlways(0);
return 0;
}
/*+/subr**********************************************************************
* NAME pprWinOpen - initialize a plotting "window" structure
*
* DESCRIPTION
* Initialize a plot window structure. This is the structure which
* keeps track of the information needed to interact with the
* device on which the "window" resides. The possible types of
* windows are:
*
* o PPR_WIN_SCREEN selects a window on a visual display. This
* will be a SunView or X window, depending on the version of
* the plotting used in linking the program. The pprWinOpen
* call actually creates a window, with the root window as the
* parent. The window thus created can be moved, resized, etc.
* according to the capabilities of the window manager of the
* windowing system being used. (To initialize a plotting
* window structure in a window which already exists, use
* pprWinOpenUW.)
*
* for SunView,
* `winDispName' is ignored and should be NULL
* `winTitle' appears on the window's title bar and icon
* `xPos' and `yPos' are pixel offsets from the upper left
* corner of the root window. If values of 0 are
* supplied, then the window will be positioned at
* 100,100.
* `xWid' and `yHt' are the width and height of the window,
* in pixels. If values of 0 are supplied, then
* a size of 512,512 will be used.
*
* for X11,
* `winDispName' specifies the X11 display name on which the
* plot window is to appear. If NULL, then the
* DISPLAY environment variable will be used.
* `winTitle' appears on the window's title bar and icon
* `xPos' and `yPos' are pixel offsets from the upper left
* corner of the root window. If values of 0 are
* supplied, then the window will be positioned at
* 100,100.
* `xWid' and `yHt' are the width and height of the window,
* in pixels. If values of 0 are supplied, then
* a size of 512,512 will be used.
*
* o PPR_WIN_POSTSCRIPT selects a "window" on a PostScript
* printer.
*
* `winDispName' is the name of a file to receive PostScript
* output. This is the file which will eventually
* be sent to a PostScript printer to get a hard
* copy of the plot. If the file exists when
* pprWinOpen is called, its contents are erased
* before writing begins.
* `winTitle' is ignored and should be NULL
* `xPos' and `yPos' are ignored
* `xWid' and `yHt' are the width and height of the window,
* in pixels. If values of 0 are supplied, then
* a size of 512,512 will be used. If the size is
* larger than the page, then the plot will be scaled
* to fit. If necessary, the plot will be printed in
* landscape mode, rather than the default of portrait
* mode.
*
* o PPR_WIN_EPS selects a "window" in an Encapsulated PostScript
* file. EPS files are intended to be included into documents
* prepared by word processing programs such as Interleaf and
* TeX. EPS files will not print directly on a PostScript printer.
* The description of the arguments for PPR_WIN_POSTSCRIPT applies,
* except that scaling and rotation aren't done.
*
* The pprXxx routines can be used for several different styles of
* usage:
*
* o a complete set of data is available prior to calling any of
* the plotting routines. In this case, grids can be drawn and
* data can be plotted at the same time.
*
* For this style of usage, the typical usage will be:
* pprWinOpen to "open" a plot window
* pprWinLoop to map the plot window to the screen
* and call the caller's replot function
* when the window is exposed, resized,
* etc.
* pprWinClose to "close" a plot window
*
* o no data (or only part of the data) is available prior to calling
* any of the plotting routines. In this case, at least some of
* the data must be plotted at a later time than when the grids
* are drawn. The pprXxx routines don't automatically support
* this style of usage fully, but they do provide some tools which
* make it relatively easy to implement. See pprWinOpenUW for
* more details.
*
* Under all circumstances, the calling program is expected to call
* pprWinClose when plotting is complete for the plot window.
*
* RETURNS
* pointer to window structure, or
* NULL if an error is encountered
*
* SEE ALSO
* pprWinOpenUW, pprWinClose, pprWinInfo, pprWinLoop
*
* EXAMPLES
* 1. Plot an existing set of data, where the data is stored in `dataStruct'.
*
* PPR_WIN *pWindow;
* .
* pWindow = pprWinOpen(PPR_WIN_SCREEN, NULL, "test", 0, 0, 0, 0);
* if (pWindow == NULL)
* abort();
* if (pprWinLoop(pWindow, replot, &dataStruct) != 0)
* abort();
* pprWinClose(pWindow);
*
*-*/
PPR_WIN *
pprWinOpen(winType, winDispName, winTitle, xPos, yPos, xWid, yHt)
PPR_WIN_TY winType; /* I type of plot window: PPR_WIN_xxx */
char *winDispName; /* I name of "display" or file for window */
char *winTitle; /* I title for window title bar and icon */
int xPos; /* I x position for window; 0 for default */
int yPos; /* I y position for window; 0 for default */
int xWid; /* I width of window; 0 for default */
int yHt; /* I height of window; 0 for default */
{
PPR_WIN *pWin; /* pointer to plot window structure */
if ((pWin = (PPR_WIN *)malloc(sizeof(PPR_WIN))) == NULL) {
(void)printf("pprWinOpen: couldn't malloc plot window struct\n");
return NULL;
}
pWin->pAreaHead = NULL;
pWin->pAreaTail = NULL;
pWin->winType = winType;
pWin->userWindow = pWin->loopDone = 0;
pWin->drawFun = NULL;
pWin->pDrawArg = NULL;
if (xPos != 0)
pWin->x = xPos;
else if (winType == PPR_WIN_POSTSCRIPT || winType == PPR_WIN_EPS)
pWin->x = 0;
else
pWin->x = 100;
if (yPos != 0)
pWin->y = yPos;
else if (winType == PPR_WIN_POSTSCRIPT || winType == PPR_WIN_EPS)
pWin->y = 0;
else
pWin->y = 100;
if (xWid != 0)
pWin->width = xWid;
else if (winType == PPR_WIN_POSTSCRIPT || winType == PPR_WIN_EPS)
pWin->width = 0;
else
pWin->width = 512;
if (yHt != 0)
pWin->height = yHt;
else if (winType == PPR_WIN_POSTSCRIPT || winType == PPR_WIN_EPS)
pWin->height = 0;
else
pWin->height = 512;
if (winDispName == NULL)
pWin->winDispName[0] = '\0';
else if (strlen(winDispName) >= 120) {
(void)printf("pprWinOpen: plot file or display name too long\n");
free((char *)pWin);
return NULL;
}
else
(void)strcpy(pWin->winDispName, winDispName);
if (winTitle == NULL)
pWin->title[0] = '\0';
else if (strlen(winTitle) >= 80) {
(void)printf("pprWinOpen: winTitle too long\n");
free((char *)pWin);
return NULL;
}
else
(void)strcpy(pWin->title, winTitle);
pWin->attr.lineThick = 1;
pWin->attr.ltCurr = -1;
pWin->attr.pPatt = NULL;
pWin->attr.myGC = 0;
pWin->attr.bgGC = 0;
/*-----------------------------------------------------------------------------
* PostScript printer initialization
* o for PostScript,
* - send the %!PS line
* o for Encapsulated PostScript,
* - send the %!PS,EPS line
* - send the %%BoundingBox line
* o send the various PostScript programs needed
* o translate, rotate, and scale the PostScript axis as needed for
* the most recent size the window had.
*----------------------------------------------------------------------------*/
if (winType == PPR_WIN_POSTSCRIPT || winType == PPR_WIN_EPS) {
int i;
int nLines;
double scale, xscale, yscale;
if ((pWin->file = fopen(winDispName, "w")) == NULL) {
perror("opening PostScript or EPS file");
PprAssertAlways(0);
}
if (winType == PPR_WIN_POSTSCRIPT)
(void)fprintf(pWin->file, "%%!PS\n");
else {
(void)fprintf(pWin->file, "%%!PS-Adobe-2.0 EPSF-1.2\n");
(void)fprintf(pWin->file, "%%%%BoundingBox: 0 0 %d %d\n",
pWin->width - 1, pWin->height - 1);
}
/*-----------------------------------------------------------------------------
* write PostScript programs and defaults to file
*----------------------------------------------------------------------------*/
nLines = sizeof(pprPSProg)/sizeof(char *);
for (i=0; i<nLines; i++)
(void)fprintf(pWin->file, "%s\n", pprPSProg[i]);
if (winType == PPR_WIN_POSTSCRIPT) {
if (pWin->width <= 560 && pWin->height <= 720) {
(void)fprintf(pWin->file, "%d %d translate\n",
(int)((612-pWin->width)/2), (760-pWin->height));
}
else if (pWin->width <= 720 && pWin->height <= 560) {
(void)fprintf(pWin->file, "612 0 translate 90 rotate\n");
(void)fprintf(pWin->file, "%d %d translate\n",
(int)((792-pWin->width)/2), (560-pWin->height));
}
else if (pWin->width <= pWin->height) {
xscale = 560. / (double)pWin->width;
yscale = 720. / (double)pWin->height;
if (xscale <= yscale)
scale = xscale;
else
scale = yscale;
(void)fprintf(pWin->file, "%.3f %.3f scale\n", scale, scale);
(void)fprintf(pWin->file, "%d %d translate\n",
(int)((612./scale-pWin->width)/2.),
(int)(760./scale-pWin->height));
}
else {
xscale = 560. / (double)pWin->width;
yscale = 720. / (double)pWin->height;
if (xscale <= yscale)
scale = xscale;
else
scale = yscale;
(void)fprintf(pWin->file, "612 0 translate 90 rotate\n");
(void)fprintf(pWin->file, "%.3f %.3f scale\n", scale, scale);
(void)fprintf(pWin->file, "%d %d translate\n",
(int)((792./scale-pWin->width)/2.),
(int)(560./scale-pWin->height));
}
}
}
return pWin;
}
/*+/subr**********************************************************************
* NAME pprWinOpenUW - open a plot "window" to an existing User Window
*
* DESCRIPTION
* Initialize a plot window structure. This is the structure which
* keeps track of the information needed to interact with the
* device on which the "window" resides.
*
* This routine is for use when the caller already has a window in
* the windowing system. It is for use exclusively for PPR_WIN_SCREEN
* plot window type. The form of the call to this routine is heavily
* dependent on the windowing system being used. This routine provides
* the basis for obtaining `asynchronous' plotting. (It can also be
* used for `batched' plotting, in which all data is available prior
* to the first plotting call.)
*
* Under all circumstances, the calling program is expected to call
* pprWinClose when plotting is complete for the plot window.
*
* RETURNS
* pointer to window structure, or
* NULL if an error is encountered
*
* SEE ALSO
* pprWinOpenUW, pprWinClose, pprWinInfo, pprWinLoop
*
* EXAMPLES
* 1. for X11
*
* PPR_WIN *pWin;
* Display *pDisp;
* Window plotWindow;
* GC plotGC;
*
* pWin = pprWinOpenUW(&pDisp, &plotWindow, &plotGC, NULL);
* ...
* pprWinReplot(pWin, drawFn, drawArg);
* ...
* pprWinClose(pWin);
*
*
* 2. for SunView
*
* PPR_WIN *pWin;
* Frame plotFrame;
* Canvas plotCanvas;
*
* pWin = pprWinOpenUW(&plotFrame, &plotCanvas, NULL, NULL);
* ...
* pprWinReplot(pWin, drawFn, drawArg);
* ...
* pprWinClose(pWin);
*
* 3. for XView
* (Since XView doesn't have any built-in line drawing capabilities,
* some fussing is needed to get the X11 items needed for plotting.
* In the following, pDisp, plotWindow, and plotGC are X11 items which
* are obtained from XView items.)
*
* PPR_WIN *pWin;
* Display *pDisp;
* Window plotWindow;
* GC plotGC;
*
* pDisp = (Display *)xv_get(frame, XV_DISPLAY);
* plotWindow = (Window)xv_get(canvas_paint_window(canvas), XV_XID);
* plotGC = DefaultGC(pDisp, DefaultScreen(pDisp));
*
* pWin = pprWinOpenUW(&pDisp, &plotWindow, &plotGC, NULL);
* ...
* pprWinReplot(pWin, drawFn, drawArg);
* ...
* pprWinClose(pWin);
*
*-*/
PPR_WIN *
pprWinOpenUW(pArg1, pArg2, pArg3, pArg4)
void *pArg1;
void *pArg2;
void *pArg3;
void *pArg4;
{
PPR_WIN *pWin; /* pointer to plot window structure */
if ((pWin = (PPR_WIN *)malloc(sizeof(PPR_WIN))) == NULL) {
(void)printf("pprWinOpenUW: couldn't malloc plot window struct\n");
return NULL;
}
pWin->pAreaHead = NULL;
pWin->pAreaTail = NULL;
pWin->winType = PPR_WIN_SCREEN;
pWin->userWindow = 1;
pWin->loopDone = 0;
pWin->drawFun = NULL;
pWin->pDrawArg = NULL;
pWin->winDispName[0] = '\0';
pWin->title[0] = '\0';
#ifdef SUNVIEW
pWin->frame = *(Frame *)pArg1;
pWin->canvas = *(Canvas *)pArg2;
pWin->pw = canvas_pixwin(pWin->canvas);
pWin->attr.bgGC = 0;
#else
#if defined XWINDOWS
pWin->pDisp = *(Display **)pArg1;
pWin->plotWindow = *(Window *)pArg2;
pWin->attr.gc = *(GC *)pArg3;
pWin->attr.myGC = 0;
pWin->attr.gcBG = XCreateGC(pWin->pDisp, pWin->plotWindow, 0, NULL);
XCopyGC(pWin->pDisp, pWin->attr.gc,
GCBackground|GCForeground, pWin->attr.gcBG);
XSetFunction(pWin->pDisp, pWin->attr.gcBG, GXclear);
pWin->attr.bgGC = 1;
#endif
#endif
pprWinAttr(pWin);
pWin->attr.lineThick = 1;
pWin->attr.ltCurr = -1;
pWin->attr.pPatt = NULL;
return pWin;
}
/*+/subr**********************************************************************
* NAME pprWinReplot - redraw a plot in a user owned window
*
* DESCRIPTION
* Calls the "replot" function to repaint the plot window. This
* routine is intended to be used with "user owned" plot windows
* which have been opened with pprWinOpenUW.
*
* Prior to calling the replot function, this routine determines
* the size of the actual window and rescales the existing plot
* areas.
*
* RETURNS
* void
*
* SEE ALSO
* pprWinOpenUW
*
*-*/
void
pprWinReplot(pWin, pFunc, pArg)
PPR_WIN *pWin;
void (*pFunc)();
void *pArg;
{
int width, height;
PPR_AREA *pArea;
width = pWin->width;
height = pWin->height;
pprWinAttr(pWin);
if (pWin->width != width || pWin->height != height) {
pArea = pWin->pAreaHead;
while (pArea != NULL) {
pprAreaRescale(pArea, pArea->xLeft, pArea->yBot,
pArea->xRight, pArea->yTop);
pArea = pArea->pNext;
}
}
pWin->drawFun = pFunc;
pWin->pDrawArg = pArg;
(pWin->drawFun)(pWin, pWin->pDrawArg);
pprWinWrapup(pWin);
}
/*+/internal******************************************************************
* NAME pprWinWrapup - wrapup plotting operations
*
* DESCRIPTION
* Wrap up plotting operations.
*
* RETURNS
* void
*
* SEE ALSO
* pprWinMap, pprWinOpen, pprWinLoop, pprWinOpenUW, pprWinReplot
*
* NOTES
* 1. This routine is called automatically by pprWinLoop. It should be
* used only by programs which don't use pprWinLoop.
*
*-*/
void
pprWinWrapup(pWin)
PPR_WIN *pWin; /* I pointer to plot window structure */
{
if (pWin->winType == PPR_WIN_POSTSCRIPT)
(void)fprintf(pWin->file, "showpage");
if (pWin->winType == PPR_WIN_POSTSCRIPT || pWin->winType == PPR_WIN_EPS) {
(void)fclose(pWin->file);
pWin->file = NULL;
}
}
/*+/subr**********************************************************************
* NAME pprYFracToXFrac - convert a Y fraction to an X fraction
*
* DESCRIPTION
* Converts a value which is a fraction of window height into a value
* which is a fraction of window width, so that the two values will
* represent the same physical size, in pixels.
*
* This routine is useful for laying out a plot area, especially when
* a grid with annotations and labels is to be used. The choice of
* "data area" size (i.e., the size of the grid) depends on the size
* of the characters which will be used for the annotations and
* labels.
*
* RETURNS
* X fraction
*
* SEE ALSO
* pprText
*
* EXAMPLE
* A plot area is use the full width and the vertical 1/3 of the window.
* x values range from 0 to 100, while y is from -10 to 10. The x
* axis is to be divided into 10 divisions, the y into 4. Use
* the default character size for annotations and labels. Also,
* use the default window position and size.
*
* PPR_WIN *pWin;
* PPR_AREA *pArea;
* float charHt; height as a fraction of window height
* float charWid; width as a fraction of window width
*
* charHt = PprDfltCharHt(.33, .67);
* charWid = pprYFracToXFrac(pWin, charHt);
* pArea = pprAreaOpen(pWin, 12.*charWid, .33+6.*charHt, 1., .67,
* 0., -10., 100., 10, 4, charHt);
*
*-*/
double
pprYFracToXFrac(pWin, yFrac)
PPR_WIN *pWin; /* I pointer to plot window structure */
double yFrac; /* I fraction of window height */
{
return (yFrac * pWin->height / pWin->width);
}
/*+/internal******************************************************************
* NAME pprSleep - simple sleep routine to use with plots
*
* DESCRIPTION
*
* RETURNS
* void
*
* BUGS
* o text
*
* SEE ALSO
*
* EXAMPLE
*
*-*/
static void
pprSleep(seconds, usec)
int seconds; /* I number of seconds (added to usec) to sleep */
int usec; /* I number of micro-sec (added to sec) to sleep */
{
#ifndef vxWorks
/* MDA - usleep isn't POSIX
usleep((unsigned)(seconds*1000000 + usec));
*/
sleep((unsigned int)seconds);
#else
int ticks;
static int ticksPerSec=0;
static int usecPerTick;
if (ticksPerSec == 0) {
ticksPerSec = sysClkRateGet();
usecPerTick = 1000000 / ticksPerSec;
}
ticks = seconds*ticksPerSec + usec/usecPerTick + 1;
taskDelay(ticks);
#endif
}