6

I am trying to generate a path from a list of directions (as seen on the numpad). The coordinates are generated correctly, but because I use multiple call to \path the arrowheads are drawn on each segment. How do I change this code to only draw the starting arrowhead on the first segment and the ending arrowhead on the last segment? I have unsuccessfully tried to have one \path outside the \foreach and only coordinates inside.

edit: It should work for any arrow shape passed in the optional argument.

enter image description here

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\newcommand{\directedPath}[5][]
{
  \edef\start{#2}
  \edef\stop{#3}
  \edef\step{#4}
  \edef\directions{#5}
  \coordinate (c0) at (\start);
  \foreach [var=\dir, count=\cur] in \directions
  {
    % current coordinate dx
    \pgfmathparse{(1-(1-1/sqrt(2))*mod(\dir, 2))*\step*(mod(\dir-1, 3)-1)}
    \edef\dx{\pgfmathresult}
    % current coordinate dy
    \pgfmathparse{(1-(1-1/sqrt(2))*mod(\dir, 2))*\step*(div(\dir-1, 3)-1)}
    \edef\dy{\pgfmathresult}
    % previous coordinate index
    \pgfmathparse{int(\cur - 1)}
    \xdef\prev{\pgfmathresult}
    % current coordinate
    \coordinate (c\cur) at ($(c\prev) + (\dx, \dy)$);
    % draw partial path
    \ifnum \cur>1
      \path [#1] (c\prev) -- (c\cur);
    \fi
  }
  \path [#1] (\start) -- (c1);
  \path [#1] (c\cur) -- (\stop);
}

\begin{document}

\begin{tikzpicture}
  \node [draw=green] (Start) at (0, 0) {Start};
  \node [draw=red] (End) at (5, 2) {End};
  \directedPath[draw=black, >->]{Start}{End}{1.0}{3,6,9,8,7,8,9,6,3}
\end{tikzpicture}

\end{document}
5
  • Quick fix would be removing >-> and using \path [#1,>-] (\start) -- (c1); \path [#1,->] (c\cur) -- (\stop);
    – percusse
    Jul 14, 2013 at 19:00
  • While this solves the problem as stated, it is not what I intended. I should have been more specific. I want it to accept the arrow type as part of the optional argument, making it work for any type of arrowhead.
    – Linus
    Jul 14, 2013 at 19:23
  • 1
    How about making the entire path a single \path command? Would that be an acceptable solution? Jul 14, 2013 at 19:27
  • You can provide the start and end arrow types as separate keys.
    – percusse
    Jul 14, 2013 at 19:46
  • @AndrewStacey Absolutely. That would probably be the best solution.
    – Linus
    Jul 14, 2013 at 19:59

2 Answers 2

6

There is no question that this need to be done in one single path but you can do this quite easily with the turtle library.

Simply define a direction (and a factor) for every digit.

As the direction key only turns the “turtle”, also include the forward key which includes a to[/tikz/turtle/how] path to the relative coordinate in direction and the given distance, i.e.

to[/tikz/turtle/how] ++ (<direction>:<distance>)

The Start and End simply insert a move to to (Start) and a (final?) line to to (End) (or whatever the how style is currently).

Of course, you can use the math from your question in the setup of the digit styles, but this is just faster (for TikZ and to write up).

I opted for a grid-like output which needs the factor sqrt(2) for the diagonal directions. Set this factor to 1 to get the same distance as in your question. (I also changed the example a little bit to get a symmetrical result.)

I have created and used an auxiliary style for the setup, marked by an @. It may also preferable to simply define this style in a /aux path as we won’t use it again or really need it in the /tikz path.

This also makes it easy to set all factors to 1 by omitting the value of the forward key (the default is /tikz/turtle/distance anyway if no value is given), i.e.

@setup turtle digits/.style n args={3}{
  /tikz/turtle/#1/.style={
    /tikz/turtle/direction=#2,
    /tikz/turtle/forward}}

(There is no real reason to set the value of the forward key to a fixed distance as it would be more consistent to change the distance value.)

If you suddenly feel that the keys shouldn’t be called 1, 2, … 9 but 1 step, 2 step, … 9 step you simply add  step after #1.

Code

\documentclass[tikz,convert]{standalone}
\usetikzlibrary{turtle}
\tikzset{
  @setup turtle digits/.style n args={3}{
    /tikz/turtle/#1/.style={
      /tikz/turtle/direction=#2,
      /tikz/turtle/forward={#3*\pgfkeysvalueof{/tikz/turtle/distance}}}},
  @setup turtle digits={1}{south west}{1.41421},
  @setup turtle digits={2}{south}     {1},
  @setup turtle digits={3}{south east}{1.41421},
  @setup turtle digits={4}{left}      {1},
  @setup turtle digits={6}{right}     {1},
  @setup turtle digits={7}{north west}{1.41421},
  @setup turtle digits={8}{north}     {1},
  @setup turtle digits={9}{north east}{1.41421},
  turtle/.cd,
    Start/.style={/tikz/insert path={(#1)}},
    End/.style={/tikz/insert path={to[/tikz/turtle/how] (#1)}},
    Start/.default=Start,
    End/.default=End,
}
\begin{document}
\begin{tikzpicture}
  \node [draw=green] (Start) at (0, 1) {Start};
  \node [draw=red]   (End)   at (5, 2) {End};
  \draw [draw=black, >->] [turtle={Start, 2, 3, 6, 9, 8, 7, 8, 9, 6, 3, End}];
\end{tikzpicture}
\end{document}

Output

with the factors

enter image description here

without the factors

enter image description here

5
  • I actually like the grid-like path more, even though it doesn't behave exactly like in my example. I assume you have the source for that as well, could you possibly provide it?
    – Linus
    Jul 15, 2013 at 11:02
  • @Linus I have updated my answer including the code for the grid-like approach. It is pretty much the same except for the factor. It shouldn’t be hard to customize this for different problems. Jul 15, 2013 at 17:07
  • @Qrrbrirlbel Trying to understand how this example works. What exactly does "@setup" do?
    – Linus
    Jul 18, 2013 at 22:30
  • @Linus I have updated my answer. @setup turtle digits is simply an auxiliary style that makes it possible to define the styles 1 through 9 consistently. You can check out two other answers of mine that uses the turtle library [1] or at least the basic principle behind it [2]. Jul 19, 2013 at 4:00
  • Thief, thief! Qrrbrbirlbel! We hates it, we hates it forever!! (That's for stealing my green tick.) Jul 19, 2013 at 11:54
5

Here's a single path version:

\documentclass{article}
%\url{https://tex.stackexchange.com/q/123997/86}
\usepackage{tikz}
\usetikzlibrary{calc}

\newcommand{\directedPath}[5][]
{
  \coordinate (c0) at (#2);
  \path (c0)
  \foreach [var=\dir,count=\cur] in {#5}
  {
    ++({(1-(1-1/sqrt(2))*mod(\dir, 2))*#4*(mod(\dir-1, 3)-1)},{(1-(1-1/sqrt(2))*mod(\dir, 2))*#4*(div(\dir-1, 3)-1)}) coordinate (c\cur)
  };
  \path[#1] (#2) -- (c1) \foreach [var=\dir,count=\cur] in {#5}
  {
    -- (c\cur)
  } -- (#3);
}


\begin{document}

\begin{tikzpicture}
  \node [draw=green] (Start) at (0, 0) {Start};
  \node [draw=red] (End) at (5, 2) {End};
  \directedPath[draw=black, >->]{Start}{End}{1.0}{3,6,9,8,7,8,9,6,3}
\end{tikzpicture}


\end{document}

The two foreach loops are because the path starts and ends at non-zero sized nodes, but the displacements are relative to the node centres. In the second path, there's an extra (c1) which is needed due to the issue raised at Draw a path between many nodes using foreach. For an alternative solution, see the answers there.

Single path with foreach

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .