# Error with hobbyconvexpath

The hobby examples given on TEX.SX don't seem to be working with texlive 2013 (at least for me. For example, copying an MWE produces an error:

\documentclass[tikz,border=2bp]{standalone}
\usetikzlibrary{calc,trees,hobby}

\newcommand{\hobbyconvexpath}[2]{
[
create hobbyhullnodes/.code={
\global\edef\namelist{#1}
\foreach [count=\counter] \nodename in \namelist {
\global\edef\numberofnodes{\counter}
\node at (\nodename)
[draw=none,name=hobbyhullnode\counter] {};
}
\node at (hobbyhullnode\numberofnodes)
[name=hobbyhullnode0,draw=none] {};
\pgfmathtruncatemacro\lastnumber{\numberofnodes+1}
\node at (hobbyhullnode1)
[name=hobbyhullnode\lastnumber,draw=none] {};
},
create hobbyhullnodes
]
($(hobbyhullnode1)!#2!-90:(hobbyhullnode0)$)
\pgfextra{
\gdef\hullpath{}
\foreach [
evaluate=\currentnode as \previousnode using int(\currentnode-1),
evaluate=\currentnode as \nextnode using int(\currentnode+1)
] \currentnode in {1,...,\numberofnodes} {
\xdef\hullpath{\hullpath
..($(hobbyhullnode\currentnode)!#2!180:(hobbyhullnode\previousnode)$)
..($(hobbyhullnode\nextnode)!0.5!(hobbyhullnode\currentnode)$)}
\ifx\currentnode\numberofnodes
\xdef\hullpath{\hullpath .. cycle}
\else
\xdef\hullpath{\hullpath
..($(hobbyhullnode\nextnode)!#2!-90:(hobbyhullnode\currentnode)$)}
\fi
}
}
\hullpath
}

\begin{document}

\begin{tikzpicture}[
every node/.style={black},
every path/.style={red},
scale=3,
transform shape,
use Hobby shortcut
]

\node at (0,0) (a) {A};
\node at (2,0) (b) {B};
\node at (3,0) (c) {C};
\node at (2,-1) (e) {E};
\node at (3,-1) (f) {F};
\node at (0,-1) (d) {D};

\draw \hobbyconvexpath{a,b,c,f,e}{12.5pt};

\end{tikzpicture}
\end{document}


The error says,

Use of \tikz@curveto@double doesn't match its definition \draw \hobbyconvexpath{a,b,c,f,e}{12.5pt}


And I can't find the error reported anywhere. The same problem is showing for all hobby convex path examples. Is this known or probably some error with my configuration?

• I suspect the error comes with cycle, but we should wait Andrew for more insights. :) – Claudio Fiandrino Jun 27 '13 at 7:46

Claudio's comment is correct: the problem is with the use of the cycle keyword.

In short, I changed the way that hobby interacted with the TikZ path parser. In the old days, a .. would mean that TikZ handed control over to hobby for the next stage of the path. That meant that anything "weird" couldn't happen unless I'd thought of it and programmed for it. "Weird" here meaning stuff like collecting nodes or adding options or even ensuring that expansion was correctly handled. All of this is already done by the TikZ path parser, so I figured it would be easiest to let TikZ do what it did best and assemble the path but have hobby sort of sit in the background and tell TikZ what to do with ... This, I hope, makes it more robust.

However, there is one place where hobby used to be able to handle something that TikZ can't. And that is the cycle specification. When hobby was in control then it could handle .. cycle because I told it what to do when it encountered that. However, TikZ can't handle that as it doesn't know what to do with .. cycle. The reason for that is that cycle can't be dropped in anywhere, it is only valid after a line-to. So -- cycle is valid (possibly with nodes or coordinates in between) but cycle is not valid anywhere else. In particular, it is not a shortcut for "the initial point on the path" (not that hobby interprets it this way: there is a difference between a hobby path where the first and last points coincide, an a hobby path that is closed).

I could emulate the line-to detection to ensure that .. cycle works. I'll think about that next time I revise the code.

In the meantime, all the cycle was doing was ensuring that the closed=true option was being issued somewhere on the path. So to fix it, all we need is to put it back in somewhere. Here's a modified version of the above which achieves this, and tidies up the start and end a little.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/121286/86}
\usepackage{tikz}
\usetikzlibrary{calc,trees,hobby}

\newcommand{\hobbyconvexpath}[2]{
[
create hobbyhullnodes/.code={
\global\edef\namelist{#1}
\foreach [count=\counter] \nodename in \namelist {
\global\edef\numberofnodes{\counter}
\node at (\nodename)
[draw=none,name=hobbyhullnode\counter] {};
}
\node at (hobbyhullnode\numberofnodes)
[name=hobbyhullnode0,draw=none] {};
\pgfmathtruncatemacro\lastnumber{\numberofnodes+1}
\node at (hobbyhullnode1)
[name=hobbyhullnode\lastnumber,draw=none] {};
},
create hobbyhullnodes
]
($(hobbyhullnode1)!#2!-90:(hobbyhullnode0)$)
\pgfextra{
\gdef\hullpath{}
\foreach [
evaluate=\currentnode as \previousnode using int(\currentnode-1),
evaluate=\currentnode as \nextnode using int(\currentnode+1)
] \currentnode in {1,...,\numberofnodes} {
\ifnum\currentnode=1\relax
\xdef\hullpath{([closed=true]$(hobbyhullnode\currentnode)!#2!180:(hobbyhullnode\previousnode)$)
..($(hobbyhullnode\nextnode)!0.5!(hobbyhullnode\currentnode)$)}
\else
\xdef\hullpath{\hullpath
..($(hobbyhullnode\currentnode)!#2!180:(hobbyhullnode\previousnode)$)
..($(hobbyhullnode\nextnode)!0.5!(hobbyhullnode\currentnode)$)}
\fi
\ifx\currentnode\numberofnodes
\else
\xdef\hullpath{\hullpath
..($(hobbyhullnode\nextnode)!#2!-90:(hobbyhullnode\currentnode)$)}
\fi
}
}
\hullpath
}

\begin{document}

\begin{tikzpicture}[
every node/.style={black},
every path/.style={red},
scale=3,
transform shape,
use Hobby shortcut
]

\node at (0,0) (a) {A};
\node at (2,0) (b) {B};
\node at (3,0) (c) {C};
\node at (2,-1) (e) {E};
\node at (3,-1) (f) {F};
\node at (0,-1) (d) {D};

\draw \hobbyconvexpath{a,b,c,f,e}{12.5pt};

\end{tikzpicture}
\end{document}


• Very detailed explanation, thanks. I was aware of closed=true, but I couldn't be able to detail the motivation so deeply. – Claudio Fiandrino Jun 27 '13 at 9:18
• It seems that the calculation goes wrong if the units are changes, e.g. x=5mm is specified. Is that possible or am I doing something else wrong? – Joachim Breitner Jun 9 '15 at 8:41
• @JoachimBreitner I tried x=5mm and got a self-intersecting path, is that what you meant? What is happening, I think, is that the nodes are too close together and the path is tied to going through certain of their anchors so the algorithm ends up getting a bit expansive. Hobby's algorithm is not the right thing to use in every case, and in my experience it works best when there are a few points spaced out. This is probably one of those problems where there's not going to be a single best solution and you have to work on a case-by-case basis. – Loop Space Jun 9 '15 at 19:41
• Possibly. I ended up using a simple ellipses with fit, served me well so far. – Joachim Breitner Jun 9 '15 at 21:47