Rounded corners in TikZ trees.

When I use TikZ tree with nodes with rounded corners, the connecting lines do not touch the nodes (near corners) but end where would rectangle end. Is there an easy way around it?

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture} [sibling distance=100]
\node[rectangle, draw, rounded corners = 3]{ }
child { node { } }
child { node { } }
;
\end{tikzpicture}
\end{document}

-
As far as I'm aware it should work correctly. Could you provide an example? –  Caramdir Aug 8 '10 at 18:30
I thought you were using rounded rectangle. –  Caramdir Aug 9 '10 at 12:18

3 Answers

As already mentioned, the only real solution is to define a new shape, with correct border anchors. So, here it is: rectangle with rounded corners. The radius of the corner is controllable by /pgf/rectangle corner radius.

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

\begin{document}

\makeatletter

\pgfkeys{/pgf/.cd,
rectangle corner radius/.initial=3pt
}
\newif\ifpgf@rectanglewrc@donecorner@
\def\pgf@rectanglewithroundedcorners@docorner#1#2#3#4{%
\edef\pgf@marshal{%
\noexpand\pgfintersectionofpaths
{%
\noexpand\pgfpathmoveto{\noexpand\pgfpoint{\the\pgf@xa}{\the\pgf@ya}}%
\noexpand\pgfpathlineto{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}%
}%
{%
\noexpand\pgfpathmoveto{\noexpand\pgfpointadd
{\noexpand\pgfpoint{\the\pgf@xc}{\the\pgf@yc}}%
{\noexpand\pgfpoint{#1}{#2}}}%
\noexpand\pgfpatharc{#3}{#4}{\cornerradius}%
}%
}%
\pgf@process{\pgf@marshal\pgfpointintersectionsolution{1}}%
\pgf@process{\pgftransforminvert\pgfpointtransformed{}}%
\pgf@rectanglewrc@donecorner@true
}
\pgfdeclareshape{rectangle with rounded corners}
{
\inheritsavedanchors[from=rectangle] % this is nearly a rectangle
\inheritanchor[from=rectangle]{north}
\inheritanchor[from=rectangle]{north west}
\inheritanchor[from=rectangle]{north east}
\inheritanchor[from=rectangle]{center}
\inheritanchor[from=rectangle]{west}
\inheritanchor[from=rectangle]{east}
\inheritanchor[from=rectangle]{mid}
\inheritanchor[from=rectangle]{mid west}
\inheritanchor[from=rectangle]{mid east}
\inheritanchor[from=rectangle]{base}
\inheritanchor[from=rectangle]{base west}
\inheritanchor[from=rectangle]{base east}
\inheritanchor[from=rectangle]{south}
\inheritanchor[from=rectangle]{south west}
\inheritanchor[from=rectangle]{south east}

\savedmacro\cornerradius{%
\edef\cornerradius{\pgfkeysvalueof{/pgf/rectangle corner radius}}%
}

\backgroundpath{%
\northeast\advance\pgf@y-\cornerradius\relax
\pgfpathmoveto{}%
\pgfpatharc{0}{90}{\cornerradius}%
\northeast\pgf@ya=\pgf@y\southwest\advance\pgf@x\cornerradius\relax\pgf@y=\pgf@ya
\pgfpathlineto{}%
\pgfpatharc{90}{180}{\cornerradius}%
\southwest\advance\pgf@y\cornerradius\relax
\pgfpathlineto{}%
\pgfpatharc{180}{270}{\cornerradius}%
\northeast\pgf@xa=\pgf@x\advance\pgf@xa-\cornerradius\southwest\pgf@x=\pgf@xa
\pgfpathlineto{}%
\pgfpatharc{270}{360}{\cornerradius}%
\northeast\advance\pgf@y-\cornerradius\relax
\pgfpathlineto{}%
}

\anchor{before north east}{\northeast\advance\pgf@y-\cornerradius}
\anchor{after north east}{\northeast\advance\pgf@x-\cornerradius}
\anchor{before north west}{\southwest\pgf@xa=\pgf@x\advance\pgf@xa\cornerradius
\northeast\pgf@x=\pgf@xa}
\anchor{after north west}{\northeast\pgf@ya=\pgf@y\advance\pgf@ya-\cornerradius
\southwest\pgf@y=\pgf@ya}
\anchor{before south west}{\southwest\advance\pgf@y\cornerradius}
\anchor{after south west}{\southwest\advance\pgf@x\cornerradius}
\anchor{before south east}{\northeast\pgf@xa=\pgf@x\advance\pgf@xa-\cornerradius
\southwest\pgf@x=\pgf@xa}
\anchor{after south east}{\southwest\pgf@ya=\pgf@y\advance\pgf@ya\cornerradius
\northeast\pgf@y=\pgf@ya}

\anchorborder{%
\pgf@xb=\pgf@x% xb/yb is target
\pgf@yb=\pgf@y%
\southwest%
\pgf@xa=\pgf@x% xa/ya is se
\pgf@ya=\pgf@y%
\northeast%
\advance\pgf@x by-\pgf@xa%
\advance\pgf@y by-\pgf@ya%
\pgf@xc=.5\pgf@x% x/y is half width/height
\pgf@yc=.5\pgf@y%
\advance\pgf@xa by\pgf@xc% xa/ya becomes center
\advance\pgf@ya by\pgf@yc%
\edef\pgf@marshal{%
\noexpand\pgfpointborderrectangle
{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}
{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}%
}%
\pgf@process{\pgf@marshal}%
\advance\pgf@x by\pgf@xa%
\advance\pgf@y by\pgf@ya%
\pgfextract@process\borderpoint{}%
%
\pgf@rectanglewrc@donecorner@false
%
% do southwest corner
\southwest\pgf@xc=\pgf@x\pgf@yc=\pgf@y
\advance\pgf@xc\cornerradius\relax\advance\pgf@yc\cornerradius\relax
\borderpoint
\ifdim\pgf@x<\pgf@xc\relax\ifdim\pgf@y<\pgf@yc\relax
\pgf@rectanglewithroundedcorners@docorner{-\cornerradius}{0pt}{180}{270}%
\fi\fi
%
% do southeast corner
\ifpgf@rectanglewrc@donecorner@\else
\southwest\pgf@yc=\pgf@y\relax\northeast\pgf@xc=\pgf@x\relax
\advance\pgf@xc-\cornerradius\relax\advance\pgf@yc\cornerradius\relax
\borderpoint
\ifdim\pgf@x>\pgf@xc\relax\ifdim\pgf@y<\pgf@yc\relax
\pgf@rectanglewithroundedcorners@docorner{0pt}{-\cornerradius}{270}{360}%
\fi\fi
\fi
%
% do northeast corner
\ifpgf@rectanglewrc@donecorner@\else
\northeast\pgf@xc=\pgf@x\relax\pgf@yc=\pgf@y\relax
\advance\pgf@xc-\cornerradius\relax\advance\pgf@yc-\cornerradius\relax
\borderpoint
\ifdim\pgf@x>\pgf@xc\relax\ifdim\pgf@y>\pgf@yc\relax
\pgf@rectanglewithroundedcorners@docorner{\cornerradius}{0pt}{0}{90}%
\fi\fi
\fi
%
% do northwest corner
\ifpgf@rectanglewrc@donecorner@\else
\northeast\pgf@yc=\pgf@y\relax\southwest\pgf@xc=\pgf@x\relax
\advance\pgf@xc\cornerradius\relax\advance\pgf@yc-\cornerradius\relax
\borderpoint
\ifdim\pgf@x<\pgf@xc\relax\ifdim\pgf@y>\pgf@yc\relax
\pgf@rectanglewithroundedcorners@docorner{0pt}{\cornerradius}{90}{180}%
\fi\fi
\fi
}
}

\makeatother

\begin{tikzpicture}
\draw node(rc)[
rectangle with rounded corners,draw,rectangle corner radius=10pt,align=center]
{\large rectangle with rounded corners\\\large rectangle with rounded corners\\\large rectangle with rounded corners};
\fill[red,every node/.style={font=\tiny}]
\foreach \d/\p in {before north east/right,after north east/above,
before north west/above,after north west/left,
before south west/left,after south west/below,
before south east/right,after south east/right}
{ (rc.\d) circle(1pt) node[\p]{\d} };
\draw[blue,draw opacity=0.3]\foreach\a in {0,...,360} {(rc)--+(\a:5cm)};
\end{tikzpicture}

\end{document}


-
Brilliant! And I love the way the image shimmers when I scroll the page (screen effect, I know, but nonetheless). How important is the intersections library? Would it be tedious-but-standard to replace it, or is it really quite crucial? –  Loop Space Aug 24 '12 at 11:26
tnx;) intersections is quite crucial... computing the intersection of a line a a circle segment is not exactly trivial (at least for me... and even more so in TeX). –  Sašo Živanović Aug 24 '12 at 11:32
Great! That works really good and is, as you said, the only proper solution to this! –  boothby81 Aug 25 '12 at 13:46
THANKS to Andrew for raising interest in this question by adding the bounty (I had exactly the same problem and asked for help in the chat) and of course to Saso for coding this solution! –  boothby81 Aug 25 '12 at 13:56

It looks a bit different, but you could use the rounded rectangle shape:

\usetikzlibrary{shapes.misc}

\begin{tikzpicture} [sibling distance=100]
\node[rounded rectangle, draw]{ }
child { node { } }
child { node { } }
;
\end{tikzpicture}


This gives

Note that the sides are now complete half-circles, not two quarter-circles joined by a line.

-
Thanks, I didnt know rounded rectangle exists. Why do we need rounded corners? ... Maybe to use in paths? –  Łukasz Lew Aug 9 '10 at 17:26
Yes, rounded corners draws paths with rounded corners. So In your example, the path around the node was drawn with rounded corners, but the shape of the node was not modified. –  Caramdir Aug 9 '10 at 18:09
"doesn't work" as in "does not compile" or as in "i do not like how it looks"? In the first case what is the error? In the second: As far as I know there is no easy way, but my knowledge of TikZ's capabilities is not complete. –  Caramdir Aug 9 '10 at 18:52
I do not like how it looks. I have very vertical nodes so the roundness doesn't look well (even if I set round rectangle=45). It just doesn't look good. I didn't found "rounded corners rectangle" in shapes library, also I don't know how to move anchors towards rounded paths ... –  Łukasz Lew Aug 10 '10 at 11:37
Sorry, in that case I cannot really help you (other than what was already suggested on SO: draw the tree with empty named nodes and then overdraw with the nodes). The only "clean" solution can think of involves defining a "rounded corners rectangle" shape and that is beyond my knowledge of TikZ. Maybe add a feature request for pgf/TikZ: sourceforge.net/tracker/?group_id=142562&atid=752795 –  Caramdir Aug 10 '10 at 15:28

If you just want the branches to connect directly to the nodes you can shorten them by a small negative amount:

\documentclass[border=4pt,png]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture} [sibling distance=100,shorten >=-1pt,shorten <=-1pt]
\node[rectangle, draw, rounded corners = 3]{ }
child { node[rectangle, draw, rounded corners = 3] { } }
child { node[rectangle, draw, rounded corners = 3] { } }
;
\end{tikzpicture}

\end{document}


-
This is a fast and simple way to achieve the desired effect. However, if you have several nodes in various relations to each other or with different values of rounded corners it requires a lot of manual work. –  boothby81 Aug 25 '12 at 13:43