ngspice/xgraph/draw.c

1264 lines
33 KiB
C
Raw Permalink Normal View History

2004-01-25 10:00:31 +01:00
/* $Header$ */
/*
* draw.c: xgraph drawing code
*
* Routines:
* void DrawWindow();
*
* $Log$
* Revision 1.1 2004-01-25 09:00:49 pnenzi
*
* Added xgraph plotting program.
*
* Revision 1.1.1.1 1999/12/03 23:15:53 heideman
* xgraph-12.0
*
*/
#ifndef lint
static char rcsid[] = "$Id$";
#endif
#include "copyright.h"
#include <stdio.h>
#include <math.h>
#include <pwd.h>
#include <ctype.h>
#include "xgraph.h"
#include "xtb.h"
#include "hard_devices.h"
#include "params.h"
static void DrawTitle();
static void DrawGridAndAxis();
static void WriteValue();
static void DrawData();
static void DrawLegend();
static int TransformCompute();
static double initGrid();
static double stepGrid();
static double RoundUp();
static void set_mark_flags();
void
DrawWindow(win_info)
LocalWin *win_info; /* Window information */
/*
* Draws the data in the window. Does not clear the window.
* The data is scaled so that all of the data will fit.
* Grid lines are drawn at the nearest power of 10 in engineering
* notation. Draws axis numbers along bottom and left hand edges.
* Centers title at top of window.
*/
{
/* Figure out the transformation constants */
if (TransformCompute(win_info)) {
/* Draw the title */
DrawTitle(win_info);
/* Draw the legend */
if (!PM_BOOL("NoLegend"))
DrawLegend(win_info);
/* Draw the axis unit labels, grid lines, and grid labels */
DrawGridAndAxis(win_info);
/* Draw the data sets themselves */
DrawData(win_info);
}
}
static void
DrawTitle(wi)
LocalWin *wi; /* Window information */
/*
* This routine draws the title of the graph centered in
* the window. It is spaced down from the top by an amount
* specified by the constant PADDING. The font must be
* fixed width. The routine returns the height of the
* title in pixels.
*/
{
if (wi->DOrder == 0)
wi->dev_info.xg_text(wi->dev_info.user_state,
(int)(wi->dev_info.area_w*0.95) ,
wi->dev_info.axis_pad,
PM_STR("TitleText"), T_UPPERRIGHT, T_TITLE);
else if (wi->DOrder == 1)
wi->dev_info.xg_text(wi->dev_info.user_state,
(int)(wi->dev_info.area_w*0.95) ,
wi->dev_info.axis_pad,
"First Derivative", T_UPPERRIGHT, T_TITLE);
else if (wi->DOrder == 2)
wi->dev_info.xg_text(wi->dev_info.user_state,
(int)(wi->dev_info.area_w*0.95) ,
wi->dev_info.axis_pad,
"Second Derivative", T_UPPERRIGHT, T_TITLE);
}
static int
TransformCompute(wi)
LocalWin *wi; /* Window information */
/*
* This routine figures out how to draw the axis labels and grid lines.
* Both linear and logarithmic axes are supported. Axis labels are
* drawn in engineering notation. The power of the axes are labeled
* in the normal axis labeling spots. The routine also figures
* out the necessary transformation information for the display
* of the points (it touches XOrgX, XOrgY, UsrOrgX, UsrOrgY, and
* UnitsPerPixel).
*/
{
double bbCenX,
bbCenY,
bbHalfWidth,
bbHalfHeight;
int idx,
maxName,
leftWidth;
char err[MAXBUFSIZE];
char *XUnitText = PM_STR("XUnitText");
/*
* First, we figure out the origin in the X window. Above the space we
* have the title and the Y axis unit label. To the left of the space we
* have the Y axis grid labels.
*/
wi->XOrgX = wi->dev_info.bdr_pad + (7 * wi->dev_info.axis_width)
+ wi->dev_info.bdr_pad;
wi->XOrgY = wi->dev_info.bdr_pad + wi->dev_info.title_height
+ wi->dev_info.bdr_pad + wi->dev_info.axis_height
+ wi->dev_info.axis_height / 2 + wi->dev_info.bdr_pad;
/*
* Now we find the lower right corner. Below the space we have the X axis
* grid labels. To the right of the space we have the X axis unit label
* and the legend. We assume the worst case size for the unit label.
*/
maxName = 0;
for (idx = 0; idx < MAXSETS; idx++) {
if (PlotData[idx].list) {
int tempSize;
tempSize = strlen(PlotData[idx].setName);
if (tempSize > maxName)
maxName = tempSize;
}
}
if (PM_BOOL("NoLegend"))
maxName = 0;
/* Worst case size of the X axis label: */
leftWidth = (strlen(XUnitText)) * wi->dev_info.axis_width;
if ((maxName * wi->dev_info.axis_width) + wi->dev_info.bdr_pad > leftWidth)
leftWidth = maxName * wi->dev_info.axis_width + wi->dev_info.bdr_pad;
wi->XOppX = wi->dev_info.area_w - wi->dev_info.bdr_pad - leftWidth;
wi->XOppY = wi->dev_info.area_h - wi->dev_info.bdr_pad
- wi->dev_info.axis_height - wi->dev_info.bdr_pad;
if ((wi->XOrgX >= wi->XOppX) || (wi->XOrgY >= wi->XOppY)) {
do_error(strcpy(err, "Drawing area is too small\n"));
return 0;
}
/*
* We now have a bounding box for the drawing region. Figure out the units
* per pixel using the data set bounding box.
*/
wi->XUnitsPerPixel = (wi->hiX - wi->loX) /
((double) (wi->XOppX - wi->XOrgX));
wi->YUnitsPerPixel = (wi->hiY - wi->loY) /
((double) (wi->XOppY - wi->XOrgY));
/*
* Find origin in user coordinate space. We keep the center of the
* original bounding box in the same place.
*/
bbCenX = (wi->loX + wi->hiX) / 2.0;
bbCenY = (wi->loY + wi->hiY) / 2.0;
bbHalfWidth = ((double) (wi->XOppX - wi->XOrgX)) / 2.0 * wi->XUnitsPerPixel;
bbHalfHeight = ((double) (wi->XOppY - wi->XOrgY)) / 2.0 * wi->YUnitsPerPixel;
wi->UsrOrgX = bbCenX - bbHalfWidth;
wi->UsrOrgY = bbCenY - bbHalfHeight;
wi->UsrOppX = bbCenX + bbHalfWidth;
wi->UsrOppY = bbCenY + bbHalfHeight;
/*
* Everything is defined so we can now use the SCREENX and SCREENY
* transformations.
*/
return 1;
}
static void
DrawGridAndAxis(wi)
LocalWin *wi; /* Window information */
/*
* This routine draws grid line labels in engineering notation,
* the grid lines themselves, and unit labels on the axes.
*/
{
int expX,
expY; /* Engineering powers */
int startX;
int Yspot,
Xspot;
char power[10],
value[10],
final[MAXBUFSIZE + 10];
double Xincr,
Yincr,
Xstart,
Ystart,
Yindex,
Xindex,
larger;
XSegment segs[2];
double initGrid(),
stepGrid();
int tickFlag = PM_BOOL("Ticks");
int axisFlag = PM_BOOL("TickAxis");
int logXFlag = PM_BOOL("LogX");
int logYFlag = PM_BOOL("LogY");
char *XUnitText = PM_STR("XUnitText");
char *YUnitText = PM_STR("YUnitText");
/*
* Grid display powers are computed by taking the log of the largest
* numbers and rounding down to the nearest multiple of 3.
*/
if (logXFlag) {
expX = 0;
}
else {
if (fabs(wi->UsrOrgX) > fabs(wi->UsrOppX)) {
larger = fabs(wi->UsrOrgX);
}
else {
larger = fabs(wi->UsrOppX);
}
expX = ((int) floor(nlog10(larger) / 3.0)) * 3;
}
if (logYFlag) {
expY = 0;
}
else {
if (fabs(wi->UsrOrgY) > fabs(wi->UsrOppY)) {
larger = fabs(wi->UsrOrgY);
}
else {
larger = fabs(wi->UsrOppY);
}
expY = ((int) floor(nlog10(larger) / 3.0)) * 3;
}
/*
* With the powers computed, we can draw the axis labels.
*/
if (expY != 0) {
(void) strcpy(final, YUnitText);
(void) strcat(final, " x 10");
Xspot = wi->dev_info.bdr_pad +
((strlen(YUnitText) + 5) * wi->dev_info.axis_width);
Yspot = wi->dev_info.bdr_pad * 2 + wi->dev_info.title_height +
wi->dev_info.axis_height / 2;
wi->dev_info.xg_text(wi->dev_info.user_state,
Xspot, Yspot, final, T_RIGHT, T_AXIS);
(void) sprintf(power, "%d", expY);
wi->dev_info.xg_text(wi->dev_info.user_state,
Xspot, Yspot, power, T_LOWERLEFT, T_AXIS);
}
else {
Yspot = wi->dev_info.bdr_pad * 2 + wi->dev_info.title_height;
wi->dev_info.xg_text(wi->dev_info.user_state,
wi->dev_info.bdr_pad, Yspot, YUnitText,
T_UPPERLEFT, T_AXIS);
}
startX = wi->dev_info.area_w - wi->dev_info.bdr_pad;
if (expX != 0) {
(void) sprintf(power, "%d", expX);
startX -= (strlen(power) * wi->dev_info.axis_width);
wi->dev_info.xg_text(wi->dev_info.user_state,
startX, wi->XOppY, power, T_LOWERLEFT, T_AXIS);
(void) strcpy(final, XUnitText);
(void) strcat(final, " x 10");
wi->dev_info.xg_text(wi->dev_info.user_state,
startX, wi->XOppY, final, T_RIGHT, T_AXIS);
}
else {
wi->dev_info.xg_text(wi->dev_info.user_state,
startX, wi->XOppY, XUnitText, T_RIGHT, T_AXIS);
}
/*
* First, the grid line labels
*/
Yincr = (wi->dev_info.axis_pad + wi->dev_info.axis_height) *
wi->YUnitsPerPixel;
Ystart = initGrid(wi->UsrOrgY, Yincr, logYFlag);
for (Yindex = Ystart; Yindex < wi->UsrOppY; Yindex = stepGrid()) {
Yspot = SCREENY(wi, Yindex);
/* Write the axis label */
WriteValue(value, PM_STR("Format X"), Yindex, expY, logYFlag);
wi->dev_info.xg_text(wi->dev_info.user_state,
wi->dev_info.bdr_pad +
(7 * wi->dev_info.axis_width),
Yspot, value, T_RIGHT, T_AXIS);
}
Xincr = (wi->dev_info.axis_pad + (wi->dev_info.axis_width * 7)) *
wi->XUnitsPerPixel;
Xstart = initGrid(wi->UsrOrgX, Xincr, logXFlag);
for (Xindex = Xstart; Xindex < wi->UsrOppX; Xindex = stepGrid()) {
Xspot = SCREENX(wi, Xindex);
/* Write the axis label */
WriteValue(value, PM_STR("Format Y"), Xindex, expX, logXFlag);
wi->dev_info.xg_text(wi->dev_info.user_state,
Xspot,
wi->dev_info.area_h - wi->dev_info.bdr_pad,
value, T_BOTTOM, T_AXIS);
}
/*
* Now, the grid lines or tick marks
*/
Yincr = (wi->dev_info.axis_pad + wi->dev_info.axis_height) *
wi->YUnitsPerPixel;
Ystart = initGrid(wi->UsrOrgY, Yincr, logYFlag);
for (Yindex = Ystart; Yindex < wi->UsrOppY; Yindex = stepGrid()) {
Yspot = SCREENY(wi, Yindex);
/* Draw the grid line or tick mark */
if (tickFlag && !(axisFlag && Yindex == Ystart)) {
segs[0].x1 = wi->XOrgX;
segs[0].x2 = wi->XOrgX + wi->dev_info.tick_len;
segs[1].x1 = wi->XOppX - wi->dev_info.tick_len;
segs[1].x2 = wi->XOppX;
segs[0].y1 = segs[0].y2 = segs[1].y1 = segs[1].y2 = Yspot;
}
else {
segs[0].x1 = wi->XOrgX;
segs[0].x2 = wi->XOppX;
segs[0].y1 = segs[0].y2 = Yspot;
}
if ((ABS(Yindex) < ZERO_THRES) && !logYFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, segs, PM_INT("ZeroWidth"),
L_ZERO, 0, 0);
if (tickFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &(segs[1]), PM_INT("ZeroWidth"),
L_ZERO, 0, 0);
}
}
else {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, segs, PM_INT("GridSize"),
L_AXIS, 0, 0);
if (tickFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &(segs[1]), PM_INT("GridSize"),
L_AXIS, 0, 0);
}
}
}
Xincr = (wi->dev_info.axis_pad + (wi->dev_info.axis_width * 7)) *
wi->XUnitsPerPixel;
Xstart = initGrid(wi->UsrOrgX, Xincr, logXFlag);
for (Xindex = Xstart; Xindex < wi->UsrOppX; Xindex = stepGrid()) {
Xspot = SCREENX(wi, Xindex);
/* Draw the grid line or tick marks */
if (tickFlag && !(axisFlag && Xindex == Xstart)) {
segs[0].x1 = segs[0].x2 = segs[1].x1 = segs[1].x2 = Xspot;
segs[0].y1 = wi->XOrgY;
segs[0].y2 = wi->XOrgY + wi->dev_info.tick_len;
segs[1].y1 = wi->XOppY - wi->dev_info.tick_len;
segs[1].y2 = wi->XOppY;
}
else {
segs[0].x1 = segs[0].x2 = Xspot;
segs[0].y1 = wi->XOrgY;
segs[0].y2 = wi->XOppY;
}
if ((ABS(Xindex) < ZERO_THRES) && !logXFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, segs, PM_INT("ZeroWidth"), L_ZERO, 0, 0);
if (tickFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &(segs[1]), PM_INT("ZeroWidth"),
L_ZERO, 0, 0);
}
}
else {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, segs, PM_INT("GridSize"), L_AXIS, 0, 0);
if (tickFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &(segs[1]), PM_INT("GridSize"), L_AXIS, 0, 0);
}
}
}
/* Check to see if he wants a bounding box */
if (PM_BOOL("BoundBox")) {
XSegment bb[4];
/* Draw bounding box */
bb[0].x1 = bb[0].x2 = bb[1].x1 = bb[3].x2 = wi->XOrgX;
bb[0].y1 = bb[2].y2 = bb[3].y1 = bb[3].y2 = wi->XOrgY;
bb[1].x2 = bb[2].x1 = bb[2].x2 = bb[3].x1 = wi->XOppX;
bb[0].y2 = bb[1].y1 = bb[1].y2 = bb[2].y1 = wi->XOppY;
wi->dev_info.xg_seg(wi->dev_info.user_state,
4, bb, PM_INT("GridSize"), L_AXIS, 0, 0);
}
}
static double gridBase,
gridStep,
gridJuke[101];
static int gridNJuke,
gridCurJuke;
#define ADD_GRID(val) (gridJuke[gridNJuke++] = log10(val))
static double
initGrid(low, step, logFlag)
double low; /* desired low value */
double step; /* desired step (user coords) */
int logFlag; /* is axis logarithmic? */
{
double ratio,
x;
double RoundUp(),
stepGrid();
gridNJuke = gridCurJuke = 0;
gridJuke[gridNJuke++] = 0.0;
if (logFlag) {
ratio = pow(10.0, step);
gridBase = floor(low);
gridStep = ceil(step);
if (ratio <= 3.0) {
if (ratio > 2.0) {
ADD_GRID(3.0);
}
else if (ratio > 1.333) {
ADD_GRID(2.0);
ADD_GRID(5.0);
}
else if (ratio > 1.25) {
ADD_GRID(1.5);
ADD_GRID(2.0);
ADD_GRID(3.0);
ADD_GRID(5.0);
ADD_GRID(7.0);
}
else {
for (x = 1.0; x < 10.0 && (x + .5) / (x + .4) >= ratio; x += .5) {
ADD_GRID(x + .1);
ADD_GRID(x + .2);
ADD_GRID(x + .3);
ADD_GRID(x + .4);
ADD_GRID(x + .5);
}
if (floor(x) != x)
ADD_GRID(x += .5);
for (; x < 10.0 && (x + 1.0) / (x + .5) >= ratio; x += 1.0) {
ADD_GRID(x + .5);
ADD_GRID(x + 1.0);
}
for (; x < 10.0 && (x + 1.0) / x >= ratio; x += 1.0) {
ADD_GRID(x + 1.0);
}
if (x == 7.0) {
gridNJuke--;
x = 6.0;
}
if (x < 7.0) {
ADD_GRID(x + 2.0);
}
if (x == 10.0)
gridNJuke--;
}
x = low - gridBase;
for (gridCurJuke = -1; x >= gridJuke[gridCurJuke + 1]; gridCurJuke++) {
}
}
}
else {
gridStep = RoundUp(step);
gridBase = floor(low / gridStep) * gridStep;
}
return (stepGrid());
}
static double
stepGrid()
{
if (++gridCurJuke >= gridNJuke) {
gridCurJuke = 0;
gridBase += gridStep;
}
return (gridBase + gridJuke[gridCurJuke]);
}
static double
RoundUp(val)
double val; /* Value */
/*
* This routine rounds up the given positive number such that
* it is some power of ten times either 1, 2, or 5. It is
* used to find increments for grid lines.
*/
{
int exponent,
idx;
exponent = (int) floor(nlog10(val));
if (exponent < 0) {
for (idx = exponent; idx < 0; idx++) {
val *= 10.0;
}
}
else {
for (idx = 0; idx < exponent; idx++) {
val /= 10.0;
}
}
if (val > 5.0)
val = 10.0;
else if (val > 2.0)
val = 5.0;
else if (val > 1.0)
val = 2.0;
else
val = 1.0;
if (exponent < 0) {
for (idx = exponent; idx < 0; idx++) {
val /= 10.0;
}
}
else {
for (idx = 0; idx < exponent; idx++) {
val *= 10.0;
}
}
return val;
}
static void
WriteValue(str, fmt, val, expv, logFlag)
char *str; /* String to write into */
char *fmt; /* Format to print str */
double val; /* Value to print */
int expv; /* Exponent */
int logFlag; /* Is this a log axis? */
/*
* Writes the value provided into the string in a fixed format
* consisting of seven characters. The format is:
* -ddd.dd
*/
{
int idx;
if (logFlag) {
if (val == floor(val)) {
if (strcmp(fmt, "%.2f") == 0)
fmt = "%.0e";
val = pow(10.0, val);
}
else {
if (strcmp(fmt, "%.2f") == 0)
fmt = "%.2g";
val = pow(10.0, val - floor(val));
}
}
else {
if (expv < 0) {
for (idx = expv; idx < 0; idx++) {
val *= 10.0;
}
}
else {
for (idx = 0; idx < expv; idx++) {
val /= 10.0;
}
}
}
if (strchr(fmt, 'd') || strchr(fmt, 'x'))
(void) sprintf(str, fmt, (int) val);
else
(void) sprintf(str, fmt, val);
}
#define LEFT_CODE 0x01
#define RIGHT_CODE 0x02
#define BOTTOM_CODE 0x04
#define TOP_CODE 0x08
/* Clipping algorithm from Neumann and Sproull by Cohen and Sutherland */
#define C_CODE(xval, yval, rtn) \
rtn = 0; \
if ((xval) < wi->UsrOrgX) rtn = LEFT_CODE; \
else if ((xval) > wi->UsrOppX) rtn = RIGHT_CODE; \
if ((yval) < wi->UsrOrgY) rtn |= BOTTOM_CODE; \
else if ((yval) > wi->UsrOppY) rtn |= TOP_CODE
void
EraseData(wi)
LocalWin *wi;
/*
* This routine draws the data sets themselves using the macros
* for translating coordinates.
*/
{
double sx1,
sy1,
sx2,
sy2,
tx = 0,
ty = 0;
int idx,
subindex;
int code1,
code2,
cd,
mark_inside;
int X_idx, StoreIDX; /* PW */
XSegment *ptr;
PointList *thisList,
*lastList;
int markFlag,
pixelMarks,
bigPixel,
colorMark;
int noLines = PM_BOOL("NoLines");
int lineWidth = PM_INT("LineWidth");
/* PW Suggests we Flush and set first */
set_mark_flags(&markFlag, &pixelMarks, &bigPixel, &colorMark);
for (idx = 0; idx < MAXSETS; idx++) {
if (wi->DOrder == 0)
thisList = PlotData[idx].list;
else if (wi->DOrder == 1)
thisList = DataD1[idx].list;
else if (wi->DOrder == 2)
thisList = DataD2[idx].list;
else {
printf ("Internal Error differentiating - order > 2!\n");
exit (1);
}
while (thisList) {
X_idx = 0;
for (subindex = 0; subindex < thisList->numPoints - 1; subindex++) {
/* Put segment in (sx1,sy1) (sx2,sy2) */
sx1 = thisList->xvec[subindex];
sy1 = thisList->yvec[subindex];
sx2 = thisList->xvec[subindex + 1];
sy2 = thisList->yvec[subindex + 1];
/* Now clip to current window boundary */
C_CODE(sx1, sy1, code1);
C_CODE(sx2, sy2, code2);
mark_inside = (code1 == 0);
while (code1 || code2) {
if (code1 & code2)
break;
cd = (code1 ? code1 : code2);
if (cd & LEFT_CODE) { /* Crosses left edge */
ty = sy1 + (sy2 - sy1) * (wi->UsrOrgX - sx1) /
(sx2 - sx1);
tx = wi->UsrOrgX;
}
else if (cd & RIGHT_CODE) { /* Crosses right edge */
ty = sy1 + (sy2 - sy1) * (wi->UsrOppX - sx1) /
(sx2 - sx1);
tx = wi->UsrOppX;
}
else if (cd & BOTTOM_CODE) {/* Crosses bottom edge */
tx = sx1 + (sx2 - sx1) * (wi->UsrOrgY - sy1) /
(sy2 - sy1);
ty = wi->UsrOrgY;
}
else if (cd & TOP_CODE) { /* Crosses top edge */
tx = sx1 + (sx2 - sx1) * (wi->UsrOppY - sy1) /
(sy2 - sy1);
ty = wi->UsrOppY;
}
if (cd == code1) {
sx1 = tx;
sy1 = ty;
C_CODE(sx1, sy1, code1);
}
else {
sx2 = tx;
sy2 = ty;
C_CODE(sx2, sy2, code2);
}
}
if (!code1 && !code2) {
/* Add segment to list */
Xsegs[0][X_idx].x1 = Xsegs[1][X_idx].x1;
Xsegs[0][X_idx].y1 = Xsegs[1][X_idx].y1;
Xsegs[0][X_idx].x2 = Xsegs[1][X_idx].x2;
Xsegs[0][X_idx].y2 = Xsegs[1][X_idx].y2;
Xsegs[1][X_idx].x1 = SCREENX(wi, sx1);
Xsegs[1][X_idx].y1 = SCREENY(wi, sy1);
Xsegs[1][X_idx].x2 = SCREENX(wi, sx2);
Xsegs[1][X_idx].y2 = SCREENY(wi, sy2);
X_idx++;
}
/* Draw markers if requested and they are in drawing region */
if (markFlag && mark_inside) {
if (pixelMarks) {
if (bigPixel) {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x1,
Xsegs[1][X_idx - 1].y1,
P_DOT, 0, idx % MAXATTR);
}
else {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x1,
Xsegs[1][X_idx - 1].y1,
P_PIXEL, 0, PIXVALUE(idx));
}
}
else {
/* Distinctive markers */
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x1,
Xsegs[1][X_idx - 1].y1,
P_MARK, MARKSTYLE(idx),
PIXVALUE(idx));
}
}
/* Draw bar elements if requested */
if (PM_BOOL("BarGraph")) {
int barPixels,
baseSpot;
XSegment line;
barPixels = (int) ((PM_DBL("BarWidth") /
wi->XUnitsPerPixel) + 0.5);
if (barPixels <= 0)
barPixels = 1;
baseSpot = SCREENY(wi, PM_DBL("BarBase"));
line.x1 = line.x2 = Xsegs[1][X_idx - 1].x1 +
(int) ((PM_DBL("BarOffset") * idx /
wi->XUnitsPerPixel) + 0.5);
if (PM_BOOL("StackGraph") && idx != 0)
line.y1 = Xsegs[0][X_idx - 1].y1;
else
line.y1 = baseSpot;
line.y2 = Xsegs[1][X_idx - 1].y1;
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &line, barPixels, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
}
}
/* Handle last marker */
if (markFlag && (thisList->numPoints > 0)) {
C_CODE(thisList->xvec[thisList->numPoints - 1],
thisList->yvec[thisList->numPoints - 1],
mark_inside);
if (mark_inside == 0) {
if (pixelMarks) {
if (bigPixel) {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x2,
Xsegs[1][X_idx - 1].y2,
P_DOT, 0, idx % MAXATTR);
}
else {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x2,
Xsegs[1][X_idx - 1].y2,
P_PIXEL, 0, PIXVALUE(idx));
}
}
else {
/* Distinctive markers */
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x2,
Xsegs[1][X_idx - 1].y2,
P_MARK, MARKSTYLE(idx),
PIXVALUE(idx));
}
}
}
/* Handle last bar */
if ((thisList->numPoints > 0) && PM_BOOL("BarGraph")) {
int barPixels,
baseSpot;
XSegment line;
barPixels = (int) ((PM_DBL("BarWidth") /
wi->XUnitsPerPixel) + 0.5);
if (barPixels <= 0)
barPixels = 1;
baseSpot = SCREENY(wi, PM_DBL("BarBase"));
line.x1 = line.x2 = Xsegs[1][X_idx - 1].x2 +
(int) ((PM_DBL("BarOffset") * idx /
wi->XUnitsPerPixel) + 0.5);
if (PM_BOOL("StackGraph") && idx != 0)
line.y1 = Xsegs[0][X_idx - 1].y2;
else
line.y1 = baseSpot;
line.y2 = Xsegs[1][X_idx - 1].y2;
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &line, barPixels, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
}
/* Erase segments */
if ((thisList->numPoints > 0) && (!noLines) && (X_idx > 0)) {
ptr = Xsegs[1];
while (X_idx > wi->dev_info.max_segs) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
wi->dev_info.max_segs, ptr,
lineWidth, L_VAR,
16, (int)(1));
/*LINESTYLE(8), (int)(1));*/
ptr += wi->dev_info.max_segs;
X_idx -= wi->dev_info.max_segs;
}
wi->dev_info.xg_seg(wi->dev_info.user_state,
X_idx, ptr,
lineWidth, L_VAR,
16,(int)(1));
}
/* Next subset */
thisList = thisList->next;
}
}
XFlush (disp);
}
static void
DrawData(wi)
LocalWin *wi;
/*
* This routine draws the data sets themselves using the macros
* for translating coordinates.
*/
{
double sx1,
sy1,
sx2,
sy2,
tx = 0,
ty = 0;
int idx,
subindex;
int code1,
code2,
cd,
mark_inside;
int X_idx, StoreIDX; /* PW */
XSegment *ptr;
PointList *thisList,
*lastList;
int markFlag,
pixelMarks,
bigPixel,
colorMark;
int noLines = PM_BOOL("NoLines");
int lineWidth = PM_INT("LineWidth");
/* PW */
int theDelay;
/* PW Suggests we Flush and set first */
theDelay = PM_INT("DelayValue")*100000;
XFlush(disp);
if (PM_BOOL("Animate")) sleep(1);
set_mark_flags(&markFlag, &pixelMarks, &bigPixel, &colorMark);
for (idx = 0; idx < MAXSETS; idx++) {
if (wi->DOrder == 0)
thisList = PlotData[idx].list;
else if (wi->DOrder == 1)
thisList = DataD1[idx].list;
else if (wi->DOrder == 2)
thisList = DataD2[idx].list;
else {
printf ("Internal Error differentiating - order > 2!\n");
exit (1);
}
while (thisList) {
X_idx = 0;
for (subindex = 0; subindex < thisList->numPoints - 1; subindex++) {
/* Put segment in (sx1,sy1) (sx2,sy2) */
sx1 = thisList->xvec[subindex];
sy1 = thisList->yvec[subindex];
sx2 = thisList->xvec[subindex + 1];
sy2 = thisList->yvec[subindex + 1];
/* Now clip to current window boundary */
C_CODE(sx1, sy1, code1);
C_CODE(sx2, sy2, code2);
mark_inside = (code1 == 0);
while (code1 || code2) {
if (code1 & code2)
break;
cd = (code1 ? code1 : code2);
if (cd & LEFT_CODE) { /* Crosses left edge */
ty = sy1 + (sy2 - sy1) * (wi->UsrOrgX - sx1) /
(sx2 - sx1);
tx = wi->UsrOrgX;
}
else if (cd & RIGHT_CODE) { /* Crosses right edge */
ty = sy1 + (sy2 - sy1) * (wi->UsrOppX - sx1) /
(sx2 - sx1);
tx = wi->UsrOppX;
}
else if (cd & BOTTOM_CODE) {/* Crosses bottom edge */
tx = sx1 + (sx2 - sx1) * (wi->UsrOrgY - sy1) /
(sy2 - sy1);
ty = wi->UsrOrgY;
}
else if (cd & TOP_CODE) { /* Crosses top edge */
tx = sx1 + (sx2 - sx1) * (wi->UsrOppY - sy1) /
(sy2 - sy1);
ty = wi->UsrOppY;
}
if (cd == code1) {
sx1 = tx;
sy1 = ty;
C_CODE(sx1, sy1, code1);
}
else {
sx2 = tx;
sy2 = ty;
C_CODE(sx2, sy2, code2);
}
}
if (!code1 && !code2) {
/* Add segment to list */
Xsegs[0][X_idx].x1 = Xsegs[1][X_idx].x1;
Xsegs[0][X_idx].y1 = Xsegs[1][X_idx].y1;
Xsegs[0][X_idx].x2 = Xsegs[1][X_idx].x2;
Xsegs[0][X_idx].y2 = Xsegs[1][X_idx].y2;
Xsegs[1][X_idx].x1 = SCREENX(wi, sx1);
Xsegs[1][X_idx].y1 = SCREENY(wi, sy1);
Xsegs[1][X_idx].x2 = SCREENX(wi, sx2);
Xsegs[1][X_idx].y2 = SCREENY(wi, sy2);
X_idx++;
}
/* Draw markers if requested and they are in drawing region */
if (markFlag && mark_inside) {
if (pixelMarks) {
if (bigPixel) {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x1,
Xsegs[1][X_idx - 1].y1,
P_DOT, 0, idx % MAXATTR);
}
else {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x1,
Xsegs[1][X_idx - 1].y1,
P_PIXEL, 0, PIXVALUE(idx));
}
}
else {
/* Distinctive markers */
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x1,
Xsegs[1][X_idx - 1].y1,
P_MARK, MARKSTYLE(idx),
PIXVALUE(idx));
}
}
/* Draw bar elements if requested */
if (PM_BOOL("BarGraph")) {
int barPixels,
baseSpot;
XSegment line;
barPixels = (int) ((PM_DBL("BarWidth") /
wi->XUnitsPerPixel) + 0.5);
if (barPixels <= 0)
barPixels = 1;
baseSpot = SCREENY(wi, PM_DBL("BarBase"));
line.x1 = line.x2 = Xsegs[1][X_idx - 1].x1 +
(int) ((PM_DBL("BarOffset") * idx /
wi->XUnitsPerPixel) + 0.5);
if (PM_BOOL("StackGraph") && idx != 0)
line.y1 = Xsegs[0][X_idx - 1].y1;
else
line.y1 = baseSpot;
line.y2 = Xsegs[1][X_idx - 1].y1;
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &line, barPixels, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
}
}
/* Handle last marker */
if (markFlag && (thisList->numPoints > 0)) {
C_CODE(thisList->xvec[thisList->numPoints - 1],
thisList->yvec[thisList->numPoints - 1],
mark_inside);
if (mark_inside == 0) {
if (pixelMarks) {
if (bigPixel) {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x2,
Xsegs[1][X_idx - 1].y2,
P_DOT, 0, idx % MAXATTR);
}
else {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x2,
Xsegs[1][X_idx - 1].y2,
P_PIXEL, 0, PIXVALUE(idx));
}
}
else {
/* Distinctive markers */
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[1][X_idx - 1].x2,
Xsegs[1][X_idx - 1].y2,
P_MARK, MARKSTYLE(idx),
PIXVALUE(idx));
}
}
}
/* Handle last bar */
if ((thisList->numPoints > 0) && PM_BOOL("BarGraph")) {
int barPixels,
baseSpot;
XSegment line;
barPixels = (int) ((PM_DBL("BarWidth") /
wi->XUnitsPerPixel) + 0.5);
if (barPixels <= 0)
barPixels = 1;
baseSpot = SCREENY(wi, PM_DBL("BarBase"));
line.x1 = line.x2 = Xsegs[1][X_idx - 1].x2 +
(int) ((PM_DBL("BarOffset") * idx /
wi->XUnitsPerPixel) + 0.5);
if (PM_BOOL("StackGraph") && idx != 0)
line.y1 = Xsegs[0][X_idx - 1].y2;
else
line.y1 = baseSpot;
line.y2 = Xsegs[1][X_idx - 1].y2;
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &line, barPixels, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
}
/* Draw segments */
if (!PM_BOOL("Animate")) {
if (thisList->numPoints > 0 && (!noLines) && (X_idx > 0)) {
ptr = Xsegs[1];
while (X_idx > wi->dev_info.max_segs) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
wi->dev_info.max_segs, ptr,
lineWidth, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
ptr += wi->dev_info.max_segs;
X_idx -= wi->dev_info.max_segs;
}
wi->dev_info.xg_seg(wi->dev_info.user_state,
X_idx, ptr,
lineWidth, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
}
} else {
StoreIDX = X_idx;
if (thisList->numPoints > 0 && (!noLines) && (X_idx > 0)) {
ptr = Xsegs[1];
while (X_idx > wi->dev_info.max_segs) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
wi->dev_info.max_segs, ptr,
lineWidth, L_VAR,
LINESTYLE(1), PIXVALUE(2));
ptr += wi->dev_info.max_segs;
X_idx -= wi->dev_info.max_segs;
}
wi->dev_info.xg_seg(wi->dev_info.user_state,
X_idx, ptr,
lineWidth, L_VAR,
LINESTYLE(1), PIXVALUE(2));
}
XFlush (disp);
for (X_idx=1;X_idx<theDelay;X_idx++);
X_idx = StoreIDX;
if ((thisList->numPoints > 0) && (!noLines) && (X_idx > 0)) {
ptr = Xsegs[1];
while (X_idx > wi->dev_info.max_segs) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
wi->dev_info.max_segs, ptr,
lineWidth, L_VAR,
16, (int)(1));
/*LINESTYLE(8), (int)(1));*/
ptr += wi->dev_info.max_segs;
X_idx -= wi->dev_info.max_segs;
}
wi->dev_info.xg_seg(wi->dev_info.user_state,
X_idx, ptr,
lineWidth, L_VAR,
16,(int)(1));
}
}
/* Next subset */
lastList = thisList;
thisList = thisList->next;
} /* End While */
}
if (PM_BOOL("Animate")) {
X_idx = StoreIDX;
thisList = lastList;
if (thisList->numPoints > 0 && (!noLines) && (X_idx > 0)) {
ptr = Xsegs[1];
while (X_idx > wi->dev_info.max_segs) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
wi->dev_info.max_segs, ptr,
lineWidth, L_VAR,
LINESTYLE(1), PIXVALUE(2));
ptr += wi->dev_info.max_segs;
X_idx -= wi->dev_info.max_segs;
}
wi->dev_info.xg_seg(wi->dev_info.user_state,
X_idx, ptr,
lineWidth, L_VAR,
LINESTYLE(1), PIXVALUE(2));
}
}
XFlush (disp);
}
static void
DrawLegend(wi)
LocalWin *wi;
/*
* This draws a legend of the data sets displayed. Only those that
* will fit are drawn.
*/
{
int idx,
spot,
lineLen,
oneLen,
incr;
XSegment leg_line;
int markFlag,
pixelMarks,
bigPixel,
colorMark;
set_mark_flags(&markFlag, &pixelMarks, &bigPixel, &colorMark);
spot = wi->XOrgY;
lineLen = 0;
incr = 2 + wi->dev_info.axis_height + wi->dev_info.bdr_pad;
/* First pass draws the text */
for (idx = 0; idx < MAXSETS; idx++) {
if ((PlotData[idx].list) &&
(spot + wi->dev_info.axis_height + 2 < wi->XOppY)) {
/* Meets the criteria */
oneLen = strlen(PlotData[idx].setName);
if (oneLen > lineLen)
lineLen = oneLen;
wi->dev_info.xg_text(wi->dev_info.user_state,
wi->XOppX + wi->dev_info.bdr_pad,
spot + 2,
PlotData[idx].setName,
T_UPPERLEFT, T_AXIS);
spot += incr;
}
}
lineLen = lineLen * wi->dev_info.axis_width;
leg_line.x1 = wi->XOppX + wi->dev_info.bdr_pad;
leg_line.x2 = leg_line.x1 + lineLen;
spot = wi->XOrgY;
/* second pass draws the lines */
for (idx = 0; idx < MAXSETS; idx++) {
if ((PlotData[idx].list) &&
(spot + wi->dev_info.axis_height + 2 < wi->XOppY)) {
leg_line.y1 = leg_line.y2 = spot - wi->dev_info.legend_pad;
if (PM_BOOL("BarGraph"))
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &leg_line,
incr / 4,
L_VAR, LINESTYLE(idx), PIXVALUE(idx));
if (!PM_BOOL("NoLines"))
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &leg_line, 1, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
if (markFlag && !pixelMarks) {
wi->dev_info.xg_dot(wi->dev_info.user_state,
leg_line.x1, leg_line.y1,
P_MARK, MARKSTYLE(idx), PIXVALUE(idx));
}
spot += incr;
}
}
}
static void
set_mark_flags(markFlag, pixelMarks, bigPixel, colorMark)
int *markFlag;
int *pixelMarks;
int *bigPixel;
int *colorMark;
/*
* Determines the values of the old boolean flags based on the
* new values in the parameters database.
*/
{
*markFlag = 0;
*pixelMarks = 0;
*colorMark = 0;
*bigPixel = 0;
if (PM_BOOL("Markers")) {
*markFlag = 1;
*pixelMarks = 0;
*colorMark = 0;
}
if (PM_BOOL("PixelMarkers")) {
*markFlag = 1;
*pixelMarks = 1;
*bigPixel = 0;
}
if (PM_BOOL("LargePixels")) {
*markFlag = 1;
*pixelMarks = 1;
*bigPixel = 1;
}
if (PM_BOOL("StyleMarkers")) {
*markFlag = 1;
*pixelMarks = 0;
*colorMark = 1;
}
}
#undef DELAY