5.26 Drawing Requests

gtroff provides a number of ways to draw lines and other figures on the page. Used in combination with the page motion commands (see Page Motions), a wide variety of figures can be drawn. However, for complex drawings these operations can be quite cumbersome, and it may be wise to use graphic preprocessors like gpic or ggrn.

All drawing is done via escape sequences.

Escape sequence: \l'l'
Escape sequence: \l'lc'

Draw a line horizontally. l is the length of the line to be drawn. If it is positive, start the line at the current location and draw to the right; its end point is the new current location. Negative values are handled differently: The line starts at the current location and draws to the left, but the current location doesn’t move.

l can also be specified absolutely (i.e., with a leading ‘|’), which draws back to the beginning of the input line. Default scaling indicator is ‘m’.

The optional second parameter c is a glyph to draw the line with. If this second argument is not specified, gtroff uses the underscore glyph, \[ru].

To separate the two arguments (to prevent gtroff from interpreting a drawing glyph as a scaling indicator if the glyph is represented by a single character) use \&.

.de textbox
\[br]\\$*\[br]\l'|0\[rn]'\l'|0\[ul]'
..

The above works by outputting a box rule (a vertical line), then the text given as an argument and then another box rule. Finally, the line-drawing escape sequences both draw from the current location to the beginning of the input line—this works because the line length is negative, not moving the current point.

Escape sequence: \L'l'
Escape sequence: \L'lg'

Draw vertical lines. Its parameters are similar to the \l escape, except that the default scaling indicator is ‘v’. The movement is downward for positive values, and upward for negative values. The default glyph is the box rule glyph, \[br]. As with the vertical motion escape sequences, text processing blindly continues where the line ends.

This is a \L'3v'test.

Here is the result, produced with grotty.

This is a
          |
          |
          |test.
Escape sequence: \D'command arg …'

The \D escape provides a variety of drawing functions. On character devices, only vertical and horizontal lines are supported within grotty; other devices may only support a subset of the available drawing functions.

The default scaling indicator for all subcommands of \D is ‘m’ for horizontal distances and ‘v’ for vertical ones. Exceptions are ‘\D'f …'’ and ‘\D't …'’, which use u as the default, and ‘\D'Fx …'’, which arguments are treated similar to the defcolor request.

\D'l dx dy'

Draw a line from the current location to the relative point specified by (dx,dy), where positive values mean right and down, respectively. The end point of the line is the new current location.

The following example is a macro for creating a box around a text string; for simplicity, the box margin is taken as a fixed value, 0.2m.

.de TEXTBOX
.  nr @wd \w'\\$1'
\h'.2m'\
\h'-.2m'\v'(.2m - \\n[rsb]u)'\
\D'l 0 -(\\n[rst]u - \\n[rsb]u + .4m)'\
\D'l (\\n[@wd]u + .4m) 0'\
\D'l 0 (\\n[rst]u - \\n[rsb]u + .4m)'\
\D'l -(\\n[@wd]u + .4m) 0'\
\h'.2m'\v'-(.2m - \\n[rsb]u)'\
\\$1\
\h'.2m'
..

First, the width of the string is stored in register @wd. Then, four lines are drawn to form a box, properly offset by the box margin. The registers rst and rsb are set by the \w escape, containing the largest height and depth of the whole string.

\D'c d'

Draw a circle with a diameter of d with the leftmost point at the current position. After drawing, the current location is positioned at the rightmost point of the circle.

\D'C d'

Draw a solid circle with the same parameters and behaviour as an outlined circle. No outline is drawn.

\D'e x y'

Draw an ellipse with a horizontal diameter of x and a vertical diameter of y with the leftmost point at the current position. After drawing, the current location is positioned at the rightmost point of the ellipse.

\D'E x y'

Draw a solid ellipse with the same parameters and behaviour as an outlined ellipse. No outline is drawn.

\D'a dx1 dy1 dx2 dy2'

Draw an arc clockwise from the current location through the two specified relative locations (dx1,dy1) and (dx2,dy2). The coordinates of the first point are relative to the current position, and the coordinates of the second point are relative to the first point. After drawing, the current position is moved to the final point of the arc.

\D'~ dx1 dy1 dx2 dy2 …'

Draw a spline from the current location to the relative point (dx1,dy1) and then to (dx2,dy2), and so on. The current position is moved to the terminal point of the drawn curve.

\D'f n'

Set the shade of gray to be used for filling solid objects to n; n must be an integer between 0 and 1000, where 0 corresponds solid white and 1000 to solid black, and values in between correspond to intermediate shades of gray. This applies only to solid circles, solid ellipses, and solid polygons. By default, a level of 1000 is used.

Nonintuitively, the current point is moved horizontally to the right by n.

Don’t use this command! It has the serious drawback that it is always rounded to the next integer multiple of the horizontal motion quantum (the value of the hor keyword in the DESC file). Use \M (see Colors) or ‘\D'Fg …'’ instead.

\D'p dx1 dy1 dx2 dy2 …'

Draw a polygon from the current location to the relative position (dx1,dy1) and then to (dx2,dy2) and so on. When the specified data points are exhausted, a line is drawn back to the starting point. The current position is changed by adding the sum of all arguments with odd index to the actual horizontal position and the even ones to the vertical position.

\D'P dx1 dy1 dx2 dy2 …'

Draw a solid polygon with the same parameters and behaviour as an outlined polygon. No outline is drawn.

Here a better variant of the box macro to fill the box with some color. The box must be drawn before the text since colors in GNU troff are not transparent; the filled polygon would hide the text completely.

.de TEXTBOX
.  nr @wd \w'\\$1'
\h'.2m'\
\h'-.2m'\v'(.2m - \\n[rsb]u)'\
\M[lightcyan]\
\D'P 0 -(\\n[rst]u - \\n[rsb]u + .4m) \
     (\\n[@wd]u + .4m) 0 \
     0 (\\n[rst]u - \\n[rsb]u + .4m) \
     -(\\n[@wd]u + .4m) 0'\
\h'.2m'\v'-(.2m - \\n[rsb]u)'\
\M[]\
\\$1\
\h'.2m'
..

If you want a filled polygon that has exactly the same size as an unfilled one, you must draw both an unfilled and a filled polygon. A filled polygon is always smaller than an unfilled one because the latter uses straight lines with a given line thickness to connect the polygon’s corners, while the former simply fills the area defined by the coordinates.

\h'1i'\v'1i'\
\# increase line thickness
\Z'\D't 5p''\
\# draw unfilled polygon
\Z'\D'p 3 3 -6 0''\
\# draw filled polygon
\Z'\D'P 3 3 -6 0''
\D't n'

Set the current line thickness to n basic units. A value of zero selects the smallest available line thickness. A negative value makes the line thickness proportional to the current type size (this is the default behaviour of AT&T troff).

Nonintuitively, the current point is moved horizontally to the right by n.

\D'Fscheme color_components'

Change current fill color. scheme is a single letter denoting the color scheme: ‘r’ (rgb), ‘c’ (cmy), ‘k’ (cmyk), ‘g’ (gray), or ‘d’ (default color). The color components use exactly the same syntax as in the defcolor request (see Colors); the command \D'Fd' doesn’t take an argument.

No position changing!

Examples:

\D'Fg .3'      \" same gray as \D'f 700'
\D'Fr #0000ff' \" blue

See Graphics Commands.

Escape sequence: \b'contents'

Pile and center a sequence of glyphs vertically on the output line. Piling vertically stacks glyphs corresponding to each character in contents, read from left to right, and placed from top to bottom. GNU troff separates the glyphs vertically by 1m, and the pile itself is centered 0.5m above the text baseline. The horizontal drawing position is then advanced by the width of the widest glyph in the pile.

This rather inflexible positioning algorithm doesn’t work with the dvi output device since its bracket pieces vary in height. Instead, use the geqn preprocessor.

See Manipulating Spacing, to see how to adjust the vertical spacing of the output line with the \x escape sequence.

The idiomatic use of \b is for building large brackets and braces, hence its name. We might construct a large opening brace as follows.

\b'\[lt]\[bv]\[lk]\[bv]\[lb]'