![带有“foreach 变量”的 calc 库的难以理解的行为](https://linux22.com/image/476849/%E5%B8%A6%E6%9C%89%E2%80%9Cforeach%20%E5%8F%98%E9%87%8F%E2%80%9D%E7%9A%84%20calc%20%E5%BA%93%E7%9A%84%E9%9A%BE%E4%BB%A5%E7%90%86%E8%A7%A3%E7%9A%84%E8%A1%8C%E4%B8%BA.png)
如果我编译以下代码:
\documentclass[12pt]{article}
\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\foreach \i in {(0,0),(0,2.1),(2.1,2.1),(2.1,0)} {
\fill[lightgray] \i rectangle ($(\i+(0.7,0.7)$); }
\draw (0,0) grid[step=0.7] (2.8,2.8);
\end{tikzpicture}
\end{document}
我没有遇到任何问题,这给了我想要的结果。但是“$”之间的表达式括号不正确。
如果我替换$(\i+(0.7,0.7)$
为,$\i+(0.7,0.7)$
则会收到以下错误消息:
Runaway argument?
\i +(0.7,0.7)$); \pgffor@endhook \ifx \pgffor@assign@after@code \pgfutil@empty
\ETC.
! Paragraph ended before \tikz@cc@parse@factor was complete.
<to be read again>
\par
l.15
如果我替换$(\i+(0.7,0.7)$
为$(\i+(0.7,0.7))$
或,$(\i)+(0.7,0.7)$
我会收到以下错误消息:
! Package tikz Error: + or - expected.
See the tikz package documentation for explanation.
Type H <return> for immediate help.
...
l.12 ...htgray] \i rectangle ($(\i)+(0.7,0.7)$); }
这是一个错误还是我做错了什么?(或者这只是一个正确的奇怪语法?)
答案1
在原帖作者给出的例子中,
\fill[lightgray] \i rectangle ($(\i+(0.7,0.7)$);
可以(并且可能应该)
\fill[lightgray] \i rectangle ++(0.7,0.7);
但是,假设这是一个 MWE,并且实际应用不可避免地需要使用该calc
库,那么这是一个扩展问题(正如已经指出的那样)。当calc
使用该库时,以下方法可能适用:
\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\foreach \i in {(0,0),(0,2.1),(2.1,2.1),(2.1,0)} {
\fill let \p1=\i in [lightgray] (\p1) rectangle ($(\p1)+(0.7,0.7)$); }
\draw (0,0) grid[step=0.7] (2.8,2.8);
\end{tikzpicture}
\end{document}
虽然
\fill let \p1=\i in [lightgray] (\p1) rectangle (\x1+.7, \y1+.7);
(我认为) 会稍微更有效率。
但如果你想生活在边缘,就把
\makeatletter
\def\pgffor@scanround(#1)#2,{\def\pgffor@value{#1#2}\pgffor@scanned}
在你的序言中。然后($(\i)+(0.7,0.7)$)
可以在 foreach 循环中使用。
答案2
我认为这是这个的复制品在 TikZ 中使用数学长话短说,这是一种奇怪的交互,它需要一个明确的(因此完全展开的)左括号才能正确获取上下文,并使用右括号来\i
正确完成语法。如果它看到另一个出错了。正确的方法是将所有内容放在它们自己的上下文中,并且非常冗长{}
。
这里有一个更好的方法来了解发生了什么,它很好地演示了 TeX 和 TikZ 如何就解析标记进行通信(尽管非常不直观)。请注意某些地方缺少括号,包括列表。
出现这种情况的主要原因是 TikZ 通过调查流中发现的下一个字符来分支。因此,如果您分支到错误的位置并在之后输入正确的术语,它就无法返回并正确分支。我认为在这种类型的编程中您无法消除所有这些问题。
\documentclass[tikz]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\foreach \i in {{(0,0},{(0,2.1},{(2.1,2.1},{(2.1,0}} {
\fill[lightgray] \i) rectangle ($(\i)+(0.7,0.7)$); }
\draw (0,0) grid[step=0.7] (2.8,2.8);
\end{tikzpicture}
\end{document}
答案3
值得注意的是,下面的代码没有多余的括号,并且设置了正确匹配的括号,可以编译并给出预期的结果:
\documentclass[12pt]{article}
\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xinttools}
\begin{document}
% \begin{tikzpicture}
% \foreach \i in {(0,0),(0,2.1),(2.1,2.1),(2.1,0)} {
% \fill[lightgray] \i rectangle ($(\i+(0.7,0.7)$); }
% \draw (0,0) grid[step=0.7] (2.8,2.8);
% \end{tikzpicture}
\begin{tikzpicture}
\xintForpair #1#2 in {(0,0),(0,2.1),(2.1,2.1),(2.1,0)} \do {
\fill[lightgray] (#1,#2) rectangle ($(#1,#2)+(0.7,0.7)$); }
\draw (0,0) grid[step=0.7] (2.8,2.8);
\end{tikzpicture}
\end{document}
答案4
所有先前的解决方案都很完美。其中一些解释了为什么 calc 会在您的代码中出错。其中一些解释了您应该进行哪些更改才能使用foreach
贯穿“点”的函数(x_i,y_i)
。
在我看来,你的foreach
TikZ 精神是“错误的”:
- 当您说
\coordinate (A) at (x,y);
然后A
代表x,y
而不是(x,y)
并且您将其用作时(A)
。 - 当您说
let \p1=(x,y)
然后\p1
代表x,y
而不是(x,y)
并且您将其用作时(\p1)
。
所以我认为当我们想要实现foreach
这一点时,我们应该
\foreach \i in {{x_1,y_1},...,{x_n,y_n}}
然后将其用作(\i)
。
在你的情况下,这将变成:
\documentclass[tikz,varwidth,border=5]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\foreach \i in {{0,0},{0,2.1},{2.1,2.1},{2.1,0}}
\fill[lightgray] (\i) rectangle ($(\i)+(0.7,0.7)$);
\draw (0,0) grid[step=0.7] (2.8,2.8);
\end{tikzpicture}
\end{document}