(* Copyright © 1995 UNICAMP. See notice at the end of this file. *) (* Last edited on 2001-11-16 17:59:58 by stolfi *) INTERFACE PSPlot; (* Version 95-04-16-stolfi *) (* Medium-level tools to generate PostScript files. This module provides tools for creating two flavors of PostScript files: Encapsulated PostScript (EPS), suitable for inclusion in other documents; and plain Postscript (PS), which can be sent directly to a printer. For more information and examples, see the comments further down. *) TYPE Axis = {X, Y}; BOOL = BOOLEAN; LONG = LONGREAL; Range = RECORD min, max: LONG END; TYPE EPSFile <: PubEPSFile; (* An Encapsulated PostScript (EPS) file contains a single figure, meant to be included in other documents. To create such a file, do | WITH f = NEW(EPSFile).open("foo.eps", ...) DO | f.segment(...); | f.circle(...) | ... | f.close() | END; *) PubEPSFile = File OBJECT METHODS open(name: TEXT; xSize, ySize: LONG := 150.0d0): EPSFile; (* Opens an Encapsulated PostScript file with the given name, and writes the file header and procedure sets. The extension ".eps" is recommended. The nominal drawing area will be a rectangle "xSize" by "ySize" in millimeters. *) END; TYPE PSFile <: PubPSFile; (* A plain PostScript (PS) file is meant to be sent to a printer, and may contain several pages, with several figures per page. To create one, do | WITH f = NEW(PSFile).open("foo.ps", ...) DO | (* Page 1: *) | f.beginPage() | f.beginDrawing(...); | f.segment(...); | ... | f.endDrawing(); | f.beginDrawing(...) | f.circle(...) | f.endDrawing(); | f.endPage(); | (* Page 2: *) | f.beginPage(); | f.beginDrawing(); | ... | f.endDrawing(); | ... | f.endPage(); | (* More pages: *) | ... | f.close() | END; *) PubPSFile = File OBJECT METHODS open( name: TEXT; xPageSize: LONG := LetterXSize; yPageSize: LONG := LetterYSize; ): PSFile; (* Opens a plain (i.e. multi-page, non-encapsulated) PostScript file with the given name, and writes the file header and procedure sets. The extension ".ps" is recommended. *) beginPage(); (* Starts a new page: writes page header line, etc. *) endPage(); (* Finishes the current page: Writes page trailer line, etc. *) beginDrawing( xSize, ySize: LONG := 150.0d0; xCenter := LetterXSize/2.0d0; yCenter := LetterYSize - LetterXSize/2.0d0; ); (* Starts a new drawing on the current page. Sets the drawing area to the specified rectangle (in millimeters from the lower left corner of page). *) endDrawing(); (* Finishes the current drawing. *) caption ( txt: TEXT; font: TEXT := "Courier"; size: REAL := 10.0; xAlign: REAL := 0.0; ); (* Prints a caption text just below the drawing area. The text will be left-justified if "xAlign=0", centered if "xAlign=0.5", and right-justified if "xAlign=1". For multi-line captions, use multiple calls and/or embedded newlines. *) END; TYPE File <: PubFile; (* Methods shared by plain and Encapsulated Postscript files. *) PubFile = OBJECT METHODS (* SCALES *) setScale(axis: Axis; min, max: LONG); (* Sets the range and scale of client coordinates along the given axis. Except where noted otherwise, all coordinate arguments in the following methods are assumed to lie in the interval "[min_max]", which gets mapped to the corresponding dimension of the drawing area. *) getRange(axis: Axis): Range; (* Returns the current range "r = {r.min, r.max}" of plottable coordinates for the given axis. *) getScaleFactor(axis: Axis): LONG; (* Returns the current plotting scale along the given "axis", that, is, the actual printed displacement in mm that corresponds to an increment of 1 in the specified coordinate of the client's reference system. *) (* LINE DRAWINGS *) setLineWidth(width: REAL); setLineColor(READONLY color: Color); setLineSolid(); setLineDashed(READONLY pattern: ARRAY OF REAL; skip: REAL := 0.0); (* Sets the color, line width, and dash length/space pattern for line drawing. The color also applies to text labels. Width and dash lengths are in millimeters, irrespective of current scale. *) segment(xa, ya, xb, yb: LONG); (* Draws a segment from "(xa,ya)" to "(xb,yb)", using the current line parameters. *) bezier(xa, ya, xb, yb, xc, yc, xd, yd: LONG); (* Draws a Bezier arc with given control points, using the current line parameters. *) coordLine(axis: Axis; coord: LONG); (* Draws a reference line perpendicular to the given axis at the given coordinate value. *) dot(xc,yc: LONG; size: REAL); (* A round dot with center "(xc,yc)" (in client coordinates) and diameter equal to "size" times the current line width. The dot is painted solid with the current *line* color and is not outlined. *) arrowhead(xa,ya, xb,yb: LONG; width, length: REAL; fraction: LONG); (* A triangular arrowhead suitable for a arrow with base at "(xa,ya)" and tip at "(xb,yb)", with given width and length relative to the current line width. The arrowhead is placed with the tip at "fraction" of the way from "(xa,ya)" to "(xb,yb)", and is painted solid with the current *line* color. *) frame(); (* Draws a frame around the plotting area. *) (* AREA PAINTING *) setFillColor(READONLY color: Color); (* Sets the color to be used for filling the interior of closed figures (circles, rectangles, etc.). *) (* The methods below will paint the interior of the figure with the current "fill" color, and then draw the outline with the current "line" parameters (color, pen width, and dash pattern). Use the "Invisible" color to prevent either of these from happening. *) circle(xc,yc: LONG; radius: REAL); (* The circle with center "(xc,yc)" (in client coordinates) and given radius (in millimeters, irrespective of current scale). Like "dot" except that the circle is filled with the current *fill* color, and outlined with the current line style and color. *) rectangle(xlo, xhi, ylo, yhi: LONG); (* The rectangle "[xlo..xhi] x [ylo..yhi]". *) triangle(xa, ya, xb, yb, xc, yc: LONG); (* The triangle "(xa,ya), (xb,yb), (xc,yc)". *) ellipse(xc,yc, xa,ya, xb,yb: LONG); (* The ellipse which corresponds to the unit circle in the affine frame with origin "(xc,yc)" and basis vectors "(xa,ya), (xb,yb)". *) (* GRID DRAWING/PAINTING *) setGridSize(xn, yn: CARDINAL); (* Implicitly divides the drawing area into an array of "xn" by "yn" cells, for use by the methods "gridCell" and "gridLines" below. The cells are numbered left to right from 0 to "xn-1", and bottom to top from 0 to "yn-1". *) gridCell(xi, yi: CARDINAL); (* Paints the specified cell of the cell grid. *) gridLines(); (* Draws the all cell grid lines with the current line parameters. *) (* TEXT *) setTextColor(READONLY color: Color); (* Sets the color to be used for labels and captions. The "color" must be visible. *) label( txt: TEXT; x, y: LONG; xAlign, yAlign: REAL := 0.0; angle: REAL := 0.0; font: TEXT := "Courier"; size: REAL := 10.0; ); (* Prints "txt" tilted by "angle" with its reference point at "(x,y)". The parameters "xAlign" and "yAlign" are the coordinates of the reference point relative to the text's bounding box: "(0,0)" means the lower left corner, "(1,1)" the upper right corner, "(0.5,0.5)" the center, etc. The "font" must be a Postscript font; the "size" is the nominal font size in points. The text must not include newlines. *) (* MISCELLANEOUS *) comment(txt: TEXT); (* Writes "txt" to the file, as a comment *) close(); (* MUST be called to write the file trailers and close the file. *) END; CONST (* Standard paper dimensions in mm: *) LetterXSize = 8.5d0 * 25.4d0; LetterYSize = 11.0d0 * 25.4d0; TYPE Color = ARRAY [0..2] OF REAL; (* RGB in the range [0__1]. If any components are negative, the color is interpreted as "invisible" (wholly transparent). *) CONST Invisible = Color{-1.0, -1.0, -1.0}; (* An invisible color. *) Black = Color{0.0, 0.0, 0.0}; Red = Color{1.0, 0.0, 0.0}; Yellow = Color{1.0, 1.0, 0.0}; Green = Color{0.0, 1.0, 0.0}; Cyan = Color{0.0, 1.0, 1.0}; Blue = Color{0.0, 0.0, 1.0}; Magenta = Color{1.0, 0.0, 1.0}; White = Color{1.0, 1.0, 1.0}; PROCEDURE Gray(v: REAL): Color; (* A gray color with given brightness. *) END PSPlot. (* This module aims to provide only the most basic drawing commands, in a simple interface. It is not meant to be a complete Postscript interface (see the "dps" package for that), nor a replacement for data graphing tools (like "gnuplot"). Some things that should be added to this package: * Other geometric primitives: circular and elliptical arcs, polygons, (with open array arguments?), incremental path construction, etc. * A "text" primitive that prints a given text in a specified rectangle, with atomatic line breaking, justification, etc. * A "landscape" argument to "PSFile.open". Note that because of the defaults, "xPageSize" and "yPageSize" should probably be interpreted before "landscape". * PSFile.open should write "xPageSize" and "yPageSize" as the appropriate Postscript structured comment. *) (****************************************************************************) (* *) (* Copyright © 1995 Universidade Estadual de Campinas (UNICAMP) *) (* *) (* Authors: *) (* Jorge Stolfi - CS Dept, UNICAMP *) (* *) (* This file can be freely used, distributed, and modified, provided that *) (* this copyright and authorship notice is included in every copy or *) (* derived version. *) (* *) (* DISCLAIMER: This software is offered ``as is'', without any guarantee *) (* as to fitness for any particular purpose. Neither the copyright *) (* holder nor the authors or their employers can be held responsible for *) (* any damages that may result from its use. *) (* *) (****************************************************************************)