如何仅在用 \foreach 绘制的路径末尾绘制箭头?

如何仅在用 \foreach 绘制的路径末尾绘制箭头?

我想定义一个命令,用 pgf/tikz 绘制一些特殊的折线。在这些折线中,线条样式是交替变化的。以下是我的 latex 代码:

\documentclass{standalone}
\usepackage{tikz}
\newcommand{\drawline}[4][]{
  \foreach \v [remember=\v as \u,count=\i] in {#4} {
    \ifnum \i > 1
      \ifodd \i \draw[#1,#3] \u -- \v; \else \draw[#1,#2] \u -- \v; \fi
    \fi
  }
}
\begin{document}
\begin{tikzpicture}
\drawline{solid,color=blue}{dashed,color=green}{(0,0),(1,1),(2,3),(5,5),(8,-1),(5,1)}
\end{tikzpicture}
\end{document}

输出结果如下:

在此处输入图片描述

现在我想在折线末端添加一个箭头。我该如何修改上述命令定义?

在此处输入图片描述

答案1

您想要做的是仅在到达最后一个元素时绘制箭头。不幸的是,正如在如何获取 \foreach 循环中元素的数量?\foreach没有内置机制先验确定传递给它的元素总数;因此,它无法检测到在处理时已经到达最后一个元素。

这里有两种替代方法。

在此处输入图片描述

1 - 反向绘制路径

反转您传递的列表\foreach(使终点成为起点)并仅在“开始处”绘制箭头(当\i=2 时)。

\documentclass{standalone}
\usepackage{tikz}

\makeatletter
\newcommand{\drawline}[4][]{
  \foreach \v [remember=\v as \u,count=\i] in {#4} {
    % draw an arrowhead only if we're processing the second element
    \ifnum \i = 2%
      \tikzset{tip/.style={<-}}%
    \else
      \tikzset{tip/.style={}}%
    \fi
    % the rest of your for loop
    \ifnum \i > 1%
      \ifodd \i%
        \draw[tip,#1,#3] \u -- \v;
      \else
        \draw[tip,#1,#2] \u -- \v;
      \fi
    \fi
  }%
}
\makeatother

\begin{document}
\begin{tikzpicture}
\drawline{solid,color=blue}{dashed,color=green}{(5,1),(8,-1),(5,5),(2,3),(1,1),(0,0)}
\end{tikzpicture}
\end{document}

2 - 预先计算元素总数

首先计算元素的数量,然后在循环主体中设置一个测试\foreach来检测是否已到达最后一个元素,并且仅在那种情况下绘制箭头。

\documentclass{standalone}
\usepackage{tikz}

\newcount\foreachNumel

\makeatletter
\newcommand{\drawline}[4][]{
  % count the number of elements in #4
  \global\foreachNumel=0%
  \foreach \v in {#4}
    {\global\advance\foreachNumel by \@ne}
  \foreach \v [remember=\v as \u,count=\i] in {#4} {
    % draw an arrowhead only if we're processing the last element
    \ifnum \i = \foreachNumel%
      \tikzset{tip/.style={->}}%
    \else
      \tikzset{tip/.style={}}%
    \fi
    % the rest of your for loop
    \ifnum \i > 1%
      \ifodd \i%
        \draw[tip,#1,#3] \u -- \v;
      \else
        \draw[tip,#1,#2] \u -- \v;
      \fi
    \fi
  }%
}
\makeatother

\begin{document}
\begin{tikzpicture}
\drawline{solid,color=blue}{dashed,color=green}{(0,0),(1,1),(2,3),(5,5),(8,-1),(5,1)}
\end{tikzpicture}
\end{document}

答案2

可能有点过度,而且效率可能不如使用迭代点列表那么高\foreach,但以下polyline装饰(我认为)几乎完全概括了任意数量风格的要求。

.1pt请注意,如果路径长度不足,则可能会失败。

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations}
\newcount\pgfdecoratedinputsegmentcount
\pgfdeclaredecoration{polyline}{start}{
\state{start}[width=0pt,
  next state=draw,
  persistent precomputation={\pgfdecoratedinputsegmentcount=1}]{}
\state{draw}[width=\pgfdecoratedinputsegmentlength,
  switch if less than=\pgfdecoratedinputsegmentlength+.1pt to final,
  persistent postcomputation={\advance\pgfdecoratedinputsegmentcount by1}]
{
  \pgfcoordinate{@1}{\pgfpointdecoratedinputsegmentfirst}%
  \pgfcoordinate{@2}{\pgfpointdecoratedinputsegmentlast}%
  \let\i=\pgfdecoratedinputsegmentcount%
  \pgfmathsetmacro\i{int(\pgfkeysvalueof{/pgf/decoration/polyline style function})}%
  \ifnum\pgfdecoratedinputsegmentcount=1\relax%
    \path [/pgf/decoration/every polyline/.try, 
      /pgf/decoration/polyline 1/.try, 
      /pgf/decoration/polyline first/.try]
      (@1) -- (@2) \pgfdecorationpolylinenodes;
  \else%
    \path [/pgf/decoration/every polyline/.try, 
      /pgf/decoration/polyline \i/.try]
      (@1) -- (@2) \pgfdecorationpolylinenodes;
  \fi%
}
\state{final}{
  \pgfcoordinate{@1}{\pgfpointdecoratedinputsegmentfirst}%
  \pgfcoordinate{@2}{\pgfpointdecoratedinputsegmentlast}%
  \let\i=\pgfdecoratedinputsegmentcount%
  \pgfmathsetmacro\i{int(\pgfkeysvalueof{/pgf/decoration/polyline style function})}%
  \path [/pgf/decoration/every polyline/.try, 
    /pgf/decoration/polyline \i/.try, 
    /pgf/decoration/polyline last/.try]
     (@1) -- (@2) \pgfdecorationpolylinenodes;
}
}
\pgfkeys{/pgf/decoration/.cd,
  polyline style function/.initial=\i}
\tikzset{%
  polyline nodes/.store in=\pgfdecorationpolylinenodes,
  polyline nodes=,
}
\begin{document}
\begin{tikzpicture}[polyline label/.style={
  circle, inner sep=1pt, font=\sffamily\footnotesize, fill=black!75, text=white,
}]
\path 
[decoration={polyline,
  polyline style function={mod(\i-1,7)+1},
  polyline 1/.style={draw=red},
  polyline 2/.style={draw=yellow},
  polyline 3/.style={draw=pink},
  polyline 4/.style={draw=green},
  polyline 5/.style={draw=orange},
  polyline 6/.style={draw=purple},
  polyline 7/.style={draw=blue},
  polyline last/.style={-stealth},
  every polyline/.style={ultra thick, 
    polyline nodes={node [midway, transform shape, polyline label] {\i}}
  }}, decorate]
  (0,0) \foreach \i in {1,...,28}{
    -- ++(rand*180-90:rnd*1+2)
  };

\end{tikzpicture}
\end{document}

在此处输入图片描述

相关内容