How to declare "newcommand" value as a sum of some number (with units) and another command so that it can be used in coordinate arithmetic?
What was originally used in the question, namely
\newcommand{\FMARGIN}{10mm+\FWIDTH}
stores as \FMARGIN
the tokens in the command. Substitution and evaluation is not made until it is used. However, when TeX is looking for a length, something like 10mm+2mm
will not do. Rather, the command \dimexpr10mm+2mm\relax
is needed to perform the addition of lengths and provide the result as a single length which can be used by the macro seeking a length input.
\dimexpr
stands for "dimensional expression" (the dimension being length) and \relax
terminates the evaluation of a dimensional expression.
If one needs the result in textual form, that is, the tokens that are equivalent to a length of 12mm
, then one uses \the\dimexpr10mm+2mm\relax
, whereas without the \the
, the result is stored as an internal length and not a series of alphanumeric tokens.
A good way to see what is happening is comparing this code:
\edef\tmp{10mm+\FWIDTH}
\detokenize\expandafter{\tmp}
to this code
\edef\tmp{\the\dimexpr10mm+\FWIDTH\relax}
\detokenize\expandafter{\tmp}
The former evaluates to 10mm+2mm
while the latter evaluates to 34.14328pt
. Here is the MWE.
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary
{%
calc,
shapes.geometric
}
\newcommand{\FWIDTH}{2mm}
\newcommand{\FMARGIN}{\dimexpr10mm+\FWIDTH\relax}
\begin{document}
\begin{tikzpicture}
\path node
[%
isosceles triangle,
draw=blue,
minimum width=30mm,
line width=1mm
] {};
\path
[%
draw=red,
line width=1mm
]
($(current bounding box.north west)+(-\FMARGIN,\FMARGIN)$)
rectangle
($(current bounding box.south east)+(\FMARGIN,-\FMARGIN)$);
\end{tikzpicture}
\end{document}
When defining macros (such as with \newcommand
), TeX does no arithmetic: you can think of it as simple substitution of strings (or to be more precise, tokens). So when you write:
\newcommand{\FWIDTH}{2mm}
\newcommand{\FMARGIN}{10mm+\FWIDTH}
no arithmetic happens in 10mm+\FWIDTH
. The result is that \FMARGIN
gets defined as a macro which expands to 10mm+\FWIDTH
(and this has no special arithmetical meaning; it's simply a sequence of five tokens 1
, 0
, m
, m
, +
, followed by the token \FWIDTH
). And when you use it somewhere as \FMARGIN
, under typical circumstances it will (ultimately) expand to the string 10mm+2mm
, which again is simply a sequence of 8 characters: it's as if you had typed 10mm+2mm
at that place.
So when you use:
($(current bounding box.north west)+(-\FMARGIN,\FMARGIN)$)
rectangle
($(current bounding box.south east)+(\FMARGIN,-\FMARGIN)$);
it's as if you had typed
($(current bounding box.north west)+(-10mm+2mm,10mm+2mm)$)
rectangle
($(current bounding box.south east)+(10mm+2mm,-10mm+2mm)$);
and although this happens to compile, it is clearly not what you want. Macros work this way because TeX was initially designed for typesetting, and macros were supposed to be a shortcut for saving typing, not for doing computation.
You can debug this for yourself (see what has \FMARGIN
been defined as) by adding \show\FMARGIN
) into the file:
\newcommand{\FWIDTH}{2mm}
\newcommand{\FMARGIN}{10mm+\FWIDTH}
\show\FMARGIN
when TeX reaches that point, it will show you the expansion and wait for you to hit Return before continuing:
> \FMARGIN=\long macro:
->10mm+\FWIDTH .
l.10 \show\FMARGIN
?
Reading this requires some training, but what the above tells you is that \FMARGIN
is defined as 10mm+\FWIDTH
(not as 12mm
).
So how do you fix this? In this case, because mm
is a dimension that TeX happens to understand (but only when it's looking for a length, not when simply defining macros and such), there are some tricks you can use:
you can define
\FMARGIN
as a length, using\setlength
, as in @cfr's answeryou can define
\FMARGIN
to expand to something that will result in12mm
when TeX is looking for a length, as in @Steven's answeryou can implement your original intention of somehow defining
\FMARGIN
to expand to12mm
, though it is slightly tricky (again, see Steven's answer).
This isn't an answer, but too long for a comment. It doesn't answer the question asked, that is. It does address a potential follow-up of how to avoid the problem.
Macros expand to their replacement text. For handling dimensions, it is easiest to use dimensions/lengths. For handling integers, it is easiest to use counts/counters.
\documentclass{standalone}
\usepackage{tikz,calc}
\usetikzlibrary{calc,shapes.geometric}
\newlength\FMARGIN
\newlength\FWIDTH
\tikzset{%
fwidth/.code={\setlength\FWIDTH{#1}},
fmargin/.code={\setlength\FMARGIN{10mm+#1}},
fwidth/.forward to=/tikz/fmargin,
fwidth=2mm,
}
\begin{document}
\begin{tikzpicture}
\path node [isosceles triangle, draw=blue, minimum width=30mm, line width=1mm ] {};
\path [draw=red, line width=1mm ] ($(current bounding box.north west)+(-\FMARGIN,\FMARGIN)$) rectangle ($(current bounding box.south east)+(\FMARGIN,-\FMARGIN)$);
\end{tikzpicture}
\begin{tikzpicture}[fwidth=20mm]
\path node [isosceles triangle, draw=blue, minimum width=30mm, line width=1mm ] {};
\path [draw=red, line width=1mm ] ($(current bounding box.north west)+(-\FMARGIN,\FMARGIN)$) rectangle ($(current bounding box.south east)+(\FMARGIN,-\FMARGIN)$);
\end{tikzpicture}
\end{document}