Variables in PostScript are defined with the def operator.
To create a variable called pi, you would use:
/pi 3.1416 defNotice the slash before the variable name. You need this only when you define the variable. Thereafter, you would get the area of a circle of radius 4 like this:
4 4 mul pi mul.
You use the slash to refer to the variable's name, not its value.
Subroutines are made exactly the same way. However, you normally want more than one command in a subroutine. To do this, you group commands with curly braces. The following defines a subroutine that makes a filled circle:
/filledcircle {
gsave
newpath
0 0 1 0 360 arc
fill
grestore
}
def
This isn't very interesting, however, since this is a very limited
subroutine. We can make it take arguments by making it use
the previous elements on the stack. So we could set the radius of the
circle like this:
/filledcircle {
/radius exch def
gsave
newpath
0 0 radius 0 360 arc
fill
grestore
}
def
Now, to make a filled circle of radius 1, you would use
1 filledcircle. Notice how exch is
used in the variable definition. The stack starts with (if our
argument is 1)
1 /radiusAfter the
exch we have
/radius 1and now the
def command will work.
There still is something not quite ideal about our subroutine -
the radius variable is global! You might be overwriting a value used
somewhere else by other code. To fix this, you need to use a
dictionary. This an advanced concept of variable scope
that you will only learn a tiny bit of here. At the
beginning of your subroutine, you can define a new dictionary
with n variables using n dict begin.
This says, for our purposes, that the next n variables
defined will be local variables. They have scope until the
next end statement. So here is our routine again.
This time it takes three arguments: x center, y center, and radius.
/filledcircle {
3 dict begin
/radius exch def
/y exch def
/x exch def
gsave
newpath
x y radius 0 360 arc
fill
grestore
end
}
def
Notice how gsave and grestore are used here.
They allow the circle to be drawn without disrupting any path
that might be in progress.
Let us now turn to making a "target" with our filled circles.
This will be a set of nested circles with different grey values.
Obviously we will use a loop to do this, in this case a for
loop. The for loop takes four arguments: an initial value
for the loop variable,
a step, a final value, and code to repeat. During each iteration
of the loop, the current value of the loop variable is pushed on the stack,
and then the code is repeated. This loop makes a target with 4 circles:
4 -1 1 {
gsave
dup
1 sub 4 div setgray
0 exch 0 exch 4 div filledcircle
grestore
} for
We can put this all together in a routine that takes a position, radius
and number of circles as its argument.
/target {
5 dict begin
/count exch def
/radius exch def
/y exch def
/x exch def
count -1 1 {
/level exch def
gsave
level 1 sub count div setgray
x y radius level count div mul filledcircle
grestore
} for
end
}
def
Here is the output of 0 0 1 10 target:
|
|
David Maxwell,
who is still writing this, would like to
hear your comments and suggestions.
And remember, parts of this manual are based on
P.J. Weingartner's work:
A First Guide to PostScript.