如何改进我的 TikZ 代码以构造三角图

如何改进我的 TikZ 代码以构造三角图

我邀请有趣的、另类的蒂克兹解决方案可以改进后面可能会发现的“三角图”代码。

代码的一个问题是,我对一些长度进行了硬编码,因为它们在不同的path/draw命令中是需要的。我可以使用 (或相关的 TeX/LaTeX 命令) 定义长度,\def但这并不是真正的 TikZ 解决方案。如果您有更高级、更优雅的 TikZ 解决方案,那么我很想知道。

请注意这个问题与此相关其他问题但这个问题的目的不同。

\documentclass{minimal}

\usepackage{tikz}
\usetikzlibrary{calc}
\tikzset{my node/.style={shape=circle,draw=black,fill=red!40,minimum size=5mm,inner sep=0pt}}

\begin{document}
    \begin{tikzpicture}
       \draw[red,thick]
            (0,0) coordinate (A) -- ++(120:6) 
                  coordinate (B) -- ++(6,0)
                  coordinate (C) -- cycle;
       \foreach \a/\b/\c in {A/C/B,B/A/C,C/B/A} {
           \draw[<->]
                ($(\a)!5mm!(\b)$)   coordinate (fst)
                ($(\a)!1!30:(fst)$) coordinate (snd)
                ($(\a)!5mm!(\c)$)   coordinate (lst)
                ($(\a)!1.5!(snd)$) node {60}
                (fst) .. controls (snd) .. (lst);
       }
       \filldraw[draw=black,fill=red!40]
                let \n{length}={1.5} in
       \foreach \r[evaluate=\r as \rr using \r*\n{length},
                   evaluate=\r as \lst using int(round(\r*(\r+1)/2)),
                   evaluate=\r as \fst using int(round(\lst-\r+1)] in {1,...,5} {
           \foreach \curr in {\fst,...,\lst} {
               ($(A)+(120:-1.5)+(120:\rr)+(-\n{length}*\fst,0)+(\n{length}*\curr,0)$)
                   node[my node] {$\curr$}
           }
       };
    \end{tikzpicture}
\end{document}

三角形

答案1

对于规则形状的东西,例如三角形网格,我倾向于使用自定义坐标系(厘米)。即便如此,使用时必须小心,只使用厘米在感兴趣的特定节点上。我还没有完成整个图,但是思路很清晰。

我决定使用厘米其中包括X-方向等级网格。并且确定级别中的列。
因此您的厘米看起来会像这样:

cm={-.5,1,1,0,(0,0)}

当然,通过改变厘米您可以更改网格中节点的大小/分离等。

要查看其样子请参见:

\begin{tikzpicture}[tri/.style={cm={-.5,1,1,0,(0,0)}}]
  \path[tri] (0,0) node (1) {1};
  \path[tri] (1,0) node (2) {2};
  \path[tri] (1,1) node (3) {3};
  \path[tri] (2,0) node (4) {4};
  \path[tri] (2,1) node (5) {5};
  \draw (1) -- (2);
  \draw (1) -- (3);
  \draw (-.25,.5) arc (120:60:.5) node[midway,above] {$60^\circ$} ;
\end{tikzpicture}

你可能会注意到不是想要做厘米全局。因为你想控制其他一切。

在此处输入图片描述

这可以轻松扩展以适应通过循环构造自动创建网格:

\foreach \lvl in {0,1,...,5} {
    \foreach \myc in {0,...,\lvl} {
        \path[tri] ...
    }
}

明天(上班时)我会扩展循环,因为要使扩展计数器等工作起来有些微妙之处(但我知道您知道这一点 :) )。但至少这会让您了解如何使绘图更简单。

所以我添加了剩余部分,以及您评论的请求。它相当复杂,因为它通过循环结构跟踪边缘节点。

\tikzset{
    my node/.style={
        shape=circle,
        draw=black,
        fill=red!40,
        minimum size=5mm,
        inner sep=0pt},
    tri levels/.initial=4,
    tri border/.style={red,thick},
}
\makeatletter
\newcommand\drawmesh[1][]{
    \bgroup
    \tikzset{#1}
    \pgfkeysgetvalue{/tikz/tri levels}{\tri@lvls}
    % just crash... :)
    \ifnum\tri@lvls<1You are not allowed to do this....\fi
    % Full draw (relies on the fill of the nodes, so only for example purpose)
    %\draw[tri,tri border] (0,0) -- (\tri@lvls,0)  -- (\tri@lvls,\tri@lvls) -- cycle;
    \foreach \i [remember=\k (initially 0)] in {0,...,\tri@lvls}
      \foreach \j [remember=\k, evaluate={\k=int(\k+1);}] in {0,...,\i}
        \path[tri] (\i,\j) node[my node] (\k) {\k};
    % Save the name of the last node
    \edef\tri@last@node{\k}
    % Connect the nodes:
    \foreach \i [remember=\k as \lastk (initially 1), % the left side
                 remember=\k, evaluate={\k=int(\lastk+\i)}, 
                 remember=\l, evaluate={\l=int(\k+\i)}, % the right side
                 remember=\lastl, evaluate={\lastl=int(\lastk+\i-1)},
                 remember=\lastt as \t (initially \tri@last@node), evaluate={\lastt=int(\tri@last@node-\i)}]
                    in {1,...,\tri@lvls} {
        \draw[tri border] (\lastt) -- (\t); 
        \draw[tri border] (\lastl) -- (\l); 
        \draw[tri border] (\lastk) -- (\k);}
    \egroup
}
\makeatother

% Drawing code:

\begin{tikzpicture}[tri/.style={cm={-.5,1,1,0,(0,0)}}]
  \drawmesh[tri levels=4]
  \draw (1) -- (2);
  \draw (1) -- (3);
  \draw (-.25,.5) arc (120:60:.5) node[midway,above] {$60^\circ$} ;
\end{tikzpicture}

在这里,您可以简单地通过宏指定大小\drawmeshtri 厘米必须预先定义,但当然也可以放入键中。通过修改键,可以轻松更改边框颜色tri border。最后,通过从键中明确绘制,tri border您可以利用shorten >=<length>来获得特殊功能。

这将允许您通过一个参数创建所有网格,即tri levels=<int>的参数\drawmesh。然后它将产生:

在此处输入图片描述

答案2

不知道“更优雅”,但我会选择下面采用的方法。请注意,三个“60”节点的位置并不相同。

\documentclass{standalone}
\usepackage{tikz}

\tikzset{
    my node/.style={
        shape=circle,
        draw=black,fill=red!40,
        minimum size=5mm,
        inner sep=0pt
    }
}

\begin{document}

\begin{tikzpicture}

\begin{scope}[x=(0:1.5cm),y=(120:1.5cm)]

\draw [red, thick] (1,1) -- (1,5) -- (5,5) -- cycle;
\foreach \i [remember=\k (initially 0)] in {1,...,5}
    \foreach \j [remember=\k, evaluate={\k=int(\k+1);}] in {1,...,\i}
        \node [my node] at (\j,\i) (circle-\k) {\k};

\end{scope}

\draw [<->] (circle-1)  ++(120:0.5) arc (120:60:0.5 and 0.5) 
    node [midway, above] {60};
\draw [<->] (circle-11) ++(0:0.5)   arc (0:-60:0.5 and 0.5)
    node [midway, below right] {60};
\draw [<->] (circle-15) ++(180:0.5) arc (180:240:0.5 and 0.5)
    node [midway, below left] {60};

\end{tikzpicture}
\end{document}

在此处输入图片描述

一个人可以尝试将角度测量部分以一种风格结合起来,可能有点像这样:

\tikzset{
    angle measurement/.style args={arc #1 for (#2) at (#3:#4)}{
        insert path={
            [shift={(#2)}] [<->] (#3-#1/2:#4) arc (#3-#1/2:#3+#1/2:#4)
            \pgfextra{\pgfinterruptpath
                \path [shift={(#2)}] (#3:#4) node [anchor=#3+180] {#1};
            \endpgfinterruptpath} 
        }
    }
}

\draw [angle measurement=arc 60 for (circle-1) at (90:0.5)];
\draw [angle measurement=arc 60 for (circle-11) at (-30:0.5)];
\draw [angle measurement=arc 60 for (circle-15) at (210:0.5)];

其形式为arc <angle> for (<node>) at (<arc midpoint>)<arc midpoint> 还确定锚点。 它肯定可以更灵活。

句柄style args允许将分隔参数传递给样式。就像

\def\mymacro(#1) and (#2);{...}

允许定义一个宏,以便在使用时可以分隔参数:

\mymacro(first arg) and (second arg);

style args键允许以类似的方式限定样式,例如(这不是一个很好的例子):

\tikzset{size/.style args={#1 x #2}{minimum width=#1, minimum height=#2}}

可以用作

\node [size=4pt x 5cm] {text};

请注意必须遵循模式确切地调用时,包括空格。需要注意的是,如果宏在空格前用作参数,例如,,则size=\w x 5cm此操作将失败。如果宏可能用作参数,则任何后续字符分隔符都不应是空格。

答案3

这是另一个解决方案:我有意使用原始代码,只是为最终用户增加了自定义的可能性:

  • 特定的键;
  • 一些风格。

提供了两个示例:

  • 第一个重现初始图表的人;
  • 第二个展示如何自定义图表。

代码:

\documentclass[tikz,png,border=10pt]{standalone}

\usepackage{tikz}
\usepackage{pdftexcmds}
\usetikzlibrary{calc}

\makeatletter

% keys to customize the aspect
\pgfkeys{/tikz/.cd,
  distance of nodes/.initial={1.5},
  distance of nodes/.get=\trig@actualnodedistance,
  distance of nodes/.store in=\trig@actualnodedistance,
  levels/.initial={5},
  levels/.get=\trig@numlevels,
  levels/.store in=\trig@numlevels,
  direction/.initial={up},
  direction/.get=\trig@direction,
  direction/.store in=\trig@direction,
  mark angle line distance/.initial={5mm},
  mark angle line distance/.get=\trig@markangledistance,
  mark angle line distance/.store in=\trig@markangledistance,
  mark angle label distance factor/.initial={1},
  mark angle label distance factor/.get=\trig@markanglelabfactor,
  mark angle label distance factor/.store in=\trig@markanglelabfactor,
} 

% key to draw the diagram
\pgfkeys{/tikz/.cd,  
  triangle diagram/.code={
    \ifnum\pdf@strcmp{\trig@direction}{up}=\z@%
      \def\trig@use@direction{($(0,0)+(120:-\trig@actualnodedistance)
               +(120:\rr)
               +(-\trig@actualnodedistance*\fst,0)
               +(\trig@actualnodedistance*\curr,0)$)}
      \def\trig@draw@border{++(120:\trigshift)}
      \def\trig@draw@angle{($(\a)!1.1!30:(fst)$)}
    \fi
    \ifnum\pdf@strcmp{\trig@direction}{down}=\z@%
      \def\trig@use@direction{($(0,0)-(120:-\trig@actualnodedistance)
               -(120:\rr)
               -(-\trig@actualnodedistance*\fst,0)
               -(\trig@actualnodedistance*\curr,0)$)}
      \def\trig@draw@border{++(-120:\trigshift)}
      \def\trig@draw@angle{($(\a)!1.1!-30:(fst)$)}      
    \fi
    \pgfmathtruncatemacro{\actualnumlevels}{\trig@numlevels-1}
    \pgfmathsetmacro{\trigshift}{\actualnumlevels*\trig@actualnodedistance}
    \draw[connection style,save path=\trigpath]
            (0,0) coordinate (A) -- \trig@draw@border
                  coordinate (B) -- ++(\trigshift,0)
                  coordinate (C) -- cycle;

    \foreach \a/\b/\c in {A/C/B,B/A/C,C/B/A} {
           \draw[<->,angle line marker]
                ($(\a)!\trig@markangledistance!(\b)$)   coordinate (fst)
                \trig@draw@angle coordinate (snd)
                ($(\a)!\trig@markangledistance!(\c)$)   coordinate (lst)
                ($(\a)!\trig@markanglelabfactor*\trig@actualnodedistance!(snd)$) 
                node {60} (fst) .. controls (snd) .. (lst);
       }
    \path
      \foreach \r
        [evaluate=\r as \rr using \r*\trig@actualnodedistance,
         evaluate=\r as \lst using int(round(\r*(\r+1)/2)),
         evaluate=\r as \fst using int(round(\lst-\r+1)] in {1,...,\trig@numlevels}{
           \foreach \curr in {\fst,...,\lst} {
               \trig@use@direction
                   node[my node] {$\curr$}
           }
       };

  },  
}

\tikzset{my node/.style={
  circle,
  draw=black,
  fill=red!40,
  minimum size=5mm,
  inner sep=0pt
  },
  connection style/.style={
    draw,
    red,
  },
  angle line marker/.style={},
  diagram grow down/.style={
    direction=down,
    xscale=-1
  }
}
\makeatother

\begin{document}
    \begin{tikzpicture}
       \node[triangle diagram]{};
    \end{tikzpicture}

    \tikzset{my node/.append style={
        top color=white, 
        bottom color=magenta!80!blue!50, 
        draw=magenta!80!blue,
        minimum size=7mm},
      connection style/.append style={
        draw=green!80!blue,
        ultra thick,
        double,
      },
      angle line marker/.append style={
        very thick,
        gray,
        text=black
      }
    }
    \begin{tikzpicture}[distance of nodes=2.5,
      levels=7,
      diagram grow down,  
      mark angle line distance=10mm,
      mark angle label distance factor=0.5,      
      ]
      \node[triangle diagram]{};   
    \end{tikzpicture}
\end{document}

第一个例子提供:

在此处输入图片描述

而第二个例子则导致:

在此处输入图片描述

相关内容