summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/epsdice/epsdice.dtx
blob: e0060567d5c6d06cb0ef864804658dba18ec2bd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
% \iffalse
%
%  EPSDICE.DTX  by Thomas Heim  (thomas.heim@unibas.ch)
%
%  LICENSE: LPPL
%
%  a small package to include dice faces in .eps format
%
%  provides the command \epsdice{#1}
%  taking one mandatory argument, an integer from 1 to 6
%  and one optional argument: 'black' (for black background, with white dots);
%  default is white background with black dots) 
%
%  HISTORY:
%  ========
%
%  2001/02/11 -- first release, for dvips only
%
%  2001/02/13 -- now works under pdfLaTeX, too
%                (with Rolf Niepraschk's help)
%
%  2001/09/04 -- "program encapsulated" by introducing "@" in counter name
%             -- distributed as .dtx and .ins files, plus binary .pdf file
%             -- some modifications in documentation                      
%             -- NO CHANGES IN USER INTERFACE                        (tah)
%
%  2007/02/11 -- added OPTIONAL argument [black] to user interface, for
%                reversed colors (extension suggested and drawings provided
%                by Christoph Zurnieden, czurnieden@gmx.de)
%
%  2007/02/15 -- removed spurious comment line from generated EPS file
%                (thanks to Christoph for spotting the bug)
% \fi
%<*sampledoc>
\documentclass[11pt]{article}
\usepackage{epsdice}
%
\title{Package `epsdice' --- a scalable dice font}
\author{2007/02/15 -- Version 2.1 \\[.5ex] Thomas Heim \\[.5ex]
  (thomas.heim@unibas.ch)}
\date{}
\begin{document}
\maketitle
\section{Introduction}
Dice fonts are already available in \textsc{metafont} format. 
(I should know, I wrote one myself: \texttt{dice3d.mf}.)
For some applications it seems preferable, however, to have the fonts
in scalable form. The package \texttt{epsdice} fills this gap.

\texttt{epsdice.sty} provides a single command,
\verb+\epsdice{#1}+, taking one mandatory argument,  an integer from 1 to 6,
and recognising one optional argument, namely \verb+[black]+
for a black die with white dots.\footnote{Thanks to Chrisoph Zurnieden for
suggesting the extension with reversed colors, and for adjusting the drawings
to this purpose.} The default behavior (i.e., with \emph{no} optional argument
or with \emph{any optional argument other} than \verb+[black]+) results in 
a white die with black dots.

The mandatory argument may also be the value of a counter. Thus 
automatic representation of (generated or input) data is possible as well. 
Of course, values outside the range 1--6 will not be represented as die faces.

Depending on the value of the argument, \verb+\epsdice+ includes the 
appropriately clipped region from a file containing simple drawings 
of die faces. The drawings scale with the current font because the 
height of the included graphics file is set in terms of `ex' units.
%
\section{Requirements and limitations}
\texttt{epsdice} relies on the \texttt{graphicx} package to include 
the drawings. 
It also uses the \texttt{ifthen} package to validate the arguments
(error checking).

The package has been tested with two widely used package drivers
for \texttt{graphicx}: \verb+[dvips]+ and \verb+[pdftex]+. By 
default, the command \verb+\epsdice+ includes
\texttt{epsdice.eps} under \LaTeXe, and \texttt{epsdice.pdf} 
under pdf\LaTeX, respectively\footnote{Many thanks to Rolf 
Niepraschk for his help with the latter!}
(unless your \texttt{graphics.cfg} file specifies non-standard 
settings).

Clipping is supported only in pdf\TeX\ versions
$\ge 0.14$. You will also need an up-to-date version of 
\texttt{pdftex.def}: Clipping is not supported in versions 
\texttt{v0.03c} \texttt{[2000/09/04]} or earlier. 
If your pdf\TeX\ is up-to-date but
you still receive error messages about clipping not being
supported, get the latest \texttt{pdftex.def}
here: \\[.5ex] 
\verb+http://www.tug.org/applications/pdftex/pdftex.def+ 
\\[.5ex]
I tested the package successfully with pdf\TeX\ 0.14e 
and \texttt{pdftex.def} v0.03f \texttt{[2000/11/10]}. 
%
\section{Configuring this package}
To finish the installation of the package,
simply move the following files somewhere in your ``local texmf tree'':
\begin{verbatim}
  epsdice.sty,  epsdice.cfg,  dice.eps,  dice.pdf
\end{verbatim}
e.g.\ to a new subdirectory
\verb+/tex/latex/epsdice/+. Refresh the 
\TeX-system's file name database, and that's it, you're all set! 
The remainder of this section applies only if you want to change
the default settings.

The command \verb+\epsdice+  works by including an
external  file, so this file must be found by \LaTeXe. The package comes with 
a configuration file \texttt{epsdice.cfg} containing the file name  in the
variable \verb+\dicefile+. By default, this variable points  to the file
\verb+dice.{eps|pdf}+ (without file name extension). If you don't like my
drawings and would like to ``roll your own'',  a look at section~\ref{pscode}
may give some hints. 
It contains the same PostScript code as \texttt{dice.eps}, 
with some comments about what's going on. Conversion to \textsc{pdf}
format has been accomplished with \texttt{epstopdf} (using 
GhostScript), see pdf\TeX's web page. 

If you intend to keep the external file with the dice drawings in a
different place or if you want to use your own version you have to 
edit the configuration file \texttt{epsdice.cfg} accordingly, 
by adding the path to the file name, or by changing the file name in the
variable \verb+\dicefile+.
If a configuration file does not exist, the external file 
is assumed to be located in the present working directory.
%
\section{Examples}
Die faces in an 11pt environment: The pictures fit into the surrounding
text, as in \epsdice{1} \epsdice[black]{2} \epsdice[black]{3} 
\epsdice[red]{4} \epsdice[black]{5} \epsdice[white]{6}. The code used to set
these die faces was: 
\begin{verbatim}
\epsdice{1} \epsdice[black]{2} \epsdice[black]{3} 
\epsdice[red]{4} \epsdice[black]{5} \epsdice[white]{6}
\end{verbatim}
The only effective option to the command \verb+\epsdice+ is \verb+[black]+.
Anything else results in the default behavior with white background.

\medskip
{\Large 
Here is some \verb+\Large+ text. The die pictures scale accordingly:% 
\footnote{\ldots as they do in footnotes, \epsdice{\value{footnote}}, 
like this.} \epsdice{3} \epsdice[black]{5}. See?} 

\medskip
Finally, note that the package works with
standard counters, too: Here's the result of \verb+\epsdice{\value{section}}+ 
\epsdice{\value{section}}.
%
\section{Drawing dice in PostScript}
\label{pscode}
Something as simple as a ``square with dots
on it'' is rather straightforward to draw in PostScript. The first line
\begin{flushleft}
\verb+%!PS-Adobe-2.0 EPSF-1.2+
\end{flushleft}
is just a standard header. Next comes the bounding box: Each face measures
$32\times 32$~pt, centered in a $43\times43$~pt box. For six faces in a row, 
this gives a bounding box of $258\times43$~pt. We have two rows of dice,
the lower row containing the white dice with black dots, the upper one the
black dice with white dots. So the total bounding box is $258\times86$~pt. 
The background color will be stored in the variable $bw=0$ or 1.
\begin{verbatim}
%%BoundingBox: 0 0 258 86
\end{verbatim}
The \verb+/frame+ macro defines a simple box with rounded corners. It takes
one argument, the face index $n$, and calculates a corresponding $x$-offset:
$x_{\mathrm{off}}=43 (n-1)$. The point $(x_{\mathrm{off}},y_{\mathrm{off}})$ 
then becomes the origin of the coordinate system for this particular face. 
This macro uses the variable $bw$ to calculate the vertical offset 
$y_{\mathrm{off}}=43 bw$.
The frame consists of straight lines separated by 5~pt from the outer margin, 
and of four quarter circles with radius $r$ ($r=5$~pt for black on white and
$r=6$~pt for white on black) centered at $(10,10),\,(32,10),\,(10,32)$, and $(32,32)$.
\begin{verbatim}
/frame {
  /n exch def         % take n off the stack, store it
  /xoffset n 1 sub 43 mul def  % xoffset = 43*(n-1)
  gsave               % save the graphics state
  newpath             % start a new path
  xoffset yoffset translate % move origin to (xoffset,yoffset)
  32 5 bw sub moveto  % go to (32,5) or (32,4) in this system
  32 10 r -90 0 arc   % SE quarter circle around (32,10)
  37 bw add 32 lineto % right line
  32 32 r 0 90 arc    % NE quarter circle around (32,32)
  10 37 bw add lineto % top line
  10 32 r 90 180 arc  % NW quarter circle around (10,32)
  5 bw add 10 lineto  % left line
  10 10 r 180 270 arc % SW quarter circle around (10,10)
  closepath           % bottom line (closes the path)
  bw 0 eq { stroke }  % either paint (lower row, bw=0) 
  { fill } ifelse     % or fill (upper row, bw=1) the path 
  grestore            % restore graphics state 
} def
\end{verbatim}
The dot positions are labelled within a face by $(x,y)$-coordinates 
running from $(1,1)$
for bottom left to $(3,3)$ for top right. The dot itself is
a filled circle with radius $3.5$~pt. Change the dots' positions
within the frame, or their radius, as you like. The \verb+/dot+ macro
takes three arguments off the stack: (i) the face index, to determine
the $x$-offset, (ii) the $x$-coordinate (1, 2, or 3) on the face, and
(iii) the $y$-coordinate (1, 2, or 3) on the face.
\begin{verbatim}
/dot {
  /y exch def         % take y-coordinate off the stack
  /x exch def         % take x-coordinate off the stack
  /n exch def         % take face index n off the stack
  /xoffset n 1 sub 43 mul def  % xoffset  = 43*(n-1)
  gsave               % save the graphics state
  newpath             % start a new path
  xoffset yoffset translate % move origin to (xoffset,yoffset)
  x 8 mul 5 add       % the dot's x-position: 8*x+5
  y 8 mul 5 add       % the dot's y-position: 8*y+5
  3.5 0 360 arc       % a circle with radius 3.5 pt
  closepath           % close the circle
  bw setgray          % set the appropriate color
  fill                % fill the circle
  grestore            % restore graphics state 
} def
\end{verbatim}
Now choose a linewidth (2~pt)
\begin{verbatim}
2 setlinewidth
\end{verbatim}
and loop over the background color (and hence the rows) from 0 to 1. 
The color counter is stored in $bw$ and used
to determine $y_{\mathrm{off}}$ as well as the radius of the circles,
$r=5+bw$~pt.
\begin{verbatim}
0 1 1 {               % set up loop from 0 to 1
  /bw exch def        % store loop index in bw
  /yoffset bw 43 mul def  % yoffset  = 43*bw
  /r 5 bw add def     % radius r = 5+bw
  0 setgray           % set color to black for all frames
\end{verbatim}
All we have to do now is draw the six faces 
\begin{verbatim}
  1 1 6 { frame } for % call /frame macro for n=1..6
\end{verbatim}
and fill in the appropriate dots.
The bottom left and top right dots appear on faces 2, 3, 4, 5, and 6.
Thus there is an outer loop from 2 to 6 in steps of 1. For each of these
face indices, we call the dot macro with $(x,y)$-argument equal to
$(1,1)$ and $(3,3)$. This can be achieved with an inner loop running
from 1 to 3 in steps of 2. Because the $x$- and $y$-coordinates coincide
for these particular points, we obtain them by duplicating the inner
loop index. The \verb+/dot+ macro gobbles not only the $x$- and
$y$-coordinates but the face index as well. In order to draw \emph{two}
dots on the same face, we thus have to duplicate the outer loop index, too.
\begin{verbatim}
  2 1 6 {      % start loop 2 to 6 in steps of 1
    dup        % duplicate index (two dots on each face)
    1 2 3 {    % start loop 1 to 3 in steps of 2
      dup      % duplicate loop index -> 1 1 and 3 3
      dot      % call /dot macro, using three arguments
    } for      % inner loop (dot positions)
  } for        % outer loop (face index)
\end{verbatim}
The center dot appears on faces 1, 3, and 5. We get it in a simple loop
from 1 to 5 in steps of 2, calling the \verb+/dot+ macro for each index
together with the coordinate set $(2,2)$ corresponding to the center.
\begin{verbatim}
  1 2 5 { 2 2 dot } for  % (2,2) dot on 1, 3, 5
\end{verbatim}
The top left and the bottom right dots appear on faces 4, 5, and 6. Again, 
in order to draw \emph{two} dots on each face, we have to duplicate the
loop index, i.e., the face index:
\begin{verbatim}
  4 1 6 {      % start loop 4 to 6 in steps of 1
    dup        % duplicate index (two dots on each face)
    1 3 dot    % call /dot macro for (1,3) dot on this face
    3 1 dot    % call /dot macro for (3,1) dot on this face 
  } for        % loop over face index 
\end{verbatim}
Finally, on face 6 we have two dots in positions $(1,2)$ and $(3,2)$. We can
use a loop, but then we have to swap the loop index, i.e., the dot's 
$x$-coordinate, with the (constant) face index 6 inside the loop.
\begin{verbatim}
  1 2 3 {      % start loop 1 to 3 in steps of 2
    6 exch     % swap loop index and constant face index 
    2          % push constant y-coordinate on stack
    dot        % call /dot macro for (x,2) dot on face 6
  } for        % loop over x-coordinates 1 and 3
\end{verbatim}
And this closes the loop over background colors:
\begin{verbatim}
} for          % loop over bw 0 and 1
\end{verbatim}
That's it!
\begin{verbatim}
%%EOF
\end{verbatim}
\section{Errors}
Of course it doesn't make sense to ask for die faces with arguments
other than 1, 2, 3, 4, 5, or 6. The package generates error
messages and simply prints the offending argument in the \TeX\ output.
%
%   This generates `benign' errors: \epsdice{99} and \epsdice{-3}.
%   The following is more serious, generating two different errors:
%   \epsdice{epsfoo}. Nevertheless, output continues with a fall-back
%   solution.
\end{document}
%
%</sampledoc>
%
%<*package>
%
%  I don't think the package code needs much of an explanation;
%  it's really very simple\ldots
%
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{epsdice}[2007/02/15 by Thomas Heim (v. 2.1)]
\RequirePackage{graphicx}
\RequirePackage{ifthen}
\InputIfFileExists{epsdice.cfg}{}{\def\dicefile{dice}}
%
\newcounter{eps@face}
\newcommand*\epsdice[2][white]{%
\setcounter{eps@face}{\number #2}%
\ifthenelse{\value{eps@face}>6}{\theeps@face\setcounter{eps@face}{0}}{}%
\ifthenelse{\value{eps@face}<0}{\theeps@face\setcounter{eps@face}{0}}{}%
\ifthenelse {\equal{#1}{black}} {\addtocounter{eps@face}{6}} {}%
\eps@dice{\value{eps@face}}}
\newcommand*\eps@dice[1]{%
\setcounter{eps@face}{\number #1}%
\ifcase\value{eps@face}%
  \PackageError{EPSDICE}{%
Argument is not a number, or its value\MessageBreak
lies outside the allowed range for dice}{%
Make sure the argument is either 1, 2, 3, 4, 5, or 6.\MessageBreak
-- Just go on and I'll write whatever you typed;\MessageBreak
   the output may not make much sense, though}%
\or
  \includegraphics[height=1.75ex,viewport= 3 4 38 39,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 46 4 81 39,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 89 4 124 39,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 132 4 167 39,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 175 4 210 39,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 218 4 253 39,%
  clip=true]{\dicefile}%
\or
  \includegraphics[height=1.75ex,viewport= 3 47 38 82,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 46 47 81 82,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 89 47 124 82,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 132 47 167 82,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 175 47 210 82,%
  clip=true]{\dicefile}%
\or 
  \includegraphics[height=1.75ex,viewport= 218 47 253 82,%
  clip=true]{\dicefile}%
\fi}
%
%</package>
%
%<config>\def\dicefile{dice}
%
%<*epsfile>
%
%  Here's the PostScript code for the drawings:
%
%<<PSFILE
%!PS-Adobe-2.0 EPSF-1.2
%%BoundingBox: 0 0 258 86
/frame { /n exch def /xoffset n 1 sub 43 mul def gsave newpath
xoffset yoffset translate 32 5 bw sub moveto 32 10 r -90 0 arc 
37 bw add 32 lineto 32 32 r 0 90 arc 10 37 bw add lineto 
10 32 r 90 180 arc 5 bw sub 10 lineto 10 10 r 180 270 arc closepath 
bw 0 eq { stroke } { fill } ifelse grestore } def
/dot { /y exch def /x exch def /n exch def /xoffset n 1 sub 43
mul def gsave newpath xoffset yoffset translate x 8 mul 5 add y 8 mul
5 add 3.5 0 360 arc closepath bw setgray fill grestore } def
2 setlinewidth 0 1 1 { /bw exch def /yoffset bw 43 mul def /r 5 bw 
add def 0 setgray 1 1 6 { frame } for 2 1 6 { dup 1 2 3 { dup dot } 
for } for 1 2 5 { 2 2 dot } for 4 1 6 { dup 1 3 dot 3 1 dot } for 
1 2 3 { 6 exch 2 dot } for } for
%%EOF
%PSFILE
%
%</epsfile>
\endinput