14

Is there any way how to convert pt to mm or cm in plain TeX?

doncherry
  • 54,637
Peter
  • 141

4 Answers4

11

To convert from a dimension given in points, save the dimension in a counter first, then do the conversion to what you need. When TeX saves the dimension in a counter it converts to sp units.

\catcode`@=11
\@tempdimb25.4mm 
\@tempcnta=\@tempdimb
\the\@tempcnta 
\divide\@tempcnta by65536\par 
\the\@tempcnta pt
\bye

Conversion from any unit to a point is a bit more involved:

\catcode`@=11
\newdimen\@tempdimb
\newcount\@tempcnta
\def\topoint#1#2{%
\@tempdimb=#1
\@tempcnta=\@tempdimb
\multiply\@tempcnta by10
\divide\@tempcnta by18647 \advance\@tempcnta by1
\multiply\@tempcnta by72 \divide\@tempcnta by2540
\expandafter\def\expandafter#2\expandafter{\the\@tempcnta}}

\topoint{25.4mm}{\test}

\test pt
\bye
yannisl
  • 117,160
10

Expandable solution without eTeX, using Heiko's bigintcalc package. Really, this is a mess, and you should use one of the solutions which make use of the eTeX extensions.

\input bigintcalc.sty
\catcode`@=11

% Step 1: expand the number.
\def\pttocm#1{\romannumeral\expandafter\pttocm@i\romannumeral-`0#1pt;;;;}
\def\pttocm@i#1{\pttocm@clean\ifcat\relax#1\the\fi#1}
\def\pttocm@clean{\expandafter\pttocm@clean@\romannumeral-`0}
\def\pttocm@clean@#1{%
  \ifcase\ifnum`#1<"2B 1\else\ifnum`#1>"39 1\else 2\fi\fi
  \or\expandafter\pttocm@clean@end
  \or\expandafter\pttocm@clean@do\fi #1}
\def\pttocm@clean@do#1#2;#3;{\pttocm@clean#2;#3#1;}

% Step 2: convert the decimal number to an integer/10^n
\def\pttocm@clean@end#1;#2;{\pttocm@clean@end@#2.;#2;.;!}
\def\pttocm@clean@end@#1.#2;#3.#4;#5!{\pttocm@decimal#4.;;#1#4}
\def\pttocm@decimal#1#2;{\ifx.#1\pttocm@decimal@\fi\pttocm@decimal#2;0}

% Step 3: convert from pt to nm (25400000nm=7227pt)
\def\pttocm@decimal@#1;0#2;#3;{\fi
  \expandafter\expandafter\expandafter\pttocm@result
  \bigintcalcDiv{\bigintcalcMul{25400000}{#3}}{7227#2}.;}

% Step 4: check the sign
\def\pttocm@result#1{%
  \ifx-#1\expandafter\pttocm@result@neg
  \else\expandafter\pttocm@result@pos\fi#1}
\def\pttocm@result@neg-{\expandafter\pttocm@rmstop
  \expandafter-\romannumeral\pttocm@result@pos}
\chardef\pttocm@rmstop=0

% Step 5: shift the period 5 steps to the left, by reversing twice.
\def\pttocm@result@pos#1;{%
  \pttocm@reverse 00000#1%
  {?\pttocm@result@shift;}?;%
  {?\pttocm@result@print;}?;}
\def\pttocm@reverse#1#2;{%
  \pttocm@gobble#1%
  \pttocm@reverse#2;#1}
\def\pttocm@gobble#1{}
\def\pttocm@result@shift#1;#2;#3;#4.#5#6#7#8#9%
  {\pttocm@reverse #4#5#6#7#8#9.}
\def\pttocm@result@print#1;#2;#3;#4;{\pttocm@trimzeros{#4}}

% Step 6: remove spurious zeros.
\def\pttocm@trimzeros#1{\pttocm@trim@#1;\pttocm@trim@ 0;\pttocm@trim@@}
\def\pttocm@trim@#10;#2{#2#1;}
\def\pttocm@trim@@#1;#2;{\pttocm@trim@@@#1}
\def\pttocm@trim@@@#1{%
  \ifx0#1\else\expandafter\pttocm@trim@end\expandafter#1\fi
  \pttocm@trim@@@}
\def\pttocm@trim@end#1#2{%
  \ifx.#1\expandafter\pttocm@rmstop\expandafter0%
  \else\expandafter\pttocm@rmstop\fi #1}
\catcode`@=12

\pttocm{-12.1232pt}

\pttocm{283000000000}

\def\foo{23}
\pttocm{12\foo.1\foo2pt}

\newdimen\testdimen
\testdimen=1cm
\pttocm{\testdimen}

\testdimen=-1mm
\pttocm{\testdimen}

\bye
6

Here is a combination of Yiannis' question from Stripping the pt from a dimension and Philippe Goutet's answer from What are the various units (ex, em, in, pt, bp, dd, pc) expressed in mm?:

\catcode`@=11
\begingroup
  \catcode `P=12  % digits and punct. catcode
  \catcode `T=12  % digits and punct. catcode
  \lowercase{%
  \def\x{\def\rem@pt##1.##2PT{##1\ifnum##2>\z@.##2\fi}}}
     \expandafter\endgroup\x%
\def\strip@pt{\expandafter\rem@pt\the}
\def\convertto#1#2{\strip@pt\dimexpr #2*65536/\number\dimexpr 1#1\relax\relax}
\catcode`@=12
\convertto{mm}{10pt}
\bye

which requires e-TeX extensions.

morbusg
  • 25,490
  • 4
  • 81
  • 162
  • 1
    And what about something without e-TeX extensions? – Peter Dec 06 '11 at 17:32
  • @Peter: Without e-TeX you need an extra assignment, which makes the macro non-expanable. – Martin Scharrer Dec 06 '11 at 17:39
  • And what about some solution to convert \the\hsize to mm? Any ideas? \catcode T=12 is not useful here. – Peter Dec 06 '11 at 17:50
  • 3
    You should terminate both \dimexpr with a \relax. Otherwise any dimen expression afterwards, like '* 10' will be taken as part of the inner \dimexpr. The \relax is removed by \dimexpr so you don't have to worry about expandable contexts. – Martin Scharrer Dec 06 '11 at 17:52
  • 2
    @Peter: \convertto{mm}{\the\hsize} will work just fine. The catcode changes are only valid during the definition of the macro, not during the execution. – Martin Scharrer Dec 06 '11 at 17:53
  • @Peter: What is your intention? Why do you need plain tex? – Marco Daniel Dec 06 '11 at 18:10
  • 1
    @MarcoDaniel: Why do you need Windows? Why do you need Linux? Why do you need Peugeot? Why do you need... >:-/ – morbusg Dec 06 '11 at 18:16
  • I agree with @MarcoDaniel. :) Thank you guys. – Peter Dec 06 '11 at 18:31
  • @morbusg: Maybe he want to create a command for a package and doesn't know the e-TeX macros or ... ;-). I think sometimes it easier to know the result. More users will find more ways ;-) – Marco Daniel Dec 06 '11 at 18:31
  • Unfortunately not everybody has "some-TeX" including the e-TeX extensions (yet). – Stephen Dec 06 '11 at 18:39
  • 1
    @Stephen: I only know one distribution which doesn't come with e-TeX, that's the commercial Scientific Workbench. Are there more? The majority of users should have e-TeX. – Martin Scharrer Dec 06 '11 at 20:52
  • @MartinScharrer: Scientific WorkPlace, Scientific Word, Scientific Notebook of mackichan.com - and then there are all those users who depend on some administrator who just refuses to update some system originating from about 1492... ("We do not do updates. The users know and want the system as it is." Not even installing security patches for Windows...) – Stephen Dec 08 '11 at 19:11
6

With help of eTeX's \scantokens, \strip@pt can be also:

\def\strip#1.#2pt{#1\ifnum#2>0.#2\fi}
\def\convertto#1#2{%
  \expandafter\expandafter\expandafter\strip
  \expandafter\expandafter\scantokens
  \expandafter{\the\dimexpr#2*65536/\number\dimexpr1#1\relax\relax\endinput}}

\convertto{pt}{1pc}

\bye
Leo Liu
  • 77,365