我在这里遇到了一个奇怪的问题...我定义了很多节点,我想使用 foreach 绘制从第一个到最后一个的路径。但是,当我尝试时,它只会在p1
所有剩余节点之间绘制边。这是怎么回事?
\begin{tikzpicture}[scale=.5]
\foreach [count=\x] \pt in {(0,5), (0,2), (2,2), (2,0), (6,0), (6,2), (8, 2), (8,6), (6,6), (6,8), (3,8)}
\node[black, circle, draw] (p\x) at \pt {};
\draw (p1)
\foreach \x in {2,...,11} {
--(p\x)
};
\end{tikzpicture}
生成:
代替:
答案1
在我看来,这是 TikZ 的一个错误。正如本网站所熟知的 (!),PGF\foreach
命令在一个组(实际上是两个组)内执行其内部操作。这意味着,当需要从一次迭代到下一次迭代记住某件事时,必须有一个明确的机制来记住它。当\foreach
使用构造来构建路径时,有一些显而易见的事情需要记住,例如最后构造的点和最后“保存”的点。因此,当 TikZ\foreach
在路径构造中遇到时,它实际上会调用一个围绕 PGF 的包装器\foreach
,其中包括这个“保存”装置。
然而,看起来实现忘记了一些东西。当 TikZ 遇到裸节点坐标(例如 )时(p1)
,它无法立即在此点构建路径。该路径将通向节点边界上的某个点,但随后将跳转到节点边界上的其他点,并且该跳转将由下一个路径的某个部分。因此 TikZ 会记住有一个moveto
“等待”的,并在知道路径的下一个部分是什么时找出答案。
不幸的是,这个等待的 moveto 不是在\foreach
迭代过程中被记住的内容的一部分。因此,它会恢复到之前记住的 moveto,也就是在所有分组开始之前设置的 moveto,即(p1)
。
一个解决方案是让 TikZ 记住组之间的 moveto。这里有一个改编版本,\tikz@foreach
添加了这个记忆功能。我怀疑在循环之间也应该记住其他一些事情,例如\tikzlastnode
,但为了避免代码过于复杂,我没有把它们放进去。
\documentclass{article}
%\url{http://tex.stackexchange.com/q/75146/86}
\usepackage{tikz}
\makeatletter
\def\tikz@foreach{%
\def\pgffor@beginhook{%
\tikz@lastx=\tikz@foreach@save@lastx%
\tikz@lasty=\tikz@foreach@save@lasty%
\tikz@lastxsaved=\tikz@foreach@save@lastxsaved%
\tikz@lastysaved=\tikz@foreach@save@lastysaved%
\let\tikz@moveto@waiting=\tikz@foreach@moveto@waiting
\setbox\tikz@figbox=\box\tikz@tempbox\expandafter\tikz@scan@next@command\pgfutil@firstofone}%
\def\pgffor@endhook{\pgfextra{%
\xdef\tikz@foreach@save@lastx{\the\tikz@lastx}%
\xdef\tikz@foreach@save@lasty{\the\tikz@lasty}%
\xdef\tikz@foreach@save@lastxsaved{\the\tikz@lastxsaved}%
\xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}%
\global\let\tikz@foreach@moveto@waiting=\tikz@moveto@waiting
\global\setbox\tikz@tempbox=\box\tikz@figbox\pgfutil@gobble}}%
\def\pgffor@afterhook{%
\tikz@lastx=\tikz@foreach@save@lastx%
\tikz@lasty=\tikz@foreach@save@lasty%
\tikz@lastxsaved=\tikz@foreach@save@lastxsaved%
\tikz@lastysaved=\tikz@foreach@save@lastysaved%
\let\tikz@moveto@waiting=\tikz@foreach@moveto@waiting
\setbox\tikz@figbox=\box\tikz@tempbox\tikz@scan@next@command}%
\global\setbox\tikz@tempbox=\box\tikz@figbox%
\xdef\tikz@foreach@save@lastx{\the\tikz@lastx}%
\xdef\tikz@foreach@save@lasty{\the\tikz@lasty}%
\xdef\tikz@foreach@save@lastxsaved{\the\tikz@lastxsaved}%
\xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}%
\global\let\tikz@foreach@moveto@waiting=\tikz@moveto@waiting
\foreach}
\makeatother
\begin{document}
\begin{tikzpicture}[scale=.5]
\foreach [count=\x] \pt in {(0,5), (0,2), (2,2), (2,0), (6,0), (6,2), (8, 2), (8,6), (6,6), (6,8), (3,8)}
\node[black, circle, draw] (p\x) at \pt {};
\draw (p1)
\foreach \x in {2,...,11} {
-- (p\x)
};
\end{tikzpicture}
\end{document}
结果:
答案2
你可以让 TikZ‘记住’前一个点,然后从该点继续绘制:
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[scale=.5]
\foreach [count=\x] \pt in {(0,5), (0,2), (2,2), (2,0), (6,0), (6,2), (8, 2), (8,6), (6,6), (6,8), (3,8)}
\node[black, circle, draw] (p\x) at \pt {};
\draw \foreach \x [remember=\x as \lastx (initially 1)] in {2,...,11}{(p\lastx) -- (p\x)};
\end{tikzpicture}
\end{document}
答案3
对于基本循环,即没有很多不同的count
s 和evaluate
s(尽管可以实现),您可以使用 PGFkeys.list
处理程序,它也是通过 a 实现的,\foreach
但不同,从而避免了分组问题。
代码
\documentclass[tikz,convert=false]{standalone}
\begin{document}
\begin{tikzpicture}[scale=.5]
\foreach [count=\x] \pt in {(0,5), (0,2), (2,2), (2,0), (6,0), (6,2), (8, 2), (8,6), (6,6), (6,8), (3,8)}
\node[black, circle, draw] (p\x) at \pt {};
\draw[foreach/.style={insert path=--(p#1)}] (p1) [foreach/.list={2,...,11}];
\end{tikzpicture}
\end{document}