diff options
Diffstat (limited to 'generic/tkbltGrPSOutput.C')
-rw-r--r-- | generic/tkbltGrPSOutput.C | 931 |
1 files changed, 931 insertions, 0 deletions
diff --git a/generic/tkbltGrPSOutput.C b/generic/tkbltGrPSOutput.C new file mode 100644 index 0000000..8f02cba --- /dev/null +++ b/generic/tkbltGrPSOutput.C @@ -0,0 +1,931 @@ +/* + * Smithsonian Astrophysical Observatory, Cambridge, MA, USA + * This code has been modified under the terms listed below and is made + * available under the same terms. + */ + +/* + * Copyright 1991-2004 George A Howlett. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <cmath> + +#include "tk.h" + +// copied from tk3d.h + +typedef struct TkBorder { + Screen *screen; /* Screen on which the border will be used. */ + Visual *visual; /* Visual for all windows and pixmaps using + * the border. */ + int depth; /* Number of bits per pixel of drawables where + * the border will be used. */ + Colormap colormap; /* Colormap out of which pixels are + * allocated. */ + int resourceRefCount; /* Number of active uses of this color (each + * active use corresponds to a call to + * Tk_Alloc3DBorderFromObj or Tk_Get3DBorder). + * If this count is 0, then this structure is + * no longer valid and it isn't present in + * borderTable: it is being kept around only + * because there are objects referring to it. + * The structure is freed when objRefCount and + * resourceRefCount are both 0. */ + int objRefCount; /* The number of Tcl objects that reference + * this structure. */ + XColor *bgColorPtr; /* Background color (intensity between + * lightColorPtr and darkColorPtr). */ + XColor *darkColorPtr; /* Color for darker areas (must free when + * deleting structure). NULL means shadows + * haven't been allocated yet.*/ + XColor *lightColorPtr; /* Color used for lighter areas of border + * (must free this when deleting structure). + * NULL means shadows haven't been allocated + * yet. */ + Pixmap shadow; /* Stipple pattern to use for drawing shadows + * areas. Used for displays with <= 64 colors + * or where colormap has filled up. */ + GC bgGC; /* Used (if necessary) to draw areas in the + * background color. */ + GC darkGC; /* Used to draw darker parts of the border. + * None means the shadow colors haven't been + * allocated yet.*/ + GC lightGC; /* Used to draw lighter parts of the border. + * None means the shadow colors haven't been + * allocated yet. */ + Tcl_HashEntry *hashPtr; /* Entry in borderTable (needed in order to + * delete structure). */ + struct TkBorder *nextPtr; /* Points to the next TkBorder structure with + * the same color name. Borders with the same + * name but different screens or colormaps are + * chained together off a single entry in + * borderTable. */ +} TkBorder; + +#include "tkbltGraph.h" +#include "tkbltGrPostscript.h" +#include "tkbltGrPSOutput.h" + +using namespace Blt; + +PSOutput::PSOutput(Graph* graphPtr) +{ + graphPtr_ = graphPtr; + + Tcl_DStringInit(&dString_); +} + +PSOutput::~PSOutput() +{ + Tcl_DStringFree(&dString_); +} + +void PSOutput::printPolyline(Point2d* screenPts, int nScreenPts) +{ + Point2d* pp = screenPts; + append("newpath\n"); + format(" %g %g moveto\n", pp->x, pp->y); + + Point2d* pend; + for (pp++, pend = screenPts + nScreenPts; pp < pend; pp++) + format(" %g %g lineto\n", pp->x, pp->y); +} + +void PSOutput::printMaxPolyline(Point2d* points, int nPoints) +{ + if (nPoints <= 0) + return; + + for (int nLeft = nPoints; nLeft > 0; nLeft -= 1500) { + int length = MIN(1500, nLeft); + printPolyline(points, length); + append("DashesProc stroke\n"); + points += length; + } +} + +void PSOutput::printSegments(Segment2d* segments, int nSegments) +{ + append("newpath\n"); + + for (Segment2d *sp = segments, *send = sp + nSegments; sp < send; sp++) { + format(" %g %g moveto %g %g lineto\n", sp->p.x, sp->p.y, sp->q.x, sp->q.y); + append("DashesProc stroke\n"); + } +} + +void PSOutput::computeBBox(int width, int height) +{ + Postscript* setupPtr = graphPtr_->postscript_; + PostscriptOptions* pops = (PostscriptOptions*)setupPtr->ops_; + + // scale from points to pica + float pica = 25.4 / 72 * + WidthOfScreen(Tk_Screen(graphPtr_->tkwin_)) / + WidthMMOfScreen(Tk_Screen(graphPtr_->tkwin_)); + + int hBorder = 2*pops->xPad/pica; + int vBorder = 2*pops->yPad/pica; + int hSize = !pops->landscape ? width : height; + int vSize = !pops->landscape ? height : width; + + // If the paper size wasn't specified, set it to the graph size plus the + // paper border. + int paperWidth = pops->reqPaperWidth > 0 ? pops->reqPaperWidth/pica : + hSize + hBorder; + int paperHeight = pops->reqPaperHeight > 0 ? pops->reqPaperHeight/pica : + vSize + vBorder; + + // Scale the plot size if it's bigger than the paper + float hScale = (hSize+hBorder) > paperWidth ? 1.0 : + (float)(paperWidth - hBorder) / hSize; + float vScale = (vSize + vBorder) > paperHeight ? 1.0 : + (float)(paperHeight - vBorder) / vSize; + + float scale = MIN(hScale, vScale); + if (scale != 1.0) { + hSize = hSize*scale + 0.5; + vSize = vSize*scale + 0.5; + } + + int x = (paperWidth > hSize) && pops->center ? + (paperWidth - hSize) / 2 : pops->xPad/pica; + int y = (paperHeight > vSize) && pops->center ? + (paperHeight - vSize) / 2 : pops->yPad/pica; + + setupPtr->left = x; + setupPtr->bottom = y; + setupPtr->right = x + hSize - 1; + setupPtr->top = y + vSize - 1; + setupPtr->scale = scale; + setupPtr->paperHeight = paperHeight; + setupPtr->paperWidth = paperWidth; +} + +const char* PSOutput::getValue(int* lengthPtr) +{ + *lengthPtr = strlen(Tcl_DStringValue(&dString_)); + return Tcl_DStringValue(&dString_); +} + +void PSOutput::append(const char* string) +{ + Tcl_DStringAppend(&dString_, string, -1); +} + +void PSOutput::format(const char* fmt, ...) +{ + va_list argList; + + va_start(argList, fmt); + vsnprintf(scratchArr_, POSTSCRIPT_BUFSIZ, fmt, argList); + va_end(argList); + Tcl_DStringAppend(&dString_, scratchArr_, -1); +} + +void PSOutput::setLineWidth(int lineWidth) +{ + if (lineWidth < 1) + lineWidth = 1; + format("%d setlinewidth\n", lineWidth); +} + +void PSOutput::printRectangle(double x, double y, int width, int height) +{ + append("newpath\n"); + format(" %g %g moveto\n", x, y); + format(" %d %d rlineto\n", width, 0); + format(" %d %d rlineto\n", 0, height); + format(" %d %d rlineto\n", -width, 0); + append("closepath\n"); + append("stroke\n"); +} + +void PSOutput::fillRectangle(double x, double y, int width, int height) +{ + append("newpath\n"); + format(" %g %g moveto\n", x, y); + format(" %d %d rlineto\n", width, 0); + format(" %d %d rlineto\n", 0, height); + format(" %d %d rlineto\n", -width, 0); + append("closepath\n"); + append("fill\n"); +} + +void PSOutput::fillRectangles(XRectangle* rectangles, int nRectangles) +{ + for (XRectangle *rp = rectangles, *rend = rp + nRectangles; rp < rend; rp++) + fillRectangle((double)rp->x, (double)rp->y, (int)rp->width,(int)rp->height); +} + +void PSOutput::setBackground(XColor* colorPtr) +{ + PostscriptOptions* pops = (PostscriptOptions*)graphPtr_->postscript_->ops_; + printXColor(colorPtr); + append(" setrgbcolor\n"); + if (pops->greyscale) + append(" currentgray setgray\n"); +} + +void PSOutput::setForeground(XColor* colorPtr) +{ + PostscriptOptions* pops = (PostscriptOptions*)graphPtr_->postscript_->ops_; + printXColor(colorPtr); + append(" setrgbcolor\n"); + if (pops->greyscale) + append(" currentgray setgray\n"); +} + +void PSOutput::setBackground(Tk_3DBorder border) +{ + TkBorder* borderPtr = (TkBorder*)border; + setBackground(borderPtr->bgColorPtr); +} + +void PSOutput::setFont(Tk_Font font) +{ + Tcl_DString psdstr; + Tcl_DStringInit(&psdstr); + int psSize = Tk_PostscriptFontName(font, &psdstr); + format("%d /%s SetFont\n", psSize, Tcl_DStringValue(&psdstr)); + Tcl_DStringFree(&psdstr); +} + +void PSOutput::setLineAttributes(XColor* colorPtr,int lineWidth, + Dashes* dashesPtr, int capStyle, + int joinStyle) +{ + setJoinStyle(joinStyle); + setCapStyle(capStyle); + setForeground(colorPtr); + setLineWidth(lineWidth); + setDashes(dashesPtr); + append("/DashesProc {} def\n"); +} + +void PSOutput::fill3DRectangle(Tk_3DBorder border, double x, double y, + int width, int height, int borderWidth, + int relief) +{ + TkBorder* borderPtr = (TkBorder*)border; + + setBackground(borderPtr->bgColorPtr); + fillRectangle(x, y, width, height); + print3DRectangle(border, x, y, width, height, borderWidth, relief); +} + +void PSOutput::setClearBackground() +{ + append("1 1 1 setrgbcolor\n"); +} + +void PSOutput::setDashes(Dashes* dashesPtr) +{ + + append("[ "); + if (dashesPtr) { + for (unsigned char* vp = dashesPtr->values; *vp != 0; vp++) + format(" %d", *vp); + } + append("] 0 setdash\n"); +} + +void PSOutput::fillPolygon(Point2d *screenPts, int nScreenPts) +{ + printPolygon(screenPts, nScreenPts); + append("fill\n"); +} + +void PSOutput::setJoinStyle(int joinStyle) +{ + // miter = 0, round = 1, bevel = 2 + format("%d setlinejoin\n", joinStyle); +} + +void PSOutput::setCapStyle(int capStyle) +{ + // X11:not last = 0, butt = 1, round = 2, projecting = 3 + // PS: butt = 0, round = 1, projecting = 2 + if (capStyle > 0) + capStyle--; + + format("%d setlinecap\n", capStyle); +} + +void PSOutput::printPolygon(Point2d *screenPts, int nScreenPts) +{ + Point2d* pp = screenPts; + append("newpath\n"); + format(" %g %g moveto\n", pp->x, pp->y); + + Point2d* pend; + for (pp++, pend = screenPts + nScreenPts; pp < pend; pp++) + format(" %g %g lineto\n", pp->x, pp->y); + + format(" %g %g lineto\n", screenPts[0].x, screenPts[0].y); + append("closepath\n"); +} + +void PSOutput::print3DRectangle(Tk_3DBorder border, double x, double y, + int width, int height, int borderWidth, + int relief) +{ + int twiceWidth = (borderWidth * 2); + if ((width < twiceWidth) || (height < twiceWidth)) + return; + + TkBorder* borderPtr = (TkBorder*)border; + + // Handle grooves and ridges with recursive calls + if ((relief == TK_RELIEF_GROOVE) || (relief == TK_RELIEF_RIDGE)) { + int halfWidth = borderWidth / 2; + int insideOffset = borderWidth - halfWidth; + print3DRectangle(border, (double)x, (double)y, width, height, halfWidth, + (relief == TK_RELIEF_GROOVE) ? + TK_RELIEF_SUNKEN : TK_RELIEF_RAISED); + print3DRectangle(border, (double)(x + insideOffset), + (double)(y + insideOffset), width - insideOffset * 2, + height - insideOffset * 2, halfWidth, + (relief == TK_RELIEF_GROOVE) ? + TK_RELIEF_RAISED : TK_RELIEF_SUNKEN); + return; + } + + XColor* lightPtr = borderPtr->lightColorPtr; + XColor* darkPtr = borderPtr->darkColorPtr; + XColor light; + if (!lightPtr) { + light.red = 0x00; + light.blue = 0x00; + light.green = 0x00; + lightPtr = &light; + } + XColor dark; + if (!darkPtr) { + dark.red = 0x00; + dark.blue = 0x00; + dark.green = 0x00; + darkPtr = &dark; + } + + XColor* topPtr, *bottomPtr; + if (relief == TK_RELIEF_RAISED) { + topPtr = lightPtr; + bottomPtr = darkPtr; + } + else if (relief == TK_RELIEF_SUNKEN) { + topPtr = darkPtr; + bottomPtr = lightPtr; + } + else if (relief == TK_RELIEF_SOLID) { + topPtr = lightPtr; + bottomPtr = lightPtr; + } + else { + topPtr = borderPtr->bgColorPtr; + bottomPtr = borderPtr->bgColorPtr; + } + + setBackground(bottomPtr); + fillRectangle(x, y + height - borderWidth, width, borderWidth); + fillRectangle(x + width - borderWidth, y, borderWidth, height); + + Point2d points[7]; + points[0].x = points[1].x = points[6].x = x; + points[0].y = points[6].y = y + height; + points[1].y = points[2].y = y; + points[2].x = x + width; + points[3].x = x + width - borderWidth; + points[3].y = points[4].y = y + borderWidth; + points[4].x = points[5].x = x + borderWidth; + points[5].y = y + height - borderWidth; + if (relief != TK_RELIEF_FLAT) + setBackground(topPtr); + + fillPolygon(points, 7); +} + +void PSOutput::printXColor(XColor* colorPtr) +{ + format("%g %g %g", + ((double)(colorPtr->red >> 8) / 255.0), + ((double)(colorPtr->green >> 8) / 255.0), + ((double)(colorPtr->blue >> 8) / 255.0)); +} + +int PSOutput::preamble(const char* fileName) +{ + Postscript* setupPtr = graphPtr_->postscript_; + PostscriptOptions* ops = (PostscriptOptions*)setupPtr->ops_; + + if (!fileName) + fileName = Tk_PathName(graphPtr_->tkwin_); + + // Comments + append("%!PS-Adobe-3.0 EPSF-3.0\n"); + + // The "BoundingBox" comment is required for EPS files. The box + // coordinates are integers, so we need round away from the center of the + // box. + format("%%%%BoundingBox: %d %d %d %d\n", + setupPtr->left, setupPtr->paperHeight - setupPtr->top, + setupPtr->right, setupPtr->paperHeight - setupPtr->bottom); + + append("%%Pages: 0\n"); + + format("%%%%Creator: (%s %s %s)\n", PACKAGE_NAME, PACKAGE_VERSION, + Tk_Class(graphPtr_->tkwin_)); + + time_t ticks = time((time_t *) NULL); + char date[200]; + strcpy(date, ctime(&ticks)); + char* newline = date + strlen(date) - 1; + if (*newline == '\n') + *newline = '\0'; + + format("%%%%CreationDate: (%s)\n", date); + format("%%%%Title: (%s)\n", fileName); + append("%%DocumentData: Clean7Bit\n"); + if (ops->landscape) + append("%%Orientation: Landscape\n"); + else + append("%%Orientation: Portrait\n"); + + append("%%DocumentNeededResources: font Helvetica Courier\n"); + addComments(ops->comments); + append("%%EndComments\n\n"); + + // Prolog + prolog(); + + // Setup + append("%%BeginSetup\n"); + append("gsave\n"); + append("1 setlinewidth\n"); + append("1 setlinejoin\n"); + append("0 setlinecap\n"); + append("[] 0 setdash\n"); + append("0 0 0 setrgbcolor\n"); + + if (ops->footer) { + const char* who = getenv("LOGNAME"); + if (!who) + who = "???"; + + append("8 /Helvetica SetFont\n"); + append("10 30 moveto\n"); + format("(Date: %s) show\n", date); + append("10 20 moveto\n"); + format("(File: %s) show\n", fileName); + append("10 10 moveto\n"); + format("(Created by: %s@%s) show\n", who, Tcl_GetHostName()); + append("0 0 moveto\n"); + } + + // Set the conversion from postscript to X11 coordinates. Scale pica to + // pixels and flip the y-axis (the origin is the upperleft corner). + // Papersize is in pixels. Translate the new origin *after* changing the scale + append("% Transform coordinate system to use X11 coordinates\n"); + append("% 1. Flip y-axis over by reversing the scale,\n"); + append("% 2. Translate the origin to the other side of the page,\n"); + append("% making the origin the upper left corner\n"); + append("1 -1 scale\n"); + format("0 %d translate\n", -setupPtr->paperHeight); + + // Set Origin + format("%% Set origin\n%d %d translate\n\n", setupPtr->left,setupPtr->bottom); + if (ops->landscape) + format("%% Landscape orientation\n0 %g translate\n-90 rotate\n", + ((double)graphPtr_->width_ * setupPtr->scale)); + + append("\n%%EndSetup\n\n"); + + return TCL_OK; +} + +void PSOutput::addComments(const char** comments) +{ + if (!comments) + return; + + for (const char** pp = comments; *pp; pp+=2) { + if (*(pp+1) == NULL) + break; + format("%% %s: %s\n", *pp, *(pp+1)); + } +} + +unsigned char PSOutput::reverseBits(unsigned char byte) +{ + byte = ((byte >> 1) & 0x55) | ((byte << 1) & 0xaa); + byte = ((byte >> 2) & 0x33) | ((byte << 2) & 0xcc); + byte = ((byte >> 4) & 0x0f) | ((byte << 4) & 0xf0); + return byte; +} + +void PSOutput::byteToHex(unsigned char byte, char* string) +{ + static char hexDigits[] = "0123456789ABCDEF"; + + string[0] = hexDigits[byte >> 4]; + string[1] = hexDigits[byte & 0x0F]; +} + +void PSOutput::prolog() +{ + append( +"%%BeginProlog\n" +"%\n" +"% PostScript prolog file of the BLT graph widget.\n" +"%\n" +"% Copyright 1989-1992 Regents of the University of California.\n" +"% Permission to use, copy, modify, and distribute this\n" +"% software and its documentation for any purpose and without\n" +"% fee is hereby granted, provided that the above copyright\n" +"% notice appear in all copies. The University of California\n" +"% makes no representations about the suitability of this\n" +"% software for any purpose. It is provided 'as is' without\n" +"% express or implied warranty.\n" +"%\n" +"% Copyright 1991-1997 Bell Labs Innovations for Lucent Technologies.\n" +"%\n" +"% Permission to use, copy, modify, and distribute this software and its\n" +"% documentation for any purpose and without fee is hereby granted, provided\n" +"% that the above copyright notice appear in all copies and that both that the\n" +"% copyright notice and warranty disclaimer appear in supporting documentation,\n" +"% and that the names of Lucent Technologies any of their entities not be used\n" +"% in advertising or publicity pertaining to distribution of the software\n" +"% without specific, written prior permission.\n" +"%\n" +"% Lucent Technologies disclaims all warranties with regard to this software,\n" +"% including all implied warranties of merchantability and fitness. In no event\n" +"% shall Lucent Technologies be liable for any special, indirect or\n" +"% consequential damages or any damages whatsoever resulting from loss of use,\n" +"% data or profits, whether in an action of contract, negligence or other\n" +"% tortuous action, arising out of or in connection with the use or performance\n" +"% of this software.\n" +"%\n" +"\n" +"200 dict begin\n" +"\n" +"/BaseRatio 1.3467736870885982 def % Ratio triangle base / symbol size\n" +"/DrawSymbolProc 0 def % Routine to draw symbol outline/fill\n" +"/DashesProc 0 def % Dashes routine (line segments)\n" +"\n" +"% Define the array ISOLatin1Encoding (which specifies how characters are \n" +"% encoded for ISO-8859-1 fonts), if it isn't already present (Postscript \n" +"% level 2 is supposed to define it, but level 1 doesn't). \n" +"\n" +"systemdict /ISOLatin1Encoding known not { \n" +" /ISOLatin1Encoding [ \n" +" /space /space /space /space /space /space /space /space \n" +" /space /space /space /space /space /space /space /space \n" +" /space /space /space /space /space /space /space /space \n" +" /space /space /space /space /space /space /space /space \n" +" /space /exclam /quotedbl /numbersign /dollar /percent /ampersand \n" +" /quoteright \n" +" /parenleft /parenright /asterisk /plus /comma /minus /period /slash \n" +" /zero /one /two /three /four /five /six /seven \n" +" /eight /nine /colon /semicolon /less /equal /greater /question \n" +" /at /A /B /C /D /E /F /G \n" +" /H /I /J /K /L /M /N /O \n" +" /P /Q /R /S /T /U /V /W \n" +" /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore \n" +" /quoteleft /a /b /c /d /e /f /g \n" +" /h /i /j /k /l /m /n /o \n" +" /p /q /r /s /t /u /v /w \n" +" /x /y /z /braceleft /bar /braceright /asciitilde /space \n" +" /space /space /space /space /space /space /space /space \n" +" /space /space /space /space /space /space /space /space \n" +" /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent \n" +" /dieresis /space /ring /cedilla /space /hungarumlaut /ogonek /caron \n" +" /space /exclamdown /cent /sterling /currency /yen /brokenbar /section \n" +" /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen \n" +" /registered /macron \n" +" /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph \n" +" /periodcentered \n" +" /cedillar /onesuperior /ordmasculine /guillemotright /onequarter \n" +" /onehalf /threequarters /questiondown \n" +" /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla \n" +" /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex \n" +" /Idieresis \n" +" /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply \n" +" /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn \n" +" /germandbls \n" +" /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla \n" +" /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex \n" +" /idieresis \n" +" /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide \n" +" /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn \n" +" /ydieresis \n" +" ] def \n" +"} if \n" +"\n" +"% font ISOEncode font \n" +"% This procedure changes the encoding of a font from the default \n" +"% Postscript encoding to ISOLatin1. It is typically invoked just \n" +"% before invoking 'setfont'. The body of this procedure comes from \n" +"% Section 5.6.1 of the Postscript book. \n" +"\n" +"/ISOEncode { \n" +" dup length dict\n" +" begin \n" +" {1 index /FID ne {def} {pop pop} ifelse} forall \n" +" /Encoding ISOLatin1Encoding def \n" +" currentdict \n" +" end \n" +"\n" +" % I'm not sure why it's necessary to use 'definefont' on this new \n" +" % font, but it seems to be important; just use the name 'Temporary' \n" +" % for the font. \n" +"\n" +" /Temporary exch definefont \n" +"} bind def \n" +"\n" +"/Stroke {\n" +" gsave\n" +" stroke\n" +" grestore\n" +"} def\n" +"\n" +"/Fill {\n" +" gsave\n" +" fill\n" +" grestore\n" +"} def\n" +"\n" +"/SetFont { \n" +" % Stack: pointSize fontName\n" +" findfont exch scalefont ISOEncode setfont\n" +"} def\n" +"\n" +"/Box {\n" +" % Stack: x y width height\n" +" newpath\n" +" exch 4 2 roll moveto\n" +" dup 0 rlineto\n" +" exch 0 exch rlineto\n" +" neg 0 rlineto\n" +" closepath\n" +"} def\n" +"\n" +"/LS { % Stack: x1 y1 x2 y2\n" +" newpath \n" +" 4 2 roll moveto \n" +" lineto \n" +" closepath\n" +" stroke\n" +"} def\n" +"\n" +"/baselineSampler ( TXygqPZ) def\n" +"% Put an extra-tall character in; done this way to avoid encoding trouble\n" +"baselineSampler 0 196 put\n" +"\n" +"/cstringshow {\n" +" {\n" +" dup type /stringtype eq\n" +" { show } { glyphshow }\n" +" ifelse\n" +" } forall\n" +"} bind def\n" +"\n" +"/cstringwidth {\n" +" 0 exch 0 exch\n" +" {\n" +" dup type /stringtype eq\n" +" { stringwidth } {\n" +" currentfont /Encoding get exch 1 exch put (\001)\n" +" stringwidth\n" +" }\n" +" ifelse\n" +" exch 3 1 roll add 3 1 roll add exch\n" +" } forall\n" +"} bind def\n" +"\n" +"/DrawText {\n" +" gsave\n" +" /justify exch def\n" +" /yoffset exch def\n" +" /xoffset exch def\n" +" /strings exch def\n" +" % Compute the baseline offset and the actual font height.\n" +" 0 0 moveto baselineSampler false charpath\n" +" pathbbox dup /baseline exch def\n" +" exch pop exch sub /height exch def pop\n" +" newpath\n" +" % overall width\n" +" /ww 0 def\n" +" strings {\n" +" cstringwidth pop\n" +" dup ww gt {/ww exch def} {pop} ifelse\n" +" newpath\n" +" } forall\n" +" % overall height\n" +" /hh 0 def\n" +" strings length height mul /hh exch def\n" +" newpath\n" +" % Translate to x,y\n" +" translate\n" +" % Translate to offset\n" +" ww xoffset mul hh yoffset mul translate\n" +" % rotate\n" +" ww 2 div hh 2 div translate\n" +" neg rotate\n" +" ww -2 div hh -2 div translate\n" +" % Translate to justify and baseline\n" +" justify ww mul baseline translate\n" +" % For each line, justify and display\n" +" strings {\n" +" dup cstringwidth pop\n" +" justify neg mul 0 moveto\n" +" gsave\n" +" 1 -1 scale\n" +" cstringshow\n" +" grestore\n" +" 0 height translate\n" +" } forall\n" +" grestore\n" +"} bind def \n" +"\n" +"% Symbols:\n" +"\n" +"% Skinny-cross\n" +"/Sc {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate 45 rotate\n" +" 0 0 3 -1 roll Sp\n" +" grestore\n" +"} def\n" +"\n" +"% Skinny-plus\n" +"/Sp {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate\n" +" 2 div\n" +" dup 2 copy\n" +" newpath \n" +" neg 0 \n" +" moveto 0 \n" +" lineto\n" +" DrawSymbolProc\n" +" newpath \n" +" neg 0 \n" +" exch moveto 0 \n" +" exch lineto\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Cross\n" +"/Cr {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate 45 rotate\n" +" 0 0 3 -1 roll Pl\n" +" grestore\n" +"} def\n" +"\n" +"% Plus\n" +"/Pl {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate\n" +" dup 2 div\n" +" exch 6 div\n" +"\n" +" %\n" +" % 2 3 The plus/cross symbol is a\n" +" % closed polygon of 12 points.\n" +" % 0 1 4 5 The diagram to the left\n" +" % x,y represents the positions of\n" +" % 11 10 7 6 the points which are computed\n" +" % below.\n" +" % 9 8\n" +" %\n" +"\n" +" newpath\n" +" 2 copy exch neg exch neg moveto \n" +" dup neg dup lineto\n" +" 2 copy neg exch neg lineto\n" +" 2 copy exch neg lineto\n" +" dup dup neg lineto \n" +" 2 copy neg lineto 2 copy lineto\n" +" dup dup lineto \n" +" 2 copy exch lineto \n" +" 2 copy neg exch lineto\n" +" dup dup neg exch lineto \n" +" exch neg exch lineto\n" +" closepath\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Circle\n" +"/Ci {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 copy pop moveto \n" +" newpath\n" +" 2 div 0 360 arc\n" +" closepath \n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Square\n" +"/Sq {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" dup dup 2 div dup\n" +" 6 -1 roll exch sub exch\n" +" 5 -1 roll exch sub 4 -2 roll Box\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Line\n" +"/Li {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 1 roll exch 3 -1 roll 2 div 3 copy\n" +" newpath\n" +" sub exch moveto \n" +" add exch lineto\n" +" closepath\n" +" stroke\n" +" grestore\n" +"} def\n" +"\n" +"% Diamond\n" +"/Di {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 1 roll translate 45 rotate 0 0 3 -1 roll Sq\n" +" grestore\n" +"} def\n" +" \n" +"% Triangle\n" +"/Tr {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate\n" +" BaseRatio mul 0.5 mul % Calculate 1/2 base\n" +" dup 0 exch 30 cos mul % h1 = height above center point\n" +" neg % b2 0 -h1\n" +" newpath \n" +" moveto % point 1; b2\n" +" dup 30 sin 30 cos div mul % h2 = height below center point\n" +" 2 copy lineto % point 2; b2 h2\n" +" exch neg exch lineto % \n" +" closepath\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"% Arrow\n" +"/Ar {\n" +" % Stack: x y symbolSize\n" +" gsave\n" +" 3 -2 roll translate\n" +" BaseRatio mul 0.5 mul % Calculate 1/2 base\n" +" dup 0 exch 30 cos mul % h1 = height above center point\n" +" % b2 0 h1\n" +" newpath moveto % point 1; b2\n" +" dup 30 sin 30 cos div mul % h2 = height below center point\n" +" neg % -h2 b2\n" +" 2 copy lineto % point 2; b2 h2\n" +" exch neg exch lineto % \n" +" closepath\n" +" DrawSymbolProc\n" +" grestore\n" +"} def\n" +"\n" +"%%EndProlog\n" +); +} |