PicScheme, or the Scheme code in `picscheme.tex`

,
provides a set of picture-making primitives that is
similar in spirit to LaTeX’s `{picture}`

environment [4, ch. 7], except that the
commands are in Scheme and can be combined using full
Scheme.

You can specify *picture objects* such as
paths and texts and position
them in a composite picture object called a *picture*.
In general, a picture specification looks as follows:

\eval{

... ;Scheme code, enhanced with ;the picture-drawing primitives ...

}

The picture produced is a *box*, which means it
will be typeset as a giant letter might be.
We can use the usual TeX approaches to centering and
displaying boxes, eg, `\centerline`

.

The picture description makes use of a *unit
length*, which is stored in the variable `*unit‑length*`

and is by default 1 bp (big point), which is 1/72 of an inch.
Regardless of the `*unit‑length*`

, PicScheme
internally manipulates lengths as multiples of big
points, and thus the default initial value of
of `*unit‑length*`

is the *number* 1.

In order to allow the resetting of `*unit‑length*`

easily,
PicScheme provides the procedure `dimen`

, which converts
lengths in other units to scaled points. For example,

(dimen 1 'in)

returns the bp equivalent of 1 inch, which is 72.
`dimen`

’s second argument is thus a symbol naming the
unit converted from, and this can be one of `pt`

(point), `pc`

(pica), `in`

(inch), `bp`

(big
point), `cm`

(centimeter), `mm`

(millimeter),
`dd`

(didot point), `cc`

(cicero), and `sp`

(scaled
point) [3, ch. 10], [2, ch. 11].
(The word *dimen* is merely standard TeX jargon for
(non-springy) length — the only physical dimension
that is relevant to typesetting.)

We can thus
set `*unit‑length*`

to be 42 mm by

(set! *unit-length* (* 42 (/ 25.4) 72))

where we make use of the equivalences 1 mm = 1/25.4 inch, 1 inch = 72 bp, or, we could say

(set! *unit-length* (dimen 42 'mm))

Use whichever is easier for you. Changing
`*unit‑length*`

is a convenient way to scale a
picture without rewriting its innards.

An important length quantity is
the *thickness* of (the lead of) the imaginary pencil used to
draw a PicScheme picture. By default this is 0.5 bp.
You may reset it using the `pencil‑width`

procedure.
Thus

(pencil-width 1/72)

sets the pencil width to 1/72 of whatever the
prevailing `*unit‑length*`

is. (Setting pencil width is
probably the only occasion where it may be more
convenient to specify a true length in bp rather than a
multiple of the prevailing `*unit‑length*`

. To set
it to 0.5 bp, you can use
`(pencil‑width (/ (dimen .5 'bp) *unit‑length*))`

,
which does the correct thing regardless of the value of
`*unit‑length*`

.)

The 0-argument procedures
`thin‑lines`

and `thick‑lines`

can be used to toggle between
the default pencil width and a value that is twice the
default width.
`(thin‑lines)`

sets pencil
thickness to the default .5 bp, while
`(thick‑lines)`

sets it to 1 bp.

A picture is introduced by a call to the
`picture`

procedure:

(picture th)

`th`

is a thunk (zero-argument procedure) that
will contain commands to populate the picture.
For example,

\centerline{

\eval{ (set! *unit‑length* (dimen 1 'cm)) (picture (lambda () (label (point 0 0) "nothing special"))) }

}

produces

The only “picture” here is a text object, created by
the procedure `label`

, but it
nevertheless serves to illustrate the use of
coordinates. The procedure `point`

makes a point
from its *x*- and *y*-coordinates. PicScheme represents
fully determined points as complex numbers, with the *x*-coordinate
as the real part and the *y*-coordinate as the imaginary
part, so `(point 2 3)`

can be more succinctly entered
as `2+3i`

. In particular, `(point 0 0)`

is simply
`0`

. In the following, we will use the shorter
complex-number notation when feasible.

The first argument to `label`

is
the
point at which to place
the second argument, which can be any valid TeX
fragment.
Eg^{1}

\eval{ (picture (lambda () (label ‑3 "West") (label +3i "North") (label 3 "East") (label ‑3i "South"))) }

produces

Note that the center of the text coincides with the
point supplied.
`label`

can take a third argument that can place
the text at a different relation to the chosen point.

In the following example, the `label`

’s point is
the center of the “cross hairs”, and we use the
position indicators `ulft`

and `lrt`

to put the text `"UPPER LEFT"`

on the upper left of the
point,
and the text `"LOWER RIGHT"`

on its lower right.
The various position
possibilities are `lft`

, `ulft`

, `top`

,
`urt`

, `rt`

, `lrt`

, `bot`

, `llft`

.

\eval{ (picture (lambda () (draw (path ‑2.5i '‑‑ +2.5i)) (draw (path ‑2.5 '‑‑ 2.5)) ; (label 0 "UPPER LEFT" 'ulft) (label 0 "LOWER RIGHT" 'lrt))) }

produces

The procedure `path`

returns a path
passing through a sequence of points.
The form of the path between successive points is
governed by the symbols `‑‑`

and `**`

, which produce straight-line
and curved segments respectively. Additional arguments such
as `direction`

, `controls`

(with `and`

), and `cycle`

can further alter the path.
The procedure
`draw`

draws its argument path.

\eval{ (set! *unit‑length* (dimen 1 'cm)) (picture (lambda () (draw (path 0 '‑‑ 10 '‑‑ 10+10i '‑‑ +10i '‑‑ 'cycle)) (let ((lft‑control‑point 3+12i) (rt‑control‑point 7+12i)) (draw (path 2+2i '** 'controls lft‑control‑point '** 7+2i)) (draw (path 3+2i '** 'controls rt‑control‑point '** 8+2i))) (label 9.8+0.2i "{\\it 020203120702, 030207120802}" 'ulft))) }

produces

`'controls z1`

uses `z1`

as a control point (instead of having the path pass through it) for
the enclosing points.
For instance, a Bezier curve with the three points
`z1`

, `zc`

, `z2`

connects `z1`

and `z2`

using
`zc`

as a control point, and can be represented as

(path z1 '** 'controls zc '** z2)

`'controls z1 'and z2`

uses both `z1`

and `z2`

as control points
for the enclosing points.
`cycle`

, if it occurs at all, should be the
last argument, and returns a closed path. `direction`

governs the direction of the part of the path at
the adjacent point (which could be directly to the left or to the right).

Here is a *grid*:

\eval{ (set! *unit‑length* (dimen .5 'cm)) (picture (lambda () ;draw vertical lines (let loop ((x 0)) (when (<= x 20) ((if (= (modulo x 5) 0) thick‑lines thin‑lines)) (draw (path (point x 0) '‑‑ (point x 10))) (loop (+ x 1)))) ;draw horizontal lines (let loop ((y 0)) (when (<= y 10) ((if (= (modulo y 5) 0) thick‑lines thin‑lines)) (draw (path (point 0 y) '‑‑ (point 20 y))) (loop (+ y 1)))) (thin‑lines))) }

produces

`draw‑arrow`

is similar to
`draw`

except it attaches an arrow to the end of
the path. `draw‑double‑arrow`

attaches arrows to
both the beginning and end of the path.

The thunks `quarter‑circle`

, `half‑circle`

and
`full‑circle`

return the relevant portions of a
circle of diameter unity and center at the origin.
`unit‑square`

returns a unit square with its lower
left at the origin.

Being so pegged to the origin is not a problem, as
one can *transform* paths using
the procedures
`shift`

, `rotate`

,
`rotate‑about`

,
`reflect‑about`

,
`slant`

,
`scale`

,
`x‑scale`

,
`y‑scale`

, and
`z‑scale`

[2, ch. 15].

\eval{ (define rectangle (lambda (z1 z4) (let ((x1 (x‑part z1)) (y1 (y‑part z1)) (x4 (x‑part z4)) (y4 (y‑part z4))) (path z1 '‑‑ (point x4 y1) '‑‑ z4 '‑‑ (point x1 y4) '‑‑ 'cycle)))) (picture (lambda () (label 0 "\\vbox{\\hbox{square}\\hbox{peg}}" 'llft) (label 4+3i "\\vbox{\\hbox{round}\\hbox{hole}}" 'urt) ;draw circle of dia = 8 (draw (scale 8 (full‑circle))) ;for square to fit in circle, ;its side must be 8/(sqrt 2) (let* ((s (/ 8 (sqrt 2))) (s/2 (/ s 2))) (draw (rectangle (point (‑ s/2) (‑ s/2)) (point s/2 s/2)))))) }

produces

The procedures `x‑part`

and `y‑part`

return the
*x*- and *y*-coordinate respectively of their argument
point.

In the following program for a spoked wheel, the path for the spoke is created only once, but we draw several differently rotated versions of it.

\eval{ (set! *unit‑length* (dimen 1 'cm)) (picture (lambda () ;draw two concentric circles for wheel rim (let ((c (full‑circle))) (draw (scale 4 c)) (draw (scale 4.5 c))) (let ((one‑deg (let ((pi (acos ‑1))) (/ pi 180)))) ;one‑deg is 1 degree in radians (let ((spoke (path 0 '‑‑ 2))) ;draw spoke at 20‑deg increments (let loop ((i 0)) (unless (>= i 360) (draw (rotate (* i one‑deg) spoke)) (loop (+ i 20)))))))) }

produces