我想用 PSTricks (或 Ti钾韓國語:
(发现于http://i1.wp.com/mathandmultimedia.com/wp-content/uploads/2012/08/polygonal-numbers.png。
我可以使用极低技术的解决方案自己完成此操作,其中我手动绘制每个蓝点和黄点,但我不知道如何“自动”完成此操作。
PS:抱歉我没有亲自尝试一下;我真的不知道从哪里开始(除了可能必须涉及到\multido
s 这一事实)。
更新
我也想要一个三角形数字的表示。
更新 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}
输出
答案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}
:
惊人的!:)