# Concentric arc arrows in TikZ

I'm attempting to produce something similar to the given image. However, regarding the "zig-zag" arrows in between the concentric circles, I want these zig-zags to themselves outline an arc of a circle with a radius halfway between the two bounding concentric circles.

Thus far I have the following MWE (note that the node placement is not important right now)

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows}

\begin{document}
\begin{tikzpicture}[scale=0.7,rotate=90]
% outer circle
\draw (0,0) circle (5);
\foreach \angle / \label in {0/0, 30/11, 60/10, 90/9, 120/8, 150/7, 180/6, 210/5, 240/4, 270/3, 300/2, 330/1}
{
}
% middle circle
\def \n {7}
\foreach \s in {1,...,\n}
{
\node[draw,fill=black,circle] at ({360/\n * (\s - 1)}:\radius) {};
}
% inner circle
\def \n {3}
\foreach \s in {1,...,\n}
{
\node[draw,fill=white,circle] at ({360/\n * (\s - 1)}:\radius) {};
}
% arrow
\draw[->] (0,0) -- (6,0);
\draw[->] (0:0) -- (240:6);
\end{tikzpicture}

\end{document}


This produces the following:

The "12 o'clock" arrow here is fine; the problem is with the 4 o'clock arrow, which should actually exit the outer circle at 3.

The Request: Ideally this arrow will:

1. Exit the white circle node;
2. Halfway (radius 2 in the MWE) before reaching the middle circle (the one with the black nodes), the arrow will turn counterclockwise until it is in line with the closest black circle node in the middle circle. But this turn should be an arc, not a straight line;
3. Proceed through this black circle node;
4. Repeat Step 2, this time in relation to the "3" node.

Edit: Here's a sample image to show the type of arrow I'm looking for:

• I'm honestly not sure what you're asking. Can you produce a mock-up version of your desired result? – Alenanno Jun 19 '16 at 18:48
• I considered it originally, but I didn't want to bog the post down with too many images; it's in there now! – Richard Jun 19 '16 at 18:58
• Do you really want to go anticlockwise even if clockwise gets you to the closest black node faster? To go anticlockwise, you have to go in almost a complete circle in some cases, which looks odd to me. But, as I say below, without know what is being represented, strange-to-me is not very meaningful. – cfr Jun 19 '16 at 20:47

The zig-zag-arc line can be done with the calc library:

\tikzset{
zigzagarc/.default={0,0},
zigzagarc/.style={to path={
let \p0=($(\tikztostart)-(#1)$),
\p1=($(\tikztotarget)-(#1)$),
\n0={atanXY(\p0)}, \n1={atanXY(\p1)},
% \n0={atan2(\y0,\x0)}, \n1={atan2(\y1,\x1)},
\n d={.5*veclen(\p1)-.5*veclen(\p0)},
\n r={.5*veclen(\p1)+.5*veclen(\p0)} in
-- ++ (\n0:\n d) arc [radius=\n r, start angle=\n0, end angle=\n1] \tikztonodes
-- (\tikztotarget)}}}


I'm using a modified atan2 function called atanXY defined as

\pgfmathdeclarefunction{atanXY}{2}{\pgfmathatantwo@{#2}{#1}}


so that it is still possible, to do atanXY(\p?) as calc's \p macro just expands to \x?, \y? (this makes it you can use it on a path without using \x and \y. (Cf. A244619)

The alternative without atanXY is also given.

Then you can just use (<p1>) to[zigzagarc] (<p2>) and it draws a straight line away from (0,0), an arc and the rest of the line.

A parameter to zigzagarc allows it to use another center for the arcs but (0,0).

## Code

\documentclass[tikz]{standalone}
\usetikzlibrary{calc,arrows.meta}
\tikzset{
zigzagarc/.default={0,0},
zigzagarc/.style={to path={
let \p0=($(\tikztostart)-(#1)$),
\p1=($(\tikztotarget)-(#1)$),
\n0={atanXY(\p0)}, \n1={atanXY(\p1)},
% \n0={atan2(\y0,\x0)}, \n1={atan2(\y1,\x1)},
\n d={.5*veclen(\p1)-.5*veclen(\p0)},
\n r={.5*veclen(\p1)+.5*veclen(\p0)} in
-- ++ (\n0:\n d) arc [radius=\n r, start angle=\n0, end angle=\n1] \tikztonodes
-- (\tikztotarget)}}}
\makeatletter
% for easy usage of calc's atanXY(\p?):
\pgfmathdeclarefunction{atanXY}{2}{\pgfmathatantwo@{#2}{#1}}

\tikzset{if/.code n args=3{\pgfmathparse{#1}\ifnum\pgfmathresult=0\relax
\expandafter\pgfutil@firstoftwo\else\expandafter\pgfutil@secondoftwo\fi
{\pgfkeysalso{#3}}{\pgfkeysalso{#2}}}}
\makeatother
\newcommand*\tvo[1]{\pgfkeysvalueof{/tikz/#1}}% tikzvalueof
\begin{document}
\begin{tikzpicture}[scale=.7,
declare function={posonarc(\x,\n)=360/\n*\x;},
n-0/.initial=3,  n-1/.initial=7,  n-2/.initial=12,
d-0/.initial=80, d-1/.initial=15, d-2/.initial=90,
every snode/.style={shape=circle, draw, inner sep=+0pt, minimum size=+5pt},
s-0/.style={every snode, node contents=,fill=white},
s-1/.style={every snode, node contents=,
if={or(#1==0,or(#1==1,or(#1==3,#1==5)))}{fill=black}{fill=white}},
s-2/.style={every snode, shape=circle, draw, inner sep=+1pt,
fill=white, node contents={#1}, fill=gray!50, minimum size=1.2em,
if={or(#1==4,#1==7)}{fill=white}
{if={#1==10}{node contents=$t$}
{if={#1==11}{fill=white, node contents=$e$}{}}}},
]
\foreach \r in {1,...,3} \draw circle[radius=\r];

\foreach \ring in {0,...,2}
\foreach \x[count=\xx from 0] in {1,...,\tvo{n-\ring}}
\node (n-\ring-\x) at ({\tvo{d-\ring}-posonarc(\xx,\tvo{n-\ring})}:
\ring+1) [s-\ring=\xx];
\foreach \a/\b/\c in {1/6/12, 2/2/5, 3/4/8}%    down here!
\draw[zigzagarc] (n-0-\a) to (n-1-\b) to (n-2-\c)
-- ++ ({\tvo{d-2}-posonarc(\c-1,\tvo{n-2})}:1) [-Latex];
\end{tikzpicture}
\end{document}

• This is exactly what I'm looking for, and it actually saves me some work with figuring some other things out in the near future. I'll need some time to study this code to figure out exactly what's going on; you may hear from me again soon, if you don't mind. Thanks! – Richard Jun 20 '16 at 11:06

Initially, I took the anticlockwise desideratum seriously. From your mock-up, I'm no longer sure it is what you want, so here's an alternative. The original is below.

# Updated Parameterised Answer Following Mock-Up

If you really want to go anticlockwise, that will sometimes mean drawing an arc through 359 degrees. This is true even if the line always passes through a white node. The closest route to the closest black node if exiting the white node at 240, for example, is clockwise to 3 and not anticlockwise to 4. I'm not sure if that is what you really want as it seems strange. Below, I've taken the shortest route, but I don't know if that is correct.

This is, of course, the trouble with trying to draw something which represents I-know-not-what. How-it-should-go is probably obvious to you, but entirely obscure to me!

\documentclass[tikz,border=10pt,multi]{standalone}
\usetikzlibrary{arrows.meta}
\begin{document}
% ateb i gwestiwn Richard: http://tex.stackexchange.com/q/315559/
\begin{tikzpicture}
[
scale=0.7,
rotate=90,
>=Triangle,
outer no/.store in=\ono,
middle no/.store in=\mno,
inner no/.store in=\ino,
outer number/.store in=\onumber,
middle number/.store in=\mnumber,
inner number/.store in=\inumber,
outer n/.code={%
\pgfmathsetmacro\tno{int(#1-1)}
\tikzset{%
outer no/.expanded=\tno,
outer number=#1,
}
},
middle n/.code={%
\pgfmathsetmacro\tno{int(#1-1)}
\tikzset{%
middle no/.expanded=\tno,
middle number=#1,
}
},
inner n/.code={%
\pgfmathsetmacro\tno{int(#1-1)}
\tikzset{%
inner no/.expanded=\tno,
inner number=#1,
}
},
outer n=12,
middle n=7,
inner n=3,
]
% outer circle
\foreach \i in {0,...,\ono}
{
\node (o\i) [draw, fill=gray!30, circle] at (-{\i*360/\onumber}:\oradius) {\i};
}
% middle circle
\foreach \s in {0,...,\mno}
{
\node (m\s) [draw, fill=black, circle] at ({360*\s/\mnumber}:\mradius) {};
}
% inner circle
\foreach \s in {0,...,\ino}
{
\node (i\s) [draw, fill=white, circle] at ({360*\s/\inumber}:\iradius) {};
}
%   \foreach \i in {0,...,\ono} \node [font=\tiny, red] at (o\i) {o\i};
%   \foreach \i in {0,...,\mno} \node [font=\tiny, red] at (m\i) {m\i};
%   \foreach \i in {0,...,\ino} \node [font=\tiny, red] at (i\i) {i\i};
% arrow
\foreach \i in {0,120,240}
{
\pgfmathsetmacro\n{int(round(\i*\mnumber/360))}
\pgfmathsetmacro\m{int(round((\n*360/\mnumber)*\onumber/360))}
}
\end{tikzpicture}
\end{document}


Do you want something like this? Applying your algorithm obviously results in a different exit node in some cases because 3 is closer to the closest black node than is 4, even though 4 is obviously closer to the original direction.

Here's the code for the one-off version shown:

\documentclass[tikz,border=10pt,multi]{standalone}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{tikzpicture}[scale=0.7, rotate=90, >=Triangle]
% outer circle
\draw (0,0) circle (5);
\foreach \angle / \label in {0/0, 30/11, 60/10, 90/9, 120/8, 150/7, 180/6, 210/5, 240/4, 270/3, 300/2, 330/1}
{
\node (o\label) [draw,fill=gray!30,circle] at (\angle:\radius) {\label};
}
% middle circle
\def \n {6}
\foreach \s in {0,...,\n}
{
\node (m\s) [draw,fill=black,circle] at ({360*\s/(\n+1)}:\radius) {};
}
% inner circle
\def \n {2}
\foreach \s in {0,...,\n}
{
\node (i\s) [draw,fill=white,circle] at ({360*\s/(\n+1)}:\radius) {};
}
%   \foreach \i in {0,...,11} \node [font=\tiny, red] at (o\i) {o\i};
%   \foreach \i in {0,...,6} \node [font=\tiny, red] at (m\i) {m\i};
%   \foreach \i in {0,...,2} \node [font=\tiny, red] at (i\i) {i\i};
% arrow
\draw[->] (0,0) -- (6,0);
\pgfmathsetmacro\n{int(round(240*7/360))}
\pgfmathsetmacro\m{int(round((\n*360/7)*12/360))}
\draw [->] (0,0) -- (240:2)  [out=180+240,in=180+\n*360/7] to ({\n*360/7}:2) -- ({\n*360/7}:4) [out=180+\n*360/7,in=180+\m*360/12] to ({\m*360/12}:4) -- ({\m*360/12}:6);
\end{tikzpicture}
\end{document}


# Parameterised Version

Here's a parameterised version:

\documentclass[tikz,border=10pt,multi]{standalone}
\usetikzlibrary{arrows.meta}
\begin{document}
% ateb i gwestiwn Richard: http://tex.stackexchange.com/q/315559/
\begin{tikzpicture}
[
scale=0.7,
rotate=90,
>=Triangle,
outer no/.store in=\ono,
middle no/.store in=\mno,
inner no/.store in=\ino,
outer number/.store in=\onumber,
middle number/.store in=\mnumber,
inner number/.store in=\inumber,
outer n/.code={%
\pgfmathsetmacro\tno{int(#1-1)}
\tikzset{%
outer no/.expanded=\tno,
outer number=#1,
}
},
middle n/.code={%
\pgfmathsetmacro\tno{int(#1-1)}
\tikzset{%
middle no/.expanded=\tno,
middle number=#1,
}
},
inner n/.code={%
\pgfmathsetmacro\tno{int(#1-1)}
\tikzset{%
inner no/.expanded=\tno,
inner number=#1,
}
},
outer n=12,
middle n=7,
inner n=3,
]
% outer circle
\foreach \i in {0,...,\ono}
{
\node (o\i) [draw, fill=gray!30, circle] at (-{\i*360/\onumber}:\oradius) {\i};
}
% middle circle
\foreach \s in {0,...,\mno}
{
\node (m\s) [draw, fill=black, circle] at ({360*\s/\mnumber}:\mradius) {};
}
% inner circle
\foreach \s in {0,...,\ino}
{
\node (i\s) [draw, fill=white, circle] at ({360*\s/\inumber}:\iradius) {};
}
%   \foreach \i in {0,...,\ono} \node [font=\tiny, red] at (o\i) {o\i};
%   \foreach \i in {0,...,\mno} \node [font=\tiny, red] at (m\i) {m\i};
%   \foreach \i in {0,...,\ino} \node [font=\tiny, red] at (i\i) {i\i};
% arrow