何时以及如何在路径命令中使用 foreach?TikZ

何时以及如何在路径命令中使用 foreach?TikZ

为什么我的代码会失败?如果没有,foreach我的代码可以正常工作。

通常,我何时以及如何在命令foreach中使用path?这是一种不好的做法吗?如果是,应该有什么替代方案?

\documentclass{standalone}

\usepackage{tikz}

\tikzset{ myVrtxStyle/.style = {
        circle, minimum size= 4mm, fill = blue
    }
}

\begin{document}
    \begin{tikzpicture}
        \node[myVrtxStyle = black] (u) {};
        
        \newcommand{\midSepAngle}{20};
        \newcommand{\remNi}{6}
        
        \draw (u.{135 + \midSepAngle}) to [out = {135 + \midSepAngle}, in = {135 - \midSepAngle}, looseness = 100]
        \foreach \i in {1,..., \remNi}{
            node[ myVrtxStyle, pos = {\i / \remNi} ] (C1\i) {} 
        }
        (u.{135 - \midSepAngle});
        
    \end{tikzpicture}
\end{document}

我看到过一些相关的帖子,例如这个但我还是不完全明白到底发生了什么。

答案1

  1. 在路径中,您应使用foreach。由于历史原因,您也可以使用\foreach来代替foreach(参见第节“14.14 Foreach 操作”,第 167 页,pgfmanual v3.1.9a)。

  2. 有两种方法可以指定直线或曲线上的节点:要么明确使用 pos 选项,要么隐式地将节点放置在路径操作“内部”(参见章节“17.8 在线或曲线上明确放置节点”,第 245 页“17.9 在线或曲线上隐式放置节点”,第 249 页,pgfmanual v3.1.9a)。

    • 隐式示例:\draw (0,0) -- node[pos=.7]{a} (1,1);只有直线到 ( --) 和曲线到 ( ..) 操作支持隐式方式。关键字foreach不受支持隐式方式。

    • 明确示例:\draw (0,0) -- (1,1) node[pos=.7] {a};只有线到(--)、水平和垂直线到(-||-)、曲线到(..)和圆弧(arc)操作支持明确的方式。

    • 对于所有其他路径构造操作(就像to你的情况一样),目前位置放置不起作用(参见第 246 页,pgfmanual,v3.1.9a)。

因此,您必须使用明确的方式,并将您的to操作替换为曲线到(..)操作,如Andrew Stacey 的解决方案

答案2

我不知道为什么它不能通过to命令工作 - 我必须调查这一点 - 但是使用明确的贝塞尔曲线它就可以工作。

  1. 目标坐标必须位于 foreach 之前
  2. foreach 是一个关键词,而不是命令
  3. 我修改了你的节点样式,以将参数作为填充颜色,默认为蓝色
\documentclass {standalone}
\usepackage{tikz}

\tikzset{
myVrtxStyle/.style = { circle, minimum size= 4mm, fill = #1 },
myVrtxStyle/.default = blue
}

\begin{document} 

\begin{tikzpicture} 
\node[myVrtxStyle = black] 
(u) {}; 
\newcommand{\midSepAngle}{20}; 
\newcommand{\remNi}{6} 
\draw (u.{135 + \midSepAngle}) 
.. controls +(135+\midSepAngle:20) and +(135-\midSepAngle: 20) ..
(u.{135-\midSepAngle})
foreach \i in {1,..., \remNi}{ 
node[ myVrtxStyle, pos = \i/\remNi ] (C1\i) {}
}
;
\end{tikzpicture}
\end{document}

答案3

以下语法实际上有效,并且与您的原始代码几乎相同。

\documentclass{standalone}
\usepackage{tikz}
\tikzset{
    myVrtxStyle/.style={
        circle,minimum size=4mm,fill=blue,fill=#1
    }
}
\begin{document}
    \begin{tikzpicture}
        \node[myVrtxStyle=black](u){};
        \newcommand{\midSepAngle}{20};
        \newcommand{\remNi}{6}
        \draw
            (u.{135 +\midSepAngle})
            to
            [out={135+\midSepAngle},in={135-\midSepAngle},looseness=100]
            node foreach\i in{1,...,\remNi}[pos=\i/\remNi,myVrtxStyle](C1\i){}
            (u.{135-\midSepAngle})
        ;
        \draw foreach\i in{1,...,\remNi}{
            (C1\i)--+(-90-\i*40:1)node{\i}
        };
    \end{tikzpicture}
\end{document}

评论

我在这个问题下的评论是错误的,因为你实际上可以在(A) --和之间使用 for 循环(B)。但是,这个 for 循环不能是任意的 for 循环;它必须是专用于节点的 for 循环。所以这
(A) -- foreach\i in{1,2,3}{node{\i}} (B)很糟糕,但这
(A) -- node foreach\i in{1,2,3}{\i} (B)是好事。

这是因为当 TiZ 的解析器已读取(A) --并正在等待(B),它还会留意是否有node...{...}。一旦发现n,它将收集节点规范并将其存储在 中\tikz@collected@onpath,后者将其传输到\tikz@tonodes\tikztonodes。 Ti 之后Z 计算了你的贝塞尔表示to path,它将节点规范放置在路径的末尾,如下所示(tikzlibrarytopaths.code.tex#L134-L140

\def\tikz@to@curve@path{%
  [every curve to]%                ⬇️ This is the main computation ⬇️
  \pgfextra{\iftikz@to@relative\tikz@to@compute@relative\else\tikz@to@compute\fi}
  \tikz@computed@path% ⬅️ this is the Bézier curve (A)..controls(B)and(C)..(D)
  \pgfextra{\tikz@updatenexttrue\tikz@updatecurrenttrue}%
  \tikztonodes% ⬅️ your nodes here (notice the plural)
}

因此,您需要做的就是确保\tikztonodes 确实捕获了您的节点规范。如果自然语法失败,您可以随时强迫。 例如
to[bend left,/utils/exec=\def\tikztonodes{...}]

相关内容