我正在尝试编写一个命令来使用 Tikz 绘制一个循环图,基本上是一个多边形。该命令的参数是顶点数 #1 和图形半径 #2。
我最初的想法是先绘制 #1 节点,给它们命名,然后用边将它们连接起来。代码如下
\newcommand{\cyclegraph}[2]{\begin{tikzpicture}
\foreach \n in {1,...,#1}{
\node[circle,fill=black] (n\n) at ({\n*360/#1}:#2cm) {};
}
\foreach \n in {1,...,#1-1}{
\draw (n\n) -- (n{1+\n})
}
\draw (n#1) -- (n1);
\end{tikzpicture}}
不幸的是,\foreach 循环中的代码不起作用。错误消息为“Package pgf Error: No shape named n{1+1} is known. \cyclegraph{7}{2}”、“Package pgf Error: No shape named n{1+2} is known. \cyclegraph{7}{2}”等。显然,这是节点命名的问题。有办法解决这个问题吗?
当然,我可以将代码重写为
\newcommand{\cyclegraph}[2]{\begin{tikzpicture}
\foreach \n in {1,...,#1}{
\node[circle,fill=black] (n\n) at ({\n*360/#1}:#2cm) {};
}
\foreach \n in {1,...,#1-1}{
\draw ({\n*360/#1}:#2cm) -- ({(1+\n)*360/#1}:#2cm);
}
\draw ({0}:#2cm) -- ({360/#1}:#2cm);
\end{tikzpicture}}
但我认为使用节点名称会更简洁。此外,这对以后的图形也很有用。有什么想法吗?
答案1
这是一个解决方案:
\documentclass[tikz]{standalone}
\newcommand{\cyclegraph}[2]{%
\begin{tikzpicture}
\foreach \n in {1,...,#1}{
\node[circle,fill=black] (n\n) at ({\n*360/#1}:#2cm) {};
}
\foreach \n[evaluate={\n as \nnext using int(mod(\n,#1)+1)}] in {1,...,#1}{
\draw (n\n) -- (n\nnext);
}
\end{tikzpicture}%
}
\begin{document}
\cyclegraph{7}{2}
\end{document}
答案2
我有与此非常相似的代码。您可以根据自己的用例进行修改,生成以下代码:
使用代码:
\documentclass{article}
\usepackage{tikz}
\newcommand\CycleGraph[2][1]{%
\begin{tikzpicture}
\foreach \pt [evaluate=\pt as \ang using {90+(\pt-1)*360/#2}] in {1,...,#2}
{
\node[circle,fill=black] (\pt) at (\ang:#1) {};
}
\foreach \pt [remember=\pt as \Pt (initially #2)] in {1,...,#2}
{
\draw (\pt)--(\Pt);
}
\end{tikzpicture}
}
\begin{document}
\CycleGraph[0.5]{3}
\CycleGraph{4}
\end{document}
请注意,我已经定义了\CycleGraph
一个可选参数,给出循环的半径,以及一个强制参数,给出点的数量。
实际上,我发现这些想法的以下变体更有用:我定义一个命令\EdgeGraph
,将顶点数以及以逗号分隔的边列表作为参数。例如,\EdgeGraph{4}{1/2,2/3,3/4,4/1}
并\EdgeGraph{4}{1/2,2/3,3/4,4/1,1/3}
产生:
代码如下\EdgeGraph
:
\documentclass{article}
\usepackage{tikz}
\newcommand\EdgeGraph[3][1]{%
\begin{tikzpicture}
\foreach \pt [evaluate=\pt as \ang using {90+(\pt-1)*360/#2}] in {1,...,#2}
{
\node[circle,fill=black] (\pt) at (\ang:#1) {};
}
\foreach \x/\y in {#3} {
\draw (\x)--(\y);
}
\end{tikzpicture}%
}
\begin{document}
\EdgeGraph{4}{1/2, 2/3, 3/4, 4/1}
\EdgeGraph{4}{1/2, 2/3, 3/4, 4/1, 1/3}
\end{document}
我通常也有标记顶点的选项,但也许我现在太忘乎所以了!
答案3
问题是由你的第二个\foreach
\foreach \n in {1,...,#1-1}{
\draw (n\n) -- (n{1+\n})
}
首先,缺少一个分号。其次,节点名称不支持计算(n{1+\n})
。这只会给出节点名称(n{1+1})
、、(n{1+2})
... 并引发错误。
除了更通用的选项evaluate
用于@PaulGaborit 的回答,这里我使用另一个选项remember
(记录在 pgfmanual 3.1.5b 末尾,第 89 节)将\n
上一次迭代中的值存储在 中\xn
。在第一次迭代中,没有“上一次”,因此我将其初始化\xn
为 1。我还将迭代列表更改为2, ..., #2
。
\documentclass{article}
\usepackage{tikz}
\newcommand{\cyclegraph}[2]{%
\begin{tikzpicture}
\foreach \n in {1,...,#1}{
\node[circle,fill=black] (n\n) at ({\n*360/#1}:#2cm) {};
}
\foreach \n[remember=\n as \xn(initially 1)] in {2,...,#1}{
\draw (n\xn) -- (n\n);
}
\draw (n#1) -- (n1);
\end{tikzpicture}%
}
\begin{document}
\cyclegraph{3}{2}
\end{document}
另外,发布完整的示例(也称为平均能量损失) 而不是完整的宏定义总是更好的。