TikZ - 如何填充绘制跨越圆弧的区域?

TikZ - 如何填充绘制跨越圆弧的区域?

我想画一个角度发射器:

在此处输入图片描述

以下代码显示了我目前想到的,基本上什么都没有。我不知道如何以径向方式填充每个象限的单元格。我成功地绘制了某种矩形和圆形,但这个不行。

从 12 点开始逆时针旋转,外环的图案为 8f(满)-8e(空)个单元格,然后第二个外环的图案相同,偏移量为 4 个单元格,然后是 4f-4e,偏移量为 2 个单元格,内环具有 2f-2e 图案,偏移量为 1。

\documentclass[
a4paper
]{scrartcl}

\usepackage{
    newtxtext,
    amsmath,
}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{tikz}
\usetikzlibrary{
    external,
}

\listfiles

\begin{document}
\begin{center}
    \begin{tikzpicture}[font=\small]
    \draw[thick] (0,0) circle [radius=2cm];
    \draw[thick] (0,0) circle [radius=4cm];
%   \foreach \a in {2,2.5,...,4}
%       \foreach \w in {0,22.5,45,...,337.5} {
%   \fill ($(\w:\a;
%   }
    \end{tikzpicture}
\end{center}
\end{document}

答案1

这是一个外行人能想到的解决办法,不用填充,直接用 画圆弧就可以了line width=0.5cm

\documentclass[
a4paper
]{scrartcl}

\usepackage[T1]{fontenc}
\usepackage{tikz}

\begin{document}
\begin{center}
    \begin{tikzpicture}[font=\small]
    \foreach \x in {0,22.5,...,337.5}{
        \draw (0,0) -- (\x:4cm);
    }
    \foreach \x in {2,2.5,...,4}{
    \draw[thick] (0,0) circle [radius=\x cm];
    }
    \draw[thick,fill=white] (0,0) circle [radius=2cm];
     \foreach \w/\t in {22.5/67.5,112.5/157.5,202.5/247.5,292.5/337.5} {
       \draw[line width=0.5cm] (\w:2.25) arc(\w:\t:2.25);
   }
   \foreach \w/\t in {135/225,315/405} {
       \draw[line width=0.5cm] (\w:2.75) arc(\w:\t:2.75);
   }
   \foreach \w/\t in {180/360} {
       \draw[line width=0.5cm] (\w:3.25) arc(\w:\t:3.25);
   }
   \foreach \w/\t in {90/270} {
       \draw[line width=0.5cm] (\w:3.75) arc(\w:\t:3.75);
   }
    \end{tikzpicture}
\end{center}
\end{document}

在此处输入图片描述

答案2

这里有一个起点。它基于杰克的轮盘

\documentclass[border=3mm]{standalone}
\usepackage{tikz}
\begin{document}

% The main macro
% #1 - List of value/color pairs
% #2 - inner radius
% #3 - outer radius
\newcommand{\wheelchart}[3]{
    % Calculate total
    \pgfmathsetmacro{\totalnum}{0}
    \foreach \value/\colour in {#1} {
        \pgfmathparse{\value+\totalnum}
        \global\let\totalnum=\pgfmathresult
    }

    % Calculate the thickness and the middle line of the wheel
    \pgfmathsetmacro{\wheelwidth}{(#3)-(#2)}
    \pgfmathsetmacro{\midradius}{(#3+#2)/2}

    % Rotate so we start from the top
    \begin{scope}[rotate=90]
    % Loop through each value set. \cumnum keeps track of where we are in the wheel
        \pgfmathsetmacro{\cumnum}{0}
        \foreach \value/\colour in {#1} {
            \pgfmathsetmacro{\newcumnum}{\cumnum + \value/\totalnum*360}

      % Draw the color segments.
            \draw[draw, fill=\colour] (-\cumnum:#2) arc (-\cumnum:-\newcumnum:#2)--(-\newcumnum:#3) arc (-\newcumnum:-\cumnum:#3)--cycle;

       % Set the old cumulated angle to the new value
            \global\let\cumnum=\newcumnum
      }
      \end{scope}
}

\begin{tikzpicture}


\wheelchart{1/white,1/black,1/black,1/white,1/white,1/black,1/black,1/white,1/white,1/black,1/black,1/white,1/white,1/black,1/black,1/white}{3cm}{3.5cm}

\wheelchart{1/white,1/white,1/black,1/black,1/black,1/black,1/white,1/white,1/white,1/white,1/black,1/black,1/black,1/black,1/white,1/white}{3.5cm}{4cm}

\wheelchart{1/white,1/white,1/white,1/white,1/black,1/black,1/black,1/black,1/black,1/black,1/black,1/black,1/white,1/white,1/white,1/white}{4cm}{4.5cm}

\wheelchart{1/white,1/white,1/white,1/white,1/white,1/white,1/white,1/white,1/black,1/black,1/black,1/black,1/black,1/black,1/black,1/black}{4.5cm}{5cm}
\end{tikzpicture}

\end{document}

在此处输入图片描述

答案3

虽然不是最理想的,但这是一种指定满/空扇区的更简洁的方法。此外,它利用了默认的填充规则,因此在矩形覆盖层中创建了“孔”,因此无需用正确的颜色填充圆圈。

需要该库的最新 PGF 版本math(这可能不是必需的,但提供了一种更简单的方法来定义/计算值)。

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{math}
\begin{document}
\begin{tikzpicture}[every sector/.style={draw}, sector-1/.style={fill=black}, sector-0/.style={fill=white}]
\tikzmath{%
  \n = 16; \N = 4;
  \R1 = 1; \R2 = 2;
  \th = (\R2-\R1) / \N;
  \st = 360 / \n;
  \S = 1;
}
\foreach \s [count=\i from 0,
  evaluate={\a=90+\i*\st; \r=\R2-floor(\i/\n)*\th;}] in 
 {%
    1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
    0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,
    0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
    0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0%
 }
   \path [every sector/.try, sector-\s] 
     (\a:\r) arc (\a:\a+\st:\r) -- 
     (\a+\st:\r-\th) arc (\a+\st:\a:\r-\th) -- cycle;

\filldraw [fill=white, rotate=\S*\st-\st/2] 
  (\R1-\th/2,-\th/2) rectangle (\R2+\th/2,\th/2)
  \foreach \i in {1,...,\N}{ (\R1+\th*\i-\th/2,0) circle [radius=\th/3] };
\end{tikzpicture}
\end{document}

在此处输入图片描述

答案4

这是我使用 LuaLaTeX 和 TikZ 制作的解决方案,没有使用任何白色填充,并使用了一些反向剪辑,因此任何背景颜色都会通过孔显示出来(参见第二张图片):

\documentclass[a4paper]{article}

\usepackage{luacode}
\usepackage{tikz}

\usetikzlibrary{calc}

% inverse clipping from: http://tex.stackexchange.com/a/59168/8844
\tikzset{
    invclip/.style={clip,%
        insert path={{[reset cm] %
            (-16383.99999pt,-16383.99999pt) rectangle (16383.99999pt,16383.99999pt)%
        }}
    }
}

\begin{luacode*}
    function draw_figure()

        tex.sprint([[\begin{tikzpicture}]])

        tex.sprint([[\begin{scope}[rotate=11.25] ]])
        tex.sprint([[\draw (2.25cm, 0.25cm) rectangle (4.75cm, -0.25cm)]])
        tex.sprint([[(2.75cm, 0) circle [radius=0.15cm] ]])
        tex.sprint([[(3.25cm, 0) circle [radius=0.15cm] ]])
        tex.sprint([[(3.75cm, 0) circle [radius=0.15cm] ]])
        tex.sprint([[(4.25cm, 0) circle [radius=0.15cm];]])
        tex.sprint([[\end{scope}]])

        -- inverse clipping from: http://tex.stackexchange.com/a/59168/8844
        tex.sprint([[\begin{pgfinterruptboundingbox}]])
        tex.sprint([[\path[invclip, rotate=11.25] (2.25cm, 0.25cm) rectangle (4.75cm, -0.25cm)]])
        tex.sprint([[(2.75cm, 0) circle [radius=0.15cm] ]])
        tex.sprint([[(3.25cm, 0) circle [radius=0.15cm] ]])
        tex.sprint([[(3.75cm, 0) circle [radius=0.15cm] ]])
        tex.sprint([[(4.25cm, 0) circle [radius=0.15cm];]])
        tex.sprint([[\end{pgfinterruptboundingbox}]])

        for radius = 2.5, 4.5, 0.5 do
            tex.sprint([[\draw (0,0) circle [radius=]])
            tex.sprint(radius)
            tex.sprint([[cm];]])
        end

        for angle = 0, 359, 22.5 do
            tex.sprint([[\draw[rotate=]])
            tex.sprint(angle)
            tex.sprint([[] (2.5cm, 0) -- (4.5cm, 0);]])
        end

        fillmatrix = {{0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0},
            {1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
            {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}}

        cols = #fillmatrix[1]
        rows = #fillmatrix

        offset = 2.5

        for i = 1, rows do

            angle = 0

            for j = 1, cols do
                if fillmatrix[i][j] == 1 then
                    tex.sprint([[\fill ($(0, 0) + (]])
                    tex.sprint(angle)
                    tex.sprint([[:]])
                    tex.sprint(offset)
                    tex.sprint([[cm)$) arc (]])
                    tex.sprint(angle)
                    tex.sprint([[:]])
                    tex.sprint(22.5 + angle)
                    tex.sprint([[:]])
                    tex.sprint(offset)
                    tex.sprint([[cm) -- ($(0, 0) + (]])
                    tex.sprint(22.5 + angle)
                    tex.sprint([[:]])
                    tex.sprint(offset + 0.5)
                    tex.sprint([[cm)$) arc (]])
                    tex.sprint(22.5 + angle)
                    tex.sprint([[:]])
                    tex.sprint(angle)
                    tex.sprint([[:]])
                    tex.sprint(offset + 0.5)
                    tex.sprint([[cm) -- cycle;]])
                end

                angle = angle + 22.5
            end

            offset = offset + 0.5
        end

        -- naive filling solution:
        -- for angle = 0, 359, 90 do
        --  tex.sprint([[\fill[rotate=]])
        --  tex.sprint(angle)
        --  tex.sprint([[] ($(0, 0) + (22.5:2.5cm)$) arc (22.5:67.5:2.5cm) -- ($(0, 0) + (67.5:3.0cm)$) arc (67.5:22.5:3.0cm) -- cycle;]])
        -- end
        -- for angle = 0, 359, 180 do
        --  tex.sprint([[\fill[rotate=]])
        --  tex.sprint(angle)
        --  tex.sprint([[] ($(0, 0) + (135:3.0cm)$) arc (135:225:3.0cm) -- ($(0, 0) + (225:3.5cm)$) arc (225:135:3.5cm) -- cycle;]])
        -- end
        -- tex.sprint([[\fill ($(0, 0) + (180:3.5cm)$) arc (180:360:3.5cm) -- ($(0, 0) + (360:4.0cm)$) arc (360:180:4.0cm) -- cycle;]])
        -- tex.sprint([[\fill ($(0, 0) + (90:4.0cm)$) arc (90:270:4.0cm) -- ($(0, 0) + (270:4.5cm)$) arc (270:90:4.5cm) -- cycle;]])

        tex.sprint([[\end{tikzpicture}]])
    end
\end{luacode*}

\begin{document}

\luadirect{draw_figure()}

\end{document}

我将其变成了一个参数化函数,您可以在其中设置图表的内半径、外半径(以厘米为单位)的值,并设置标尺的位置。以下代码包含一些示例,但我也在这里展示了其中的一些。

\documentclass[a4paper]{article}

\usepackage{luacode}
\usepackage{tikz}

\usetikzlibrary{calc}

% inverse clipping from: http://tex.stackexchange.com/a/59168/8844
\tikzset{
    invclip/.style={clip,%
        insert path={{[reset cm] %
            (-16383.99999pt,-16383.99999pt) rectangle (16383.99999pt,16383.99999pt)%
        }}
    }
}

\begin{luacode*}
    function draw_chart(fillmatrix, inner_radius, outer_radius, ruler_step)

        cols = #fillmatrix[1]
        rows = #fillmatrix

        angle_offset = 360 / cols

        radius_offset = (outer_radius - inner_radius) / rows

        tex.sprint([[\begin{tikzpicture}]])

        if ruler_step >= 1 and ruler_step <= cols then
            tex.sprint([[\begin{scope}[rotate=]])
            tex.sprint(angle_offset * ruler_step - angle_offset / 2)
            tex.sprint([[] ]])
            tex.sprint([[\draw (]])
            tex.sprint(inner_radius - radius_offset * 0.5)
            tex.sprint([[cm, ]])
            tex.sprint(radius_offset * 0.5)
            tex.sprint([[cm) rectangle (]])
            tex.sprint(outer_radius + radius_offset * 0.5)
            tex.sprint([[cm, ]])
            tex.sprint(radius_offset * -0.5)
            tex.sprint([[cm)]])
            for i = inner_radius, (outer_radius - radius_offset), radius_offset do
                tex.sprint([[(]])
                tex.sprint(i + radius_offset * 0.5)
                tex.sprint([[cm, 0) circle [radius=]])
                tex.sprint(radius_offset * 0.5 * 0.6)
                tex.sprint([[cm] ]])
            end
            tex.sprint([[;]])
            tex.sprint([[\end{scope}]])

            -- inverse clipping from: http://tex.stackexchange.com/a/59168/8844
            tex.sprint([[\begin{pgfinterruptboundingbox}]])
            tex.sprint([[\path[invclip, rotate=]])
            tex.sprint(angle_offset * ruler_step - angle_offset / 2)
            tex.sprint([[] (]])
            tex.sprint(inner_radius - radius_offset * 0.5)
            tex.sprint([[cm, ]])
            tex.sprint(radius_offset * 0.5)
            tex.sprint([[cm) rectangle (]])
            tex.sprint(outer_radius + radius_offset * 0.5)
            tex.sprint([[cm, ]])
            tex.sprint(radius_offset * -0.5)
            tex.sprint([[cm)]])
            for i = inner_radius, (outer_radius - radius_offset), radius_offset do
                tex.sprint([[(]])
                tex.sprint(i + radius_offset * 0.5)
                tex.sprint([[cm, 0) circle [radius=]])
                tex.sprint(radius_offset * 0.5 * 0.6)
                tex.sprint([[cm] ]])
            end
            tex.sprint([[;]])
            tex.sprint([[\end{pgfinterruptboundingbox}]])
        end

        for radius = inner_radius, outer_radius, radius_offset do
            tex.sprint([[\draw (0,0) circle [radius=]])
            tex.sprint(radius)
            tex.sprint([[cm];]])
        end

        for angle = 0, 359, angle_offset do
            tex.sprint([[\draw[rotate=]])
            tex.sprint(angle)
            tex.sprint([[] (]])
            tex.sprint(inner_radius)
            tex.sprint([[cm, 0) -- (]])
            tex.sprint(outer_radius)
            tex.sprint([[cm, 0);]])
        end

        radius = inner_radius

        for i = 1, rows do

            angle = 0

            for j = 1, cols do
                if fillmatrix[i][j] == 1 then
                    tex.sprint([[\fill ($(0, 0) + (]])
                    tex.sprint(angle)
                    tex.sprint([[:]])
                    tex.sprint(radius)
                    tex.sprint([[cm)$) arc (]])
                    tex.sprint(angle)
                    tex.sprint([[:]])
                    tex.sprint(angle + angle_offset)
                    tex.sprint([[:]])
                    tex.sprint(radius)
                    tex.sprint([[cm) -- ($(0, 0) + (]])
                    tex.sprint(angle + angle_offset)
                    tex.sprint([[:]])
                    tex.sprint(radius + radius_offset)
                    tex.sprint([[cm)$) arc (]])
                    tex.sprint(angle + angle_offset)
                    tex.sprint([[:]])
                    tex.sprint(angle)
                    tex.sprint([[:]])
                    tex.sprint(radius + radius_offset)
                    tex.sprint([[cm) -- cycle;]])
                end

                angle = angle + angle_offset
            end

            radius = radius + radius_offset
        end

        tex.sprint([[\end{tikzpicture}]])
    end
\end{luacode*}

\begin{document}

\setlength{\parindent}{0pt}

With this code you can set the inner and outer radius of the chart, and also set the position of the ruler.

inner radius = 2.5cm\\
outer radius = 4.5cm\\
ruler position = 1

\luadirect{
    fillmatrix = {{0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0},
        {1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1},
        {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
        {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}}

    draw_chart(fillmatrix, 2.5, 4.5, 1)
}

inner radius = 1cm\\
outer radius = 3cm\\
ruler position = 10

\luadirect{draw_chart(fillmatrix, 1, 3, 10)}

You can disable the ruler, by setting its position to zero.

inner radius = 0cm\\
outer radius = 2cm\\
ruler position = 0

\luadirect{
    fillmatrix = {{0, 0, 0, 0, 1, 1, 1, 1},
    {0, 0, 1, 1, 0, 0, 1, 1},
    {0, 1, 0, 1, 0, 1, 0, 1}}

    draw_chart(fillmatrix, 0, 2, 0)
}

You can also use this chart to visualize binary numbers. The third 3 bit binary number (binary 010 = octal 2 = decimal 2 = hexadecimal 2):

\luadirect{draw_chart(fillmatrix, 1, 2, 3)}

The sixteenth 4 bit binary number (binary 1111 = octal 17 = decimal 15 = hexadecimal F):

\luadirect{
    fillmatrix = {{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
        {0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1},
        {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1},
        {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}}

    draw_chart(fillmatrix, 2, 3, 16)
}

The sixth 5 bit binary number (00101):

\luadirect{
    fillmatrix = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
        {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
        {0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1},
        {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1},
        {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}}

    draw_chart(fillmatrix, 3, 6, 6)
}

\end{document}

左边

  • 内半径 = 1cm,外半径 = 3cm,标尺位置 = 10

正确的

  • 内半径 = 2.5cm,外半径 = 4.5cm,标尺位置 = 1

您还可以使用此图表来可视化二进制数。

左边:

  • 第三个 3 位二进制数(二进制 010 = 八进制 2 = 十进制 2 = 十六进制 2)
  • 内半径 = 1cm,外半径 = 2cm,标尺位置 = 3

正确的:

  • 第十六个 4 位二进制数(二进制 1111 = 八进制 17 = 十进制 15 = 十六进制 F)
  • 内半径 = 2cm,外半径 = 3cm,标尺位置 = 16

相关内容