# How to make a ruler

In The TeXbook (Ch. 10, after exercise 10.3), DEK shows some nice rulers. But I couldn't figure out how he did them. I'm sure I could look it up from the texbook source, but for some reason I'm drawing a blank on where that might be.

So the question is: how do you typeset rulers (I assume they'd be some form of \leaders)?

-
May I give a TkiZ answer? ;-) –  Caramdir Apr 7 '11 at 4:50
@Caramdir: of course! :-) –  morbusg Apr 7 '11 at 6:22
@morsbusg Please also check ctan.org/tex-archive/macros/generic/misc for package ruler for some mind boggling rulers by Victor Eijkhout –  Yiannis Lazarides Apr 7 '11 at 14:02
Thanks @Yiannis, that's a pretty complete TeX ruler! –  morbusg Apr 8 '11 at 7:22

Nothing as complex as \leaders, but still clever. The relevant source is

$$\abovedisplayskip 15pt plus 4pt minus 4pt \belowdisplayskip 15pt plus 4pt minus 4pt \vbox{ \def\1{\vrule height 0pt depth 2pt} \def\2{\vrule height 0pt depth 4pt} \def\3{\vrule height 0pt depth 6pt} \def\4{\vrule height 0pt depth 8pt} \def\ruler#1#2#3{\leftline{\vcenter{\hrule\hbox{\4#1}}\,\,\rm#2\,{#3}}} \def\\#1{\hbox to .125in{\hfil#1}} \def\8{\\\1\\\2\\\1\\\3\\\1\\\2\\\1\\\4} \ruler{\8\8\8\8}4{in} \vskip 18pt \def\\#1{\hbox to 10pt{\hfil#1}} \def\8{\\\1\\\1\\\1\\\1\\\2\\\1\\\1\\\1\\\1\\\4} \ruler{\8\8\8}{300}{pt} \vskip 18pt \def\\#1{\hbox to 10dd{\hfil#1}} \def\8{\\\1\\\1\\\1\\\1\\\2\\\1\\\1\\\1\\\1\\\4} \ruler{\8\8\8}{300}{dd} \vskip 18pt \def\\#1{\hbox to 5mm{\hfil#1}} \def\8{\\\2\\\4} \ruler{\8\8\8\8\8\8\8\8\8\8}{10}{cm} \vskip 6pt}$$


So the ruler is defined by a series of vertical rules (given names \1, \2, etc.), a horizontal rule and some stretch.

-
Ouch. I think that this has the highest density of backslash that I have seen. Is this from the source of the TeXbook? –  Aditya Apr 7 '11 at 1:58
@Aditya: Knuth really likes to use \\ for helper macros. I find it impossible to read, myself. –  TH. Apr 7 '11 at 3:35
Now that's just wicked. :-D I think it's going to take me a while to fully digest the code. Thanks! –  morbusg Apr 7 '11 at 6:50
@Aditya: Yes, copied directly (in the spirit that DEK made it available - we can learn from it). –  Joseph Wright Apr 7 '11 at 7:00
@TH. I'd agree: DEK shows off some amazing TeX ability, but us mere mortals may need different approaches. –  Joseph Wright Apr 7 '11 at 7:01

Here is a simpler ruler with 10 units. The code relies on \hbox to <dimension> for the overall size of the ruler and uses \hfil to distribute the ruler ticks evenly within. The \morebars macro adds 5 more units but lacks the first vertical tick which must be provided explicitly. Things become obviously more complicated when you want to show units. (The idea used here can be also used to create series of boxes by putting an additional rule on top.)

\documentclass{minimal}

\def\bars#1{\hbox to #1{\vrule width0pt height 1mm depth 2mm%
\vrule\morebars\morebars}}
\def\morebars{\hfil\vrule\hfil\vrule\hfil\vrule\hfil\vrule\hfil\vrule}
\def\ruler#1{\vbox{\bars{#1}\hrule}}

\begin{document}
\ruler{10cm}

\ruler{5cm}
\end{document}


Typesetting this document results in two rulers, 5 and 10 centimeters wide and each with 10 units:

-

I don't have the TeXbook with me, but judging by Christian Lindig's solution, this is how I will implement the command in ConTeXt: using Metapost!

\definenamespace
[ruler]
[name=ruler,
setup=yes,
command=yes,
parent=ruler]

\def\useruler
{\dodoubleempty\douseruler}

\starttexdefinition douseruler [#1][#2]
\begingroup
% To keep options local
\edef\currentruler{#1}
\setupruler[#1][#2]
\useMPgraphic{ruler}
\endgroup
\stoptexdefinition

\startuseMPgraphic{ruler}
begingroup ;
newpath x_axis ;
newpath y_axis ;

newnumeric n, width, height ;
n := \rulerparameter{n} ;
width  := \rulerparameter{width}  ;
height := \rulerparameter{height} ;

x_axis := origin -- (n*width, 0) ;
y_axis := origin -- (0, height) ;

for i = 0 upto n:
draw y_axis shifted (i*width,0) withcolor \MPcolor{\rulerparameter{color}} ;
endfor

draw x_axis withcolor \MPcolor{\rulerparameter{color}} ;

endgroup ;
\stopuseMPgraphic


The code is slightly verbose to make it easier to read. \definenamespace defines two commands, \defineruler and \setupruler. \defineruler[name][options] is used to define a new ruler, where name is the name of the ruler, and options are key-value options. \setupruler sets the default values for all rulers. I have chosen three options, n for the number of markers, width for the distance between markers, and height for the height of each marker. This can be used as

\setupruler[color=blue]

\defineruler[normal][n=5,width=1cm,height=0.2cm]
\defineruler[small] [n=5,width=0.5cm,height=0.2cm]

\starttext
\useruler[normal]

\useruler[normal][color=red]

\useruler[small]
\stoptext


\useruler[name] just draws the rule with a particular name. \useruler[name][options] draws the ruler with those options. Here is the result.

-
This serves as a nice introductory example of the \definenamespace command. –  Charles Stewart Apr 7 '11 at 6:09
I just love to see ConTeXt answers, too few of those around. Thanks! :-) –  morbusg Apr 7 '11 at 6:43