TiKZ 中線與節點的擬合效果較好

TiKZ 中線與節點的擬合效果較好

我正在使用 TiKZ 的自動機庫,並在節點之間放置 18pt 厚的線。問題是線條和狀態之間的邊界不太吻合:

在此輸入影像描述

我想要這個

在此輸入影像描述

有任何想法嗎?

這是產生第一個的最小範例:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{automata}

\begin{document}

\begin{tikzpicture}[thick]
  \node[state] (1) {};
  \draw[-, blue!20, line width=18pt] (1) to (0,1);
\end{tikzpicture}

\end{document}

答案1

這是帶有箭頭提示的嘗試。
(我也有一個裝飾的解決方案,但這些比箭頭提示更讓我困惑。)

不幸的是,Round Cap箭頭尖端僅從線端添加(或使用選項刪除reversed)一個半圓。如果線寬是圓形節點半徑的兩倍,這將非常有效。

setup code箭頭尖端的Hug Cap計算一些數學並保存三個值:

  • 半徑(取自箭頭鍵length),
  • H,這是插圖(高度),並且
  • 一個角度(畢竟它是繪製的弧線)。

可以擴展箭頭提示的定義以包含reversedopenleft等選項。

deround樣式根據圓形節點計算半徑。 (雖然這個答案的靈感來自圖書館circle connection bar的風格和裝飾mindmap,但它使用不同的方法從現有節點中提取半徑。)

顯然,路徑必須與圓邊界正交。

to此解決方案必須與/運算子一起使用edge(它使用\tikztostart\tikztotarget來自動計算半徑。不要使用除(預設)line caps之外的其他butt內容,這也可以在箭頭提示的定義中進行檢查。

如果線寬大於直徑且半徑非常大,則這種情況會破裂(但為什麼要使用它?)。

程式碼

\documentclass[tikz]{standalone}
\usetikzlibrary{automata,arrows.meta}
\pgfdeclarearrow{
  name=Hug Cap,
  parameters=\the\pgfarrowlength,
  setup code={
    % h = r - .5 sqrt(4 r^2 - s^2)
    \pgfmathsetlengthmacro\pgfarrowh{\pgfarrowlength-.5*sqrt(4*\pgfarrowlength*\pgfarrowlength-\pgflinewidth*\pgflinewidth}
    % a = asin(s / (2 r))
    \pgfmathsetmacro\pgfarrowangle{asin(\the\pgflinewidth/(2*\the\pgfarrowlength))}
    \pgfarrowssavethe\pgfarrowlength % radius
    \pgfarrowssave\pgfarrowh         % h
    \pgfarrowssave\pgfarrowangle     % a
    \pgfarrowsupperhullpoint{0pt}{.5\pgflinewidth}
    \pgfarrowsupperhullpoint{\pgfarrowh}{.5\pgflinewidth}
    \pgfarrowssetlineend{.1pt}       % eeh :\
  },
  drawing code={
    \pgfpathmoveto{\pgfqpoint{\pgfarrowh}{-.5\pgflinewidth}}
    \pgfpatharc{180+\pgfarrowangle}{180-\pgfarrowangle}{\pgfarrowlength}
    \pgfpathlineto{\pgfqpoint{0pt}{.5\pgflinewidth}}
    \pgfpathlineto{\pgfqpoint{0pt}{-.5\pgflinewidth}}
    \pgfpathclose
    \pgfusepathqfill}}
\makeatletter
\def\qrr@tikz@circle{circle}
\newcommand*\qrr@getRadius[1]{%
  \def\qrr@radius{0pt}%
  \tikz@scan@one@point\pgfutil@firstofone(#1)\relax
  \iftikz@shapeborder
    \edef\qrr@shape{\csname pgf@sh@ns@\tikz@pp@name{\tikz@shapeborder@name}\endcsname}%
    \ifx\qrr@tikz@circle\qrr@shape
      % ah circle, get the radius!
      \begingroup
        \csname pgf@sh@np@\tikz@pp@name{\tikz@shapeborder@name}\endcsname
        \let\qrr@radius\radius
        \pgfmath@smuggleone\qrr@radius
      \endgroup
    \fi
  \fi}
\tikzset{
  deround/.style={
    /utils/exec={%
     \qrr@getRadius\tikztostart
     \ifdim\qrr@radius=0pt
       \def\qrr@arrowsettings{-}\else
       \edef\qrr@arrowsettings{{Hug Cap[length=+\qrr@radius]}-}\fi
     \qrr@getRadius\tikztotarget
     \ifdim\qrr@radius=0pt\else
       \edef\qrr@arrowsettings{\qrr@arrowsettings{Hug Cap[length=+\qrr@radius]}}\fi
   },
   arrows/.expanded=\qrr@arrowsettings}
}
\makeatother
\begin{document}
\begin{tikzpicture}[thick]
  \node[state]          (1) {};
  \node[state] at (2,1) (2) {abcdef};
  \path[line width=12pt, every edge/.append style=deround]
    (2) edge (1)
        edge[line width=10pt, red, out=150, in=90] (1);
  \path[line width=12pt] (1) edge[out=180-30, in=180+30, looseness=4, deround] (1);
\end{tikzpicture}
\end{document}

輸出

在此輸入影像描述

答案2

我找到了一種方法,但它似乎不是規範的方法,只是一種有效的方法:使用圖層,然後增加線的長度:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{automata}

\begin{document}

\pgfdeclarelayer{bg}
\pgfsetlayers{bg,main}
\begin{tikzpicture}[thick]
  \node[state,fill=white] (1) {};
  \begin{pgfonlayer}{bg}
    \draw[-,shorten >=-4pt,shorten <=-4pt,blue!20, line width=18pt]
    (1) to (0,1);
  \end{pgfonlayer}
\end{tikzpicture}

\end{document}

結果

編輯 第二種解決方案,基於下面的評論(使用中心作為坐標而不是較長的線)

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{automata}

\begin{document}

\pgfdeclarelayer{bg}
\pgfsetlayers{bg,main}
\begin{tikzpicture}[thick]
  \node[state,fill=white] (1) {};
  \begin{pgfonlayer}{bg}
    \draw[-,blue!20, line width=18pt]
    (1.center) to (0,1);
  \end{pgfonlayer}
\end{tikzpicture}

\end{document}

相關內容