Making Pictures With GNU PIC

		      Eric S. Raymond


	  The  pic  language  is a troff extension that
     makes it easy to create  and  alter  box-and-arrow
     diagrams  of the kind frequently used in technical
     papers and	 textbooks.   This  paper  is  both  an
     introduction  to  and  reference  for gpic(1), the
     implementation distributed by  the	 Free  Software
     Foundation for use with groff(1).

1.  Introduction to PIC

1.1.  Why PIC?

     The   pic	language  provides  an	easy  way  to  write
procedural box-and-arrow diagrams to be	 included  in  troff
documents.   The  language  is	sufficiently  flexible to be
quite useful for  state	 charts,  Petri-net  diagrams,	flow
charts, simple circuit schematics, jumper layouts, and other
kinds of illustration involving repetitive  uses  of  simple
geometric forms and splines.  Because these descriptions are
procedural and object-based, they are both compact and	easy
to modify.

     The gpic(1) implementation of pic is distributed by the
Free  Software	Foundation  for	 use  with  their   groff(1)
implementation	of  troff.  Because both implementations are
widely available in source form for free, they are good bets
for writing very portable documentation.

1.2.  PIC Versions

     The original 1984 pre-ditroff(1) version of pic is long
obsolete.  The rewritten 1991 version is still available  as
part of the Documenter's Work Bench module of System V.

     Where   differences  between  Documenter's	 Work  Bench
(1991) pic and GNU pic need to be described, original pic is
referred  to  as  "DWB	pic".  Details on the history of the
program are given at the end of this document.

     In this document, the gpic(1) extensions will be marked
as such.


2.  Invoking PIC

     Every  pic	 description is a little program, which gets
compiled by pic(1) into	 gtroff(1)  macros.   Programs	that
process	 or  display  gtroff(1) output need not know or care
that parts of the image began life as pic descriptions.

     The pic(1) program tries to translate anything  between
.PS  and  .PE  markers,	 and passes through everything else.
The normal definitions of  .PS	and  .PE  in  the  ms  macro
package and elsewhere have also the side-effect of centering
the pic output on the page.

     Other details of the [gt]roff(1) interface

2.1.  PIC Error Messages

     If you make a pic syntax error, gpic(1) will  issue  an
error message in the standard gcc(1)-like syntax.  A typical
error message looks like this, parse error before `' giving up on this picture

where  is a line number, and  is  a	 token	near
(usually just after) the error location.

3.  Basic PIC Concepts

     Pictures  are described procedurally, as collections of
objects connected by motions.  Normally, pic tries to string
together  objects  left-to-right  in  the  sequence they are
described, joining them at visually natural points.  Here is
an example illustrating the flow of data in pic processing:

       ------	    --gtbl(1) or geqn(1)---	 ------
document     gpic(1)	 +(optional) +	 gtroff(1)   PostScript

		Figure 3-1: Flow of pic data

     This was produced from the following pic program:


     ellipse "document";
     box "\fIpic\fP(1)"
     box width 1.2 "\fIgtbl\fP(1) or \fIgeqn\fP(1)" "(optional)" dashed;
     box "\fIgtroff\fP(1)";
     ellipse "PostScript"

This   little	program	  illustrates  several	pic  basics.
Firstly, we see how to invoke three object types;  ellipses,
arrows,	 and  boxes.  We see how to declare text lines to go
within an object (and that text can  have  font	 changes  in
it).   We see how to change the line style of an object from
solid to dashed.  And we see that a box can  be	 made  wider
than  its  default  size  to  accommodate  more	 text (we'll
discuss this facility in detail in the next section).

     We also get to see pic's simple syntax.  Statements are
ended by newlines or semicolons.  String quotes are required
around all text	 arguments,  whether  or  not  they  contain
spaces.	  In  general,	the  order  of command arguments and
modifiers like	"width	1.2"  or  "dashed"  doesn't  matter,
except that the order of text arguments is significant.

     Here  are all but one of the basic pic objects at their
default sizes:

	     -line-    arrow-
   box				 circle	    ellipse

	       Figure 3-2: Basic pic objects

     The missing simple object type is a spline.   There  is
also  a	 way  to collect objects into block composites which
allows you to treat the	 whole	group  as  a  single  object
(resembling  a	box) for many purposes.	 We'll describe both
of these later on.

     The box, ellipse, circle, and block  composite  objects
are  closed; lines, arrows, arcs and splines are open.	This
distinction will often be important  in	 explaining  command

     Figure  3-2  was produced by the following pic program,
which introduces some more basic concepts:


     box "box";
     line "line" "";
     arrow "arrow" "";
     circle "circle";
     ellipse "ellipse";
     arc; down; move; "arc"

     The first thing to notice is the  move  command,  which
moves  a default distance (1/2 inch) in the current movement

     Secondly, see how we can also decorate lines and arrows
with  text.   The  line	 and  arrow  commands  each take two
arguments here, specifying text to go above  and  below	 the
object.	  If  you  wonder  why	one  argument  would not do,
contemplate the output of arrow "ow!":


	   Figure 3-3: Text centered on an arrow

     When a command takes one  text  string,  pic  tries  to
place  it at the object's geometric center.  As you add more
strings, pic treats them as a vertical block to be centered.
The program

     line "1";
     line "1" "2";
     line "1" "2" "3";
     line "1" "2" "3" "4";
     line "1" "2" "3" "4" "5";

for example, gives you this:

			     1	  1    2
			2    3	  3    4
				  4    5

       Figure 3-4: Effects of multiple text arguments


     The  last	line  of  Figure  3.2's program, `arc; down;
move;  "arc"',	describing  the	 captioned  arc,  introduces
several	 new  ideas.   Firstly,	 we  see  how  to change the
direction in which objects are joined.	Had we written	arc;
move;  "arc",  omitting	 down  the  caption  would have been
joined to the top of the arc, like this:


	      Figure 3-5: Result of arc; move;

     This is because drawing  an  arc  changes	the  default
direction  to  the one its exit end points at.	To reinforce
this point, consider:

	    Figure 3-6: Result of arc cw; move;

     All we've done differently here is specify "cw"  for  a
clockwise arc.	Observe how it changes the default direction
to down, rather than up.

     Another good way to see this  via	with  the  following

     line; arc; arc cw; line

which yields:



       Figure 3-7: Result of line; arc; arc cw; line

Notice	that  we did not have to specify "up" for the second
arc to be joined to the end of the first.

     Finally, observe that a string, alone,  is	 treated  as
text  to  be surrounded by an invisible box of a size either


specified by width and height attributes or by the  defaults
textwid	 and  textht.	Both  are initially zero (because we
don't know the default font size).

4.  Sizes and Spacing

     Sizes are specified  in  inches.	If  you	 don't	like
inches,	 it's  possible to set a global style variable scale
that  changes  the  unit.   Setting  scale   =	 2.54	will
effectively  change  the  internal  unit to centimeters (all
other size variable valuess will be scaled correspondingly).

4.1.  Default Sizes of Objects

     Here are the default sizes for pic objects:
     Object  | Default Size
     box     | 0.75" wide by 0.5" high
     circle  | 0.5" diameter
     ellipse | 0.75" wide by 0.5" high
     arc     | 0.5" radius
     line    | 0.5" long
     arrow   | 0.5" long

     The  simplest way to think about these defaults is that
they make the other basic objects fit snugly into a default-
sized box.

4.2.  Objects Do Not Stretch!

     Text  is rendered in the current font with normal troff
line  spacing.	 Boxes,	 circles,  and	 ellipses   do	 not
automatically resize to fit enclosed text.  Thus, if you say
box "text far too long" you'll get this:

	this text is far too long for a default box

       Figure 4-1: Boxes do not automatically resize

     which is probably not the effect you want.

4.3.  Resizing Boxes

     To change the box size, you can  specify  a  box  width
with the "width" modifier:


	 this text is far too long for a default box

	     Figure 4-2: Result of box width 3

     This  modifier  takes  a dimension in inches.  There is
also a "height" modifier that will change  a  box's  height.
The  width  keyword  may  be abbreviated to ewid; the height
keyword to height.

4.4.  Resizing Other Object Types

     To change the size of a circle, give it a rad  or	diam
modifier; this changes the radius or diameter of the circle,
according to the numeric argument that follows.

			 0.2	   0.3


	 Figure 4-3: Circles with increasing radii

     The move command can also take a dimension, which	just
tells it how many inches to move in the current direction.

     Ellipses  are  sized  to  fit  in	the  rectangular box
defined by their axes, and can be  resized  with  width	 and
height like boxes.

     You  can  also change the radius of curvature of an arc
with rad (which specifies the radius of the circle of  which
the  arc is a segnmment).  Larger values yield flatter arcs.

		      0.1 0.2  0.3

	 Figure 4-4: arc rad with increasing radii

     Observe that because an arc is  defined  as  a  quarter
circle, increasing the radius also increases the size of the
arc's bounding box.


4.5.  The `same' Keyword

     In place of a dimension specification, you can use	 the
keyword	 same.	 This  gives the object the same size as the
previous one of its type.  As an example, the program

     box; box wid 1 ht 1; box same; box

gives you

		Figure 4-5: The same keyword

5.  Generalized Lines and Splines

5.1.  Diagonal Lines

     It is possible to specify diagonal lines or  arrows  by
adding	multiple  up, down, left, and right modifiers to the
line object.  Any  of  these  can  have	 a  multiplier.	  To
understand  the	 effects, think of the drawing area as being
gridded with standard-sized boxes.

++++++	  +++++++++++	 ++++++++++++++++    +++++++++++++++++++++
+    +	  +    +    +	 +    +	   +	+    +	  +    +    +	 +
+    +	  +    +    +	 +    +	   +	+    +	  +    +    +	 +
++++++	  +++++++++++	 ++++++++++++++++    +++++++++++++++++++++

line up learrow up left 1  arrow up left 1.5	  arrow up left 2
Figure 5-1: Diagonal arrows (dotted boxes show	the  implied
		       0.5-inch grid)

5.2.  Multi-Segment Line Objects

     A	"line"	or  "arrow"  object  may  actually be a path
consisting of any number of segments of varying lengths	 and
directions.   To  describe  a  path, connect several line or
arrow commands with the keyword then.




 Figure 5-2: line right 1 then down .5 left 1 then right 1

5.3.  Spline Objects

     If you start a path with the spline keyword,  the	path
vertices  are  treated	as control points for a spline curve

			      1 ++++++++++2
			      3 ++++++++++4
	    The spline c...with tangents displayed

Figure 5-3: spline right 1 then down .5 left 1 then right 1

     You can describe  many  natural-looking  but  irregular
curves this way. For example:

spline right then up then leftsplinedleft-then up right then down right ->;

	    Figure 5-4: Two more spline examples

     Note  the arrow decorations.  Arrowheads can be applied
naturally to any path-based object, line or  spline.   We'll
see how in the next section.

6.  Decorating Objects.

6.1.  Dashed Objects

     We've  already seen that the modifier dashed can change
the line style of an object from solid to dashed.  GNU	gpic
permits	 you to dot or dash ellipses, circles, and arcs (and
splines in x mode only);  some	versions  of  DWB  may	only
permit	dashing of lines and boxes.  It's possible to change
the dash interval by specifying a number after the modifier.


 ++++++++    +++++++++	  +------+    |-- -- -+	   +--	--+
 +	+    +	     +	  |	 |    |	      |	   |	  |
 default+    + 0.05  +	  | 0.1	 |    | 0.15  |	   | 0.2  |
 ++++++++    +++++++++	  +------+    +- -- --|	   +--	--+

		 Figure 6-1: Dashed objects

6.2.  Dotted Objects

     Another   available  qualifier  is	 dotted.   GNU	gpic
permits you to dot or dash ellipses, circles, and arcs	(and
splines	 in  x	mode  only);  some  versions of DWB may only
permit dashing of lines and boxes.  It too can	be  suffixed
with a number to specify the interval between dots:

 ++++++++    +++++++++	  ++++++++    + ++ ++ +	   + + + ++
 +	+    +	     +	  +	 +    +	      +	   +	  +
 default+    + 0.05  +	  + 0.1	 +    + 0.15  +	     0.2
 ++++++++    +++++++++	  ++++++++    + ++ ++ +	   + + + ++

		 Figure 6-2: Dotted objects

6.3.  Rounding Box Corners

     It	 is also possible, in GNU gpic only, to modify a box
so it has rounded corners

 -------|    |------	   -----	----	     ---
 |	|    |	     |	  |	 |    |	      |	   +	  +
 rad 0.05    |rad 0.1|	  rad=0.15    |rad=0.2|	   rad=0.25
 |-------      ------|	    -----	 ----	      ---

     Figure 6-3: box rad with increasing radius values;

     Radius  values  higher  than  half	 the   minimum	 box
dimension are silently truncated to that value.

6.4.  Arrowheads

     Lines  and	 arcs can be decorated as well.	 Any line or
arc  (and  any	spline	as  well)  can	be  decorated	with
arrowheads by adding one or more as modifiers:


    Figure 6-4: Double-headed line made with  line <- ->

     In	 fact,	the arrow command is just shorthand for line
->.  And there is a double-head modifier <->, so the  figure
above could have been made with Wline <->.


     Arrowheads	 have a width attribute, the distance across
the  rear;  and	 a  height  attribute,	the  length  of	 the
arrowhead along the shaft.

     Arrowhead	style  is  controlled  by the style variable
arrowhead.   The  DWB  and   GNU   versions   interpret	  it
differently.	DWB  defaults  to  open	 arrowheads  and  an
arrowhead value of 2; the Kernighan paper says a value of  7
will  make  solid  arrowheads.	 GNU  gpic defaults to solid
arrowheads and an arrowhead value of 1; a value	 of  0	will
produce open arrowheads.

6.5.  Line Thickness

     It's  also	 possible to change the line thickness of an
object (this is a GNU extension,  DWB  pic  doesn't  support
it.).	The  default  thickness	 of  the  lines used to draw
objects is controlled by the linethick variable.  This gives
the  thickness	of  lines in points.  A negative value means
use the default thickness: in x output mode, this means	 use
a  thickness  of 8 milliinches; in x output mode with the -c
option, this means use the line thickness specified  by	 .ps
lines;	in  troff  output  mode,  this means use a thickness
proportional to the pointsize.	A zero value means draw	 the
thinnest  possible  line  supported  by	 the  output device.
Initially it has a value of -1.	 There is also	a  thickness
attribute (which can be abbreviated to thick).	For example,
circle thickness 1.5 would draw a circle using a line with a
thickness  of  1.5  points.   The  thickness of lines is not
affected by the value of the  scale  variable,	nor  by	 any
width or height given in the .PS line.

6.6.  Invisible Objects

     The  modifier invis makes an object entirely invisible.
This used to be useful for positioning text in an  invisible
object	that  is properly joined to neighboring ones.  Newer
DWB versions and GNU pic treat standalone  text	 in  exactly
this way.

6.7.  Filled Objects

     It	 is  possible  to fill boxes, circles, and ellipses.
The modifier fill[ed] accomplishes this.  You can suffix  it
with  a	 fill  value;  the  default  is	 given	by the stule
variable fillval.

     DWB pic and gpic have  opposite  conventions  for	fill
values	and different defaults.	 DWB fillval defaults to 0.3
and smaller values are darker; GNU fillval uses 0 for  white
and 1 for black.


Figure 6-5: circle fill; move; circle fill 0.4; move; circle
			 fill 0.9;

     GNU gpic makes  some  additional  guarantees.   A	fill
value  greater than 1 can also be used: this means fill with
the shade of gray that is currently being used for text	 and
lines.	 Normally this will be black, but output devices may
provide	 a  mechanism  for  changing  this.   The  invisible
attribute  does not affect the filling of objects.  Any text
associated with a filled object	 will  be  added  after	 the
object	has  been  filled,  so	that  the  text	 will not be
obscured by the filling.

     The closed-object modifier solid is equivalent to	fill
with the darkest fill value (DWB pic had this capability but
mentioned it only in a reference opinion).

7.  More About Text Placement

     By default, text is centered at the geometric center of
the object it is associated with.  The modifier ljust causes
the left end to be at the specified point (which means	that
the  text  lies	 to  the right of the specified place!), The
modifier rjust	puts  the  right  end  at  the	place.	 The
modifiers  above  and  below  center  the text one half line
space in the given direction.

     Text attributes can be combined:

       |	      |
       |	      |	   -----ljust-above----------
       ljustrjust text|		    rjust below
       |	      |

		Figure 7-1: Text attributes

     What actually  happens  is	 that  n  text	strings	 are
centered in a box that is textwid wide by textht high.	Both
these variables are initially zero (that is pic's way of not
making	assumptions about [tg]roff(1)'s default point size).

     In GNU gpic, objects can  have  an	 aligned  attribute.
This  will  only  work when the postprocessor is grops.	 Any
text associated with an object having the aligned  attribute
will be rotated about the center of the object so that it is
aligned in the direction from the start	 point	to  the	 end
point  of the object.  Note that this attribute will have no


effect	for  objects  whose  start  and	  end	points	 are

8.  More About Direction Changes

     We've already seen how to change the direction in which
objects are composed from rightwards to downwards.  Here are
some more illustrative examples:

	  right; box; arrow; circle; arrow; ellipse

		      ------	------

	  left; box; arrow; circle; arrow; ellipse

		      ------	------

Figure	8-1:  Effects  of different motion directions (right
			 and left)

down; box; arrow; circle; arrup; box;parrow; circle; arrow; ellipse;

		|			   |
		|			   |
		|			   |
		|			   |

		|			   |
		|			   |
		|			   |
		|			   |

Figure 8-2: Effects of different motion directions (up and down)

     Something that may appear	surprising  happens  if	 you
change directions in the obvious way:


			  ------    |

    Figure 8-3: box; arrow; circle; down; arrow; ellipse

You might have expected that program to yield this:



		Figure 8-4: More intuitive?

But, in fact, to get Figure 8.3 you have to do this:

     move to last circle .s;

Why  is	 this?	 Because  the  exit  point  for	 the current
direction is already set when  you  draw  the  object.	 The
second	arrow  in  Figure  8.2	dropped	 downwards  from the
circle's attachment point for an object to be joined to	 the

     The  meaning  of  the  command  move  to last circle .s
should be obvious.  In order  to  see  how  it	generalizes,
we'll  need  to	 go  into  detail  on  two important topics;
locations and object names.


9.  Naming Objects

     The most natural  way  to	name  locations	 in  pic  is
relative  to  objects.	 In order to do this, you have to be
able you have to be able to name objects.  The pic  language
has  rich facilities for this that try to emulate the syntax
of English.

9.1.  Naming Objects By Order Of Drawing

     The simplest (and generally the  most  useful)  way  to
name  an  object  is  with  a  last  clause.  It needs to be
followed by an object type name; box, circle, ellipse, line,
arrow,	spline	or  []	(the last type refers to a composite
object which we'll discuss later).   So,  for  example,	 the
last  circle  clause in the program attached to Figure 9.1.3
refers to the last circle drawn.

     More generally, objects of a given type are  implicitly
numbered  (starting  from  1).	 You  can refer to (say) the
third ellipse in the current picture with 3rd ellipse, or to
the  first box as 1st box, or to the fifth line as 5th line.

     Objects are also numbered backwards by  type  from	 the
last  one  of You can say 2nd last box to get the second-to-
last box, or 3rd last ellipse to get the third-to-last	box.

     In	 places	 where	nth  is	 allowed,  `expr'th  is also
allowed.  Note that 'th is  a  single  token:  no  space  is
allowed between the ' and the th.  For example,

	  for i = 1 to 4 do {
	     line from `i'th box.nw to `i+1'th

9.2.  Naming Objects With Labels

     You can also specify an object by referring to a label.
A label is a word (which must begin with a  capital  letter)
followed   by	a  colon;  you	declare	 it  by	 placing  it
immediately before the object drawing command.	For example,
the program

     A: box "first" "object"
     B: ellipse "second" "object"
     arrow left at A;


declares  labels  A  and B for its first and second objects.
Here's what that looks like:

	       ------first	 second
		     object	 object

	      Figure 9-1: Example of label use

The at statement in the fourth line uses the  label  A	(the
behavior  of  at  will	be  explained  in the next section).
We'll see later on that labels are most useful for referring
to block composite objects.

     Labels  are  not  constants but variables (you can view
colon as a sort of assignment).	 You can say something	like
A: A + (1,0); and the effect will be to reassign the label A
to designate a position one inch to the	 right	of  its	 old

10.  Describing locations

     The  location  of	points	can  be	 described  in	many
different ways.	 All these forms are interchangeable as	 for
as  the	 pic language syntax is concerned; where you can use
one, any of the others that would make	semantic  sense	 are

     The  special  label  Here	always refers to the current

10.1.  Absolute Coordinates

     The simplest is absolute  coordinates  in	inches;	 pic
uses a Cartesian system with (0, 0) at the lower left corner
of the virtual drawing surface for each picture (that is,  X
increases  to  the  right  and	Y  increases  upwards).	  An
absolute location may always be written in the	conventional
form   as   two	  comma-separated   numbers   surrounded  by
parentheses (and  this	is  recommended	 for  clarity).	  In
contexts  where it creates no ambiguity, the pair of X and Y
coordinates suffices without punctuation.

     It is  a  good  idea  to  avoid  absolute	coordinates,
however.   They	 tend to make picture descriptions difficult
to understand and modify.  Instead, there are quite a number
of  ways  to  specify  locations relative to pic objects and
previous locations.


10.2.  Locations Relative to Objects

     The symbol here always refers to the  position  of	 the
last object drawn or the destination of the last move.

     Alone  and	 unqualified, a last circle or any other way
of specifying a closed-object or arc location  refers  as  a
position   to	the   geometric	  center   of	the  object.
Unqualified, the name of a line or spline object  refers  to
the position of the object start.

     Also,  pic	 objects  have	quite  a few named locations
associated with them.  One of these is	the  object  center,
which can be indicated (redundantly) with the suffix .center
(or just .c).  Thus, last circle .center  is  equivalent  to
last circle.

10.2.1.	 Locations Relative to Closed Objects

     Every  closed  object  (box,  circle, ellipse, or block
composite) also has eight compass points associated with it;

  .nw	   .n	  .ne	     .n		      .n
			.nw	.ne	.nw	    .ne

 .w	     .c	    .e.w       .c   ..w		.c	.e

			.sw	.se	.sw	    .se
  .sw	   .s	  .se	     .s		      .s
		Figure 10-1: Compass points

these  are  the	 locations where eight compass rays from the
geometric center would intersect the figure.  So when we say
last  circle  .s we are referring to the south compass point
of the last circle drawn.  The explanation of  Figure  7.3's
program is now complete.

     (In  case	you  dislike compass points, the names .top,
.bottom, .left and .right are synonyms for .n, .s,  .e,	 and
.w  respectively; they can even be abbreviated to .t, .b, .l
and .r).

     The names center, top, bottom, left and right can	also
be used (without the leading dot) in a prefix form marked by
of; thus, center of last circle and top of 2nd last  ellipse
are both valid object references.

     Arc  objects  also	 have  compass	point;	they are the
compass points of the implied circle.


10.2.2.	 Locations Relative to Open Objects

     Every open object (line, arrow,  arc,  or	spline)	 has
three  named  points;  .start,	.center, and .end.  They can
also be used without leading dots in  the  of  prefix  form.
The  center  of	 an arc is the center of its circle, but the
center of a line, path, or spline  is  halfway	between	 its

       .end.start     .start		 .end
.center			   .center     .center
.start	       .center .end	       .end .start

	Figure 10-2: Special points on open objects

10.3.  Ways of Composing Positions

     Once  you	have  two  positions to work with, there are
several ways to combine them to specify new positions.

10.3.1.	 Vector Sums and Displacements

     Any two positions may be added or subtracted to yield a
new  position.	The result is the conventional vector sum or
difference of coordinates.  For	 example,  last	 box  .ne  +
(0.1,  0)  is  a valid position.  This example illustrates a
common use, to define a	 position  slightly  offset  from  a
named one (say, for captioning purposes).

10.3.2.	 Interpolation Between Positions

     A	 position   may	 be  interpolated  between  any	 two
positions.  The syntax	is  `fraction  of  the	way  between
position1  and	position2.'  For example, you can say 1/3 of
the way between here and last ellipse .ne.  The fraction may
be  in	numerator/denominator  form  or	 may  be an ordinary
number	(values	 are  not  restricted  to  [0,1]).   As	  an
alternative  to	 this  verbose syntax, you can say `fraction
.'; thus, the example could  also  be
written 1/3 .



Figure 10-3: P: 1/3 of the way between last arrow .start and
		      last arrow .end

     This facility can	be  used,  for	example,  to  double

		      yin  ------ yang

		Figure 10-4: Doubled arrows

You can get Figure 10-4 from the following program:

     A: box "yin"; move;
     B: box "yang";
     arrow right at 1/4 ;
     arrow left	 at 1/4 ;

Note the use of the short form for interpolating points.

10.3.3.	 Projections of Points

     Given  two	 positions  p and q, the position (p, q) has
the X coordinate of p and the Y coordinate of q.   This	 can
be helpful in placing an object at one of the corners of the
virtual box defined by two other objects.

		   A			 (B,A) is here

      (A,B) is here			 B

	   Figure 10-5: Using (x, y) composition


10.4.  Using Locations

     There are four ways to use locations; at, from, to, and
with.  All three are object modifiers; that is, you use them
as suffixes to a drawing command.

     The at modifier says to draw a  closed  object  or	 arc
with  its  center  at  the  following location, or to draw a
line/spline/arrow starting at the following location.

     The to modifier can be used alone	to  specify  a	move
destination.   The  from  modifier  can be used alone in the
same way as at.

     The from and to modifiers can be used with	 a  line  or
arc  command  to specify start and end points of the object.
In conjunction with named  locations,  this  offers  a	very
flexible mechanism for connecting objects.  For example, the
following program

     box "from"
     move 0.75;
     ellipse "to"
     arc cw from 1/3 of the way \
	 between last box .n and last box .ne to last ellipse .n;


		     from	     to

Figure 10-6: A tricky connection specified with English-like syntax

     The with  modifier	 allows	 you  to  identify  a  named
attachment  point  of an object with another point.  This is
very useful for connecting objects in a natural way.  For an
example, consider these two programs:


box wid 0.5 ht 0.5;boxxwidd0.57hth0.5;7box wid 0.75 ht 0.75 with .sw at last box .se;

    Figure 10-7: Using the with modifier for attachments

10.5.  The chop modifier

     When drawing lines between circles that don't intersect
them at a compass point, it is useful to be able to  shorten
a  line	 by the radius of the circle at either or both ends.
Consider the following program:

     circle "x"
     circle "y" at 1st circle - (0.4, 0.6)
     circle "z" at 1st circle + (0.4, -0.6)
     arrow from 1st circle to 2nd circle chop
     arrow from 2nd circle to 3rd circle chop
     arrow from 3rd circle to 1st circle chop

It yields the following:


			 y  ---- z

	       Figure 10-8: The chop modifier

Notice that the chop attribute moves arrowheads rather	than
stepping  on  them.  By	 default, the chop modifier shortens
both ends of the line by circlerad.  By suffixing it with  a
number you can change the amount of chopping.

     If you say line ... chop r1 chop r2 with r1 and r2 both
numbers, you can vary the amount of chopping at	 both  ends.
You can use this in combination with trigonometric functions
to  write  code	  that	 will	deal   with   more   complex


11.  Object Groups

     There  are	 two different ways to group objects in pic;
brace grouping and block composites.

11.1.  Brace Grouping

     The simpler method is simply to group a set of  objects
within curly bracket or brace characters.  On exit from this
grouping, the current position and direction are restored to
their value when the opening brace was encountered.

11.2.  Block Composites

     A	block  composite  object  is  created  a  series  of
commands enclosed by square brackets.  The composite can  be
treated	 for most purposes like a single closed object, with
the size and shape of its bounding box.	 Here is an example.
The program fragment

     A: [
	 line up 1 at last circle .n;
	 line down 1 at last circle .s;
	 line right 1 at last circle .e;
	 line left 1 at last circle .w;
	 box dashed with .nw at last circle .se + (0.2, -0.2);
	 Caption: center of last box;

yields the block in figure 11-1, which we show both with and
without its attachment points.	The block's location becomes
the value of A.


	      |		      .nw	    .n		.ne
	      |				     |
	      |				     |
	      |				     |
	      |				     |
	      |				     |
	      |				     |

  -----------	 ----------- .w -----------   .c----------.e
	      |				     |
	      |	  +++++++++		     |	+++++++++
	      |	  +	  +		     |	+	+
	      |	  +	  +		     |	+	+
	      |	  +++++++++		     |	+++++++++
	      |				     |
	      |				     |
			      .sw	    .s		.se
	   Figure 11-1: A sample composite object

To  refer  to  one of the composite's attachment points, you
can say (for example) A .s.  For purposes of object  naming,
composites  are	 a  class.  You could write last [] .s as an
equivalent refrence, usable anywhere a location	 is  needed.
This  construction  is	very  important for putting together
large, multi-part diagrams.

     Blocks are also a variable-scoping	 mechanism,  like  a
groff(1)  environment.	All variable assignments done inside
a block are undone at the end  of  it.	 To  get  at  values
within a block, write a name of the block followed by a dot,
followed by the variable or label you want.  For example, we
could refer the the center of the box in the above composite
as last [] .Caption or A.Caption.

     This kind of reference to a label can be  used  in	 any
way  any  other	 location  can be.  For example, if we added
"Hi!" at A.Caption the result would look like this:


		 -----------	-----------

			     |	 +++++++++
			     |	 + Hi!	 +
			     |	 +	 +
			     |	 +++++++++

   Figure 11-2: Adding a caption using interior labeling

     You can also use interior labels in either	 part  of  a
with  modifier.	 This means that the example composite could
be  placed  relative  to  its  caption	box  by	 a   command
containing with A.Caption at.

     Blocks  may  be  nested.	This means you can use block
attachment   points   to   build   up	 complex    diagrams
hierarchically, from the inside out.  Note that last and the
other sequential naming mechanisms don't look inside blocks,
so if you have a program that looks like

     P: [box "foo"; ellipse "bar"];
     Q: [
	  [box "baz"; ellipse "quxx"]
	  "random text";
     arrow from 2nd last [];

the arrow in the last line will be attached to object P, not
object Q.

     In	 DWB  pic,  only  references  one  level  deep	into
enclosed  blocks  were	permitted.  GNU	 gpic  removes	this

     The   combination	 of    block	variable    scoping,
assignability  of  labels  and the macro facility that we'll
describe later on can be used  to  simulate  functions	with
local  variables (just wrap the macro body in block braces).


12.  Style Variables

     There are a number of global  style  variables  in	 pic
that  can  be  used  to	 change its overall behavior.  We've
mentioned several of them in previous sections.	 They're all
described here.	 For each variable, the default is given.
	       |	 |
Style Variable | Default | What It Does
boxht	       |   0.5	 | Default height of a box
boxwid	       |   0.75	 | Default height of a box
lineht	       |   0.5	 | Default length of vertical line
linewid	       |   0.75	 | Default length of horizontal line
arcrad	       |   0.25	 | Default radius of an arc
circlerad      |   0.25	 | Default radius of a circle
ellipseht      |   0.5	 | Default height of an ellipse
ellipsewid     |   0.75	 | Default width of an ellipse
moveht	       |   0.5	 | Default length of vertical move
movewid	       |   0.75	 | Default length of horizontal move
textht	       |   0	 | Default height of box enclosing a text object
textwid	       |   0	 | Default width of box enclosing a text object
arrowht	       |   0.1	 | Length of arrowhead along shaft
arrowwid       |   0.05	 | Width of rear of arrowhead
arrowhead      |   1	 | Enable/disable arrowhead filling
dashwid	       |   0.05	 | Interval for dashed lines
maxpswid       |  11	 | Maximum width of picture
maxpsht	       |   8.5	 | Maximum height of picture
scale	       |   1	 | Unit scale factor
fillval	       |   0.5	 | Default fill value

Any  of	 these variables can be set with a simple assignment
statement.  For example:

Figure 12-1: boxht=1; boxwid=0.3;  movewid=0.2;	 box;  move;
		 box; move; box; move; box;

     In	 GNU  pic,  setting the scale variable re-scales all
size-related state variables so	 that  their  values  remain
equivalent in the new units.

     The  command  reset resets all style variables to their
defaults.   You	 can  give  it	a  comma-separated  list  of
variable  names	 as  arguments, in which case it resets only


     State variables retain  their  values  across  pictures
until reset.

13.  Expressions, Variables, and Assignment

     A	number is a valid expression, of course (all numbers
are stored  internally	as  floating-point).   Decimal-point
notation  is acceptable; in GNU gpic, scientific notation in
C's `e' format (like 5e-2) is accepted.

     Anywhere a number is expected, the language  will	also
accept	a  variable.   Variables  may  be the built-in style
variable described in the last	section,  or  new  variables
created by assignment.

     DWB  pic  supports	 only the ordinary assignment via =,
defines the variable in the  current  block  if	 it  is	 not
already	 defined  there,  and  then changes the value in the
current block.	GNU  gpic  supports  an	 alternate  form  of
assignment  using :=. The variable (right side) must already
be defined, and the value of variable will be  changed	only
in the innermost block in which it is defined.

     You  can  use  the	 height,  width, radius, and x and y
coordinates of any object or corner in expressions If  A  is
an object label or name, all the following are valid:

     A.x		  # x coordinate of the center of A		  # y coordinate of the northeast corner of A
     A.wid		  # the width of A		  # and its height
     2nd last circle.rad  # the radius of the 2nd last circle

Note  the second expression, showing how to extract a corner

     Basic arithmetic resembling those of  C  operators	 are
available;  +,	*, -, /, and %.	 So is ^ for exponentiation.
Grouping is permitted in the usual  way	 using	parentheses.
GNU  gpic allows logical operators to appear in expressions;
! (logical negation, not factorial), &&, ||, ==, !=, >=, <=,
<, >.

     Various   built-in	 functions  are	 supported:  sin(x),
cos(x),	 log(x),  exp(x),  sqrt(x),  max(x,y),	 atan2(x,y),
min(x,y),  int(x), and rand(), Both exp and log are base 10;
int does integer truncation; and  rand()  returns  a  random
number in [0-1).

     GNU  gpic	also  documents a one-argument form or rand,
rand(x), which returns a random number between 1 and x,	 but
this is deprecated and may be removed in a future version.


     The function sprintf() behaves like a C sprintf(3) that
only takes %, %e, %f, and %g format strings.

14.  Macros

     You can define macros  in	pic.   This  is	 useful	 for
diagrams  with	repetitive  parts.   In conjunction with the
scope rules for block composites, it effectively  gives	 you
the ability to write functions.

     The syntax is

     define name { replacement text }

This  defines  name  as	 a  macro  to  be  replaced  by	 the
replacement text (not including the braces).  The macro	 may
be called as

     name(arg1, arg2, ... argn)

The arguments (if any) will be substituted for tokens $1, $2
... $n appearing in the replacement text.

     As an example of macro use, consider the following:


     # Plot a single jumper in a $1 by $2 box, $3 is the on-off state
     define jumper { [
	 shrinkfactor = 0.8;
	 Outer: box invis wid 0.5 ht 1;

	 # Count on end ] to reset these
	 boxwid = Outer.wid * shrinkfactor / 2;
	 boxht	=  * shrinkfactor / 2;

	 box fill (!$1) with .s at center of Outer;
	 box fill ($1)	with .n at center of Outer;
     ] }

     # Plot a block of six jumpers
     define jumperblock {

	 jwidth	 = last [].Outer.wid;
	 jheight = last [];

	 box with .nw at 6th last [].nw wid 6*jwidth ht jheight;

	 # Use {} to avoid changing position from last box draw.
	 # This is necessary so move in any direction will work as expected
	 {"Jumpers in state $1$2$2$3$4$5$6" at last box .s + (0, -0.2);}

     # Sample macro invocations

It yields the following:

   Jumpers in state 1110010	      Jumpers in state 1001011

	     Figure 14-1: Sample use of a macro


This macro example illustrates how you can combine [], brace
grouping, and variable assignment to write true functions.

     One detail the example above does not illustrate is the
fact that macro argument parsing is not token-oriented.	  If
you  call  jumper(  1  ), the value of $1 will be " 1 ". You
could even call jumper(big  string) to	give  $1  the  value
"big  string".

     If you want to pass in a coordinate pair, you can avoid
getting tripped up by the comma	 by  wrapping  the  pair  in

     Macros  persist  through pictures.	 To undefine a mcro,
say undef name; for example,

     undef jumper
     undef jumperblock

would undefine the two macros in the jumper block example.

15.  Import/Export Commands

     Commands that import or export data between pic and its
environment are described here.

15.1.  File and Table Insertion

     The statement

     copy filename

inserts	 the  contents	of filename in the pic input stream.
Any .PS/.PE pair in the file will be ignored.  This, you can
use this to include pre-generated images.

     A	variant	 of  this statement replicates the copy thru
feature of grap(1).  If you say

     copy filename thru macro

calls the macro (which may be either a name  or	 replacement
text) on the arguments obtained by breaking each line of the
file into blank-separated fields.  The macro may have up  to
9  arguments.	The  replacement  text	may  be delimited by
braces or by a	pair  of  instances  of	 any  character	 not
appearing in the rest of the text.

     If you write

     copy thru macro


omitting the filename, lines to be parsed are taken from the
input source up to the next .PE.

     In either of the copy  commands,  GNU  gpic  permits  a
trailing  `until  word'	 clause to be added which terminates
the copy when the  first  word	matches	 the  argument	(the
default behavior is therefore equivalent to until .PE,

     Accordingly, the command

	  copy thru % circle at ($1,$2) % until "END"
	  1 2
	  3 4
	  5 6

is equivalent to

	  circle at (1,2)
	  circle at (3,4)
	  circle at (5,6)

15.2.  Debug Messages

     The command print accepts any number of comma-separated
arguments, concatenates their output forms, and	 writes	 the
result	 to  standard  error.	Each  argument	must  be  an
expression, a position, or a text string.

15.3.  Escape to Post-Processor

     If you write

     command arg...

pic concatenates the arguments and pass them  through  as  a
line  to  troff	 or  TeX.  Each arg must be an expression, a
position, or text.  This has a	similar	 effect	 to  a	line
beginning  with	 .  or \, but allows the values of variables
to be passed through.

15.4.  Executing Shell Commands

     The command

     sh { anything... }


macroexpands the text in braces, then executes it as a shell
command.   This	 could	be  used  to generate images or data
tables for later inclusion.  The delimiters shown as {} here
may  also  be two copies of any one character not present in
the shell command  text.   In  either  case,  the  body	 may
contain	 balanced {} pairs.  Strings in the body may contain
balanced or unbalanced braces in any case.

16.  Control-flow constructs

     The pic language  provides	 conditionals  and  looping.
For example,

     pi = atan2(0, -1);
     for i = 0 to 2 * pi by 0.1 do {
	 "-" at (i/2, 0);
	 "." at (i/2, sin(i)/2);
	 ":" at (i/2, cos(i)/2);

which yields this:

	      :::  .....		  :::
		:::	...		:::
	       ..  ::	  ...	      ::
		      ::      ..   ::	  ...
			::	:::	...
			  ::::::: .......

	   Figure 16-1: Plotting with a for loop

The syntax of the for statement is:

     for variable = expr1 to expr2 [by [*]expr3] do X body X

The  semantics	are  as	 follows:   Set	 variable to expr1 .
While the value of variable is less than or equal to  expr2,
do body and increment variable by expr3; if by is not given,
increment variable by 1.  If expr3 is  prefixed	 by  *	then
variable  will instead be multiplied by expr3.	X can be any
character not occurring in body; or the two Xs may be paired
braces (as in the sh command).

     The syntax of the if statement is as follows:

     if expr then X if-true X [else Y if-false Y]

Its  semantics	are as follows: Evaluate expr; if it is non-
zero then do if-true, otherwise do if-false.  X can  be	 any
character  not occurring in if-true.  Y can be any character
not occurring in if-false.


     Eithe or both of the  X  or  Y  pairs  may	 instead  be
balanced pairs of braces ({ and }) as in the sh command.  In
either case, the  if-true  may	contain	 balanced  pairs  of
braces.	  None	of  these  delimiters  will  be	 seen inside

     All the  usual  relational	 operators  my	be  used  in
conditional    expressions;   !	  (logical   negation,	 not
factorial), &&, ||, ==, !=, >=, <=, <, >.

     String comparison is also supported using	==  and	 !=.
String	comparisons  may  need	to be parenthesized to avoid
syntactic ambiguities.

17.  Interface To [gt]roff

     The output of pic is [gt]roff  drawing  commands.	 The
GNU   gpic(1)  command	warns  that  it	 relies	 on  drawing
extensions present in  groff(1)	 that  are  not	 present  in

17.1.  Scaling Arguments

     The DWB pic(1) program will accept one or two arguments
to .PS, which is interpreted as a width and height in inches
to  which  the results of pic(1) should be scaled (width and
height scale independently).  If there is only one argument,
it  is	interpreted  as a width to scale the picture to, and
height will be scaled by the same proportion.

     GNU gpic is less general; it will accept a single width
to  scale  to, or a zero width and a maximum height to scale
to.  With two  nonzero	arguments,  it	will  scale  to	 the
maximum height.

17.2.  How Scaling is Handled

     When  pic	processes a picture description on input, it
passes .PS and .PE through to  the  postprocessor.  The	 .PS
gets  decorated	 with  two numeric arguments which are the X
and Y dimensions  of  the  picture  in	inches.	  The  post-
processor can use these to reserve space for the picture and
center it.

     The mgs macros,  for  example,  include  the  following


     .de PS
     .sp \n[DD]u
     .ie \n[.$]<2 .@error bad arguments to PS (not preprocessed with pic?)
     .el .     ds@need (u;\$1)+1v
     .	  in +(u;\n[.l]-\n[.i]-\$2/2>?0)
     .de PE
     .sp \n[DD]u+.5m

Equivalent  definition will be supplied by GNU pic(1) if you
use the -mpic option; this should make it usable with  macro
pages other than ms(1).

     if	 .PF  is  used instead of .PE, the troff position is
restored to what it was	 at  the  picture  start  (Kernighan
notes that the F stands for "flyback").

     The invocation

     .PS ;
	 filter "\fBpic\fP";
	 filter "\fBeqn\fP";
	 filter "\fBtbl\fP";
	 filter "\fBgroff\fP";
	 box "PostScript";

	 # HTML column
	 move to Anchor .se;
	 line down right then down ->;
	 A: filter dotted "\fBpic2img\fP";
	 B: filter dotted "\fBeqn2html\fP";
	 C: filter dotted "\fBtbl2html\fP";
	 filter "\fBms2html\fP";
	 box "HTML";


	 # Nonexistence caption
	 box dashed wid 1 at B + (2, 0) "These tools" "don't yet exist";
	 line chop 0 chop 0.1 dashed from last box .nw to A.e ->;
	 line chop 0 chop 0.1 dashed from last box .w  to B.e ->;
	 line chop 0 chop 0.1 dashed from last box .sw to C.e ->;

   ms	      HTML	  linuxdoc-sgml	     Texinfo
sources	     sources	     sources	     sources
    |		|		|		 |
    |	      --+---	      --+---	      ---+--
    |	    +html2ms+	     format +	    texi2roff
    |	      --+---	      --+---	      ---+--
    |		|		|		 |


		|		    |
		|		    |
	      ------		 ++++++++
	    + -pic--+		+pic2img++++++
		|		    |	      ++++++++++++++++
	      ------		 ++++++++	   These tools
	    + -eqn--+		eqn2html+++++++++don't yet exist
		|		    |		 ++++++++ ++++
	      ------		 ++++++++ +++++++
	    + -tbl--+		tbl2html++
		|		    |
	      ------		  ------
	    + groff-+		+ms2html+
		|		    |

	   PostScript		  HTML

Figure 20-2: Hypothetical production flow for dual-mode publishing


21.  PIC Reference

     This is an annotated grammar of PIC.

21.1.  Lexical Items

     In	  general,  pic	 is  a	free-format,  token-oriented
language  that	ignores	 whitespace  outside  strings.	 But
certain lines and contructs are specially interpreted at the
lexical level:

     A comment begins with # and continues to  \n  (comments
may  also  follow  text in a line).  A line beginning with a
period or backslash may be interpreted as text to be  passed
through	 to  the  post-processor,  depending on command-line
options.  An  end-of-line  backslash  is  interpreted  as  a
request	 to  continue  the line; the backslash and following
newline are ignored.

Here are the grammar terminals:

     A decimal numeric	constant.   May	 contain  a  decimal
     point  or	be  expressed  in scientific notation in the
     style of printf(3)'s  %e  escape.	(All  variables	 are
     represented internally in floating-point.)

     Any  ASCII	 characters  surrounded	 by a pair of double
     quotes.  May contain a double quote if  preceded  by  a

     A	lower-case  alphabetic	character,  followed  by any
     number of	alphanumerics.	 (Values  of  variables	 are
     preserved across pictures.)