/in { 72 mul } def
/pagewidth 8.5 in def
/pageheight 11 in def
<< /PageSize [ pagewidth pageheight ] >> setpagedevice
/xmargin 0.5 in def
/ymargin 0.5 in def
/imargin 0.5 in def
/across 2 def
/down 3 def
/cardwidth pagewidth xmargin 2 mul sub imargin across 1 sub mul sub across div def
/cardheight pageheight ymargin 2 mul sub imargin down 1 sub mul sub down div def
cardheight cardwidth gt
{
/symbolsize cardwidth 1.5 div def
/xoffset cardwidth symbolsize sub 2 div def
/yoffset cardheight cardwidth sub 2 div xoffset add def
}
{
/symbolsize cardheight 1.5 div def
/yoffset cardheight symbolsize sub 2 div def
/xoffset cardwidth cardheight sub 2 div yoffset add def
}
ifelse
/halfsymbol symbolsize 2 div def
/circle
{
4 dict begin
/r exch def
/y exch def
/x exch def
/o 2 sqrt 1 sub r mul 4 3 div mul def
x r sub y moveto
x r sub y o add x o sub y r add x y r add curveto
x o add y r add x r add y o add x r add y curveto
x r add y o sub x o add y r sub x y r sub curveto
x o sub y r sub x r sub y o sub x r sub y curveto
closepath
end
} def
/circlecard {
halfsymbol dup dup circle
stroke
} def
/crosscard {
halfsymbol 0 moveto
0 symbolsize rlineto
0 halfsymbol moveto
symbolsize 0 rlineto
stroke
} def
/squarecard {
1 dict begin
/scale 0.1 def
scale symbolsize mul dup
1 scale 2 mul sub symbolsize mul dup
rectstroke
end
} def
/starcard {
3 dict begin
/points 5 def
/shortsize halfsymbol 72 cos mul 36 cos div def
/halfangle 180 5 div def
halfsymbol dup translate
0 halfsymbol moveto
1 1 points
{
pop
halfangle rotate
0 shortsize lineto
halfangle rotate
0 halfsymbol lineto
}
for
closepath
stroke
end
} def
/trianglecard {
halfsymbol dup translate
0 1 30 sin sub halfsymbol mul neg 2 div translate
0 halfsymbol moveto
120 rotate
0 halfsymbol lineto
120 rotate
0 halfsymbol lineto
closepath
stroke
} def
/wavycard {
8 dict begin
/lines 4 def
/wiggles 5 def
/wiggleheight symbolsize wiggles 2 mul div def
/linegap symbolsize wiggleheight sub lines 1 sub div def
/wigglewidth symbolsize wiggles div def
/y 0 def
1 1 lines
{
pop
/x 0 def
x y moveto
1 1 wiggles
{
/midx x wigglewidth 2 div add def
1 and 0 ne
{
midx y
midx y wiggleheight add
x wigglewidth add y wiggleheight add curveto
}
{
midx y wiggleheight add
midx y
x wigglewidth add y curveto
}
ifelse
/x x wigglewidth add def
}
for
stroke
/y y linegap add def
}
for
end
} def
/cardnumber 0 def
/cards [ /circlecard /crosscard /squarecard /starcard /trianglecard /wavycard ] def
1 setlinecap
1 setlinejoin
1 1 down
{
/yn exch def
/cornery ymargin yn 1 sub cardheight imargin add mul add def
1 1 across
{
/xn exch def
/cornerx xmargin xn 1 sub cardwidth imargin add mul add def
gsave
cornerx cornery translate
0 0 cardwidth cardheight rectstroke
currentlinewidth
0.1 in setlinewidth
xoffset yoffset translate
cards cardnumber get cvx exec
setlinewidth
grestore
/cardnumber cardnumber 1 add def
}
for
}
for
showpage
Looks good!
If you put a %! at the beginning, it's slightly easier to see where
the
code begins.
> /in { 72 mul } def
>
> /pagewidth 8.5 in def
> /pageheight 11 in def
>
> << /PageSize [ pagewidth pageheight ] >> setpagedevice
>
> /xmargin 0.5 in def
> /ymargin 0.5 in def
> /imargin 0.5 in def
I usually use shorter names, just to save typing.
It used to be the case that short names are better
so the program can execute faster; but if you're
converting to pdf, that's largely irrelevant.
> /across 2 def
> /down 3 def
>
> /cardwidth pagewidth xmargin 2 mul sub imargin across 1 sub mul sub across div def
> /cardheight pageheight ymargin 2 mul sub imargin down 1 sub mul sub down div def
>
> cardheight cardwidth gt
> {
> /symbolsize cardwidth 1.5 div def
> /xoffset cardwidth symbolsize sub 2 div def
> /yoffset cardheight cardwidth sub 2 div xoffset add def}
>
> {
> /symbolsize cardheight 1.5 div def
> /yoffset cardheight symbolsize sub 2 div def
> /xoffset cardwidth cardheight sub 2 div yoffset add def}
>
> ifelse
There's a lot of duplication in these two procs.
It might be easier to use ifelse to define two new
names.
Or maybe not. I just tried to rewrite this part like this:
cardheight cardwidth 2 copy gt { exch } if
/smaller exch def
/bigger exch def
/symbolsize smaller 1.5 div def
/xoffset smaller symbolsize sub 2 div def
/yoffset bigger smaller sub 2 div xoffset add def
And then I noticed that the offsets are flopped.
So, your way is probably better here, but bear in
mind that stack manipulation can sometimes simplify
things.
>
> /halfsymbol symbolsize 2 div def
>
> /circle
> {
> 4 dict begin
>
> /r exch def
> /y exch def
> /x exch def
>
> /o 2 sqrt 1 sub r mul 4 3 div mul def
>
> x r sub y moveto
> x r sub y o add x o sub y r add x y r add curveto
> x o add y r add x r add y o add x r add y curveto
> x r add y o sub x o add y r sub x y r sub curveto
> x o sub y r sub x r sub y o sub x r sub y curveto
> closepath
>
> end
>
> } def
I'd probably use arc for a circle, but it's fun to see
how you calculate the control points.
I'm probably too used to C programming.
It looks funny to me to have a for loop start on 1.
I'd probably do
0 1 down across mul 1 sub
and then separate the rows with
loopindex across mod 0 eq { move_to_next_row } if
That way your loopindex matches the array index.
> {
> /yn exch def
>
> /cornery ymargin yn 1 sub cardheight imargin add mul add def
>
> 1 1 across
> {
> /xn exch def
> /cornerx xmargin xn 1 sub cardwidth imargin add mul add def
>
> gsave
>
> cornerx cornery translate
> 0 0 cardwidth cardheight rectstroke
>
> currentlinewidth
> 0.1 in setlinewidth
> xoffset yoffset translate
>
> cards cardnumber get cvx exec
>
> setlinewidth
>
> grestore
>
> /cardnumber cardnumber 1 add def
Again, from too much C, I like to make a little
helper proc:
/++ { dup load 1 add store } def
If you use more dictionaries, store is often
better for changing a value where it already
exists.
> }
> for}
It looks like most of your braces line up
with the opening brace or the beginning of
text on the line with the opening brace.
But a scattered few sit on the end of the line.
Not a big deal, but it looks a little weird.
>
> for
>
> showpage
That's true. Though with 'roll' I always have to test it out, I usually
get it wrong first try! exch is okay though. (-:
>> /circle
(snip)
> I'd probably use arc for a circle, but it's fun to see
> how you calculate the control points.
Huh, good point, I wonder why I didn't use arc too. (I pulled that
procedure from an old project.) Given that a pathforall after an arc
gives us curveto anyway, I wonder if what I did is pretty much what
interpreters do internally with arc.
>> 1 1 down
>
> I'm probably too used to C programming.
> It looks funny to me to have a for loop start on 1.
> I'd probably do
>
> 0 1 down across mul 1 sub
>
> and then separate the rows with
>
> loopindex across mod 0 eq { move_to_next_row } if
>
> That way your loopindex matches the array index.
Oh, yes, that's a good idea.
> Again, from too much C, I like to make a little
> helper proc:
> /++ { dup load 1 add store } def
Ohh, that's a nice trick, I'd not seen it before.
>> }
>> for}
>
> It looks like most of your braces line up
> with the opening brace or the beginning of
> text on the line with the opening brace.
> But a scattered few sit on the end of the line.
> Not a big deal, but it looks a little weird.
Hmmm, it doesn't look like that in my original here or in the Google
archive; perhaps your newsreader helpfully reformatted a little?
Thanks very much -- I appreciate you taking the time to form and share
your thoughts.
Mark
I had difficulty with roll, too, for a very long time.
I remember it now this way:
n j roll
positive j to roll away
negative to get it back
Perhaps a better way to think of it is a physical stack
(of books, say) so the top of stack is literally "on top".
Then a positive roll goes up:
for j number of times
pick up n books
put the top one on the bottom (shifting the substack "up")
put them back down
And a negative roll goes down:
for j number of times
pick up n books
put the bottom one on top (shifting the substack "down")
put them back down
But I usually picture the stack sideways, the way the objects
would look in a file as a sequence of literals. So I think of
the positive roll as stashing the top j things behind the nth
thing; and the negative roll as snagging j things starting
with the nth thing. Give and Take. Jesus says giving is better
so it's the positive thing to do.
HTH
Still another way is to picture it sideways,
and laying a sticky wheel on top (a lint-roller, maybe)
(a) (b) (c) (d) (e) 5 3 roll
_______
/ \
| 3 |
| / | \ |
\_______/
(a) (b) (c) (d) (e)
Then a positive roll goes counterclockwise
just like arc and rotate.
_______ (e)
/ / \
| 3 --| (d)
| \ |
\_______/ (c)
(a) (b)
(e)__(d)__(c)
/\ | /\
| 3 |
| |
\_______/
(a) (b)
(c)_______
/\ \
(d) |-- 3 |
|/ |
\_______/
(e) (a) (b)
_______
/ \
| 3 |
| / | \ |
\_______/
(c) (d) (e) (a) (b)
And a negative roll goes clockwise
like arcn and a negative rotation.
_______
/ \
| 3 |
| / | \ |
\_______/
(a) (b) (c) (d) (e)
(a)_______
/\ \
(b) |-- 3 |
|/ |
\_______/
(c) (d) (e)
(c)__(b)__(a)
/\ | /\
| 3 |
| |
\_______/
(d) (e)
_______ (c)
/ / \
| 3 --| (b)
| \ |
\_______/ (a)
(d) (e)
_______
/ \
| 3 |
| / | \ |
\_______/
(d) (e) (a) (b) (c)