![在 \draw[->] 上使用 tikz 更好地利用從多個節點到多個節點的連結的圓角](https://rvso.com/image/392438/%E5%9C%A8%20%5Cdraw%5B-%3E%5D%20%E4%B8%8A%E4%BD%BF%E7%94%A8%20tikz%20%E6%9B%B4%E5%A5%BD%E5%9C%B0%E5%88%A9%E7%94%A8%E5%BE%9E%E5%A4%9A%E5%80%8B%E7%AF%80%E9%BB%9E%E5%88%B0%E5%A4%9A%E5%80%8B%E7%AF%80%E9%BB%9E%E7%9A%84%E9%80%A3%E7%B5%90%E7%9A%84%E5%9C%93%E8%A7%92.png)
我的問題如下我之前的問題之一。
這是我目前的程式碼:
\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
進行多個連接的樣式。 (我一般不太熱衷於編寫宏,但我認為應該為 Ti 使用樣式kZ. 需要明確的是,我沒有因為這個原因查看 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}