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}
|