# Dynamic radius for rounded corners

When using rounded corners, I sometimes specify a radius that looks great for most corners in the path, but a couple of points are too close together, so that I get ugly artifacts. I'd like to be able to specify the radius for rounded corners as a "target" or "maximum" value, with the radius automatically being reduced if points are too close together.

Consider the following example

In the first path, I manually reduced the radius for the first two corners, while in the second, the radius is identical for all corners, which introduces unwanted spikes.

Is there a clever way of getting rounded corners on paths that won't introduce these artifacts?

Here's the MWE:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\draw [rounded corners=0.5cm] (0,0) -- (2,0) -- (2,1) [rounded corners=1cm] -- (4,1) -- (4,-1);
\draw [rounded corners=1cm] (0,-2) -- (2,-2) -- (2,-1) -- (4,-1) -- (4,-3);
\end{tikzpicture}
\end{document}

-
How about just using [rounded corners] and not specifying a value? This seems to work for this particular example. – Peter Grill Oct 23 '11 at 2:46
@PeterGrill: In this example it works, because the default value of rounded corners is 4pt, which is small enough. But I'd like to be able to specify a value for the corners without having to worry about whether there are points on my path that are too close together. – Jake Oct 23 '11 at 2:57
It seems a lot of calculations is needed. – Leo Liu Oct 23 '11 at 6:16
I think that this would involve some severe hackery. Tracing through the code, I think that the rounded corners are calculated by \pgfprocess@specialround in basiclayer/pgfcorepathprocessing.code.tex. I guess you need some calculation in there to prevent the curve becoming too big. – Loop Space Oct 25 '11 at 10:52

Here's one approach using decorations. For each segment, the decoration automaton checks whether the target radius of the rounded corners is larger than half the length of the segment. If it is, the corner radius is set to half the length of the segment, otherwise it is left untouched. In some cases, this approach will reduce the corner radius unnecessarily, but it avoids having to analyse the complete path in order to determine the maximum possible radius for each corner:

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

\pgfdeclaredecoration{dynamic rounded corners}{initial}{
\state{initial}[width=\pgfdecoratedinputsegmentlength,
next state=middle,
persistent postcomputation=\pgfmathsetmacro\previousroundedendlength{min(\pgfdecorationsegmentlength,\pgfdecoratedinputsegmentlength)}
]{}
\state{middle}[width=\pgfdecoratedinputsegmentlength,next state=middle,
persistent precomputation={
\pgfmathsetmacro\roundedstartlength{min(\previousroundedendlength,\pgfdecoratedinputsegmentlength/2)}
},
persistent postcomputation=\pgfmathsetmacro\previousroundedendlength{min(\pgfdecorationsegmentlength,\pgfdecoratedinputsegmentlength/2)}
]{
\pgfsetcornersarced{\pgfpoint{\roundedstartlength}{\roundedstartlength}}
\pgfpathlineto{\pgfpoint{0pt}{0pt}}
}
\state{final}[if input segment is closepath={\pgfpathclose}]
{
\pgfpathlineto{\pgfpointdecoratedpathlast}
}
}

\tikzset{
dynamic rounded corners/.style={
decorate,
decoration={
dynamic rounded corners,
segment length=#1
}
}
}

\begin{document}
\begin{tikzpicture}[every node/.style={below right, align=center}]
\draw [xshift=-1.5cm, gray!50] (0,0) node {Original\\Path} -- (2,0) -- (1,1) -- (1,3) -- (3,3);
\draw [rounded corners=1cm]  node {Normal\\rounded\\corners} (0,0) -- (2,0) -- (1,1) -- (1,3) -- (3,3);
\draw [dynamic rounded corners=1cm,red,xshift=1.5cm] (0,0) node {Dynamic\\rounded\\corners}-- (2,0) -- (1,1) -- (1,3) -- (3,3);
\end{tikzpicture}
\end{document}

-
+1, great idea. Two minor nitpicks: it seems cycles are broken (and not rounded); and of course, you can't use it on decorations... :) (cf. the pgf doc p.596, red "complicated example decoration" to see an example where it would have been useful (zoom)) – FelixCQ Oct 26 '11 at 8:35