tikz foreach 循环:是否有与 metapost 的步骤等效的步骤?

tikz foreach 循环:是否有与 metapost 的步骤等效的步骤?

如果我使用和搜索的术语不正确,我深表歉意。这对我来说似乎是一个显而易见的问题,所以我很惊讶我没有找到任何东西(所以我假设我遗漏了一些东西)。

在中metapost,我可以使用以下内容来定义循环:

for i=some-value step 0.05 until some-other-value:
    fill fullcircle scaled so-and-so withcolor i*white;
    so-and-so := so-and-so - something;
    something-else := i;
endfor;

这意味着我可以定义增量应该有多大,而不需要知道的初始值和最终值i

类似的事情可能发生吗tikz

我可以通过用第一个值加上步长值来计算循环的第二个值,以更迂回的方式实现相同的效果。但是,我想知道是否有更简单的方法。

也就是说,下面的代码可以工作:

\documentclass[border=5pt,tikz]{standalone}

\begin{document}
  \tikzset{
    /mytree/key1/.initial={-10},
    /mytree/key2/.initial={10},
    /mytree/step1/.initial={2},
  }
  \begin{tikzpicture}
    \pgfmathsetmacro{\myfirststep}{\pgfkeysvalueof{/mytree/key1} + \pgfkeysvalueof{/mytree/step1}}%
    \foreach \i in {\pgfkeysvalueof{/mytree/key1},\myfirststep,...,\pgfkeysvalueof{/mytree/key2}}
      \node at (\i,0) {\i};
  \end{tikzpicture}
\end{document}

但我想知道是否可以更换线路

    \pgfmathsetmacro{\myfirststep}{\pgfkeysvalueof{/mytree/key1} + \pgfkeysvalueof{/mytree/step1}}%
    \foreach \i in {\pgfkeysvalueof{/mytree/key1},\myfirststep,...,\pgfkeysvalueof{/mytree/key2}}

用一些更优雅的东西

    \foreach \i [step=\pgfkeysvalueof{/mytree/step1}] in {\pgfkeysvalueof{/mytree/key1},...,\pgfkeysvalueof{/mytree/key2}}

step这与in的用法类似metapost

答案1

带有 的实现expl3;生成完整列表,从而减轻 PGF 自行完成工作的负担。

\documentclass{article}
\usepackage{xparse,tikz}

\ExplSyntaxOn
\NewDocumentCommand{\mpfor}{mm}
 {% #1 = variable, #2 = keys
  \cfr_mpfor:nn { #1 } { #2 }
 }

\keys_define:nn { cfr/mpfor }
 {
  start .fp_set:N = \l_cfr_mpfor_start_fp,
  start .value_required:,
  end   .fp_set:N = \l_cfr_mpfor_end_fp,
  end   .value_required:,
  step  .fp_set:N = \l_cfr_mpfor_step_fp,
 }

\clist_new:N \l_cfr_mpfor_values_clist

\cs_new_protected:Npn \cfr_mpfor:nn #1 #2
 {
  \keys_set:nn { cfr/mpfor } { step = 1 , #2 } % default step 1
  \bool_do_while:nn
   {
    (% if the step is positive, continue until <= holds
     \fp_compare_p:n { \l_cfr_mpfor_step_fp > \c_zero_fp }
     &&
     \fp_compare_p:n { \l_cfr_mpfor_start_fp <= \l_cfr_mpfor_end_fp }
    )
    ||
    (% if the step is negative, continue until >= holds
     \fp_compare_p:n { \l_cfr_mpfor_step_fp < \c_zero_fp }
     &&
     \fp_compare_p:n { \l_cfr_mpfor_start_fp >= \l_cfr_mpfor_end_fp }
    )
   }
   {
    \clist_put_right:Nx \l_cfr_mpfor_values_clist { \fp_eval:n { \l_cfr_mpfor_start_fp } }
    \fp_add:Nn \l_cfr_mpfor_start_fp { \l_cfr_mpfor_step_fp }
   }
  \cfr_mpfor_foreach:Vn \l_cfr_mpfor_values_clist { #1 }
 }

\cs_new_protected:Npn \cfr_mpfor_foreach:nn #1 #2
 {
  \foreach #2 in ~ { #1 }
 }
\cs_generate_variant:Nn \cfr_mpfor_foreach:nn { V }

\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
\mpfor{\i}{start=-4,step=2,end=8}{\node at (\i,0) {$\i$};}
\end{tikzpicture}

\begin{tikzpicture}
\mpfor{\i}{start=8,step=-2,end=-4}{\node at (\i,0) {$\i$};}
\end{tikzpicture}

\end{document}

注意,不会检查循环是否结束(可能会添加)。如果步长为零,则仅使用起点。

可以使用任何值,只要它符合模块接受的值fp

在此处输入图片描述

答案2

这不是很简单的方法,也不是很优雅,但是...是一种可能性。这是TikZ唯一的解决方案。它可以适应添加其他键(例如,,,,... second)。random stepexclusive startexclusive end

\documentclass[border=5pt,tikz]{standalone}

\pgfkeys{
  /stepfor/.cd,
  start/.store in={\startvalue},
  step/.store in={\stepvalue},
  end/.store in={\endvalue}
}
\def\for[#1]#2{
  \pgfkeys{/stepfor/.cd,#1}
  \pgfmathsetmacro{\secondvalue}{int(\startvalue+\stepvalue)}
  \foreach \i in {\startvalue,\secondvalue,...,\endvalue}{#2}
}

\begin{document}
  \begin{tikzpicture}
    \for[start=-4,step=2,end=8]{\node at (\i,0) {\i};}
  \end{tikzpicture}
\end{document}

在此处输入图片描述

笔记: 我加入int评估\secondvalue只是为了让输出更好;)但是为了处理实数,当然应该将其删除。

答案3

如果您接受使用 之外的库TikZ,并且只想循环整数,则可以举例说明xinttools

方法 1:仅使用xint

\documentclass[tikz,border=5pt]{standalone}
\usepackage{xinttools}

\begin{document}
  \begin{tikzpicture}
    \xintFor* #1 in {\xintSeq[2]{-4}{8}} \do {
      \node at (#1,0) {#1};
    }
  \end{tikzpicture}
\end{document}

在此处输入图片描述

方法 2:使用xint\foreach

\documentclass[tikz,border=5pt]{standalone}
\usepackage{xinttools}

\begin{document}
  \begin{tikzpicture}
    \edef\interval{\xintListWithSep{,}{\xintSeq[2]{-4}{8}}}
    \foreach \i in \interval 
      \node at (\i,0) {\i};
  \end{tikzpicture}
\end{document}

方法 2+:使用xint\foreach样式。

\documentclass[border=5pt]{standalone}
\usepackage{tikz}
\usepackage{xinttools}
\tikzset{
  /pgf/foreach/interval/.code args={from #1 to #2 by #3}{
    \edef\interval{\xintListWithSep{,}{\xintSeq[#3]{#1}{#2}}}
  }
}
\begin{document}
  \begin{tikzpicture}
    \foreach[interval=from -4 to 8 by 2] \i in \interval
      \node at (\i,0) {\i};
  \end{tikzpicture}
\end{document}

相关内容