summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/smartunits/smartunits.tex
blob: fe57502fbd45d74b97a06f12335fd51070b27776 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
\documentclass[svgnames]{report}
\usepackage{smartunits}
\usepackage{manfnt}
\usepackage{enumitem}
\setlist[description]{font=\sffamily\bfseries\color{DodgerBlue},labelwidth=\textwidth}
\usepackage{booktabs}
\usepackage[a4paper,margin=18mm]{geometry}
\synctex=1

\usepackage{fixltx2e} % LaTeX patches, \textsubscript
\usepackage{cmap} % fix search and cut-and-paste in Acrobat
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\setcounter{secnumdepth}{0}

\usepackage{listings}\lstset{language=[LaTeX]TeX,framerule=2pt}
\lstset{language=[LaTeX]TeX,
        texcsstyle=*\bfseries\color{Blue},
        backgroundcolor=\color{Ivory},
        numbers=none,
        breaklines=true,
        keywordstyle=\color{Blue},
        commentstyle=\color{Brown},
        tabsize=2,
        morekeywords={SmartUnit,SmartUnitSettings,sisetup},
        resetmargins=true,
}
% hyperref links to ctan
\newcommand\ctan[1]{\href{https://www.ctan.org/pkg/#1}{\texttt{#1}}}

\usepackage{xparse}
\NewDocumentCommand{\Verb}{v}{{\color{blue}#1}}

\newcommand\Section[1]{\subsection{\textcolor{blue}{#1}}}

\makeatletter
\author{Andrew Mathas}
\usepackage{tikz}
\usetikzlibrary{shadows.blur}
\tikzset{shadowed/.style={blur shadow={shadow blur steps=5},
                          bottom color=LightSkyBlue!30,
                          draw=MidnightBlue!70,shade,
                          font=\normalfont\Huge\bfseries\scshape,
                          rounded corners=8pt,
                          top color=SkyBlue,
      },
      boxes/.style={draw=MidnightBlue,
                    fill=Cornsilk,
                    font=\sffamily\small,
                    inner sep=5pt,
                    rectangle,
                    rounded corners=8pt,
                    text=RoyalBlue,
     }
}
\def\SmartTitle{
  \begin{tikzpicture}[remember picture,overlay]
      \node[yshift=-3cm] at (current page.north west)
        {\begin{tikzpicture}[remember picture, overlay]
          \draw[shadowed](30mm,0) rectangle node[white]{Smart Units} (\paperwidth-30mm,16mm);
          \node[anchor=west,boxes] at (4cm,0cm) {\@author};
          \node[anchor=east,boxes] at (\paperwidth-4cm,0) {\smart@version};
         \end{tikzpicture}
        };
   \end{tikzpicture}
   \vspace*{20mm}
}


\def\@oddfoot{\textsc{Smart Units} -- \smart@version\hfill\thepage}

\usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
\hypersetup{pdfcreator={ Generated by pdfLaTeX },
            pdfinfo={Author  ={ Andrew Mathas },
                     Keywords={ units, metric, Imperial },
                     License ={ LaTeX Project Public License v1.3c or later },
                     Subject ={ Convert between metric and Imperial units },
                     Title   ={ smartunits - \smart@version }
            },
}
\makeatother

\begin{document}

    \SmartTitle

    %\Section{Smart units}
    This package implements a \Verb|\SmartUnit| macro for
    converting between the following metric and Imperial units:

    \begin{center}
      \begin{tabular}{@{\color{Grey!50}}ll@{\quad$\longleftrightarrow$\quad}l}\toprule
                    & Metric      &    Imperial      \\\midrule
        \color{LightSkyBlue}distance    & kilometers  &  miles           \\
        \color{LightSkyBlue}length      & centimeters &  feet and inches \\
        \color{LightSkyBlue}temperature & Celsius     &  Fahrenheit      \\
        \color{LightSkyBlue}time        & 24-hour time&  12-hour time    \\
        \color{LightSkyBlue}volume      & litres      &  USA/UK gallons  \\
        \color{LightSkyBlue}weight      & kilograms   &  pounds          \\
        \bottomrule
      \end{tabular}
    \end{center}
    Of course, the underlying unit for length and distance is the same
    but it makes sense to convert between units of similar ``scale''.
    The \Verb|\SmartUnit| macro is designed to print only one unit at a
    time, where the quantity is given in terms of either metric or
    Imperial units (there is no error checking, however).  Depending on
    the (global) settings the unit will be printed either as a metric
    unit, or as an Imperial unit, or both.  If the required unit is not
    given as an  argument to \Verb|\SmartUnit| then it is computed.

    The units are printed using \ctan{siunitx}, so the formatting of the
    units can be controlled using \Verb|\sisetup| together with
    formatting parameters from \ctan{siunitx}.  Some aspects of the
    formatting can be controlled ``locally'' using \Verb|\SmartUnit| and
    ``globally'' using \Verb|\SmartUnitSettings|.

    The \Verb|\SmartUnit| macro can print units in the following
    four different formats:

    \begin{lstlisting}
      \SmartUnit{metric}          % --> metric
      \SmartUnit{imperial}        % --> Imperial
      \SmartUnit{metric imperial} % --> metric (Imperial)
      \SmartUnit{imperial metric} % --> Imperial (metric)
    \end{lstlisting}

    For the impatient, here are some examples:

    \bgroup
    \sisetup{round-mode=places,round-precision=2}
    \small
    \begin{lstlisting}[escapeinside=<>]
      \documentclass{article}
      \usepackage{smartunits}
      \begin{document}
          \SmartUnitSettings{places=2}      % Some global settings < \SmartUnitSettings{places=2} >
          \SmartUnit{metric imperial}       % Output format: metric (Imperial) < \SmartUnit{metric imperial} >
          \SmartUnit{cm=10}                 % < \SmartUnit{cm=10} >
          \SmartUnit{cm=66}                 % < \SmartUnit{cm=66} >
          \SmartUnit{feet=4,inches=3}       % < \SmartUnit{feet=4,inches=3} >
          \SmartUnit{celsius=20}            % < \SmartUnit{celsius=20} >
          \SmartUnit{metric}                % Output format: metric            < \SmartUnit{metric} >
          \SmartUnit{miles=5, places=1}     % < \SmartUnit{miles=5,places=1} >
          \SmartUnit{imperial}              % Output format: Imperial          < \SmartUnit{imperial} >
          \SmartUnit{hours=12, minutes=1}   % < \SmartUnit{hours=12, minutes=1} >
          \SmartUnit{km=5,places=3}         % < \SmartUnit{km=5,places=3} >
          \SmartUnit{imperial metric}       % Output format: Imperial (metric) < \SmartUnit{imperial metric} >
          \SmartUnit{miles=5, km=7}         % < \SmartUnit{miles=5,km=7} >
          \SmartUnit{l=1.0, places=1}       % < \SmartUnit{l=1.0, places=1} >
          \SmartUnit{L=1.0, places=1}       % < \SmartUnit{L=1.0, places=1} >
          \SmartUnit{gal=25.0,uk,places=2}  % < \SmartUnit{gal=25.0, places=2,uk} >
          \SmartUnit{gal=25.0,usa,places=2} % < \SmartUnit{gal=25.0, places=2,usa} >
      \end{document}
    \end{lstlisting}
    \egroup

    The calculations done by \Verb|\SmartUnit| are reasonably accurate
    but LaTeX is not a calculator so rounding and other errors can and
    do happen (indeed, see the displayed example below). In addition, even assuming
    that the calculations done by \Verb|\SmartUnit| are accurate this
    may not be what you want. For example, if the metric unit is given
    as \SI{100}{km} then many people will want the Imperial unit to be
    written as \SI{60}{\text{mi}}, rather than the more accurate
    \SI{62.137119}{\text{mi}}. In fact, \Verb|\SmartUnit| can cater for
    these considerations because all units are printed using the
    \ctan{siunitx} package, which is really clever. The precision of the
    printed units can be controlled using \Verb|\sisetup|, from the
    \ctan{siunitx} package or by using the short-hands, \textsf{figures}
    and \textsf{places}, provided by \Verb|\SmartUnit|:
    \begin{lstlisting}[texcl]
      \SmartUnit{km=100.0, figures=1} % \SmartUnit{km=100.0,figures=1}
      \SmartUnit{km=100.0, places=5}  % \SmartUnit{km=100.0,places=5}
    \end{lstlisting}
    \noindent (Comparing with the paragraph above, the last calculation
    is only accurate to three decimal places!) The values of the
    computed units can be overridden, during proof-reading for example,
    by specifying both the metric and Imperial units:
    \begin{lstlisting}[texcl]
      \SmartUnit{km=100,miles=70} % \SmartUnit{km=100,miles=70}
    \end{lstlisting}
    \noindent \raisebox{3.9mm}{\dbend}\quad Of course, if you specify
    units incorrectly like this then incorrect values will be printed.

    Behind the scenes all units are printed using \ctan{siunitx}. Therefore,
    the precision and formatting of the units can be changed using the
    options to \Verb|\sisetup| described in the \ctan{siunitx}\ manual. In
    particular, when the rounding capabilities of~\ctan{siunitx}\ are enabled
    any units calculated by \Verb|\SmartUnit| will be rounded.
    In this case there is a shorthand for overriding the global
    \ctan{siunitx}\ settings for the rounding precision on an individual
    ``smart unit'':

    \begin{lstlisting}[escapeinside=<>]
      % Locally=\sisetup{round-precision=3, round-mode=places}
      \SmartUnit{cm=2, places=3} % < \SmartUnit{cm=2, places=3} >
    \end{lstlisting}

    Section~5.5 of the \ctan{siunitx}\ manual should be consulted for all of the
    options for controlling ``post-processing'' of numbers. In particular,
    units that are given as integers will always be printed as integers.
    For example, the metric version of \Verb|\SmartUnit{cm=2, places=3}|
    is printed as \SmartUnit{cm=2, places=3, metric} whereas the Imperial version is
    \num{0.787}$'$. If, instead, we use
    \Verb|\SmartUnit{cm=2.0, places=3}| then the metric unit is
    printed as \SmartUnit{cm=2.0, places=3, metric}.


    \Section{Unit conversions}
    For all of these examples we use the following global settings:
    \begin{lstlisting}[texcl]
      \SmartUnitSettings{places=2, metric imperial} % Global settings
    \end{lstlisting}
    \SmartUnitSettings{places=2, metric imperial}
    \noindent Of course, as in some of the example below, this can always be overridden locally.

    \begin{description}
      \item[Distance -- km, miles, mi]
         Conversions between kilometers and miles. Miles can be specified
         using either \textbf{miles} or \textbf{mi}.
        \begin{lstlisting}[texcl]
          \SmartUnit{km=100,miles=60}               % \SmartUnit{km=100,miles=60}
          \SmartUnit{km=100.0,figures=1}            % \SmartUnit{km=100,figures=1}
          \SmartUnit{miles=62.15,places=1}          % \SmartUnit{miles=62.15,places=1}
        \end{lstlisting}

      \item[Length -- cm, inches, feet]
        Feet are always printed as integers. Significant figures/places
        are applied only to the printing of inches.
        \begin{lstlisting}[texcl]
          \SmartUnit{feet=7, inches=1}              % \SmartUnit{feet=7, inches=1}
          \SmartUnit{cm=189, feet=7, inches=1}      % \SmartUnit{cm=189, feet=7, inches=1}
          \SmartUnit{cm=191, places=1}              % \SmartUnit{cm=191, places=1}
        \end{lstlisting}

      \item[Temperature -- celsius, fahrenheit]
        Convesions between Celsius and Fehrenheit can be speficied using
        \textsf{celsius}, \textsf{C}, \textsf{fahrenheit} or \textsf{F}.

        \begin{lstlisting}[texcl]
          \SmartUnit{celsius=32,places=3}           % \SmartUnit{celsius=32,places=3}
          \SmartUnit{celsius=0}                     % \SmartUnit{celsius=0}
          \SmartUnit{C=37}                          % \SmartUnit{C=37}
          \SmartUnit{fahrenheit=0}                  % \SmartUnit{fahrenheit=0,places=2}
          \SmartUnit{F=22,figures=4}                % \SmartUnit{F=212,figures=4}
        \end{lstlisting}

      \item[Time -- hours, minutes, seconds, am, pm]
        \begin{lstlisting}[texcl]
          \SmartUnit{hours=0, minutes=59}           % \SmartUnit{hours=0, minutes=59}
          \SmartUnit{hours=12, minutes=12}          % \SmartUnit{hours=12, minutes=12}
          \SmartUnit{hours=13, minutes=9}           % \SmartUnit{hours=13, minutes=9}
          \SmartUnit{hours=8, minutes=31, pm}       % \SmartUnit{hours=8, minutes=31, pm}
          \SmartUnit{hours=9, minutes=3, am}        % \SmartUnit{hours=9, minutes=3, am}
          \SmartUnit{hours=0, minutes=0,seconds=1}  % \SmartUnit{hours=0, minutes=0,seconds=1}
          \SmartUnit{hours=12, minutes=0,seconds=1} % \SmartUnit{hours=12, minutes=0,seconds=1}
        \end{lstlisting}

      \item[Volume -- L, l, gal, gallons]
        Converting between litres and gallons.  Liters can be specified
        using \textbf{L} or \textbf{l} and gallons can be given with
        \textbf{gallons} or \textbf{gal}. Both UK gallons and USA
        gallons are supported, with USA gallons being the default.
        \begin{lstlisting}[texcl]
          \SmartUnit{l=10.0, places=1}              % \SmartUnit{l=10.0, places=1}
          \SmartUnit{L=10.0, places=1,uk}           % \SmartUnit{L=10.0, places=1,uk}
          \SmartUnit{gal=10.0, places=2}            % \SmartUnit{gal=10.0, places=2}
        \end{lstlisting}

      \item[Weight -- kg, pounds, lbs]
        \begin{lstlisting}[texcl]
          \SmartUnit{kg=10.0, places=1}             % \SmartUnit{kg=10.0, places=1}
          \SmartUnit{pound=10.0, places=1}          % \SmartUnit{pound=10.0, places=1}
          \SmartUnit{pound=10.0,figures=1}          % \SmartUnit{pound=10.0,figures=1}
        \end{lstlisting}
    \end{description}

    \Section{Formatting options}

    The following options can either be used inside \Verb|\SmartUnit| to
    control the formatting \textit{locally} for just the unit being
    printed. They can also be used as arguments to
    \Verb|\SmartUnitSettings| to change the formatting of all subsequent
    smart units (unless these settings are overridden locally). More
    control over the formatting of the units is given by the
    \Verb|\sisetup| macro from the \ctan{siunitx} package.

    \begin{description}
      \item[figures] This is equivalent to \Verb|\sisetup{round-mode=figures, precision=#1}|.
      Units are printed with \#1 significant figures.
           \begin{lstlisting}[texcl]
               \SmartUnit{miles=60, metric, figures=0} % \SmartUnit{miles=60, metric, figures=0}
               \SmartUnit{miles=60, metric, figures=1} % \SmartUnit{miles=60, metric, figures=1}
               \SmartUnit{miles=60, metric, figures=2} % \SmartUnit{miles=60, metric, figures=2}
               \SmartUnit{miles=60, metric, figures=3} % \SmartUnit{miles=60, metric, figures=3}
               \SmartUnit{miles=60, metric, figures=4} % \SmartUnit{miles=60, metric, figures=4}
           \end{lstlisting}

      \item[places]
      This is equivalent to \Verb|\sisetup{round-mode=places, precision=#1}|.
      Units are printed with \#1 decimal places.
           \begin{lstlisting}[texcl]
               \SmartUnit{miles=60, metric, places=0} % \SmartUnit{miles=60, metric, places=0}
               \SmartUnit{miles=60, metric, places=1} % \SmartUnit{miles=60, metric, places=1}
               \SmartUnit{miles=60, metric, places=2} % \SmartUnit{miles=60, metric, places=2}
               \SmartUnit{miles=60, metric, places=3} % \SmartUnit{miles=60, metric, places=3}
               \SmartUnit{miles=60, metric, places=4} % \SmartUnit{miles=60, metric, places=4}
           \end{lstlisting}


      \item[imperial]
          Print only Imperial units.
          \begin{lstlisting}[texcl]
            \SmartUnit{km=1.0, imperial}    % \SmartUnit{km=1.0, imperial, figures=2}
            \SmartUnit{miles=1.0, imperial} % \SmartUnit{miles=1.0, imperial, figures=2}
          \end{lstlisting}
      \item[imperial metric]
          Print Imperial units with metric units enclosed in brackets.
          \begin{lstlisting}[texcl]
            \SmartUnit{km=1.0, imperial metric}    % \SmartUnit{km=1.0, imperial metric, figures=2}
            \SmartUnit{miles=1.0, imperial metric} % \SmartUnit{miles=1.0, imperial metric, figures=2}
          \end{lstlisting}
      \item[metric (default)]
          Print only metric units.
          \begin{lstlisting}[texcl]
            \SmartUnit{km=1.0, metric}    % \SmartUnit{km=1.0, metric, figures=2}
            \SmartUnit{miles=1.0, metric} % \SmartUnit{miles=1.0, metric, figures=2}
          \end{lstlisting}
      \item[metric imperial]
          Print metric units with Imperial units enclosed in brackets.
          \begin{lstlisting}[texcl]
            \SmartUnit{km=1.0, metric imperial}    % \SmartUnit{km=1.0, metric imperial, figures=2}
            \SmartUnit{miles=1.0, metric imperial} % \SmartUnit{miles=1.0, metric imperial, figures=2}
          \end{lstlisting}
      \item[uk]
          Selects the UK variants of the Imperial units (currently this
          only affects gallons):
          \begin{lstlisting}[texcl]
            \SmartUnit{l=1.0, imperial metric, figures=2,uk}   % \SmartUnit{l=1.0, imperial metric, figures=2,uk}
            \SmartUnit{gal=1.0, imperial metric, figures=2,uk} % \SmartUnit{gal=1.0, imperial metric, figures=2,uk}
          \end{lstlisting}
      \item[usa (default)]
          Selects the USA variants of the Imperial units (currently this
          only affects gallons):
          \begin{lstlisting}[texcl]
            \SmartUnit{l=1.0, imperial metric, figures=2,usa}   % \SmartUnit{l=1.0, imperial metric, figures=2,usa}
            \SmartUnit{gal=1.0, imperial metric, figures=2,usa} % \SmartUnit{gal=1.0, imperial metric, figures=2,usa}
          \end{lstlisting}
          By default \Verb|\SmartUnit| uses the American Imperial units.
          This is a purely democratic choice dictated by the populations
          of the two countries.
    \end{description}

    \Section{The code}
    Behind the scenes, the \Verb|\SmartUnit| macro uses \ctan{pgfkeys}  and
    \ctan{pgfmath} to convert between the different units.  The interface is
    surprisingly simple and easy to extend. For example, the following
    code takes care of the conversion between kilometers and miles:
    \bgroup\footnotesize
      \begin{lstlisting}
      %%%% convert=distance:  km <-> miles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      km/.style={convert=distance, unit km=#1},%
      mi/.style={convert=distance, unit miles=#1},%
      miles/.style={convert=distance, unit miles=#1},%
      distance/metric/.style={/SmartUnit/conversion={km}{miles}{0}{1.609344}{0}{km}},%
      distance/imperial/.style={/SmartUnit/conversion={miles}{km}{0}{0.62137119}{0}{\text{mi}}},%
      \end{lstlisting}
    \egroup
    \noindent
    Most of the conversions are done in this way --- the exceptions are
    ``length'' and ``time'', which are more complicated. The key
    \Verb|/SmartUnit/conversion| is a macro that takes six arguments and
    then implements the generic conversion formula:
    \[
    \text{New unit}(\Verb|#1|) = \Big(\text{Old unit}(\Verb|#2)|+\text{Pre-offset}(\Verb|#3|)\Big)*\text{Multiplier}(\Verb|#4|) + \text{Post-offset}(\Verb|#5|),
    \]
    where \Verb|#6| is the metric or Imperial symbol for the unit being
    printed.

    \textit{Adding additional conversions is quite straightforward and I am
    happy to incorporate suggestions.}

    There is, of course, some trickery driving how the units are printed.
    Here is the definition of \Verb|\SmartUnit|:
    \begin{lstlisting}
      \newcommand\SmartUnit[1]{%
          \bgroup%=> changes are local to \SmartUnit => no need to reset
              \pgfkeys{/SmartUnit,#1}% Pass the keys to /SmartUnit
              \pgfkeys{/SmartUnit,printunit}% Calculate units and print
          \egroup%
      }
    \end{lstlisting}
    So \Verb|\SmartUnit| calls \ctan{pgfkeys} twice: the first time to
    set the keys and the second time to print them using
    \Verb|/SmartUnit/printunit|. In turn, this uses
    \Verb|/SmartUnit/convert| to identify the unit being printed,
    after which the pgf key
    \Verb|/SmartUnit/output| is called. This has subkeys for the four
    different \textit{output formats}:
    \begin{center}
    \texttt{metric}, \texttt{imperial},
    \texttt{metric imperial} and \texttt{imperial metric}.
    \end{center}
    Finally, \Verb|/SmartUnit/output/<format>| uses
    \Verb|/SmartUnit/convert| to perform the required conversion.
    This multi-step printing process is necessary for converting between
    inputs like time or centimeters, feet and inches, where the
    output units depend on more than one input value. It is also used to
    print the four different output formats discussed above.


    \Section{Acknowledgement}
    The package was written in response to a
    \href{http://tex.stackexchange.com/questions/241169/}{TeX.SX question},
    partly as a proof-of-concept and partly as an exercise to learn how
    to use \ctan{pgfkeys}. Thanks to Mark Adams for asking the question.

    \Section{Author}
    \href{mailto:Andrew.Mathas@gmail.com?smartunits}{Andrew Mathas},
    \copyright\space 2015, 2016.

    \Section{Licence}
    Released under the
    \href{http://www.latex-project.org/lppl.txt}%
         {LaTeX Project Public License}, v1.3c or later.

\end{document}