![如何将“newcommand”值声明为某个数字(带单位)和另一个命令的总和,以便它可以用于坐标算术?](https://linux22.com/image/361503/%E5%A6%82%E4%BD%95%E5%B0%86%E2%80%9Cnewcommand%E2%80%9D%E5%80%BC%E5%A3%B0%E6%98%8E%E4%B8%BA%E6%9F%90%E4%B8%AA%E6%95%B0%E5%AD%97%EF%BC%88%E5%B8%A6%E5%8D%95%E4%BD%8D%EF%BC%89%E5%92%8C%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%91%BD%E4%BB%A4%E7%9A%84%E6%80%BB%E5%92%8C%EF%BC%8C%E4%BB%A5%E4%BE%BF%E5%AE%83%E5%8F%AF%E4%BB%A5%E7%94%A8%E4%BA%8E%E5%9D%90%E6%A0%87%E7%AE%97%E6%9C%AF%EF%BC%9F.png)
我怀疑我输入的算术newcommand
没有按照我预期的方式处理。
\FMARGIN
声明为后的值是什么
\newcommand{\FWIDTH}{2mm}
\newcommand{\FMARGIN}{10mm+\FWIDTH}
是12mm还是其他的?
因为当我在坐标算法中使用它时,我得到了意想不到的结果。并非所有边距与边界框的距离都相同。
完整代码:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary
{%
calc,
shapes.geometric
}
\newcommand{\FWIDTH}{2mm}
\newcommand{\FMARGIN}{10mm+\FWIDTH}
\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}
输出:
\FWIDTH
当设置为更高的值(例如 5 毫米)时,差异变得更加明显。
答案1
问题中最初使用的内容是
\newcommand{\FMARGIN}{10mm+\FWIDTH}
存储为\FMARGIN
命令中的标记。直到使用它时才会进行替换和评估。但是,当 TeX 正在寻找长度时,类似这样的操作10mm+2mm
将不起作用。相反,\dimexpr10mm+2mm\relax
需要该命令来执行长度的添加并将结果作为单个长度提供,该长度可供寻求长度输入的宏使用。
\dimexpr
代表“维度表达式”(维度为长度)并\relax
终止维度表达式的计算。
如果需要文本形式的结果,即相当于长度的标记12mm
,则使用\the\dimexpr10mm+2mm\relax
,而如果没有\the
,则结果将存储为内部长度而不是一系列字母数字标记。
了解正在发生的事情的一个好方法是比较以下代码:
\edef\tmp{10mm+\FWIDTH}
\detokenize\expandafter{\tmp}
到此代码
\edef\tmp{\the\dimexpr10mm+\FWIDTH\relax}
\detokenize\expandafter{\tmp}
前者计算结果为 ,10mm+2mm
而后者计算结果为34.14328pt
。以下是 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}
答案2
当定义宏(例如\newcommand
)时,TeX 不进行任何算术运算:你可以将其视为字符串(或更准确地说,标记)的简单替换。因此,当你写:
\newcommand{\FWIDTH}{2mm}
\newcommand{\FMARGIN}{10mm+\FWIDTH}
在 中不发生任何算术运算10mm+\FWIDTH
。结果是\FMARGIN
被定义为一个宏,它扩展为10mm+\FWIDTH
(这没有特殊的算术含义;它只是五个标记1
、0
、m
、m
、的序列+
,后跟标记\FWIDTH
)。当你在某处将它用作 时\FMARGIN
,在典型情况下,它将(最终)扩展为字符串10mm+2mm
,这又只是一个 8 个字符的序列:就像你10mm+2mm
在那个地方输入一样。
因此当你使用:
($(current bounding box.north west)+(-\FMARGIN,\FMARGIN)$)
rectangle
($(current bounding box.south east)+(\FMARGIN,-\FMARGIN)$);
就像你输入了
($(current bounding box.north west)+(-10mm+2mm,10mm+2mm)$)
rectangle
($(current bounding box.south east)+(10mm+2mm,-10mm+2mm)$);
虽然这恰好可以通过编译,但这显然不是你想要的。宏之所以以这种方式工作,是因为 TeX 最初是为排版而设计的,而宏应该是节省打字的捷径,而不是进行计算。
您可以通过在文件中添加 )来自己调试这个问题(查看已\FMARGIN
定义的内容) :\show\FMARGIN
\newcommand{\FWIDTH}{2mm}
\newcommand{\FMARGIN}{10mm+\FWIDTH}
\show\FMARGIN
当 TeX 到达该点时,它将向您显示扩展并等待您按下 Return 键后再继续:
> \FMARGIN=\long macro:
->10mm+\FWIDTH .
l.10 \show\FMARGIN
?
阅读本文需要一些训练,但上面的内容告诉您,\FMARGIN
定义为10mm+\FWIDTH
(而不是12mm
)。
那么如何解决这个问题呢?在这种情况下,因为mm
是 TeX 恰好理解的一个维度(但只有当它是看着对于长度,而不是简单地定义宏等),您可以使用一些技巧:
你可以定义
\FMARGIN
为长度,使用\setlength
,如@cfr 的回答你可以定义
\FMARGIN
扩展为12mm
当 TeX 寻找长度时会导致的结果,例如@Steven 的回答您可以实现您的初衷,即以某种方式定义
\FMARGIN
扩展为12mm
,尽管这有点棘手(再次参见史蒂文的回答)。
答案3
这不是一个答案,但对于评论来说太长了。也就是说,它没有回答提出的问题。它确实解决了如何避免该问题的潜在后续问题。
宏扩展为替换文本。对于处理尺寸,最简单的方法是使用尺寸/长度。对于处理整数,最简单的方法是使用计数/计数器。
\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}
答案4
我发现\pgfmathsetlengthmacro
这是最简单的解决方案。
我所做的就是\newcommand
替换
\newcommand{\FWIDTH}{2mm} \newcommand{\FMARGIN}{10mm+\FWIDTH}
与\pgfmathsetlengthmacro
得到
\pgfmathsetlengthmacro{\FWIDTH}{2mm} \pgfmathsetlengthmacro{\FMARGIN}{10mm+\FWIDTH}
现在坐标算术计算\FMARGIN
正确。