根据模型更新参数化答案

根据模型更新参数化答案

我正在尝试制作一些东西相似的给定图像。但是,关于同心圆之间的“之字形”箭头,我希望这些之字形本身勾勒出一个圆弧,其半径位于两个边界同心圆的中间。

在此处输入图片描述

到目前为止,我有以下 MWE(请注意,节点位置现在并不重要)

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

\begin{document}
    \begin{tikzpicture}[scale=0.7,rotate=90]
        % outer circle
        \def \radius {5}
            \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[draw,fill=gray!30,circle] at (\angle:\radius) {\label};
                    }
        % middle circle
        \def \n {7}
        \def \radius {3}
            \draw (0,0) circle (\radius);
                \foreach \s in {1,...,\n}
                    {
                        \node[draw,fill=black,circle] at ({360/\n * (\s - 1)}:\radius) {};
                    }
        % inner circle
        \def \n {3}
        \def \radius {1}
            \draw (0,0) circle (\radius);
                \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}

这将产生以下内容:

在此处输入图片描述

这里的“12 点钟”箭头没有问题;问题在于 4 点钟箭头,它应该实际上在 3 点时退出外圈。

请求:理想情况下,这支箭将:

  1. 退出白圈节点;
  2. 在到达中间圆(有黑色节点的圆)的一半位置(MWE 中的半径 2),箭头将逆时针旋转,直到与中间圆中最近的黑色圆节点对齐。但这个转弯应该是弧线,而不是直线;
  3. 通过这个黑色圆圈节点前进;
  4. 重复步骤 2,这次与“3”节点相关。

编辑:下面是一个示例图像,显示了我正在寻找的箭头类型:

在此处输入图片描述

答案1

锯齿形圆弧线可以用以下calc库来完成:

\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)}}}

我正在使用一个修改过的atan2函数,atanXY定义为

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

因此仍然可以这样做,atanXY(\p?)因为calc\p宏只是扩展为\x?, \y?(这使得您可以在路径上使用它而无需使用\x\y。(参见A244619

atanXY同时还给出了不带的替代方案。

然后您就可以使用(<p1>) to[zigzagarc] (<p2>)它来绘制一条直线(0,0)、一条圆弧和线的其余部分。

参数zigzagarc允许它使用另一个圆心作为圆弧,但是(0,0)

代码

\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}

答案2

最初,我非常重视逆时针旋转的要求。从你的模型来看,我不再确定这是你想要的,所以这里有一个替代方案。原始版本如下。

根据模型更新参数化答案

如果你真的想逆时针走,有时就意味着要画一条 359 度的弧。即使这条线总是经过一个白色节点,情况也是如此。例如,如果从 240 处的白色节点离开,那么到最近的黑色节点的最近路线是顺时针到 3,而不是逆时针到 4。我不确定这是否是你真正想要的,因为它看起来很奇怪。下面,我选择了最短的路线,但我不知道这是否正确。

当然,这就是试图画出代表我不知道是什么的东西的麻烦。它应该如何进行对你来说可能很明显,但对我来说却完全晦涩难懂!

\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 radius/.store in=\oradius,
    middle radius/.store in=\mradius,
    inner radius/.store in=\iradius,
    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 radius=5,
    middle radius=3,
    inner radius=1,
    outer n=12,
    middle n=7,
    inner n=3,
  ]
  % outer circle
  \draw (0,0) circle (\oradius);
  \foreach \i in {0,...,\ono}
  {
    \node (o\i) [draw, fill=gray!30, circle] at (-{\i*360/\onumber}:\oradius) {\i};
  }
  % middle circle
  \draw (0,0) circle (\mradius);
  \foreach \s in {0,...,\mno}
  {
    \node (m\s) [draw, fill=black, circle] at ({360*\s/\mnumber}:\mradius) {};
  }
  % inner circle
  \draw (0,0) circle (\iradius);
  \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
  \draw[->] (0,0) -- ({\oradius+1},0);
  \foreach \i in {0,120,240}
  {
    \pgfmathsetmacro\n{int(round(\i*\mnumber/360))}
    \pgfmathsetmacro\m{int(round((\n*360/\mnumber)*\onumber/360))}
    \draw [->, magenta] (0,0) -- (\i:{(\iradius+\mradius)/2}) arc (\i:{\n*360/\mnumber}:{(\iradius+\mradius)/2}) -- ({\n*360/\mnumber}:{(\oradius+\mradius)/2}) arc ({\n*360/\mnumber}:{\m*360/\onumber}:{(\oradius+\mradius)/2}) -- ({\m*360/\onumber}:{\oradius+1});
  }
\end{tikzpicture}
\end{document}

基于模型的参数化版本

原始答案

你想要这样的东西吗?在某些情况下,应用你的算法显然会导致不同的出口节点,因为 3 比 4 更接近最近的黑色节点,即使 4 显然更接近原始方向。

界

以下是一次性版本的代码:

\documentclass[tikz,border=10pt,multi]{standalone}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{tikzpicture}[scale=0.7, rotate=90, >=Triangle]
  % outer circle
  \def \radius {5}
  \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}
  \def \radius {3}
  \draw (0,0) circle (\radius);
  \foreach \s in {0,...,\n}
  {
    \node (m\s) [draw,fill=black,circle] at ({360*\s/(\n+1)}:\radius) {};
  }
  % inner circle
  \def \n {2}
  \def \radius {1}
  \draw (0,0) circle (\radius);
  \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}

参数化版本

这是一个参数化版本:

\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 radius/.store in=\oradius,
    middle radius/.store in=\mradius,
    inner radius/.store in=\iradius,
    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 radius=5,
    middle radius=3,
    inner radius=1,
    outer n=12,
    middle n=7,
    inner n=3,
  ]
  % outer circle
  \draw (0,0) circle (\oradius);
  \foreach \i in {0,...,\ono}
  {
    \node (o\i) [draw, fill=gray!30, circle] at (-{\i*360/\onumber}:\oradius) {\i};
  }
  % middle circle
  \draw (0,0) circle (\mradius);
  \foreach \s in {0,...,\mno}
  {
    \node (m\s) [draw, fill=black, circle] at ({360*\s/\mnumber}:\mradius) {};
  }
  % inner circle
  \draw (0,0) circle (\iradius);
  \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
  \draw[->] (0,0) -- ({\oradius+1},0);
  \foreach \j [evaluate=\j as \i using (\j*360/\mnumber)+20] in {0,...,\mno}
  {
    \pgfmathsetmacro\n{int(round(\i*\mnumber/360))}
    \pgfmathsetmacro\m{int(round((\n*360/\mnumber)*\onumber/360))}
    \draw [->, blue] (0,0) -- (\i:{(\iradius+\mradius)/2})  [out=180+\i,in=180+\n*360/\mnumber] to ({\n*360/\mnumber}:{(\iradius+\mradius)/2}) -- ({\n*360/\mnumber}:{(\oradius+\mradius)/2}) [out=180+\n*360/\mnumber,in=180+\m*360/\onumber] to ({\m*360/\onumber}:{(\oradius+\mradius)/2}) -- ({\m*360/\onumber}:{\oradius+1});
  }
\end{tikzpicture}
\end{document}

蓝色重复

相关内容