7

I'm using \zsavepos to record the position of a box on the page and then writing the position to the box. It works fine but the functions I've got give measurements in mm to quite a few decimal places - I only need it to an integer number of millimetres...

\newcommand\dimtomm[1]{%
    \strip@pt\dimexpr 0.352777778\dimexpr#1\relax\relax
}
\newcommand\getPOS[3]{%
    \dimtomm{\zposx{#1}sp},\dimtomm{\zposy{#1}sp},\dimtomm{#2},\dimtomm{#3}
}

\getPOS is called with arguments of the ZPOS reference and arguments 2 and 3 are the width and height of the box. How can the \dimtomm function be adjusted so that it returns the number of mm as an integer and nothing else? I tried the suggestions like this but to no avail...

tornadof3
  • 349
  • 1
  • 8
  • 1
    are you sure you only an integer multiple of millimeters? for typography, that's not precise enough. –  Jan 18 '15 at 18:17
  • The conversion factor in your \dimtomm is wrong, as TeX's pt is 25.4/72.27 mm and not 25.4/72 mm. See my answer. –  Jan 19 '15 at 07:53

2 Answers2

11

The easiest no package way is to use the following macro.

\def\dimtomm #1{\the\numexpr \dimexpr #1\relax*635/118407168\relax }

But before going further I should point out that your conversion factor which is approximately 25.4/72 is wrong as TeX expresses via \the (which is used by the LaTeX macro \strip@pt) dimensions in TeX points, not Postscript points.

With the conversion factor in your question, \dimtomm {100cm} gives 1003.76543 and \dimtomm {10in} produces 254.9564. The theoretically exact conversion factor is 25.4/72.27 which one could approximate by 0.35146, and one would then get after this replacement 999.98828 and resp. 253.99702.

Let's get back however to the macro to convert to a (rounded) integer multiple of millimeters.

\def\dimtomm #1{\the\numexpr \dimexpr #1\relax*635/118407168\relax }

\tt

1cm is \dimtomm {1cm}mm

100cm is \dimtomm {100cm}mm

1in is (approximately) \dimtomm {1in}mm

10in is \dimtomm {10in}mm

1pt is (approximately) \dimtomm {1pt}mm

100pt is (approximately) \dimtomm {100pt}mm

10000pt  is (approximately) \dimtomm {10000pt}mm

% added in post update
\the\maxdimen\ is (approximately) \dimtomm\maxdimen mm

\bye

If you use LaTeX, define the macro with \newcommand rather than \def, that's all. If you use plain TeX make sure you compile with etex or pdftex but not with the tex executable, as the e-TeX extensions must be enabled.

dimtomm

The \maxdimen line produces:

16383.99998pt is (approximately) 5758mm

Additional note: as documented in the etex manual, a multiplication immediately followed by a division in \numexpr has its intermediate value computed in double precision (two words) hence no overflow arises whereas \numexpr \maxdimen*635\relax would generate an arithmetic overflow. Indeed \maxdimen is 2^30-1 sp units and (2^30-1)*635 is naturally larger than the maximal allowed integer 2^31-1.

7

The easiest way is using expl3:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\dimtomm}{m}
 {
  \fp_eval:n { round ( \dim_to_decimal_in_unit:nn { #1 } { 1mm }, 0 ) } ~ mm
 }
\ExplSyntaxOff

\begin{document}

\dimtomm{186467sp}

\end{document}

This prints “1 mm”, because 186467sp is exactly 1 millimeter. With \dimtomm{10in} you'd get ”254 mm”.

Here the length is rounded, you may want trunc instead of round.

egreg
  • 1,121,712