使用 tikz 上的 \draw[->] 更好地利用从多个节点到多个节点的链接的圆角

使用 tikz 上的 \draw[->] 更好地利用从多个节点到多个节点的链接的圆角

我的问题如下我之前的一个问题

这是我当前的代码:

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{matrix,positioning}

\newcommand{\multilinkstoonenode}[3]{
    \begin{scope}[x=1em,y=1em]
        \newdimen\xend
        \newdimen\yend  
        \path (#2.west);
        \pgfgetlastxy{\xend}{\yend}
        \foreach \i in {#1} {
            \newdimen\xstart
            \newdimen\ystart 
            \path (\i.east);
            \pgfgetlastxy{\xstart}{\ystart}
            \coordinate (1) at ({\xend-#3 em},\ystart);
            \coordinate (2) at ({\xend-#3 em},\yend);
            \ifdim\ystart=\yend
                \draw[->] (\i.east)--(#2.west);
            \else
                \draw[->,rounded corners] (\i.east)--(1)--(2)--(#2.west);
            \fi
        }
    \end{scope}
}

% \multilinkstomultiplenodes{list of left nodes}{list of right nodes}{distance between the right nodes and the right vertical line}{distance between the left vertical line and the right vertical line}
\newcommand{\multilinkstomultiplenodes}[4]{ %TODO
}

\begin{document}
    \tikzset{
        basic/.style={
            draw, 
            rounded corners=2pt, 
            thick, 
            text width=8em, 
            align=flush center, 
            node distance=2em
        }
    }
    \begin{tikzpicture}[]
        \matrix[row sep=2em, column sep=4em, every node/.style={basic}] {
            \node(n1){Text}; & \node(n6){another text}; \\
            \node(n2){one thing}; & \node(n7){again text}; \\
            \node(n3){text}; & \node(n8){text}; \\
            \node(n4){text}; & \node(n9){text}; \\
            \node(n5){text}; & \node(n0){text}; \\
        };
        \multilinkstoonenode{n1,n2}{n6}{3}

        %to modify
        \multilinkstoonenode{n2,n3,n4,n5}{n7}{1}
        \multilinkstoonenode{n2,n3,n4,n5}{n8}{1}
        \multilinkstoonenode{n2,n3,n4,n5}{n9}{1}
        \multilinkstoonenode{n2,n3,n4,n5}{n0}{1}
        % Expected: \multilinkstomultiplenodes{n2,n3,n4,n5}{n2,n3,n4,n5}{1}{1}
    \end{tikzpicture}

\end{document}

结果如下:

我现在尝试定义一个新命令,因此它看起来像这样:

我需要能够确定右节点和右垂直线之间的距离,以及左垂直线和右垂直线之间的距离。中间水平线必须相对于右节点居中。

我目前完全不知道该如何继续。

答案1

这是一个建议。它带有一个样式connect through,用于检查拉伸是否水平(以避免出现圆角问题),以及另一个样式multiconnect,用于执行多个连接。(我通常不太喜欢编写宏,但我认为应该使用样式来处理 TiZ。需要说明的是,出于这个原因,我没有看过 Jasper 的答案。有些事情可能是平行的,也可能不是,如果是的话,他是第一个。我没心情看这些宏,抱歉。)

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{matrix,positioning,fit,calc}

\begin{document}
    \tikzset{
        basic/.style={
            draw, 
            rounded corners=2pt, 
            thick, 
            text width=8em, 
            align=flush center, 
            node distance=2em
        },
        horizontal stretch/.initial=1em,
        connect through/.style={to path={
        let \p1=($(\tikztostart)-(#1)$),\p2=($(\tikztotarget)-(#1)$),
        \n1={abs(\y1)},\n2={abs(\y2)} in 
        \ifdim\n1<1pt
         (\tikztostart) -- (#1)
        \else 
         [/utils/exec=\pgfmathsetmacro{\mysign}{sign(\x1)}]
         (\tikztostart) -|
         ([xshift=\mysign*\pgfkeysvalueof{/tikz/horizontal stretch}/2]#1)  
         -- (#1)
        \fi
        \ifdim\n2<1pt 
         (#1) -- (\tikztotarget)    
        \else
         [/utils/exec=\pgfmathsetmacro{\mysign}{sign(\x2)}]
         (#1) --  
         ([xshift=\mysign*\pgfkeysvalueof{/tikz/horizontal stretch}/2]#1)
         |- (\tikztotarget) 
        \fi
        }},
       multiconnect/.style n args={3}{insert path={%
       [/utils/exec={\foreach \X [count=\Y] in {#2}
    {\ifnum\Y=1
      \xdef\LstTargets{(\X)}
    \else
      \xdef\LstTargets{\LstTargets (\X)}
    \fi}}]
    node[fit=\LstTargets,inner sep=0pt] (auxR){}
    ($(#1.east)!#3!(auxR.west)$) coordinate (auxM)
    foreach \Y in {#2}
     {
      (#1.east) edge[connect through=auxM|-auxR,-latex] (\Y)
     }}}    
    }
    \begin{tikzpicture}[]
        \matrix[row sep=2em, column sep=4em, every node/.style={basic}] {
            \node(n1){Text}; & \node(n6){another text}; \\
            \node(n2){one thing}; & \node(n7){again text}; \\
            \node(n3){text}; & \node(n8){text}; \\
            \node(n4){text}; & \node(n9){text}; \\
            \node(n5){text}; & \node(n0){text}; \\
        };
    \foreach \XX in {n1,n2} 
    {\draw[rounded corners,multiconnect={\XX}{n6}{0.5}] ;}
    \foreach \XX in {n2,n3,n4,n5}   
    {\draw[rounded corners,multiconnect={\XX}{n7,n8,n9,n0}{0.5}] ;}
    \end{tikzpicture}

\end{document}

在此处输入图片描述

答案2

我不完全理解 OP 想要连接节点的规则,而且我很确定有一种更简单的方法(通过包)来实现以下结果,但也许以下代码有助于想出一个好的解决方案。

连接的水平线并不像 OP 所希望的那样相对于右侧的节点居中,而是相对于左侧的节点居中(否则结果将类似于 OP 的版本)。

(仅将两个节点相互连接(1:1)时会导致连接有些难看。)

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{matrix,positioning,calc}

\newcommand{\multilinkstoonenode}[3]{
    \begin{scope}[x=1em,y=1em]
        \xdef\j{#2}
        \foreach \c [count=\x] in {#1} {
            \ifnum\x=1
                \xdef\xtop{\c}
                \xdef\xbottom{\c}
            \else
                \xdef\xbottom{\c} % redefining \xbottom until end of loop
            \fi
        }
        \coordinate (left) at ([xshift=#3 em]$(\xtop.east)!0.5!(\xbottom.east)$);
        \coordinate (right) at ([xshift=-#3 em]$(#2.west)!0.5!(#2.west)$);
        \foreach \i in {#1} {
            \draw[->,rounded corners]
            (\i.east)-|(left)
                     -|(right)
                     --(\j.west);
        }
    \end{scope}
}

\begin{document}
    \tikzset{
        basic/.style={
            draw, 
            rounded corners=2pt, 
            thick, 
            text width=8em, 
            align=flush center, 
            node distance=2em
        }
    }
    \begin{tikzpicture}[]
        \matrix[row sep=2em, column sep=4em, every node/.style={basic}] {
            \node(n1){Text}; & \node(n6){another text}; \\
            \node(n2){one thing}; & \node(n7){again text}; \\
            \node(n3){text}; & \node(n8){text}; \\
            \node(n4){text}; & \node(n9){text}; \\
            \node(n5){text}; & \node(n0){text}; \\
        };
        \multilinkstoonenode{n1,n2}{n6}{1}
        \multilinkstoonenode{n2,n3,n4,n5}{n7}{1}
        \multilinkstoonenode{n2,n3,n4,n5}{n8}{1}
        \multilinkstoonenode{n2,n3,n4,n5}{n9}{1}
        \multilinkstoonenode{n2,n3,n4,n5}{n0}{1}
    \end{tikzpicture}

\end{document}

结果:

在此处输入图片描述


编辑

我想到了一个新的解决方案,其中宏采用两个应连接的节点列表。我在这里遇到了几个问题。

首先,正如 OP 在上面链接的问题中已经发现的那样,当我们尝试将具有相同坐标的节点与具有圆角的笔触连接起来时,会出现问题。由于在我们的例子中节点是自动生成的,因此我们无法避免节点具有相同的坐标。因此,我们需要测试连接路径的节点的 y 坐标。

我们遇到了舍入误差的问题。我尝试通过将 y 坐标除以 10 来解决这个问题,以便截断最后一位数字并消除舍入误差。

好吧,也许下面的代码可以简化,但它可以作为一个起点......

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{matrix,positioning,calc}

\newcommand{\multilinkstoonenode}[3]{
    \begin{scope}[x=1em,y=1em]
        \xdef\j{#2}
        \foreach \c [count=\x] in {#1} {
            \ifnum\x=1
                \xdef\xtop{\c}
                \xdef\xbottom{\c}
            \else
                \xdef\xbottom{\c}
            \fi
        }
        \foreach \d [count=\y] in {#2} {
            \ifnum\y=1
                \xdef\ytop{\d}
                \xdef\ybottom{\d}
            \else
                \xdef\ybottom{\d}
            \fi
        }
        \newdimen\xmiddle
        \newdimen\ymiddle
        \newdimen\xleft
        \newdimen\yleft 
        \newdimen\xright
        \newdimen\yright
        \coordinate (right) at ([xshift=-#3 em]$(\ytop.west)!0.5!(\ybottom.west)$);
        \coordinate (left) at ([xshift=#3 em]\xtop.east |- right);
        \path(left);
        \pgfgetlastxy{\xmiddle}{\ymiddle}
        \pgfmathsetlengthmacro{\ymiddlex}{\ymiddle/10}
        \foreach \i in {#1} {
            \path(\i);
            \pgfgetlastxy{\xleft}{\yleft}
            \pgfmathsetlengthmacro{\yleftx}{\yleft/10}
            \foreach \j in {#2} {
                \path(\j);
                \pgfgetlastxy{\xright}{\yright}
                \pgfmathsetlengthmacro{\yrightx}{\yright/10}
                \ifdim\yleftx=\ymiddlex
                    \draw[->](\i.east)--(\j.west);
                \else
                    \draw[->,rounded corners]
                    (\i.east)-|(left)
                             --(right)
                    \ifdim\ymiddlex=\yrightx
                             --(\j.west);
                    \else
                             |-(\j.west);
                    \fi
                \fi
            }
        }
    \end{scope}
}

\begin{document}
    \tikzset{
        basic/.style={
            draw, 
            rounded corners=2pt, 
            thick, 
            text width=8em, 
            text depth=0em,
            align=flush center, 
            node distance=2em
        }
    }
    \begin{tikzpicture}[]
        \matrix[row sep=2em, column sep=4em, every node/.style={basic}] {
            \node(n1){Text}; & \node(n6){another text}; \\
            \node(n2){one thing}; & \node(n7){again text}; \\
            \node(n3){text}; & \node(n8){text}; \\
            \node(n4){text}; & \node(n9){text}; \\
            \node(n5){text}; & \node(n0){text}; \\
            \node(n10){text}; & \node(n11){text}; \\
            \node(n20){text}; & \node(n21){text}; \\
            \node(n30){text}; & \node(n31){text}; \\
        };
        \multilinkstoonenode{n1,n2}{n6}{.5}
        \multilinkstoonenode{n2,n3,n4,n5}{n7,n8,n9,n0}{1.5}
        \multilinkstoonenode{n10}{n11}{1}
        \multilinkstoonenode{n20}{n21,n31}{1}
    \end{tikzpicture}

\end{document}

结果:

在此处输入图片描述

答案3

我用了这个代码:

\documentclass[border=5mm]{standalone}

\usepackage{tikz}
\usepackage{xstring}

\usetikzlibrary{matrix}
\usetikzlibrary{positioning}
\usetikzlibrary{calc}

\newcommand{\listbcs}[4]{
    \tikzset{
        barycentric setup/.code={\foreach \X [count=\Y] in {#1}
            {\ifnum\Y=1
                \xdef\baryarg{\X=1}
            \else
                \xdef\baryarg{\baryarg,\X=1}
            \fi}},
        barycentric list/.style={barycentric setup={#1},insert path={%
                (barycentric cs:\baryarg)}}
    }
    \path[barycentric list={#1}] node[anchor=center,align=flush center,#2] (#3) {#4};
}

\newcommand{\multilinks}[4]{%
    \begin{scope}[x=1em,y=1em]
        \listbcs{#2}{}{bcright}{}
        \newdimen\xright
        \newdimen\ybc
        \newdimen\dump
        \path(bcright);
        \pgfgetlastxy{\dump}{\ybc}
        \getfirst{#2}

        \path(#3em,0em);
        \newdimen\xtemp
        \pgfgetlastxy{\xtemp}{\dump}
        \coordinate (midright) at ({\xnow-#3 em},\ybc);
        \coordinate (midleft) at ({\xnow-#3em-#4em},\ybc);
        \foreach \i in {#1} {
            \foreach \j in {#2}{
                \newdimen\ystart
                \path (\i.east);
                \pgfgetlastxy{\dump}{\ystart}
                \newdimen\xmidl
                \newdimen\xmidr
                \path (midleft);
                \pgfgetlastxy{\xmidl}{\dump}
                \path (midright);
                \pgfgetlastxy{\xmidr}{\dump}
                \newdimen\yend
                \path (\j.west);
                \pgfgetlastxy{\dump}{\yend}
                \coordinate (cl) at (\xmidl,\ystart);
                \coordinate (cr) at (\xmidr,\yend);
                \ifdim\ystart=\ybc\relax%
                    \ifdim\ybc=\yend\relax%
                        \draw[->] (\i.east)--(\j.west);%
                    \else\relax%
                        \draw[->,rounded corners] (\i.east)--(midright)--(cr)--(\j.west);%
                    \fi\relax%
                \else\relax%
                    \ifdim\ybc=\yend\relax%
                        \draw[->,rounded corners] (\i.east)--(cl)--(midleft)--(\j.west);%
                    \else\relax%
                        \draw[->,rounded corners] (\i.east)--(cl)--(midleft)--(midright)--(cr)--(\j.west);%
                    \fi\relax%
                \fi\relax%
            }
        }
    \end{scope}
}

\newcommand{\getfirst}[1]{
    \StrCount{#1}{,}[\numofelem]
    \ifnum\numofelem>0\relax
        \StrBefore[1]{#1}{,}[\myhead]
    \else
        #1
    \fi
}

\begin{document}
    \tikzset{
        basic/.style={
            draw, 
            rounded corners=2pt, 
            thick, 
            text width=8em, 
            align=flush center,
        }
    }
    \begin{tikzpicture}
        \matrix[row sep=2em, column sep=4em, every node/.style={basic}] {
            \node(a){text}; & \node(c){text}; \\
            \node(b){text}; & \node(d){text}; \\
            \node(e){text}; & \node(f){text}; \\
        };
        \multilinks{a,e}{c,d,f}{1}{1}
    \end{tikzpicture}
\end{document}

相关内容