0

I am using the automata library of TiKZ, and putting lines between nodes 18pt thick. The problem is that the border between the lines and the state do not fit well:

enter image description here

I would like to have this

enter image description here

Any ideas?

Here is a minimal example producing the first one:

\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}
Alejandro DC
  • 1,956
  • Is the curve fixed? I mean, if you want the node to be "malleable" according to the path below, then it gets harder to do. And considering your answer, is it a curve or a circular node below it? – Alenanno Apr 28 '15 at 18:06
  • Sorry for not being clear: it is a line between nodes (states) with the automata library. Just like in my answer below. – Alejandro DC Apr 28 '15 at 18:08
  • This looks like a job for a decoration. See the circle connection bar decoration (used in mindmaps). Or maybe the Round Cap arrow tip. However, that can only do semi-circles. – Qrrbrbirlbel Apr 28 '15 at 22:48
  • What surprise me is that there is the need to add a decoration, or layers as in my answer below, or some other add-hoc solution... but this look as a pretty common situation! If the line is thick enough, it will look ugly because it does not follow the border of the object it is touching. Nobody thought this problem before? – Alejandro DC Apr 29 '15 at 02:54
  • 1
    Usually, one uses rather thin lines in relation to the size of nodes so the "dis-connection" doesn't show even more so on paper. For same-colored lines you can use the rect but. For more complex borders this will get complex really fast (just think of all the connections from a corner of an rectangle with varying angles of the lines). – Qrrbrbirlbel Apr 29 '15 at 19:20
  • @Qrrbrbirlbel Replace rect but with line cap=rect. (My mind was elsewhere …) – Qrrbrbirlbel Apr 29 '15 at 22:26

2 Answers2

2

I found a way, but it does not seems to be the canonical one, just a way that works: Using layers, and then increasing the length of the line:

\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}

Result

EDIT Second solution, based on the comment below (use center as coordinate instead of longer lines)

\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}
Alejandro DC
  • 1,956
2

Here is an attempt with arrow tips.
(I also have a solution with decorations but those confuse me more than arrow tips.)

Unfortunately the Round Cap arrow tip only adds (or removes with the reversed option) a semi-circle from the line end. This would work great if the line width is twice the radius of a circular node.

The setup code for the arrow tip Hug Cap calculates some math and saves three values:

  • radius (this is taken from the arrow key length),
  • h, this is the inset (the height), and
  • an angle (its an arc that gets drawn after all).

There is the possibility to extend the arrow tip's definition to include options like reversed, open, left, etc.

The deround style calculates the radius from circular nodes. (While this answer is inspired by the circle connection bar style and decoration from the mindmap library, it uses a different approach to extract the radius from already existing nodes.)

Obviously, the paths must be orthogonal to the circles border.

This solution must be used with to/edge operators (it uses \tikztostart and \tikztotarget to automatic the radii calculations. Do not use other line caps than butt (the default), this could also be checked inside the definition of the arrow tip.

This breaks if the line width is higher than the diameter and also for very large radii (but then why use this even?).

Code

\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}

Output

enter image description here

Qrrbrbirlbel
  • 119,821