回答在 TikZ 中创建齿轮,我会plot
在 foreach 循环中将其用于单个路径。但似乎不可能...
以下举例说明我的问题:
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw
(0,0)
\foreach \myvar in {1,2,3}{
--
plot[domain=0:1] (\myvar-\x,\myvar)
};
\end{tikzpicture}
\end{document}
本文档应产生以下结果:
事实上,它会产生以下错误:
! Package tikz Error: Giving up on this path. Did you forget a semicolon?.
编辑:我添加了一个更复杂的例子来展示这个问题。
这里,没有的代码\foreach
:
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw
(0,0)
--
plot[domain=0:120] ({1-cos(3*\x)},{1-sin(\x)})
--
plot[domain=0:120] ({2-cos(3*\x)},{2-sin(2*\x)})
--
plot[domain=0:120] ({3-cos(3*\x)},{3-sin(3*\x)})
;
\end{tikzpicture}
\end{document}
结果如下:
分解后的代码如下\foreach
(但此代码会产生错误):
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw[dahsed]
(0,0)
\foreach \myvar in {1,2,3}{
--
plot[domain=0:120] ({\myvar-cos(3*\x)},{\myvar-sin(\myvar*\x)})
};
\end{tikzpicture}
\end{document}
答案1
这是一个错误。
\foreach
执行 时发生的和执行 时发生的\draw ... \foreach ...
不一样。它是\foreach
\foreach ... \draw ...
真实的 \foreach
在调用实际命令之前,先设置一些钩子。包装器命令是:
\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%
\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\setbox\tikz@tempbox=\copy\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%
\setbox\tikz@figbox=\box\tikz@tempbox\tikz@scan@next@command}%
\global\setbox\tikz@tempbox=\copy\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}%
\foreach}
钩子\pgffor@beginhook
等在代码中的特定位置被调用。重要的是在:\foreach
末尾发生的事情。这样做的实际结果是,它将 TikZ 解析器置于扫描 foreach 循环主体的正确模式:它正在等待路径构造命令。这就是工作的原因:当 TikZ 最终看到它处于正确的“模式”时。beginhook
\expandafter\tikz@scan@next@command\pgfutil@firstofone
\draw (0,0) \foreach \i in {1} { -- (1,0) };
-- (1,0)
plot 函数通过调用来\foreach
生成绘制路径时经过的所有点。但是当 plot 函数运行时,它不希望 TikZ 解析器生效,而是想做自己的事情。所以\pgffor@beginhook
这里完全是错误的地方,因为 TikZ 现在会在开始生成路径点时期待路径构造命令,但 plot 代码还没有准备好将控制权交还给解析器。最终发生的是解析器进入无限循环,但 TikZ 内置了对这些循环的检查并最终退出...
一个解决方法是在 plot 函数调用其循环之前清空钩子。我不知道这有多可靠 - 我没有对其进行过广泛的测试。以下是一些执行此操作的代码:
\documentclass{article}
%\url{http://tex.stackexchange.com/q/58829/86}
\usepackage{tikz}
%\usepackage{trace}
\makeatletter
\def\tikz@clear@foreach{%
\let\pgffor@beginhook=\pgfutil@empty
\let\pgffor@endhook=\pgfutil@empty
\let\pgffor@afterhook=\pgfutil@empty
}
\def\tikz@plot@expression(#1){%
\edef\tikz@plot@data{\noexpand\tikz@clear@foreach\noexpand\pgfplotfunction{\expandafter\noexpand\tikz@plot@var}{\tikz@plot@samplesat}}%
\expandafter\def\expandafter\tikz@plot@data\expandafter{\tikz@plot@data{\tikz@scan@one@point\pgfutil@firstofone(#1)}}%
\tikz@@@plot%
}
\makeatother
\begin{document}
\begin{tikzpicture}
%\traceon
\draw[dashed]
(0,0) \foreach \myvar in {1,2,3} {%
-- plot[domain=0:120] ({\myvar-cos(3*\x)},{\myvar-sin(\myvar*\x)})
%-- ++(\myvar,1)
}%
;
%\traceoff
\end{tikzpicture}
\end{document}
这将产生所需的结果:
正如我所说的,可能有更好的解决办法,但在实施真正的解决办法之前,可以将其视为一种创可贴。
答案2
我假定问题是,像你那样\draw
用循环来切断命令是非法的\foreach
。看来我错了。不过,一个解决方案可以规避这个问题漏洞(正如其他海报所建议的),我建议使用较低级别的命令,即\pgfpathlineto
:
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\pgfpathmoveto{\pgfpointorigin}
\foreach \myvar/\x in {1cm/0cm,1cm/1cm,2cm/0cm,2cm/1cm,3cm/0cm,3cm/1cm}{
\pgfpathlineto{\pgfpoint{\myvar-\x}{\myvar}}
};
\pgfusepathqstroke
\end{tikzpicture}
\end{document}
首先将路径的起点设置为画布坐标系的原点。然后在循环中将\foreach
连续的线段添加到路径中,最后实际绘制路径。如果省略\pgfusepathqstroke
,您将获得一条路径,但它不可见。
答案3
可以用 \foreach 循环剪切 \draw 命令,例如:\draw (0,0) \foreach \myvar in {1,2,3}{ -- (\myvar,\myvar*\myvar-\myvar)} ;
。
我认为,但我不确定问题是否来自于plot
和之间的冲突\foreach
这是获得结果的解决方案
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw (0,0)
\foreach \myvar in {1,2,3}{%
-- (\myvar,\myvar) -- (\myvar-1,1+\myvar)} ;
\end{tikzpicture}
\end{document}