使用 PSTricks (或 TikZ) 绘制多边形数字

使用 PSTricks (或 TikZ) 绘制多边形数字

我想用 PSTricks (或 Ti韓國語:

多边形数

(发现于http://i1.wp.com/mathandmultimedia.com/wp-content/uploads/2012/08/polygonal-numbers.png

我可以使用极低技术的解决方案自己完成此操作,其中我手动绘制每个蓝点和黄点,但我不知道如何“自动”完成此操作。

PS:抱歉我没有亲自尝试一下;我真的不知道从哪里开始(除了可能必须涉及到\multidos 这一事实)。

更新

我也想要一个三角形数字的表示。

更新 2

考虑以下代码(来自 Qrrbrbirlbel):

\documentclass{article}

\usepackage[margin=2.4cm]{geometry}
\usepackage{tikz}

\pgfkeys{%
  /handlers/.tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.code=\tikzset{#1}},%
  /handlers/.append tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.append code=\tikzset{#1}},%
  /handlers/.prefix tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.prefix code=\tikzset{#1}}
}
\def\polynumset{\pgfqkeys{/polynum}}
\polynumset{
  sides/.initial=4,
  levels/.initial=5,
  side length/.initial=+0.5cm,
  %
  every node/.tikz={shape=circle,draw,inner sep=+0pt,minimum size=+4pt},
  center node/.tikz={fill=red},
  level nodes/.tikz={fill=blue},
  sublevel nodes/.tikz={fill=yellow},
  %
  every edge/.tikz={draw},
  %
  every corner edge/.code={
    \ifnum\polynumcorner>1\relax
      \ifnum\polynumcorner<\polynumcorners\relax
        \tikzset{draw=none}
      \fi
    \fi
  }
}
\makeatletter
\def\polynumutil@firstofone#1{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@firstoftwo#1#2{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@secondoftwo#1#2{\tikz@scan@next@command#2\pgf@stop}
\tikzset{
  polynum/.default=,
  polynum/.style={
    insert path={
      node[/polynum/every node/.try, /polynum/inner nodes/.try, /polynum/center node/.try] (pn@0@1@0) {}
      { [/polynum/.cd,#1]
        [/utils/exec=%
          \pgfmathtruncatemacro\polynumcorners{\pgfkeysvalueof{/polynum/sides}-1}%
          \pgfmathtruncatemacro\polynum@levels{\pgfkeysvalueof{/polynum/levels}}%
          \pgfmathsetlengthmacro\polynum@sidelength{\pgfkeysvalueof{/polynum/side length}}%
          \pgfmathsetmacro\polynum@angle{360/(\the\numexpr\polynumcorners+1\relax)}%
        ]
        \foreach \polynumcorner[evaluate={\polynum@@angle={(\polynumcorner-1)*\polynum@angle}}] in {1,...,\polynumcorners} {
          % get to the next corner,
          % level 1
          ++ (\polynum@@angle:\polynum@sidelength)
            node[/polynum/every node/.try, /polynum/level nodes/.try, /polynum/level 1 nodes/.try] (pn@\polynumcorner @1@0) {}
          % last level
          [/utils/exec={%
            \ifnum\polynumcorner=1\relax
              \expandafter\polynumutil@firstoftwo
            \else
              \expandafter\polynumutil@secondoftwo
            \fi
              {+(\polynum@@angle:\the\numexpr\polynum@levels-1\relax*\polynum@sidelength)}
              {   (pn@\the\numexpr\polynumcorner-1\relax @\polynum@levels @0.center)
               ++ (\polynum@@angle:\polynum@levels*\polynum@sidelength)}}]
          % it's only a coordinate because it is used to place everything else
          % including the node at the exact same position
          node[shape=coordinate, alias=pn@\polynumcorner @last] (pn@\polynumcorner @\polynum@levels @0) {}
          % all other levels
          \foreach \polynumlevel[count=\polynum@level from 1, evaluate={\polynum@pos=\polynum@level/\the\numexpr\polynum@levels-1\relax}] in {2,...,\polynum@levels} {
            (pn@\polynumcorner @[email protected])
              edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/level nodes/.try, style/.expanded={/polynum/level \polynumlevel\space nodes/.try}] (pn@\polynumcorner @\polynumlevel @0) {}
            (pn@\polynumcorner @last.center)
            % the edges between the corner nodes (blue -- blue)
            (pn@\polynumcorner @\the\numexpr\polynumlevel-1\relax @0) edge[/polynum/every edge/.try, /polynum/every corner edge/.try] (pn@\polynumcorner @\polynumlevel @0)
            % now the sublevels (except for the first corner because it has no previous corner)
            [/utils/exec={%
              \ifnum\polynumcorner>1\relax
                \expandafter\polynumutil@firstofone
              \else
                \expandafter\pgfutil@gobble
              \fi
              {\foreach \polynumsublevel[evaluate={\polynum@pos=\polynumsublevel/\polynumlevel}] in {1,...,\the\numexpr\polynumlevel-1\relax}{
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @0.center)
                   edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/sublevel nodes/.try, style/.expanded={/polynum/sublevel \polynumsublevel\space nodes/.try}] (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel) {}
                 (pn@\polynumcorner @\polynumlevel @0.center)
                 % the edges between sublevel nodes (blue -- yellow and yellow -- yellow)
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumsublevel-1\relax)
                   edge[/polynum/every edge/.try]
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel)
               }
               % the edge between the last sublevel node and the next corner node (yellow -- blue)
               (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumlevel-1\relax)
                 edge[/polynum/every edge/.try]
               (pn@\polynumcorner @\polynumlevel @0)
              }}]
          }
          % the edges between corner nodes (level 1, the smallest polygon: red -- blue and blue -- blue)
           (pn@\the\numexpr\polynumcorner-1\relax @1@0) edge[/polynum/every edge/.try] (pn@\polynumcorner @1@0)
           (pn@\polynumcorner @[email protected])
        }
        % the last edge (blue -- red)
        (pn@\polynumcorners @1@0) edge[/polynum/every edge/.try] (pn@0@1@0)
      }
    }
  }
}
\makeatother

\newcommand*\polygonnumbers[1]{%
\foreach \sides in {3,...,#1}{%
\begin{tikzpicture}
\path [polynum={/tikz/rotate=360/\sides/2,sides=\sides}];
\foreach \corner in {1,...,\the\numexpr\sides-1\relax}{%
  \pgfmathanglebetweenpoints{\pgfpointanchor{pn@\corner@1@0}{center}}
                            {\pgfpointanchor{pn@\corner@\pgfkeysvalueof{/polynum/levels}@0}{center}}
  \let\angle\pgfmathresult
  \draw[
    blue,
    rotate=\angle,
    rounded corners=1pt,
    thick] (pn@\corner@1@0.\angle+180) ++ (left:2pt) coordinate (@aux)
                                         -- ++ (up:4pt)
                                         -| ([shift=(right:2pt)] pn@\corner@\pgfkeysvalueof{/polynum/levels}@0.\angle)
                                         |- ([shift=(down:4pt)] @aux)
                                         -- cycle
                                        ;
}
\end{tikzpicture}
}
}

\begin{document}

\begin{figure}[htbp]
  \centering
    \polygonnumbers{6}
\end{figure}

\end{document}

如何创建一个\polygonnumbers带有两个参数#1 = <number of dots in each row>和的命令#2 = <maximal n-gon>?(现在,我只有一个带有单个参数#1 = <maximal n-gon>的命令。)

更新 3

不幸的是,如果我在以下代码中更改\polygonnumbers{5}{6}为,我会收到错误:\polygonnumbers{4}{6}

\documentclass{article}

\usepackage[margin=2.4cm]{geometry}
\usepackage{tikz}

\pgfkeys{%
  /handlers/.tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.code=\tikzset{#1}},%
  /handlers/.append tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.append code=\tikzset{#1}},%
  /handlers/.prefix tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.prefix code=\tikzset{#1}}
}
\def\polynumset{\pgfqkeys{/polynum}}
\polynumset{
  sides/.initial=4,
  levels/.initial=5,
  side length/.initial=+0.5cm,
  %
  every node/.tikz={shape=circle,draw,inner sep=+0pt,minimum size=+4pt},
  center node/.tikz={fill=red},
  level nodes/.tikz={fill=blue},
  sublevel nodes/.tikz={fill=yellow},
  %
  every edge/.tikz={draw},
  %
  every corner edge/.code={
    \ifnum\polynumcorner>1\relax
      \ifnum\polynumcorner<\polynumcorners\relax
        \tikzset{draw=none}
      \fi
    \fi
  }
}
\makeatletter
\def\polynumutil@firstofone#1{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@firstoftwo#1#2{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@secondoftwo#1#2{\tikz@scan@next@command#2\pgf@stop}
\tikzset{
  polynum/.default=,
  polynum/.style={
    insert path={
      node[/polynum/every node/.try, /polynum/inner nodes/.try, /polynum/center node/.try] (pn@0@1@0) {}
      { [/polynum/.cd,#1]
        [/utils/exec=%
          \pgfmathtruncatemacro\polynumcorners{\pgfkeysvalueof{/polynum/sides}-1}%
          \pgfmathtruncatemacro\polynum@levels{\pgfkeysvalueof{/polynum/levels}}%
          \pgfmathsetlengthmacro\polynum@sidelength{\pgfkeysvalueof{/polynum/side length}}%
          \pgfmathsetmacro\polynum@angle{360/(\the\numexpr\polynumcorners+1\relax)}%
        ]
        \foreach \polynumcorner[evaluate={\polynum@@angle={(\polynumcorner-1)*\polynum@angle}}] in {1,...,\polynumcorners} {
          % get to the next corner,
          % level 1
          ++ (\polynum@@angle:\polynum@sidelength)
            node[/polynum/every node/.try, /polynum/level nodes/.try, /polynum/level 1 nodes/.try] (pn@\polynumcorner @1@0) {}
          % last level
          [/utils/exec={%
            \ifnum\polynumcorner=1\relax
              \expandafter\polynumutil@firstoftwo
            \else
              \expandafter\polynumutil@secondoftwo
            \fi
              {+(\polynum@@angle:\the\numexpr\polynum@levels-1\relax*\polynum@sidelength)}
              {   (pn@\the\numexpr\polynumcorner-1\relax @\polynum@levels @0.center)
               ++ (\polynum@@angle:\polynum@levels*\polynum@sidelength)}}]
          % it's only a coordinate because it is used to place everything else
          % including the node at the exact same position
          node[shape=coordinate, alias=pn@\polynumcorner @last] (pn@\polynumcorner @\polynum@levels @0) {}
          % all other levels
          \foreach \polynumlevel[count=\polynum@level from 1, evaluate={\polynum@pos=\polynum@level/\the\numexpr\polynum@levels-1\relax}] in {2,...,\polynum@levels} {
            (pn@\polynumcorner @[email protected])
              edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/level nodes/.try, style/.expanded={/polynum/level \polynumlevel\space nodes/.try}] (pn@\polynumcorner @\polynumlevel @0) {}
            (pn@\polynumcorner @last.center)
            % the edges between the corner nodes (blue -- blue)
            (pn@\polynumcorner @\the\numexpr\polynumlevel-1\relax @0) edge[/polynum/every edge/.try, /polynum/every corner edge/.try] (pn@\polynumcorner @\polynumlevel @0)
            % now the sublevels (except for the first corner because it has no previous corner)
            [/utils/exec={%
              \ifnum\polynumcorner>1\relax
                \expandafter\polynumutil@firstofone
              \else
                \expandafter\pgfutil@gobble
              \fi
              {\foreach \polynumsublevel[evaluate={\polynum@pos=\polynumsublevel/\polynumlevel}] in {1,...,\the\numexpr\polynumlevel-1\relax}{
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @0.center)
                   edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/sublevel nodes/.try, style/.expanded={/polynum/sublevel \polynumsublevel\space nodes/.try}] (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel) {}
                 (pn@\polynumcorner @\polynumlevel @0.center)
                 % the edges between sublevel nodes (blue -- yellow and yellow -- yellow)
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumsublevel-1\relax)
                   edge[/polynum/every edge/.try]
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel)
               }
               % the edge between the last sublevel node and the next corner node (yellow -- blue)
               (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumlevel-1\relax)
                 edge[/polynum/every edge/.try]
               (pn@\polynumcorner @\polynumlevel @0)
              }}]
          }
          % the edges between corner nodes (level 1, the smallest polygon: red -- blue and blue -- blue)
           (pn@\the\numexpr\polynumcorner-1\relax @1@0) edge[/polynum/every edge/.try] (pn@\polynumcorner @1@0)
           (pn@\polynumcorner @[email protected])
        }
        % the last edge (blue -- red)
        (pn@\polynumcorners @1@0) edge[/polynum/every edge/.try] (pn@0@1@0)
      }
    }
  }
}
\makeatother

\newcommand*\polygonnumbers[2]{%
\foreach \sides in {3,...,#2}{%
\begin{tikzpicture}
\path [polynum={/tikz/rotate=360/\sides/2,levels=#1,sides=\sides}];
\foreach \corner in {1,...,\the\numexpr\sides-1\relax}{%
  \pgfmathanglebetweenpoints{\pgfpointanchor{pn@\corner@1@0}{center}}
                            {\pgfpointanchor{pn@\corner@\pgfkeysvalueof{/polynum/levels}@0}{center}}
  \let\angle\pgfmathresult
  \draw[
    blue,
    rotate=\angle,
    rounded corners=1pt,
    thick] (pn@\corner@1@0.\angle+180) ++ (left:2pt) coordinate (@aux)
                                         -- ++ (up:4pt)
                                         -| ([shift=(right:2pt)] pn@\corner@\pgfkeysvalueof{/polynum/levels}@0.\angle)
                                         |- ([shift=(down:4pt)] @aux)
                                         -- cycle
                                        ;
}
\end{tikzpicture}
}
}

\begin{document}

\begin{figure}[htbp]
  \centering
    \polygonnumbers{4}{6}
\end{figure}

\end{document}

错误是

! Package pgf Error: No shape named pn@1@5@0 is known.

See the pgf package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.134     \polygonnumbers{4}{6}

最终的

这是我最终得到的结果(经过另一次轻微的改进):

\documentclass{article}

\usepackage[margin=2cm]{geometry}
\usepackage[figureposition=bottom]{caption}
\usepackage{tikz}

\DeclareCaptionLabelSeparator{tilpasning}{:\quad}
\captionsetup{%
  font=small,
  labelfont=sc,
  labelsep=tilpasning,
  width=0.7\textwidth
}

\pgfkeys{%
  /handlers/.tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.code=\tikzset{#1}},
  /handlers/.append tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.append code=\tikzset{#1}},
  /handlers/.prefix tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.prefix code=\tikzset{#1}}
}
\def\polynumset{\pgfqkeys{/polynum}}
\newif\ifpolynumbars
\polynumset{%
  sides/.initial=4,
  levels/.initial=5,
  side length/.initial=+0.5cm,
  x padding/.initial=+2pt,
  y padding/.initial=+2pt,
  bars/.is if=polynumbars,
  every bar/.tikz={draw=blue, thick, rounded corners=+1pt},
  %
  every node/.tikz={shape=circle,draw,inner sep=+0pt,minimum size=+4pt},
  center node/.tikz={fill=red},
  level nodes/.tikz={fill=blue!60},
  sublevel nodes/.tikz={fill=yellow},
  %
  every edge/.tikz={},
  %
  every corner edge/.code={%
    \ifnum\polynumcorner>1\relax
      \ifnum\polynumcorner<\polynumcorners\relax
        \tikzset{draw=none}
      \fi
    \fi
  }
}
\makeatletter
\def\polynumutil@firstofone#1{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@firstoftwo#1#2{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@secondoftwo#1#2{\tikz@scan@next@command#2\pgf@stop}
\polynumset{%
  bar path/.style={%
    to path={%
      [/utils/exec=%
         \pgfmathanglebetweenpoints{\pgfpointanchor{\tikztostart} {center}}
                                   {\pgfpointanchor{\tikztotarget}{center}}
         \let\polynum@a\pgfmathresult
         \pgftransformrotate{\polynum@a}
         \pgfpointdiff{\pgfpointanchor{\tikztostart}{center}}
                      {\pgfpointshapeborder{\tikztostart}{\pgfpointadd{\pgfpointanchor{\tikztostart}{center}}{\pgfpointpolar{90}{1pt}}}}
         \pgfmathveclen{\pgf@x}{\pgf@y}
         \edef\polynum@ydistance{\pgfmathresult pt}
         \pgfcoordinate{pn@aux1}
                       {\pgfpointshapeborder
                         {\tikztostart}
                         {\pgfpointadd{\pgfpointanchor{\tikztostart}{center}}
                                      {\pgfpointpolar{180}{1pt}}}}
         \pgfcoordinate{pn@aux2}
                       {\pgfpointshapeborder
                         {\tikztotarget}
                         {\pgfpointadd{\pgfpointanchor{\tikztotarget}{center}}
                                      {\pgfpointpolar{0}{1pt}}}}
       ]
             ([shift=(left:\pgfkeysvalueof{/polynum/x padding})]pn@aux1) coordinate (pn@aux)
       -- ++ (up:\polynum@ydistance+\pgfkeysvalueof{/polynum/y padding})
       -|    ([shift=(right:\pgfkeysvalueof{/polynum/x padding})] pn@aux2)
       |-    ([shift=(down:\polynum@ydistance+\pgfkeysvalueof{/polynum/y padding})] pn@aux)
       -- cycle
    }
  }}
\tikzset{%
  polynum/.default=,
  polynum/.style={%
    insert path={%
      node[/polynum/every node/.try, /polynum/inner nodes/.try, /polynum/center node/.try] (pn@0@1@0) {}
      { [/polynum/.cd,#1]
        [/utils/exec=%
          \pgfmathtruncatemacro\polynumcorners{\pgfkeysvalueof{/polynum/sides}-1}
          \pgfmathtruncatemacro\polynum@levels{\pgfkeysvalueof{/polynum/levels}-1}
          \pgfmathsetlengthmacro\polynum@sidelength{\pgfkeysvalueof{/polynum/side length}}
          \pgfmathsetmacro\polynum@angle{360/(\the\numexpr\polynumcorners+1\relax)}
        ]
        \foreach \polynumcorner[evaluate={\polynum@@angle={(\polynumcorner-1)*\polynum@angle}}] in {1,...,\polynumcorners} {%
          % Get to the next corner;
          % level 1
          ++ (\polynum@@angle:\polynum@sidelength)
            node[/polynum/every node/.try, /polynum/level nodes/.try, /polynum/level 1 nodes/.try] (pn@\polynumcorner @1@0) {}
          % last level.
          [/utils/exec={%
            \ifnum\polynumcorner=1\relax
              \expandafter\polynumutil@firstoftwo
            \else
              \expandafter\polynumutil@secondoftwo
            \fi
              {+(\polynum@@angle:\the\numexpr\polynum@levels-1\relax*\polynum@sidelength)}
              {   (pn@\the\numexpr\polynumcorner-1\relax @\polynum@levels @0.center)
               ++ (\polynum@@angle:\polynum@levels*\polynum@sidelength)}}]
          % It is only a coordinate because it is used to place everything else,
          % including the node at the exact same position.
          node[shape=coordinate, alias=pn@\polynumcorner @last] (pn@\polynumcorner @\polynum@levels @0) {}
          % All other levels
          \foreach \polynumlevel[count=\polynum@level from 1, evaluate={\polynum@pos=\polynum@level/\the\numexpr\polynum@levels-1\relax}] in {2,...,\polynum@levels} {%
            (pn@\polynumcorner @[email protected])
              edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/level nodes/.try, style/.expanded={/polynum/level \polynumlevel\space nodes/.try}] (pn@\polynumcorner @\polynumlevel @0) {}
            (pn@\polynumcorner @last.center)
            % The edges between the corner nodes (blue -- blue).
            (pn@\polynumcorner @\the\numexpr\polynumlevel-1\relax @0) edge[/polynum/every edge/.try, /polynum/every corner edge/.try] (pn@\polynumcorner @\polynumlevel @0)
            % Now the sublevels (except for the first corner because it has no previous corner).
            [/utils/exec={%
              \ifnum\polynumcorner>1\relax
                \expandafter\polynumutil@firstofone
              \else
                \expandafter\pgfutil@gobble
              \fi
              {\foreach \polynumsublevel[evaluate={\polynum@pos=\polynumsublevel/\polynumlevel}] in {1,...,\the\numexpr\polynumlevel-1\relax}{%
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @0.center)
                   edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/sublevel nodes/.try, style/.expanded={/polynum/sublevel \polynumsublevel\space nodes/.try}] (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel) {}
                 (pn@\polynumcorner @\polynumlevel @0.center)
                 % The edges between sublevel nodes (blue -- yellow and yellow -- yellow).
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumsublevel-1\relax)
                   edge[/polynum/every edge/.try]
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel)
               }
               % The edge between the last sublevel node and the next corner node (yellow -- blue).
               (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumlevel-1\relax)
                 edge[/polynum/every edge/.try]
               (pn@\polynumcorner @\polynumlevel @0)
              }}]
          }
          % The edges between corner nodes (level 1, the smallest polygon: red -- blue and blue -- blue).
           (pn@\the\numexpr\polynumcorner-1\relax @1@0) edge[/polynum/every edge/.try] (pn@\polynumcorner @1@0)
           (pn@\polynumcorner @[email protected])
        }
        % The last edge (blue -- red).
        (pn@\polynumcorners @1@0) edge[/polynum/every edge/.try] (pn@0@1@0)
        % The bars are drawn in an extra loop to make sure they are on top.
        [/utils/exec=%
          \ifpolynumbars\expandafter\polynumutil@firstofone\else\expandafter\pgfutil@gobble\fi
            {\foreach \polynumcorner in {1,...,\polynumcorners} {%
            (pn@\polynumcorner @1@0) edge[/polynum/bar path/.try, /polynum/every bar/.try] (pn@\polynumcorner @\polynum@levels @0)}}
        ]
      }
    }
  }
}
\makeatother
\polynumset{bars}
\newcommand*\polynum[4][1]{%
  \foreach \sides in {#3,...,#4}{%
    \begin{tikzpicture}[scale=#1,/polynum/levels=#2]
      \path [/tikz/rotate=360/\sides/2,polynum={sides=\sides}];
    \end{tikzpicture}
  }
 \caption{Illustration of the polygonal numbers~$f_{#3}(#2)$--$f_{#4}(#2)$.}
}

\pagestyle{empty}

\begin{document}

\begin{figure}[htbp]
 \centering
  \polynum[1.5]{5}{3}{8}
\end{figure}

\end{document}

答案1

这是使用 TikZ 的解决方案。

有几个可以改变图形参数的键:

  • sides:多边形的边数/角数;
  • level:多边形的重复次数;
  • side length:多边形一边的长度;
  • 对于“酒吧”:
    • x padding
    • y padding
    • bars可用于关闭/打开条形图绘制的开关。

多边形是用 绘制的,center node位于您使用 键的当前路径所在的位置polynum。可以通过旋转路径来旋转“多边形”。如果您将路径旋转 ,多边形将位于其中心角360/<corners>/2

绘制条形图时会考虑主动旋转(这就是 的原因\pgfpointshapeborder),这样就可以按原样包含节点,而无需旋转它们或使用transform shape。但是,如果节点大小不相同,条形图绘制算法将产生不良结果。

  • \polynumcorner
  • \polynumlevel
  • \polynumsublevel
  • \polynumcorners(即角球总数)

可用于影响样式,这在every corner edge样式(实际上是一个.code键)中使用,可以明确关闭某些角节点之间的边的绘制。

节点名为:pn@<corner>@<level>@<sublevel>。红色中心节点名为pn@0@1@0,它是唯一的第 0 个角节点。

代码

\documentclass[tikz,png={size=315,density=600},convert=false]{standalone}
\pgfkeys{% http://tex.stackexchange.com/a/125700/16595
  /handlers/.tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.code=\tikzset{#1}},%
  /handlers/.append tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.append code=\tikzset{#1}},%
  /handlers/.prefix tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.prefix code=\tikzset{#1}}}
\def\polynumset{\pgfqkeys{/polynum}}
\newif\ifpolynumbars
\polynumset{
  sides/.initial=4,
  levels/.initial=5,
  side length/.initial=+.5cm,
  x padding/.initial=+2pt,
  y padding/.initial=+2pt,
  bars/.is if=polynumbars,
  every bar/.tikz={draw=blue, thick, rounded corners=+1pt},
  %
  every node/.tikz={shape=circle,draw,inner sep=+0pt,minimum size=+4pt},
  center node/.tikz={fill=red},
  level nodes/.tikz={fill=blue},
  sublevel nodes/.tikz={fill=yellow},
  %
  every edge/.tikz={},
  %
  every corner edge/.code={
    \ifnum\polynumcorner>1\relax
      \ifnum\polynumcorner<\polynumcorners\relax
        \tikzset{draw=none}
      \fi
    \fi
  },
}
\makeatletter
\def\polynumutil@firstofone#1{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@firstoftwo#1#2{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@secondoftwo#1#2{\tikz@scan@next@command#2\pgf@stop}
\polynumset{
  bar path/.style={
    to path={
      [/utils/exec=%
         \pgfmathanglebetweenpoints{\pgfpointanchor{\tikztostart} {center}}
                                   {\pgfpointanchor{\tikztotarget}{center}}%
         \let\polynum@a\pgfmathresult
         \pgftransformrotate{\polynum@a}%
         \pgfpointdiff{\pgfpointanchor{\tikztostart}{center}}
                      {\pgfpointshapeborder{\tikztostart}{\pgfpointadd{\pgfpointanchor{\tikztostart}{center}}{\pgfpointpolar{90}{1pt}}}}%
         \pgfmathveclen{\pgf@x}{\pgf@y}%
         \edef\polynum@ydistance{\pgfmathresult pt}%
         \pgfcoordinate{pn@aux1}
                       {\pgfpointshapeborder
                         {\tikztostart}
                         {\pgfpointadd{\pgfpointanchor{\tikztostart}{center}}
                                      {\pgfpointpolar{180}{1pt}}}}%
         \pgfcoordinate{pn@aux2}
                       {\pgfpointshapeborder
                         {\tikztotarget}
                         {\pgfpointadd{\pgfpointanchor{\tikztotarget}{center}}
                                      {\pgfpointpolar{0}{1pt}}}}%
       ]
             ([shift=(left:\pgfkeysvalueof{/polynum/x padding})]pn@aux1) coordinate (pn@aux)
       -- ++ (up:\polynum@ydistance+\pgfkeysvalueof{/polynum/y padding})
       -|    ([shift=(right:\pgfkeysvalueof{/polynum/x padding})] pn@aux2)
       |-    ([shift=(down:\polynum@ydistance+\pgfkeysvalueof{/polynum/y padding})] pn@aux)
       -- cycle
    }
  }}
\tikzset{
  polynum/.default=,
  polynum/.style={
    insert path={
      node[/polynum/every node/.try, /polynum/inner nodes/.try, /polynum/center node/.try] (pn@0@1@0) {}
      { [/polynum/.cd,#1]
        [/utils/exec=%
          \pgfmathtruncatemacro\polynumcorners{\pgfkeysvalueof{/polynum/sides}-1}%
          \pgfmathtruncatemacro\polynum@levels{\pgfkeysvalueof{/polynum/levels}}%
          \pgfmathsetlengthmacro\polynum@sidelength{\pgfkeysvalueof{/polynum/side length}}%
          \pgfmathsetmacro\polynum@angle{360/(\the\numexpr\polynumcorners+1\relax)}%
        ]
        \foreach \polynumcorner[evaluate={\polynum@@angle={(\polynumcorner-1)*\polynum@angle}}] in {1,...,\polynumcorners} {
          % get to the next corner,
          % level 1
          ++ (\polynum@@angle:\polynum@sidelength)
            node[/polynum/every node/.try, /polynum/level nodes/.try, /polynum/level 1 nodes/.try] (pn@\polynumcorner @1@0) {}
          % last level
          [/utils/exec={%
            \ifnum\polynumcorner=1\relax
              \expandafter\polynumutil@firstoftwo
            \else
              \expandafter\polynumutil@secondoftwo
            \fi
              {+(\polynum@@angle:\the\numexpr\polynum@levels-1\relax*\polynum@sidelength)}
              {   (pn@\the\numexpr\polynumcorner-1\relax @\polynum@levels @0.center)
               ++ (\polynum@@angle:\polynum@levels*\polynum@sidelength)}}]
          % it's only a coordinate because it is used to place everything else
          % including the node at the exact same position
          node[shape=coordinate, alias=pn@\polynumcorner @last] (pn@\polynumcorner @\polynum@levels @0) {}
          % all other levels
          \foreach \polynumlevel[count=\polynum@level from 1, evaluate={\polynum@pos=\polynum@level/\the\numexpr\polynum@levels-1\relax}] in {2,...,\polynum@levels} {
            (pn@\polynumcorner @[email protected])
              edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/level nodes/.try, style/.expanded={/polynum/level \polynumlevel\space nodes/.try}] (pn@\polynumcorner @\polynumlevel @0) {}
            (pn@\polynumcorner @last.center)
            % the edges between the corner nodes (blue -- blue)
            (pn@\polynumcorner @\the\numexpr\polynumlevel-1\relax @0) edge[/polynum/every edge/.try, /polynum/every corner edge/.try] (pn@\polynumcorner @\polynumlevel @0)
            % now the sublevels (except for the first corner because it has no previous corner)
            [/utils/exec={%
              \ifnum\polynumcorner>1\relax
                \expandafter\polynumutil@firstofone
              \else
                \expandafter\pgfutil@gobble
              \fi
              {\foreach \polynumsublevel[evaluate={\polynum@pos=\polynumsublevel/\polynumlevel}] in {1,...,\the\numexpr\polynumlevel-1\relax}{
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @0.center)
                   edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/sublevel nodes/.try, style/.expanded={/polynum/sublevel \polynumsublevel\space nodes/.try}] (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel) {}
                 (pn@\polynumcorner @\polynumlevel @0.center)
                 % the edges between sublevel nodes (blue -- yellow and yellow -- yellow)
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumsublevel-1\relax)
                   edge[/polynum/every edge/.try]
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel)
               }
               % the edge between the last sublevel node and the next corner node (yellow -- blue)
               (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumlevel-1\relax)
                 edge[/polynum/every edge/.try]
               (pn@\polynumcorner @\polynumlevel @0)
              }}]
          }
          % the edges between corner nodes (level 1, the smallest polygon: red -- blue and blue -- blue)
           (pn@\the\numexpr\polynumcorner-1\relax @1@0) edge[/polynum/every edge/.try] (pn@\polynumcorner @1@0)
           (pn@\polynumcorner @[email protected])
        }
        % the last edge (blue -- red)
        (pn@\polynumcorners @1@0) edge[/polynum/every edge/.try] (pn@0@1@0)
        % the bars are drawn in an extra loop to make sure they are on top
        [/utils/exec=%
          \ifpolynumbars\expandafter\polynumutil@firstofone\else\expandafter\pgfutil@gobble\fi
            {\foreach \polynumcorner in {1,...,\polynumcorners} {
            (pn@\polynumcorner @1@0) edge[/polynum/bar path/.try, /polynum/every bar/.try] (pn@\polynumcorner @\polynum@levels @0)}}
        ]
      }
    }
  }
}
\makeatother
\polynumset{bars}
\begin{document}
\foreach \sides in {3,...,6}{
\begin{tikzpicture}[/polynum/levels=3]
\path [polynum={/tikz/rotate=360/\sides/2,sides=\sides}];
\end{tikzpicture}}
\foreach \level in {2,...,5,5,4,3,2}{
\begin{tikzpicture}
\path [polynum={levels=\level}];
\useasboundingbox (-8pt,-8pt) rectangle (2.5cm+8pt,2.5cm+8pt);
\end{tikzpicture}}
\end{document}

输出

在此处输入图片描述在此处输入图片描述在此处输入图片描述在此处输入图片描述<code>sides=7</code> 的图片在此处输入图片描述

答案2

在此处输入图片描述

此解决方案基于 的面向对象特性Asymptote。基本结构struct PolygonalNumber在环境中定义asydef,稍后可在asy图片中用于创建和绘制此类对象。例如,一个名为 的三角形对象,P3其层数为 , PolygonalNumber P3=PolygonalNumber(3,5);命令draw(P3);将绘制它。 PolygonalNumber对象可以像往常一样进行变换,例如 draw(shift(6,0)*P4);绘制P4向右移动的对象。或者它们可以直接在命令中使用draw:生成上述图像的代码只是

size(400);
for(int i=3;i<=7;++i){
  draw(shift((i-3)*(5+i-3),0)*PolygonalNumber(i,5));
};

完整的 MWE polynum.tex

\documentclass{article}
\usepackage[inline]{asymptote}
\begin{asydef}
struct PolygonalNumber{
  int n,m;
  real unitStep;
  real boxW;
  transform t;
  pair O=(0,0);
  pair[][] dots;

  pen originPen=red;
  pen sideLinePen=darkblue;
  pen cornerDotPen=blue;
  pen sideDotPen=orange;
  pen boxPen=blue;

  void drawSides(){
    guide g; 
    pair center,p;
    pair[] skin;    
    for(int i=1;i<=m;++i){
      p=(i*unitStep,0);
      g=O;
      center=i*unitStep/2*(1,1/Tan(180/n));
      for(int j=0;j<n-1;++j){
        g=g--(rotate(j*360.0/n,center)*p);
      }
      g=g--cycle;
      draw(t*g,sideLinePen);
      skin=new pair[];      
      for(int j=0;j<size(g);++j){
        skin.push(point(g,j));  
      }
      dots.push(skin);
    }
  }

  void drawCornerDots(){
    for(int i=0;i<dots.length;++i){
      for(int j=1;j<dots[i].length;++j){
        dot(t*dots[i][j],cornerDotPen);
      }
    }
  }

  void drawSideDots(){
    pair p,q;
    real s;
    for(int i=1;i<dots.length;++i){
      for(int j=1;j<dots[i].length-1;++j){
        p=dots[i][j];
        q=dots[i][j+1];
        for(int k=1;k<i+1;++k){
          s=k/(i+1);
          dot(t*(p*(1-s)+q*s),sideDotPen);
        }  
      }
    }
  }

  void drawOriginDots(){
    for(int i=0;i<dots.length;++i){
      dot(t*O,originPen);      
    }    
  }

  guide buildBox(pair a, pair b){
    pair d,p,q,ds;
    d=dir(b-a);
    ds=boxW*d;
    p=a-ds; q=b+ds; 
    guide[] g=strokepath(p--q,red+boxW);
    return g[0];
  }

  void drawBoxes(){
    pair a,b;
    for(int j=1;j<n;++j){
      a=dots[0][j];
      b=dots[m-1][j];
      draw(t*buildBox(a,b),boxPen);      
    }
  }

  void draw(){
    drawSides();
    drawCornerDots();
    drawSideDots();
    drawOriginDots();
    drawBoxes();
  }

  void operator init(int n=3,int m=6,real unitStep=1,transform t=identity(),real boxW=0.4){
    assert(n>2 && m>0);
    this.n=n; this.m=m; 
    this.unitStep=unitStep;
    this.boxW=boxW;
    this.t=t;
  }
}
PolygonalNumber operator*(transform t=identity(),PolygonalNumber p){p.t=t; return p;}; 
void draw(PolygonalNumber p){p.draw();};
\end{asydef}

\begin{document}
\begin{figure}
\begin{asy}
size(400);
for(int i=3;i<=7;++i){
  draw(shift((i-3)*(5+i-3),0)*PolygonalNumber(i,5));
};
\end{asy}
\end{figure}
\end{document}

为了处理它latexmk,请创建文件latexmkrc

sub asy {return system("asy '$_[0]'");}
add_cus_dep("asy","eps",0,"asy");
add_cus_dep("asy","pdf",0,"asy");
add_cus_dep("asy","tex",0,"asy");

然后运行latexmk -pdf polynum.tex

答案3

我开始用这个,但后来就觉得无聊了 :) 总是很高兴能从 Jakencbar那里偷来TikZ 是否有与 PSTricks \ncbar 命令等效的命令?

\numofsides\numofiters定义多边形的形状以及重复的次数。我没有 Qrrbrbirlbel 的耐心。所以这只是为了好玩。

\documentclass[tikz,border=4mm]{standalone}
\usetikzlibrary{calc,shapes.geometric,backgrounds}
\begin{document}
\tikzset{
    ncbar angle/.initial=90,
    ncbar/.style={to path=(\tikztostart)--($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)
        -- ($(\tikztotarget)!($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztostart)$)
        -- (\tikztotarget)},
    ncbar/.default=0.5cm,
}
\begin{tikzpicture}[
bluedot/.style={circle,fill=blue,draw,inner sep=0,minimum size=3pt,anchor=center},
yellowdot/.style={bluedot,fill=yellow},
]
\def\numofsides{10} %Change these
\def\numofiters{10} %Change these
\foreach \x in {1,...,\numofiters}{
\begin{scope}[on background layer]\node[rotate={floor(\numofsides/2)*360/\numofsides}, 
      inner sep=0,anchor=corner 1,
      draw,minimum size=\x*8mm,
      blue,regular polygon,regular polygon sides=\numofsides] (n\x) {};\end{scope}
    \foreach \y[count=\yi,count=\yj from 0,remember=\y as \lasty] in {corner 2,corner 3,corner ...,corner \numofsides} {
    \node[bluedot,rotate={((1-(1-(2/\numofsides)))*90)*\yj-90}] (n\x c\yi) at (n\x.\y) {};
    \ifnum\x>1\ifnum\yi>1\foreach\z in{1,...,\numexpr\x-1\relax}{
        \node[yellowdot] at ($(n\x.\lasty)!\z/\x!(n\x.\y)$){};}\fi\fi
    }
}
\foreach \x[count=\xi from 0] in {1,...,\numexpr\numofsides-1}{
\pgfmathsetmacro\myangle{((1-(1-(2/\numofsides)))*90)*\xi+180}
\draw[rounded corners=1pt,blue] ([shift={(\myangle:1pt)}]n1c\x.south) to[ncbar=2pt] 
                           ([shift={(\myangle:-1pt)}]n\numofiters c\x.north) to[ncbar=2pt]
                           ([shift={(\myangle:1pt)}]n1c\x.south);
}

\end{tikzpicture}

\end{document}

真是可笑的画面

在此处输入图片描述

使用\def\numofsides{24}\def\numofiters{24}

输出

惊人的!:)

相关内容