我很难理解GitHub 问题 pgf-tikz/pgf#356。
原始提问者发布了以下 MWE。\begin{document}
为了完整起见,我已将其包装起来。
\documentclass[tikz,border=2mm]{standalone}
\begin{document}
\begin{tikzpicture}
\coordinate (v1) at (0,0);
\coordinate (c21) at (1,0);
\coordinate (c22) at (2,0);
\coordinate (v2) at (2,1);
\coordinate (c31) at (2,2);
\coordinate (c32) at (3,2);
\coordinate (v3) at (4,2);
\node[draw,inner sep=0pt,minimum size=6pt,circle] (a) at (v1) {};
\draw (a) \foreach \i in {2,3} {.. controls (c\i1) and (c\i2) .. (v\i)};
\end{tikzpicture}
\end{document}
对链接问题的答复表明,\foreach
扩大到
\draw (a) .. controls (c21) and (c22) .. (v2)
(a) .. controls (c31) and (c32) .. (v3);
(a)
但是,如果将包含其 MWE 的行中的节点\foreach
替换为坐标(v1)
,则\foreach
循环不会扩展为
\draw (v1) .. controls (c21) and (c22) .. (v2)
(v1) .. controls (c31) and (c32) .. (v3);
为什么会像下面这样展开呢?
\draw (v1) .. controls (c21) and (c22) .. (v2)
.. controls (c31) and (c32) .. (v3);
答复没有解释这一点。
没有提到\iftikz@shapeborder
PGF 和 Ti 中钾Z 手册,其第 88 章说
请注意,
node
和路径命令也以特殊方式pic
支持该语句。foreach
不幸的是,手册中没有关于“特殊方法”的解释。
答案1
坐标和节点之间的区别在于节点(通常)具有大小。也就是说,节点的高度、深度和宽度中至少有一个大于零。Ti钾Z/pgf 会处理这个尺寸,并且当使用没有锚点的节点作为坐标时,无论是否绘制该边界,它都会始终从/到节点边界绘制。请参阅 pgfmanual,第 17.11 节“连接节点:使用节点作为坐标”(html) 了解更多信息。
然后是 的范围属性(\)foreach
。为了支持路径,每次离开和进入循环foreach
时,应该备份和恢复相当多的信息。Tiforeach
钾Z 已经处理了一些此类信息(见tikz.code.tex
,的定义\tikz@foreach
),但它远非全面。问题 #356是曲线到路径操作的一种情况,并且问题 #1047是另一种turn
选择的情况。
对于OP当前的问题,可以认为坐标版本已经得到处理(通过备份和恢复\tikz@last[xy]
和\tikz@last[xy]saved
),而节点版本尚未得到处理。
无论如何,对于 OP 的问题(以及问题 #356,似乎唯一缺少的信息是\tikz@moveto@waiting
,它要么被设置为\relax
,要么\edef
被设置为持有\tikz@shapeborder@name
(一个节点名)。
\documentclass[tikz,border=2mm]{standalone}
\usepackage{regexpatch}
\tikzset{
expected/.style={blue!10, line width=5pt},
simulated/.style={blue!50, line width=3pt, opacity=.5},
actual/.style={line width=.6pt}
}
\newcommand\test[2][]{
\begin{tikzpicture}
\coordinate (v1) at (0,0);
\coordinate (c21) at (1,0);
\coordinate (c22) at (2,0);
\coordinate (v2) at (2,1);
\coordinate (c31) at (2,2);
\coordinate (c32) at (3,2);
\coordinate (v3) at (4,2);
\node[draw,inner sep=0pt,minimum size=6pt,circle] (a) at (v1) {};
\begin{scope}[shift={(3,0)}, nodes={font=\sffamily\scriptsize}, y=.5cm]
\node[anchor=south west, align=center] at (0,1.5) {start from (#2)#1};
\draw[expected] (0, 1) -- +(1,0) node[right] {expected};
\draw[simulated] (0,.5) -- +(1,0) node[right] {simulated};
\draw[actual] (0, 0) -- +(1,0) node[right] {actual};
\end{scope}
% expected
\draw[expected]
(#2) .. controls (c21) and (c22) .. (v2)
.. controls (c31) and (c32) .. (v3);
% simulated foreach
\draw[simulated]
(#2) .. controls (c21) and (c22) .. (v2)
(#2) .. controls (c31) and (c32) .. (v3);
% actual
\draw[actual]
(#2) \foreach \i in {2,3} {.. controls (c\i1) and (c\i2) .. (v\i)};
\end{tikzpicture}
}
\begin{document}
\test[\\before patch]{a}
\test[\\before patch]{v1}
\makeatletter
% backup globally
\xpatchcmd*\tikz@foreach
{\xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}}
{\xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}%
\global\let\tikz@foreach@moveto@waiting=\tikz@moveto@waiting
}
{}{\PatchFailed}
% restore locally
\xpatchcmd*\tikz@foreach
{\tikz@lastysaved=\tikz@foreach@save@lastysaved}
{\tikz@lastysaved=\tikz@foreach@save@lastysaved
\let\tikz@moveto@waiting=\tikz@foreach@moveto@waiting
}
{}{\PatchFailed}
\makeatother
\test[\\after patch]{a}
\test[\\after patch]{v1}
\end{document}
答案2
我的理解是\foreach
创建完整的本地子路径——所以它基本上相当于
\draw (a) { [current point is local] .. controls (c21) and (c22) .. (v2) }
{ [current point is local] .. controls (c31) and (c32) .. (v3) };
关于边界的事情:这个想法是,如果你使用一个节点(a)
作为坐标,Ti钾Z 将把坐标放在形状的边框上 --- 在这种情况下,使用(v1)
就像使用 一样(a.center)
。
可玩代码:
\documentclass[tikz,border=2mm]{standalone}
\begin{document}
\begin{tikzpicture}
\coordinate (v1) at (0,0);
\coordinate (c21) at (1,0);
\coordinate (c22) at (2,0);
\coordinate (v2) at (2,1);
\coordinate (c31) at (2,2);
\coordinate (c32) at (3,2);
\coordinate (v3) at (4,2);
\node[draw,inner sep=0pt,minimum size=6pt,circle] (a) at (v1) {};
\draw (a) \foreach \i in {2,3} {.. controls (c\i1) and (c\i2) .. (v\i)};
\draw[blue] (a) .. controls (c21) and (c22) .. (v2)
.. controls (c31) and (c32) .. (v3);
\draw[red, dashed] (a) { [current point is local] .. controls (c21) and (c22) .. (v2) }
{ [current point is local] .. controls (c31) and (c32) .. (v3) };
\end{tikzpicture}
\end{document}