寻求帮助简化 TikZ Tonnetz

寻求帮助简化 TikZ Tonnetz

我创建了一个音调网络,Ti 中的一种音乐网络Z:

%LuaLaTeX
\documentclass{article}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}[xscale=1.5,yscale=2.5]
\footnotesize

\begin{scope}
\newcommand*\columns{7}
\newcommand*\rows{2}
\clip(0,0.5) rectangle (\columns,\rows);
\foreach \x in {0,0.5,1,...,\columns}
\foreach \y in {0,0.5,1,...,\rows}
\foreach \z in {-1.5,-0.5,...,\columns} 
{
    \draw (0,\y) -- (\columns,\y);
    \draw (\z,\rows) -- (\z+2,0);
    \draw (\z,0) -- (\z+2,\rows);
}
\end{scope}

\draw[fill=gray!50] (3.5,1) -- (4.5,1) -- (4,1.5) -- cycle;
\foreach \toprow/\topx in {E/0.5,B/1.5,F$\sharp$/2.5,C$\sharp$/3.5,G$\sharp$/4.5,D$\sharp$/5.5,A$\sharp$/6.5}
\foreach \secondrow/\secondx in {C/0,G/1,D/2,A/3,E/4,B/5,F$\sharp$/6,C$\sharp$/7}
\foreach \thirdrow/\thirdx in {E$\flat$/0.5,B$\flat$/1.5,F/2.5,C/3.5,G/4.5,D/5.5,A/6.5}
\foreach \fourthrow/\fourthx in {C$\flat$/0,G$\flat$/1,D$\flat$/2,A$\flat$/3,E$\flat$/4,B$\flat$/5,F/6,C/7}
%\foreach \bottomrow/\bottomx in {E$\flat\flat$/0.5,B$\flat\flat$/1.5,F$\flat$/2.5,C$\flat$/3.5,G$\flat$/4.5,D$\flat$/5.5,A$\flat$/6.5}
{
\node[draw,circle,minimum size=0.75cm,fill=white] at (\topx,2) {\toprow};
\node[draw,circle,minimum size=0.75cm,fill=white] at (\secondx,1.5) {\secondrow};
\node[draw,circle,minimum size=0.75cm,fill=white] at (\thirdx,1) {\strut \thirdrow};
\node[draw,circle,minimum size=0.75cm,fill=white] at (\fourthx,0.5) {\strut \fourthrow};
%\node[draw,circle,minimum size=0.75cm,fill=white] at (\bottomx,0) {\strut \bottomrow};
}

\end{tikzpicture}

\end{document}

在此处输入图片描述

如上所述,注释掉这两行后,输出是正确的。然而,非常编译速度很慢。(甚至 Inkscape 和 PDF 阅读器打开文件的速度也很慢!)当我取消注释这两行以创建底行时,什么也没有产生;有时我会得到“超出 TeX 容量”的错误,但其他时候编译时间太长,我只能放弃。

理想情况下,我会在本章(本身是一本更大的书的一部分)中列出四到五个这样的图表,因此这些编译时间是不现实的。有没有办法简化这个图表以帮助它更快地编译?

答案1

正如前面提到的,你的问题是你在做同样的事情许多次,因为你嵌套了循环。以绘制网格的循环为例。最内层循环(在 上\z)中的绘制指令在该循环的每次迭代中重复。但整个循环再次重复第二个循环(在 上\y)的每次迭代。并且该循环在最外层循环(在 上\x)的每次迭代中重复。因此,由于 x 循环中有 10 个步骤,z 循环中有 14 个步骤,因此您将绘制每条水平线 140 次。

节点也会发生同样的事情。每个连续循环都会在其所在循环的每次迭代中重复,因此当您达到 5 级深度时,每级有 7 或 8 次迭代,您最终会绘制每个节点超过 3000 次。

对于网格,你可以这样做:

\begin{scope}
\newcommand*\columns{7}
\newcommand*\rows{2}
\clip(0,-\pgflinewidth) rectangle (\columns,\rows);
\foreach \y in {0,0.5,1,...,\rows} 
  \draw (0,\y) -- (\columns,\y);

%the previous loop has ended, start a new:
\foreach \z in {-1.5,-0.5,...,\columns} 
{
    \draw (\z,\rows) -- (\z+2,0);
    \draw (\z,0) -- (\z+2,\rows);
}
\end{scope}

水平线画在一个循环中,对角线画在另一个循环中。

对于节点,您可以执行相同的操作,每行一个循环:

\foreach \toprow [count=\topx] in {E,B,F$\sharp$,C$\sharp$,G$\sharp$,D$\sharp$,A$\sharp$}
   \node[note] at (\topx-0.5,2) {\toprow};

\foreach \secondrow [count=\secondx from 0] in {C,G,D,A,E,B,F$\sharp$,C$\sharp$}
   \node[note] at (\secondx,1.5) {\secondrow};

\foreach \thirdrow[count=\thirdx] in {E$\flat$,B$\flat$,F,C,G,D,A}
   \node[note] at (\thirdx-0.5,1) {\strut \thirdrow};
   
\foreach \fourthrow[count=\fourthx from 0] in {C$\flat$,G$\flat$,D$\flat$,A$\flat$,E$\flat$,B$\flat$,F,C}
  \node[note] at (\fourthx,0.5) {\strut \fourthrow};

\foreach \bottomrow[count=\bottomx] in {E$\flat\flat$,B$\flat\flat$,F$\flat$,C$\flat$,G$\flat$,D$\flat$,A$\flat$}
  \node[note] at (\bottomx-0.5,0) {\strut \bottomrow};

即,您不是拥有 ,而是foreach x (foreach y (foreach z <do stuff x y and z> ) )拥有foreach x <do stuff x>,然后foreach y <do stuff y>等等。

上面我利用了count的功能\foreach,这样你就不必费心摆弄语法了a/b。你还可以迭代列表列表:

\foreach  \notelist [count=\row from 0] in {
  {E$\flat\flat$,B$\flat\flat$,F$\flat$,C$\flat$,G$\flat$,D$\flat$,A$\flat$},
  {C$\flat$,G$\flat$,D$\flat$,A$\flat$,E$\flat$,B$\flat$,F,C},
  {E$\flat$,B$\flat$,F,C,G,D,A},
  {C,G,D,A,E,B,F$\sharp$,C$\sharp$},
  {E,B,F$\sharp$,C$\sharp$,G$\sharp$,D$\sharp$,A$\sharp$}}
  \foreach \note [count=\column from 0,evaluate={\colX=\column+0.5-mod(\row,2)/2;}] in \notelist
     \node [note] at (\colX,\row*0.5) {\strut \note};

需要进行一些简单的计算才能获得正确的坐标。

完整代码,包含节点的两个变体:

在此处输入图片描述

\documentclass{article}
\usepackage{tikz}
\begin{document}

\begin{tikzpicture}[
  xscale=1.5,yscale=2.5981,
  note/.style={draw,circle,minimum size=0.75cm,fill=white},
  every node/.append style={font=\footnotesize}
  ]
%\footnotesize

\begin{scope}
\newcommand*\columns{7}
\newcommand*\rows{2}
\clip(0,-\pgflinewidth) rectangle (\columns,\rows);
\foreach \y in {0,0.5,1,...,\rows} 
  \draw (0,\y) -- (\columns,\y);
\foreach \z in {-1.5,-0.5,...,\columns} 
{
    \draw (\z,\rows) -- (\z+2,0);
    \draw (\z,0) -- (\z+2,\rows);
}
\end{scope}

\draw[fill=gray!50] (3.5,1) -- (4.5,1) -- (4,1.5) -- cycle;
%\foreach \toprow [count=\topx] in {E,B,F$\sharp$,C$\sharp$,G$\sharp$,D$\sharp$,A$\sharp$}
%   \node[note] at (\topx-0.5,2) {\toprow};
%
%\foreach \secondrow [count=\secondx from 0] in {C,G,D,A,E,B,F$\sharp$,C$\sharp$}
%   \node[note] at (\secondx,1.5) {\secondrow};
%
%\foreach \thirdrow[count=\thirdx] in {E$\flat$,B$\flat$,F,C,G,D,A}
%   \node[note] at (\thirdx-0.5,1) {\strut \thirdrow};
%   
%\foreach \fourthrow[count=\fourthx from 0] in {C$\flat$,G$\flat$,D$\flat$,A$\flat$,E$\flat$,B$\flat$,F,C}
%  \node[note] at (\fourthx,0.5) {\strut \fourthrow};
%
%\foreach \bottomrow[count=\bottomx] in {E$\flat\flat$,B$\flat\flat$,F$\flat$,C$\flat$,G$\flat$,D$\flat$,A$\flat$}
%  \node[note] at (\bottomx-0.5,0) {\strut \bottomrow};


\foreach [count=\row from 0] \notelist in {
  {E$\flat\flat$,B$\flat\flat$,F$\flat$,C$\flat$,G$\flat$,D$\flat$,A$\flat$},
  {C$\flat$,G$\flat$,D$\flat$,A$\flat$,E$\flat$,B$\flat$,F,C},
  {E$\flat$,B$\flat$,F,C,G,D,A},
  {C,G,D,A,E,B,F$\sharp$,C$\sharp$},
  {E,B,F$\sharp$,C$\sharp$,G$\sharp$,D$\sharp$,A$\sharp$}}
  \foreach \note [count=\column from 0,evaluate={\colX=\column+0.5-mod(\row,2)/2;}] in \notelist
     \node [note] at (\colX,\row*0.5) {\strut \note};

\end{tikzpicture}

\end{document}

答案2

我不会不必要地嵌套循环,而是在单个循环中测试要显示的节点数(每行 7;8;7 和 8)。

截屏

%LuaLaTeX
\documentclass[tikz,border=5mm]{standalone}
%\usepackage{tikz}

\begin{document}

\begin{tikzpicture}[xscale=1.5,yscale=2.5981]
\footnotesize

\begin{scope}
\newcommand*\columns{7}
\newcommand*\rows{2}
\clip(0,0.5) rectangle (\columns,\rows);
 %\foreach \x in {0,0.5,1,...,\columns}
\foreach \y in {0,0.5,1,...,\rows}
\foreach \z in {-1.5,-0.5,...,\columns} 
{
    \draw (0,\y) -- (\columns,\y);
    \draw (\z,\rows) -- (\z+2,0);
    \draw (\z,0) -- (\z+2,\rows);
}
\end{scope}

\draw[fill=gray!50] (3.5,1) -- (4.5,1) -- (4,1.5) -- cycle;
\foreach \row/\x [count=\n]in {E/0.5,B/1.5,F$\sharp$/2.5,C$\sharp$/3.5,G$\sharp$/4.5,D$\sharp$/5.5,A$\sharp$/6.5,C/0,G/1,D/2,A/3,E/4,B/5,F$\sharp$/6,C$\sharp$/7,E$\flat$/0.5,B$\flat$/1.5,F/2.5,C/3.5,G/4.5,D/5.5,A/6.5,C$\flat$/0,G$\flat$/1,D$\flat$/2,A$\flat$/3,E$\flat$/4,B$\flat$/5,F/6,C/7}
%\foreach \bottomrow/\bottomx in {E$\flat\flat$/0.5,B$\flat\flat$/1.5,F$\flat$/2.5,C$\flat$/3.5,G$\flat$/4.5,D$\flat$/5.5,A$\flat$/6.5}
{
\ifnum \n < 8
\node[draw,circle,minimum size=0.75cm,fill=white] at (\x,2) {\row};
\else 
    \ifnum \n <16
    \node[draw,circle,minimum size=0.75cm,fill=white] at (\x,1.5) {\row};
    \else   
        \ifnum \n <23    
        \node[draw,circle,minimum size=0.75cm,fill=white] at (\x,1) {\strut \row};
        \else 
        \node[draw,circle,minimum size=0.75cm,fill=white] at (\x,0.5) {\strut \row};
        \fi
    \fi
\fi
%\node[draw,circle,minimum size=0.75cm,fill=white] at (\bottomx,0) {\strut \bottomrow};
}

\end{tikzpicture}

相关内容