使用 foreach 在多个节点之间绘制路径

使用 foreach 在多个节点之间绘制路径

我在这里遇到了一个奇怪的问题...我定义了很多节点,我想使用 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}

结果:

使用记住的 moveto 进行 foreach

答案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

对于基本循环,即没有很多不同的counts 和evaluates(尽管可以实现),您可以使用 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}

输出

在此处输入图片描述

相关内容