I'm trying to make paths that are shaded to as to appear as cylinders with spherical ends.
I've found a way to do this with decorations.
I use vertical shading on rectangles for the path segments, and radial shading on circles for the path ends.
I need to get the ends visually behind the segments. I have thought of two ways to do this.
One method is to draw both ends before I draw the segments. The downside of this is that I don't have the right angle for the radial shading.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{decorations}
\usetikzlibrary{shadings}
\pgfdeclarelayer{barends}
\pgfsetlayers{barends,main}
\pgfdeclaredecoration{cylindricalbar}{initial}
{
\state{initial}[width=2pt,next state=middle]{
% sphere on end
\begin{pgfscope}
\pgfpathcircle{\pgfpointdecoratedpathlast}{5pt}
\pgfshadepath{barendshading}{\pgfdecoratedangle}
\end{pgfscope}
% sphere on start
\begin{pgfscope}
\pgfpathcircle{\pgfpoint{0}{0}}{5pt}
\pgfshadepath{barendshading}{\pgfdecoratedangle}
\end{pgfscope}
% first cylindrical segment
\begin{pgfscope}
\pgfpathrectanglecorners
{\pgfpoint{-1pt}{-5pt}}
{\pgfpoint{3pt}{5pt}}
\pgfshadepath{barshading}{\pgfdecoratedangle}
\end{pgfscope}
}
\state{middle}[width=2pt]
{
\begin{pgfscope}
\pgfpathrectanglecorners
{\pgfpoint{-1pt}{-5pt}}
{\pgfpoint{3pt}{5pt}}
\pgfshadepath{barshading}{\pgfdecoratedangle}
\end{pgfscope}
}
\state{final}
{
}
}
\begin{document}
\begin{tikzpicture}[decoration=cylindricalbar]
\pgfdeclareradialshading[mycolor,white]
{barendshading}
{\pgfpoint{0bp}{5bp}}
{color(0bp)=(white);
color(28bp)=(mycolor);
color(60bp)=(mycolor)}
\pgfdeclareverticalshading[mycolor,white]
{barshading}
{100bp}
{color(0bp)=(mycolor);
color(25bp)=(mycolor);
color(55bp)=(white);
color(75bp)=(mycolor);
color(100bp)=(mycolor)}
\colorlet{mycolor}{green}
\path [decorate] (0,0) -- (0,3);
\colorlet{mycolor}{red}
\path [decorate] (3,0) .. controls (3,2) and (2,3) .. (0,3);
\colorlet{mycolor}{blue}
\path [decorate] (0,0) -- (3,0);
\end{tikzpicture}
\end{document}
The second method is to put the bar ends on a layer that is placed behind the main layer. The downside to this is that if I draw two different bars, the end of the second bar lies behind the body of the first bar so it looks strange.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{decorations}
\usetikzlibrary{shadings}
\pgfdeclarelayer{barends}
\pgfsetlayers{barends,main}
\pgfdeclaredecoration{cylindricalbar}{initial}
{
\state{initial}[width=2pt,next state=middle]{
% sphere on start
\begin{pgfscope}
\pgfpathcircle{\pgfpoint{0}{0}}{5pt}
\pgfshadepath{barendshading}{\pgfdecoratedangle}
\end{pgfscope}
% first cylindrical segment
\begin{pgfscope}
\pgfpathrectanglecorners
{\pgfpoint{-1pt}{-5pt}}
{\pgfpoint{3pt}{5pt}}
\pgfshadepath{barshading}{\pgfdecoratedangle}
\end{pgfscope}
}
\state{middle}[width=2pt]
{
\begin{pgfscope}
\pgfpathrectanglecorners
{\pgfpoint{-1pt}{-5pt}}
{\pgfpoint{3pt}{5pt}}
\pgfshadepath{barshading}{\pgfdecoratedangle}
\end{pgfscope}
}
\state{final}
{
% sphere on end
\begin{pgfscope}
\begin{pgfonlayer}{barends}
\pgfpathcircle{\pgfpointdecoratedpathlast}{5pt}
\pgfshadepath{barendshading}{\pgfdecoratedangle}
\end{pgfonlayer}
\end{pgfscope}
}
}
\begin{document}
\begin{tikzpicture}[decoration=cylindricalbar]
\pgfdeclareradialshading[mycolor,white]
{barendshading}
{\pgfpoint{0bp}{5bp}}
{color(0bp)=(white);
color(28bp)=(mycolor);
color(60bp)=(mycolor)}
\pgfdeclareverticalshading[mycolor,white]
{barshading}
{100bp}
{color(0bp)=(mycolor);
color(25bp)=(mycolor);
color(55bp)=(white);
color(75bp)=(mycolor);
color(100bp)=(mycolor)}
\colorlet{mycolor}{green}
\path [decorate] (0,0) -- (0,3);
\colorlet{mycolor}{red}
\path [decorate] (3,0) .. controls (3,1) and (1,3) .. (0,3);
\colorlet{mycolor}{blue}
\path [decorate] (0,0) -- (3,0);
\end{tikzpicture}
\end{document}
Is there any way to (1) get the \pgfdecoratedangle of the final segment during while drawing the ininital segment, or (2) Put the final segment automatically on a layer below the the previous segment, but above all the segments on a previously drawn path?
I realize that I could create a bar end layer for each bar, and properly arrange the layers, but I'd rather not have to add a layer for each bar.




