Is there a better way to check divisibility in LaTeX?
Solution 1
\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}
Solution 2
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
Solution 3
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)
Solution 4
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}

kiss my armpit
Updated on January 04, 2022Comments
-
kiss my armpit over 1 year
I want to draw a trimmed ruler, for example, from
2.3cm
to3.9cm
where the distance between two consecutive marks is1mm
.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 is9pt
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}
Is there a better way to check divisibility in LaTeX?
-
egreg over 9 yearsIn LaTeX3 you can do
\int_compare:nTF{\int_mod:nn {#1}{5} = 0}{true}{false}
. I don't think that using fixed point numbers for doing integer arithmetic is the best way to proceed. -
Qrrbrbirlbel over 9 years
-
-
SDrolet over 8 yearsTo make a true inch ruler, one has to scale Qrrbrbirlbel ruler: \Ruler[ruler=in, scale=2.54,ruler to=8]
-
Qrrbrbirlbel over 1 year@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.