6

I want to draw a trimmed ruler, for example, from 2.3cm to 3.9cm where the distance between two consecutive marks is 1mm.

I have difficulty to efficiently check whether or not the counter is a multiple of 5 or 10. If the counter is a multiple of 5 then the mark is 6pt long else if the counter is a multiple of 10 then the mark is 9pt long plus printing the quotient as a label.

The following is my complete code.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage[nomessages]{fp}
\usepackage{multido}
\newcommand\Ruler[2]{%
\FPeval\start{round(10*#1:0)}%
\FPeval\stop{round(10*#2:0)}%
\FPeval\width{round(stop-start:0)}%
\FPeval\count{round(\width+1:0)}
\psset{xunit=\dimexpr\psxunit/10}
\begin{pspicture}[linecap=2](\width,1)
    \psline(\width,0)
    \multido{\ix=0+1,\i=\start+1}{\count}{%
        \FPeval\quo{trunc(\i/5:0)}
        \FPeval\rem{round(\i-5*quo:0)}
        \psline(\ix,0)(\ix,3pt)
        \FPifzero\rem
            \psline(\ix,0)(\ix,6pt)% if \i can be defined by 5
        \fi
        \FPeval\quo{trunc(\i/10:0)}
        \FPeval\rem{round(\i-10*quo:0)}
        \FPifzero\rem
            \psline(\ix,0)(\ix,9pt)% if \i can be defined by 10
            \uput[90](\ix,6pt){\quo}% if \i can be defined by 10 and put the result of \i divided by 10
        \fi
    }
\end{pspicture}\ignorespaces
}

\begin{document}
\Ruler{2.3}{3.9}
\end{document}

enter image description here

Is there a better way to check divisibility in LaTeX?

4 Answers4

7

For comparison, here is Metapost code to implement such a macro (using ConTeXt; because I don't know how to embed Metapost in LaTeX).

\define[2]\drawMPruler% from to (in mm)
    {\startMPcode
        newnumeric height;   height   := 3mm;
        newnumeric distance; distance := 1mm;

        newpath tic, medium_tic, big_tic;
        tic        := origin -- (0,  height);
        medium_tic := origin -- (0, 2height);
        big_tic    := origin -- (0, 3height);

        linecap := butt;

        % Draw base
        draw (#1*distance, 0) -- (#2*distance,0);

        for i = #1 step 1 until #2 :

          % Draw tics
          draw 
            (if (i mod 10) = 0 : big_tic elseif i mod 5 = 0 : medium_tic else : tic fi)
            shifted (i*distance,0);

          % Draw label
          if i mod 10 = 0 :
            draw textext.top (decimal (i/10)) shifted (i*distance, 3*height + 2pt);
          fi
        endfor;

      \stopMPcode}

\starttext

\drawMPruler{23}{39}

\stoptext

enter image description here

Aditya
  • 62,301
4
\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}
\makeatletter
\newcommand\Ruler[2]{%
  \pstFPMul\Start{#1}{10}%
  \pstFPMul\Stop{#2}{10}%
  \def\Width{\numexpr\Stop-\Start\relax}%
  \psset{xunit=0.1\psxunit}
  \begin{pspicture}[linecap=2](\Width,1)
    \psline(\Width,0)
    \multido{\ix=0+1,\i=\Start+1}{\numexpr\Width+1}{%
       \pst@mod{\i}{5}\result
       \psline(\ix,0)(\ix,3pt)
       \ifnum\result=0  \psline(\ix,0)(\ix,6pt) \fi  % i mod 5=0
        \pst@mod{\i}{10}\result
        \ifnum\result=0
            \psline(\ix,0)(\ix,9pt)%
            \uput[90](\ix,6pt){\the\numexpr\i/10}%  i mod 10 = 0
        \fi}
  \end{pspicture}\ignorespaces}
\makeatother
\begin{document}
\Ruler{2.3}{3.9}
\end{document}

enter image description here

4

Just a little fun with TikZ (and PGFkeys).

The ticks can also be added with the decoration.markings library which would make it possible to create a ruler along a curved line (but obviously not with a fixed length but for certain coordinates (Bézier/to).

Following SDrolet's comment, I've fixed the code so that it actually uses inches for the Inch ruler. I've also changed the ticks so that they can be easier individualized by the user of \Ruler.

Using the array function is not fast (since we could just step through the list with every iteration) but it is the shortest implementation.

Code

\documentclass[tikz,border=12pt]{standalone}
\tikzset{
  ruler from/.initial=0,
  ruler to/.initial=10,
  ruler steps/.initial=10,
  ruler ticks/.initial={9,3,3,3,3,6,3,3,3,3},
  ruler rotate/.initial=0,
  every ruler picture/.style={line cap=rect},
  % presets
  ruler/.is choice,
  ruler/cm/.style={
    x=1cm,
    ruler ticks={9,3,3,3,3,6,3,3,3,3},
    ruler steps=10},
  ruler/in/.style={
    x=1in,
    ruler ticks={9,3,5,3,7,3,5,3},
    ruler steps=8}}
\makeatletter
\newcommand\Ruler[1][]{%
\begin{tikzpicture}[
  every ruler picture/.try,#1,rotate=\pgfkeysvalueof{/tikz/ruler rotate}]
  \pgfmathtruncatemacro\ruler@steps{\pgfkeysvalueof{/tikz/ruler steps}}
  \pgfmathtruncatemacro\ruler@Start
                                {floor((\pgfkeysvalueof{/tikz/ruler from})*\ruler@steps)}
  \pgfmathtruncatemacro\ruler@End{ceil((\pgfkeysvalueof{/tikz/ruler to})*\ruler@steps)}
  \draw (\ruler@Start/\ruler@steps,0) -- (\ruler@End/\ruler@steps,0);
  \foreach \ruler@Cnt[
    evaluate={\ruler@CntMod=int(Mod(\ruler@Cnt,\ruler@steps))},
    evaluate={\ruler@CntModLength=
              array({\pgfkeysvalueof{/tikz/ruler ticks}},\ruler@CntMod)}
  ] in {\ruler@Start,...,\ruler@End}
    \draw (\ruler@Cnt/\ruler@steps,0) -- ++(up:+\ruler@CntModLength pt)
      \ifnum\ruler@CntMod=0
        node[above, text depth=+2pt, inner sep=+0pt,
             rotate=\pgfkeysvalueof{/tikz/ruler rotate}]
          {$\pgfmathprint{int(\ruler@Cnt/\ruler@steps)}$}
      \fi;
\end{tikzpicture}\ignorespaces}

\begin{document} \Ruler[ruler from=2.3, ruler to=3.9] \Ruler[ruler=in, ruler to=8] \Ruler[ruler rotate=30, ruler to=-5] \end{document}

Output (not to scale)

Snipped of a centimetre ruler

Inch ruler

Rotated centimetre ruler

Qrrbrbirlbel
  • 119,821
  • 1
    To make a true inch ruler, one has to scale Qrrbrbirlbel ruler: \Ruler[ruler=in, scale=2.54,ruler to=8] – SDrolet Feb 01 '15 at 17:04
  • @SDrolet You're right, the use and the order of every ruler picture wasn't set up correctly. I've updated the answer to reflect that and changed the way the ticks are drawn so that it supports the inch ruler properly. – Qrrbrbirlbel Jan 03 '22 at 11:04
1

Herbert's solution with modified algorithm to avoid redundancies.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}
\psset{unit=2cm}
\makeatletter
\newcommand\Ruler[2]{%
\pstFPMul\Start{#1}{10}%
\pstFPMul\Stop{#2}{10}%
\def\Width{\numexpr\Stop-\Start\relax}%
\psset{xunit=.1\psxunit}
\begin{pspicture}[linecap=2](\Width,.325)
    \psline(\Width,0)
    \multido{\ix=0+1,\i=\Start+1}{\numexpr\Width+1}{%
        \pst@mod{\i}{10}\rem
        \ifnum\rem=0
            \psline(\ix,0)(\ix,9pt)
            \uput[90](\ix,6pt){\the\numexpr\i/10}
        \else
            \pst@mod{\i}{5}\rem
            \ifnum\rem=0
                \psline(\ix,0)(\ix,6pt)
            \else
                \psline(\ix,0)(\ix,3pt)
            \fi
        \fi
    }
\end{pspicture}\ignorespaces
}
\makeatother

\begin{document}
\Ruler{2.3}{3.9}
\end{document}