6061 lines
196 KiB
C
6061 lines
196 KiB
C
/* 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
|
||
}
|