/* $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 #include #include #include #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_idxnumPoints > 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