14

I'm trying to create a cylinder with 3D shading effects. The cylinders in the picture are standing vertically, and have a body and an end. I'd like the body to be shaded so that it varies uniformly from dark on the left side of the cylinder body to light in the middle (facing the viewer) to dark on the right again (light shading effect). The color should remain the same in a vertical direction. If the same is possible for the cylinder end that would be nice, but it is not so important.

I did some experimentation. Cylinder A below has some shading effect, but I have no idea how I got it. I don't even know whether it makes sense to use shade as an argument to a node, except that it is clearly doing something.

Cylinder B is similar to what I want, except for the shading effect.

This was tested with PGF 2.0 and Tex Live 2009 on Debian squeeze.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,decorations.fractals,shadows}
\usepackage[active,tightpage]{preview}
\PreviewEnvironment{tikzpicture}
\begin{document}
\pagestyle{empty}
\begin{tikzpicture}    
\tikzset{draw, name=s, shape=cylinder, line width=0.1cm, shape
    border rotate=90, aspect=.2, inner xsep=3cm, inner ysep=2cm,
    cylinder uses custom fill, cylinder end fill=blue!25, cylinder
    body fill=blue!40};
  \node [aspect=0.25, shade={left color=red!20,right color=blue!50}] at (1,0) {A};
  \node[aspect=0.10] at (10,0) {B};
\end{tikzpicture}
\end{document}
Hendrik Vogt
  • 37,935
Faheem Mitha
  • 7,778
  • 1
    As far as I can tell, even in pgf 2.10, there seems to be no way to shade the cylinder body and the cylinder end separately. Any shading or filling that you apply to a cylinder node will be applied to the outline path of the node. I think the only ways to do it are: 1) define a custom shape by modifying the cylinder shape, or 2) don't use shapes and draw the cylinders from scratch. – Jan Hlavacek Feb 09 '11 at 16:57
  • Hi Jan. Ok, how would one shade them together? I'd also be interested in solutions to the other two possibilities you suggest. – Faheem Mitha Feb 09 '11 at 17:03
  • I'd also like to know what is going on with cylinder A? Though should that be a separate question? – Faheem Mitha Feb 09 '11 at 18:56
  • For the cylinder A, you specify shading for the node. TikZ shades the node like you asked it, but for the cylinder, it considers the node to be the whole cylinder. That's what I meant by writing that you cannot shade the body and the end separately. It should be possible to modify the code in pgflibraryshapes.geometric.code.tex and add keys and code for shading, but I don't have time to do that right now. Give me few days, I will try something, unless someone else comes up with a better solution. – Jan Hlavacek Feb 09 '11 at 19:20
  • Hi Jan, Well except that for my code for cylinder A the shading is the wrong way (it goes from top to bottom, not left to right) and the color is a sort of grey. If appropriate and useful, I could upload the figure here. – Faheem Mitha Feb 09 '11 at 21:31
  • @Faheem: Don't use shade={left color=red!20,right color=blue!50}, but instead just the two options left color=red!20,right color=blue!50. That automatically sets shading=axis and shade (see p. 140 in the pgf manual v 2.0). If you want a middle color, add middle color=<some color> after left color and right color. – Jake Feb 09 '11 at 22:14
  • Wow! Thanks Jake, that does work, and looks good. Though not as good as yours and Jans solutions. I wonder what tikz thought the shade option was for... – Faheem Mitha Feb 11 '11 at 06:59
  • The shade option just switches shading on, it discards any arguments you pass to it. If you do not specify a type of shading using the shading=<name> option or using the left color right color options, the standard shading will be used, which is an axial shading from grey to white (see p. 165, section 15.6 in the manual). – Jake Feb 12 '11 at 11:33
  • If you want people to be notified of your comment, you need to include @ in your comment. Only the creator of the question or answer that a comment is added to will get notified automatically. In this thread, that's only you, because you are the poster of the question. See this question on meta. – Jake Feb 12 '11 at 11:37
  • @Faheem: Note that you don't have to (and in fact shouldn't) sign with your name since it automatically appears in the lower right corner of your post. – Hendrik Vogt Feb 12 '11 at 20:57

3 Answers3

15

You can use the predefined cylinder shape and then draw an ellipse with a solid fill on top. With the following code, you can supply all the options to the cylinder shape as before, the let code in the ellipse takes care of the position, size and rotation of the ellipse. You only need to adjust the colour.

The operation let \p<number> = (<coordinate>) in ... is described on p. 150 (section 14.15) in the pgf manual: It assigns a point described by (<coordinate>) to the local variable \p<number>, where <number> can be arbitrarily chosen. The variables \x<number> and \y<number> then contain the x and y values of the point. The registers \n<number> can be used to store results from mathematical operations.

The construct <coordinate>!<number>!<second coordinate> is described on p. 135 (section 13.5.5) in the manual: It describes a point along the line from <first coordinate> to <second coordinate>, where the value 0 would be at the first point, 1 at the second, and 0.5 halfway in between.

The points (cyl.before top), (cyl.after top) and (cyl.top) are defined by the cylinder shape (see p. 434, section 48.3 in the pgf manual).

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,calc}
\begin{document}
\begin{tikzpicture}

\node [draw,
  shape=cylinder,
  name=nodename, % Can be defined arbitrarily
  alias=cyl, % Will be used by the ellipse to reference the cylinder
  aspect=1.5,
  minimum height=3cm,
  minimum width=2cm,
  left color=blue!30,
  right color=blue!60,
  middle color=red!20, % Has to be called after left color and middle color
  outer sep=-0.5\pgflinewidth, % to make sure the ellipse does not draw over the lines
  shape border rotate=90
] at (1,2) {A};

\fill [red!20] let
  \p1 = ($(cyl.before top)!0.5!(cyl.after top)$),
  \p2 = (cyl.top),
  \p3 = (cyl.before top),
  \n1={veclen(\x3-\x1,\y3-\y1)},
  \n2={veclen(\x2-\x1,\y2-\y1)},
  \n3={atan2((\y2-\y1),(\x2-\x1))}
 in 
  (\p1) ellipse [x radius=\n1, y radius = \n2, rotate=\n3];

\end{tikzpicture}
\end{document}

enter image description here


Version for PGF 2.0

For PGF 2.0, the code needs to be adapted slightly, because the mathematical function atan2 is missing in the old version and the syntax for an ellipse is different.

The operation let \p = () in ... is described on p. 127 (section 13.14) in the pgf 2.0 manual ('The Let Operation').

The construct <coordinate>!<number>!<coordinate> is described on p. 116, section 12.4.3 in the pgf 2.0 manual.

The points (cyl.before top), (cyl.after top) and (cyl.top) are defined by the cylinder shape (see p. 326, section 39.3 ('Geometric Shapes') in the pgf 2.0 manual).

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,calc}
\begin{document}
\begin{tikzpicture}

\node [draw,
  shape=cylinder,
  name=nodename, % Can be defined arbitrarily
  alias=cyl, % Will be used by the ellipse to reference the cylinder
  aspect=1.5,
  minimum height=3cm,
  minimum width=2cm,
  left color=blue!30,
  right color=blue!60,
  middle color=red!20, % Has to be called after left color and middle color
  outer sep=-0.5\pgflinewidth, % to make sure the ellipse does not draw over the lines
  shape border rotate=90
] at (1,2) {A};

\fill [red!20] let
  \p1 = ($(cyl.before top)!0.5!(cyl.after top)$),
  \p2 = (cyl.top),
  \p3 = (cyl.before top),
  \n1={veclen(\x3-\x1,\y3-\y1)},
  \n2={veclen(\x2-\x1,\y2-\y1)}
 in 
  (\p1) ellipse (\n1 and \n2);

\end{tikzpicture}
\end{document}
Jake
  • 232,450
  • Hi Jake. Well, that looks very fancy. I'll have to study it. Hmm. I get ERROR: Package PGF Math Error: Unknown function `atan2'. – Faheem Mitha Feb 09 '11 at 21:11
  • @Faheem: Thank you, I'm flattered =) My understanding is that it is appropriate to ask questions directly related to the answer (like "why did you use atan2 here?"), but if more general topics are touched upon ("How do I rotate predefined shapes by an arbitrary angle?"), they should be in a separate question. – Jake Feb 09 '11 at 21:15
  • Sorry, I guess I edited at the same time as you answered. I'm guessing that atan2 is only in 2.10? – Faheem Mitha Feb 09 '11 at 21:17
  • @Faheem: Ah, it seems that this very useful function is not included in pgf v 2.0 (you should upgrade to 2.10 independently of this issue, there are many excellent features in the current version!). If you only need vertical cylinders, you can remove the line \n3=..., the final comma in the line before that, and the rotate=\n3 command in the ellipse options, and everything should work fine. – Jake Feb 09 '11 at 21:20
  • Assuming I followed your instructions properly, I'm now getting: ERROR: Package tikz Error: Cannot parse this radius. l.27 in (\p1) ellipse [x radius=\n1, y radius =\n2]; – Faheem Mitha Feb 09 '11 at 21:37
  • I'd like to upgrade, but Debian currently only has 2.10, and other people need to be able to run this code too. I guess I could create a 2.10 package and distribute it... – Faheem Mitha Feb 09 '11 at 21:39
  • @Faheem: Okay, I've played around with the online LaTeX compiler "scribtext", which still uses pgf 2.0: The syntax for drawing ellipses changed between the versions. If you change the (\p1) ellipse... line to (\p1) ellipse (\n1 and \n2);, it should work. – Jake Feb 09 '11 at 22:07
  • Thanks, it works now. Shall I edit your solution to add a 2.0 version? Unless you'd rather. – Faheem Mitha Feb 11 '11 at 07:42
  • @Faheem: By all means, go ahead! – Jake Feb 11 '11 at 07:43
  • Hi Jake, I'm going through the example, but am unable to figure out what the syntax \p1 = ($(cyl.before top)!(cyl.top)!(cyl.after top)$) means. Can you explain, preferably with a reference to the manual? From context this must be the center of the ellipse. Thanks. – Faheem Mitha Feb 12 '11 at 11:30
  • @Faheem: I've added the code for v 2.0 and the explanations to my answer. – Jake Feb 12 '11 at 13:07
  • @Jake: Hi Jake. You forgot to mention these references are to the 2.10 manual. I suggest moving the discussion section following "Version for PGF 2.0" earlier to correspond to the 2.10 code (since it applies to both), and you can add references to the PGF 2.0 manual after. I don't have space here, so I added it in an answer below. If you want to merge it into the your answer, I can delete the answer after. – Faheem Mitha Feb 12 '11 at 15:57
  • @Faheem: It would still have fitted in a comment, I think. But don't worry. What I recommend: If you really need to post an "answer" like your answer here, say in the beginning of it that it's not an answer, and that you'll delete it soon. – Hendrik Vogt Feb 12 '11 at 16:05
  • @Hendrik: With the extra verbiage above, no, it wouldn't, I tried. :-) I guess I could have split it into two comments. In any case, comments for anything longer than a tweet are a drag. After a while they can't be edited, and they can't be properly formatted either. Thanks for the suggestion, I changed my "answer". – Faheem Mitha Feb 12 '11 at 17:04
  • @Faheem: Thanks for looking up all the references, I've incorporated them into the answer now. – Jake Feb 12 '11 at 17:08
  • @Jake: Hmm, apparently I can't just delete the post. Didn't realise that. Well, live and learn. Next time I guess I'll use multiple comments. Have voted to delete. :-) – Faheem Mitha Feb 12 '11 at 17:53
  • @Faheem: I was really confused the first time I deleted one of my answers, too: Your post is already deleted. A "vote to close" on one's own post or by a moderator immediately counts as "enough votes to reach the threshold". – Jake Feb 12 '11 at 17:56
  • @Jake: Thanks for the clarification. It is still showing here in a sort of pinkified zombie state, though now marked "deleted by owner". – Faheem Mitha Feb 12 '11 at 18:27
  • @Faheem: Yeah, I believe it will stay there indefinitely for you, but no one else can see any trace of it. – Jake Feb 12 '11 at 18:31
  • @Jake: Minor comment. One could alternatively use \p1 =($(cyl1.before top)!0.5!(cyl1.after top)$) (Section 12.4.4, 'The Syntax of Distance Modifiers' pg 115 in the TikZ 2.0 manual). This (the midpoint) seems simpler and all that is needed unless I'm missing something. Incidentally, what do the $ do here? I do get an error without them. – Faheem Mitha Feb 12 '11 at 19:51
  • @Jake: Minor question. You write - alias=cyl, % Will be used by the ellipse to reference the cylinder. However, if I set name=cyl1, for example, omit the alias, and use cyl1 as you do, it works just fine. So, why is the alias necessary? – Faheem Mitha Feb 12 '11 at 20:32
  • @Faheem: Good point about the halfway modifier, that is indeed simpler and sufficient. I've changed the code accordingly. The ($...$) invokes the coordinate transformation operations provided by the calc library (see p. 134, section 13.5 "Coordinate Calculations" in the pgf manual v 2.1). – Jake Feb 12 '11 at 20:47
  • @Faheem: alias allows to add an alternative name to a node. I've used it here as an "internal" name that is not changed or referenced by the user, but only by the ellipse macro. Imagine you want to draw a second cylinder: You can then just copy the code for the cylinder-ellipse pair, change the name of the second, and then refer to them unambiguously. If the ellipse would use the name, you'd have to change all instances of the reference in the ellipse code. Of course, you could just as well define the internal name using name and define an alias to refer to the cylinders later on. – Jake Feb 12 '11 at 20:55
  • @Jake: Re the halfway modifier, suggest updating the 2.0 reference accordingly. Thanks for the clarification about the $. I should have looked earlier in the section. – Faheem Mitha Feb 12 '11 at 21:22
  • @Jake: wrt your alias comment, are you thinking of each cylinder pair as a separate tikzpicture? If not, I don't understand how alias could be considered as a name internal to the cylinder/ellipsa pair that is only used by the ellipse macro. Within one picture, the alias is visible everywhere, right? If you are thinking about separate pictures, this then becomes a scoping issue. It seems that names are visible across pictures (globally), with the remember picture option, but I don't know if aliases are visible too. Of course, I may be misunderstanding you completely. – Faheem Mitha Feb 13 '11 at 10:07
  • @Faheem: I guess "internal" isn't the correct term, I meant that the name defined by alias is not supposed to be used by the user, but only by the ellipse command. If there's only once cylinder in the tikzpicture, there's no point in having anameand analias, but if you have two or more, you need a unique name for each cylinder so you can refer to them later on (\draw (cylinder1) -- (cylinder2);, for example). In my code,cylwill always refer to the most recent cylinder, but the user chosennamewill refer to the same cylinder throughout thetikzpicture`. – Jake Feb 13 '11 at 10:27
  • @Jake: Ah, I think I see what you mean. Just to elaborate, suppose I have two cylinders with names username1 and username2 and both with the same alias cyl, and corresponding ellipses ellipse1 and ellipse2 as in your example. Then, provided the ellipse code follows the cylinder code in each case, the ellipse code for both ellipse1 and ellipse2 can be the identical block of code since it references cyl, and the alias cyl gets overwritten to point to cylinder2 after the cylinder2 code runs. – Faheem Mitha Feb 14 '11 at 21:27
  • @Jake: Addendum: please correct "is described on p. 116 (section 12.4.5)..." in your answer to use the correct 2.0 reference for midpoint, namely Section 12.4.3, 'The Syntax of Partway Modifiers' pg 114. – Faheem Mitha Feb 14 '11 at 21:28
  • @Faheem: That's exactly what I meant! And thanks for looking up the correct reference, I've included it in the answer now. – Jake Feb 14 '11 at 21:42
  • 1
    @Jake: Thanks for all your assistance with this. I learned a lot! – Faheem Mitha Feb 15 '11 at 07:47
9

For creating a standalone cylinder, without using the predefined TikZ shapes, you can do something like this:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\pagestyle{empty}
\begin{tikzpicture}    
   \coordinate (ll) at (-3,-2);
   \coordinate (lr) at (3,-2);
   \coordinate (ul) at (-3,2);
   \coordinate (ur) at (3,2);
   \shade [shading angle=90] (ll) arc (-180:-60:3cm and .75cm) -- +(0,4) arc (-60:-180:3cm and .75cm) -- cycle;
   \shade [shading angle=270] (lr) arc (0:-60:3cm and .75cm) -- +(0,4) arc (-60:0:3cm and .75cm) -- cycle;
   \draw [thick] (ll) arc (-180:0:3cm and .75cm) -- (ur) arc (0:-180:3cm and .75cm) -- cycle;
   \draw [thick, shade, shading angle=30] (ul) arc (-180:180:3cm and .75cm);
   \node at (0,-.75){\Huge A};
\end{tikzpicture}
\end{document} 
Jan Hlavacek
  • 19,242
7

Just for fun. The above answers are great. However, Jan's answer doesn't create a node. Jake's fantastic answer constructs the ellipse in two steps. This is not at all a bad thing, but one may want to construct it in one go. Here is a way to do it in one step. I did not come up with the path of the end, rather this is just copied from the shapes.geometric library. It seems possible to (ab)use path pictures to "host" some pgf code that one finds some other places. I do not know if that has been mentioned before on this site, if it was, I will be happy to give proper credit, nor do I know if there are major pitfalls. I only did very limited testing, so please use this with care.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{shapes.geometric}
\begin{document}
\tikzset{cylinder end fill/.style={path picture={
\pgftransformshift{\centerpoint}%
\pgftransformrotate{\rotate}%  
\pgfpathmoveto{\beforetop}%
\pgfpatharc{90}{-270}{\xradius and \yradius}%
\pgfpathclose
\pgfsetfillcolor{#1}%
\pgfusepath{fill}}
}}
\begin{tikzpicture}
\pgfmathsetmacro{\myaspect}{pi/4}
\node [draw,
  shape=cylinder,
  aspect=\myaspect,
  minimum height=3cm,
  minimum width=2cm,
  rotate=20,
  cylinder end fill=blue,
  left color=blue!30,
  right color=black,
  middle color=blue!80,
  shading angle=20,
  font=\sffamily,
  text width=pi*1cm,
  text=white]  {Hello world, ducks, koalas and marmots!};
\end{tikzpicture}
\end{document}

enter image description here

OLDER ANSWER: (unnecessarily complicated) In this answer, a "new" shape gets declared based on the standard cylinder. I did not extensively test it, I merely did it to learn something new. The new thing I learned is in the upper part of the answer.

\documentclass{beamer}
\setbeamertemplate{navigation symbols}{}
\usepackage{tikz} 
\usetikzlibrary{shapes.geometric}
\makeatletter

% Additional keys for shape "shaded cylinder"
%
% /pgf/cylinder body top shade  : Custom shading color for the cylinderbody.
% /pgf/cylinder body middle shade: Custom shading color for the cylinderbody.
% /pgf/cylinder body bottom shade : Custom shading color for the cylinderbody.
%


\newif\ifpgfcylinderusescustomshade
\pgfkeys{/pgf/.cd,
    cylinder uses custom shade/.is if=pgfcylinderusescustomshade,
    cylinder end fill/.initial=white,
    cylinder body top shade/.initial=white,
    cylinder body middle shade/.initial=white,
    cylinder body bottom shade/.initial=white,
    cylinder body shade angle/.initial=0,
}



\pgfdeclareshape{shaded cylinder}{%
    \savedmacro\getcylinderpoints{%
        \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/inner xsep}}%
        \pgf@x\pgf@xc%
        \advance\pgf@x.5\wd\pgfnodeparttextbox%
        \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/inner ysep}}%
        \pgf@y\pgf@yc%
        \advance\pgf@y.5\ht\pgfnodeparttextbox%
        \advance\pgf@y.5\dp\pgfnodeparttextbox%
        \ifpgfshapeborderusesincircle%
            \pgfmathsetmacro\rotate{\pgfkeysvalueof{/pgf/shape border rotate}}%
            \ifdim\pgf@x<\pgf@y%
                \pgf@x\pgf@y%
            \else%
                \pgf@y\pgf@x%
            \fi%
            \pgf@x1.414213\pgf@x%
            \pgf@y1.414213\pgf@y%           
        \else%
            \pgfmathmod{\pgfkeysvalueof{/pgf/shape border rotate}}{360}%
            \ifdim\pgfmathresult pt<0pt\relax%
                \pgfmathadd@{\pgfmathresult}{360}%
            \fi%
            \pgfmathsetcount\c@pgf@counta{+\pgfmathresult}%
            \advance\c@pgf@counta45\relax%
            \divide\c@pgf@counta90\relax%
            \multiply\c@pgf@counta90\relax%
            \edef\rotate{\the\c@pgf@counta}%
            \ifnum\c@pgf@counta=90\relax%
                \pgf@xa\pgf@x%
                \pgf@x\pgf@y%
                \pgf@y\pgf@xa%
                \pgf@yc\pgf@xc%
            \else%
                \ifnum\c@pgf@counta=270\relax%
                    \pgf@xa\pgf@x%
                    \pgf@x\pgf@y%
                    \pgf@y\pgf@xa%
                    \pgf@yc\pgf@xc%
                \fi%
            \fi%
        \fi%
        \addtosavedmacro\rotate%
        \pgf@xa\pgf@x%
        \pgf@ya\pgf@y%
        \pgfutil@tempdima\pgfshapeaspect\pgf@ya%
        \pgfutil@tempdimb\pgf@ya%
        %
        % Adjust for minimum height.
        %
        \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}%
        \ifdim\pgfutil@tempdimb<.5\pgf@xc\relax%
            \pgfutil@tempdimb.5\pgf@xc%
            \pgf@ya\pgfutil@tempdimb%
        \fi%
        %
        % Calculate how far the node contents can extend into the cylinder bottom.
        %
        \pgf@yb\pgfutil@tempdimb%
        \advance\pgf@yb-\pgf@yc%
        \pgfmathdivide@{\pgfmath@tonumber{\pgf@yb}}{\pgfmath@tonumber{\pgfutil@tempdimb}}%
        \pgfmathasin@{\pgfmathresult}%
        \pgfmathcos@{\pgfmathresult}%
        \let\angle\pgfmathresult%
        \pgf@xb\pgfmathresult\pgfutil@tempdima%
        %
        % Adjust for minimum width.
        %
        \pgf@x.5\pgflinewidth%
        \advance\pgf@x2.0\pgf@xa%
        \advance\pgf@x3.0\pgfutil@tempdima%
        \advance\pgf@x-\pgf@xb%
        \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum height}}%
        \ifdim\pgf@x<\pgf@xc%
            \advance\pgf@xc-\pgf@x%
            \advance\pgf@xa.5\pgf@xc%
        \fi%        
        %
        % Add the larger of the outer sep to the radii.
        %
        \pgf@x\pgfutil@tempdima\relax%
        \pgf@y\pgfutil@tempdimb\relax%
        \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/outer xsep}}%
        \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/outer ysep}}%
        \ifdim\pgf@xc>\pgf@yc%
            \advance\pgf@x\pgf@xc%
            \advance\pgf@y\pgf@xc%
            \edef\outersep{\the\pgf@xc}%
        \else%
            \advance\pgf@x\pgf@yc%
            \advance\pgf@y\pgf@yc%
            \edef\outersep{\the\pgf@yc}%
        \fi%
        \edef\xradius{\the\pgf@x}%
        \edef\yradius{\the\pgf@y}%
        \addtosavedmacro\xradius%
        \addtosavedmacro\yradius%
        \addtosavedmacro\outersep%
        %
        \pgfextract@process\cylindercenter{%
            \pgf@x\pgfutil@tempdima%
            \advance\pgf@x.5\pgflinewidth%
            \advance\pgf@x\pgf@xb%
            \pgf@x.5\pgf@x% 
            \pgf@y0pt%
        }%
        \addtosavedmacro\cylindercenter%
        %
        \pgfextract@process\beforetop{%
            \pgf@x\pgf@xa%
            \advance\pgf@x\pgfutil@tempdima%
            \advance\pgf@x.5\pgflinewidth%
            \pgf@y\pgf@ya%
        }%
        \pgfextract@process\afterbottom{%
            \pgf@x-\pgf@xa%
            \advance\pgf@x\pgf@xb%
            \pgf@y\pgf@ya%
        }%
        \addtosavedmacro\beforetop%
        \addtosavedmacro\afterbottom%       
        \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/outer ysep}}%
        \pgfextract@process\beforetopanchor{%
            \beforetop%
            \advance\pgf@y\pgf@yc%
        }%
        \pgfextract@process\afterbottomanchor{%
            \afterbottom%
            \advance\pgf@y\pgf@yc%
        }%
        \addtosavedmacro\beforetopanchor%       
        \addtosavedmacro\afterbottomanchor% 
        %
        \beforetopanchor%
        \advance\pgf@x\xradius\relax%
        \ifdim\pgf@x>\pgf@y%
            \edef\externalradius{\the\pgf@x}%
        \else%
            \edef\externalradius{\the\pgf@y}%
        \fi%
        \addtosavedmacro\externalradius%
    }
    \savedanchor\centerpoint{%
        \pgf@x.5\wd\pgfnodeparttextbox%
        \pgf@y.5\ht\pgfnodeparttextbox%
        \advance\pgf@y-.5\dp\pgfnodeparttextbox%
    }%
    \savedanchor\midpoint{%
        \pgf@x.5\wd\pgfnodeparttextbox%
        \pgfmathsetlength\pgf@y{+0.5ex}%
    }%
    \savedanchor\basepoint{%
        \pgf@x.5\wd\pgfnodeparttextbox%
        \pgf@y0pt%
    }%
    \anchor{center}{\centerpoint}
    \anchor{shape center}{%
        \getcylinderpoints%
        \pgfmathrotatepointaround{\pgfpointadd{\cylindercenter}{\centerpoint}}%
            {\centerpoint}{\rotate}%    
    }%
    \anchor{mid}{\midpoint}%
    \anchor{mid east}{%
        \getcylinderpoints%
        \let\pgf@cylinder@referencepoint\midpoint%
        \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{0pt}}%
    }%
    \anchor{mid west}{%
        \getcylinderpoints%
        \let\pgf@cylinder@referencepoint\midpoint%
        \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{0pt}}%
    }%
    \anchor{base}{\basepoint}%
    \anchor{base east}{%
        \getcylinderpoints%
        \let\pgf@cylinder@referencepoint\basepoint%
        \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{0pt}}%
    }%
    \anchor{base west}{%
        \getcylinderpoints%
        \let\pgf@cylinder@referencepoint\basepoint%
        \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{0pt}}%
    }%
    \anchor{north}{%
        \getcylinderpoints%
        \pgf@anchor@cylinder@border{\pgfqpoint{0pt}{\externalradius}}%
    }%
    \anchor{south}{%
        \getcylinderpoints%
        \pgf@anchor@cylinder@border{\pgfqpoint{0pt}{-\externalradius}}%
    }%
    \anchor{east}{%
        \getcylinderpoints%
        \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{0pt}}%
    }%
    \anchor{west}{%
        \getcylinderpoints%
        \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{0pt}}%
    }%
    \anchor{north east}{%
        \getcylinderpoints%
        \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{\externalradius}}%
    }%
    \anchor{south west}{%
        \getcylinderpoints%
        \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{-\externalradius}}%
    }%
    \anchor{south east}{%
        \getcylinderpoints%
        \pgf@anchor@cylinder@border{\pgfqpoint{\externalradius}{-\externalradius}}%
    }%
    \anchor{north west}{%
        \getcylinderpoints%
        \pgf@anchor@cylinder@border{\pgfqpoint{-\externalradius}{\externalradius}}%
    }%
    \anchor{before top}{%
        \getcylinderpoints%
        \pgfmathrotatepointaround{\pgfpointadd{\beforetopanchor}{\centerpoint}}{\centerpoint}{\rotate}%
    }
    \anchor{top}{%
        \getcylinderpoints%
        \pgfmathrotatepointaround{%
            \pgfpointadd{%
                \beforetop%
                \pgf@y0pt\relax%
                \advance\pgf@x\xradius\relax%
            }{\centerpoint}}{\centerpoint}{\rotate}%
    }
    \anchor{after top}{%
        \getcylinderpoints%
        \pgfmathrotatepointaround{\pgfpointadd{\beforetopanchor\pgf@y-\pgf@y}{\centerpoint}}{\centerpoint}{\rotate}%
    }
    \anchor{before bottom}{%
        \getcylinderpoints%
        \pgfmathrotatepointaround{\pgfpointadd{\afterbottomanchor\pgf@y-\pgf@y}{\centerpoint}}{\centerpoint}{\rotate}%
    }
    \anchor{bottom}{%
        \getcylinderpoints%
        \pgfmathrotatepointaround{%
            \pgfpointadd{%
                \afterbottom%
                \pgf@y0pt\relax%
                \advance\pgf@x-\xradius\relax%
            }{\centerpoint}}{\centerpoint}{\rotate}%
    }
    \anchor{after bottom}{%
        \getcylinderpoints%
        \pgfmathrotatepointaround{\pgfpointadd{\afterbottomanchor}{\centerpoint}}{\centerpoint}{\rotate}%
    }   
    \backgroundpath{%
        \getcylinderpoints%
        {%
            \pgf@x\xradius\relax%
            \advance\pgf@x-\outersep\relax%
            \edef\xradius{\the\pgf@x}%
            \pgf@y\yradius\relax%
            \advance\pgf@y-\outersep\relax%
            \edef\yradius{\the\pgf@y}%
            \pgftransformshift{\centerpoint}%
            \pgftransformrotate{\rotate}%
            \pgfpathmoveto{\afterbottom}%
            \pgfpatharc{90}{270}{\xradius and \yradius}%
            \pgfpathlineto{\beforetop\pgf@y-\pgf@y}%
            \pgfpatharc{-90}{90}{\xradius and \yradius}%
            \pgfpathclose%
            \pgfpathmoveto{\beforetop}%
            \pgfpatharc{90}{270}{\xradius and \yradius}%
        }%
    }%
    \behindbackgroundpath{%
        \ifpgfcylinderusescustomfill%
            \getcylinderpoints%
            \pgf@x\xradius\relax%
            \advance\pgf@x-\outersep\relax%
            \edef\xradius{\the\pgf@x}%
            \pgf@y\yradius\relax%
            \advance\pgf@y-\outersep\relax%
            \edef\yradius{\the\pgf@y}%
            {%              
                \pgftransformshift{\centerpoint}%
                \pgftransformrotate{\rotate}%
                \pgfpathmoveto{\afterbottom}%
                \pgfpatharc{90}{270}{\xradius and \yradius}%
                \pgfpathlineto{\beforetop\pgf@y-\pgf@y}%
                \pgfpatharc{270}{90}{\xradius and \yradius}%
                \pgfpathclose%
                \expandafter\pgfsetfillcolor\expandafter{\pgfkeysvalueof{/pgf/cylinder body fill}}%
                \pgfusepath{fill}%
                %
                \pgfpathmoveto{\beforetop}%
                \pgfpatharc{90}{-270}{\xradius and \yradius}%
                \pgfpathclose
                \expandafter\pgfsetfillcolor\expandafter{\pgfkeysvalueof{/pgf/cylinder end fill}}%
                \pgfusepath{fill}%
            }%      
        \fi%    
        \ifpgfcylinderusescustomshade%
            \getcylinderpoints%
            \pgf@x\xradius\relax%
            \advance\pgf@x-\outersep\relax%
            \edef\xradius{\the\pgf@x}%
            \pgf@y\yradius\relax%
            \advance\pgf@y-\outersep\relax%
            \edef\yradius{\the\pgf@y}%
            {%                  
                %
                \expandafter\pgfdeclareverticalshading{cylindershade}{\yradius}
                    {color(0bp)=(\expandafter{\pgfkeysvalueof{/pgf/cylinder body top shade}});
                    color(0.5*\yradius)=(\expandafter{\pgfkeysvalueof{/pgf/cylinder body middle shade}});  
                    color(\yradius)=(\expandafter{\pgfkeysvalueof{/pgf/cylinder body bottom shade}})}           
                \pgftransformshift{\centerpoint}%
                \pgftransformrotate{\rotate}%
                \begin{pgfscope}%   
                \pgfpathmoveto{\afterbottom}%
                \pgfpatharc{90}{270}{\xradius and \yradius}%
                \pgfpathlineto{\beforetop\pgf@y-\pgf@y}%
                \pgfpatharc{270}{90}{\xradius and \yradius}%
                \pgfpathclose%
                \typeout{\pgfkeysvalueof{/pgf/cylinder body shade angle}}
                \expandafter\pgfshadepath{cylindershade}{\pgfkeysvalueof{/pgf/cylinder body shade angle}}%
                \pgfsetfillcolor{white}%
                \pgfsetfillopacity{0}%
                \pgfusepath{fill}%
                \end{pgfscope}
                %
                \pgfpathmoveto{\beforetop}%
                \pgfpatharc{90}{-270}{\xradius and \yradius}%
                \pgfpathclose
                \expandafter\pgfsetfillcolor\expandafter{\pgfkeysvalueof{/pgf/cylinder end fill}}%
                \pgfusepath{fill}%
            }%      
        \fi%    
    }%
    \anchorborder{%
        \pgfextract@process\externalpoint{}%
        \getcylinderpoints%
        \pgfutil@ifundefined{pgf@cylinder@referencepoint}{\let\referencepoint\centerpoint}{%
            \let\referencepoint\pgf@cylinder@referencepoint}%
        \pgfextract@process\externalpoint{%
            \externalpoint%
            \pgf@xa\pgf@x%
            \pgf@ya\pgf@y%
            \referencepoint%
            \advance\pgf@x\pgf@xa%
            \advance\pgf@y\pgf@ya%
        }%
        \pgfmathanglebetweenpoints{\centerpoint}{\externalpoint}%
        \pgfmathsubtract@{\pgfmathresult}{\rotate}%
        \ifdim\pgfmathresult pt<0pt\relax%
            \pgfmathadd@{\pgfmathresult}{360}%
        \fi%
        \let\externalangle\pgfmathresult%
        %
        \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\afterbottomanchor}{\centerpoint}}%
        \ifdim\externalangle pt<\pgfmathresult pt\relax%
            \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\beforetopanchor}{\centerpoint}}%
            \ifdim\externalangle pt<\pgfmathresult pt\relax%
                \pgfmathrotatepointaround{%
                    \pgfmathpointintersectionoflineandarc%
                        {\pgfmathrotatepointaround{\externalpoint}{\centerpoint}{-\rotate}}%
                        {\pgfmathrotatepointaround{\referencepoint}{\centerpoint}{-\rotate}}%
                        {%
                            \beforetop%
                            \pgf@xa\pgf@x%
                            \centerpoint%
                            \advance\pgf@x\pgf@xa%
                        }%
                        {0}{90}{\xradius and \yradius}%
                    }{\centerpoint}{\rotate}%
            \else%
                \pgfpointintersectionoflines{%
                    \pgfmathrotatepointaround{\pgfpointadd{\afterbottomanchor}{\centerpoint}}%
                        {\centerpoint}{\rotate}}{%
                    \pgfmathrotatepointaround{\pgfpointadd{\beforetopanchor}{\centerpoint}}%
                        {\centerpoint}{\rotate}}%
                    {\referencepoint}{\externalpoint}%
            \fi%
        \else%
            \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\afterbottomanchor\pgf@y-\pgf@y}{\centerpoint}}%
            \ifdim\externalangle pt>\pgfmathresult pt\relax%
                \pgfmathanglebetweenpoints{\referencepoint}{\pgfpointadd{\beforetopanchor\pgf@y-\pgf@y}{\centerpoint}}%
                \ifdim\externalangle pt>\pgfmathresult pt\relax%
                    \pgfmathrotatepointaround{%
                        \pgfmathpointintersectionoflineandarc%
                            {\pgfmathrotatepointaround{\externalpoint}{\centerpoint}{-\rotate}}%
                            {\pgfmathrotatepointaround{\referencepoint}{\centerpoint}{-\rotate}}%
                            {%
                                \beforetop%
                                \pgf@xa\pgf@x%
                                \centerpoint
                                \advance\pgf@x\pgf@xa%
                            }%
                            {270}{360}{\xradius and \yradius}%
                        }{\centerpoint}{\rotate}%
                \else%
                    \pgfpointintersectionoflines{%
                        \pgfmathrotatepointaround{\pgfpointadd{\afterbottomanchor\pgf@y-\pgf@y}{\centerpoint}}%
                            {\centerpoint}{\rotate}}{%
                        \pgfmathrotatepointaround{\pgfpointadd{\beforetopanchor\pgf@y-\pgf@y}{\centerpoint}}%
                            {\centerpoint}{\rotate}}%
                        {\referencepoint}{\externalpoint}%
                \fi%
            \else%
                \pgfmathrotatepointaround{%
                    \pgfmathpointintersectionoflineandarc%
                        {\pgfmathrotatepointaround{\externalpoint}{\centerpoint}{-\rotate}}%
                        {\pgfmathrotatepointaround{\referencepoint}{\centerpoint}{-\rotate}}%
                        {%
                            \afterbottom%
                            \pgf@xa\pgf@x%
                            \centerpoint
                            \advance\pgf@x\pgf@xa%
                        }%
                        {90}{270}{\xradius and \yradius}%
                    }{\centerpoint}{\rotate}%
            \fi%
        \fi%
    }
}
\makeatother



\begin{document}
\begin{frame}[t]
\frametitle{}
\begin{tikzpicture}[scale=1., transform shape]
\node [rotate=30,shaded cylinder,draw,thick,aspect=2.,minimum height=5cm,
minimum width=4cm,shape border rotate=30,cylinder uses custom shade, 
cylinder body top shade=black,
cylinder body middle shade=blue,
cylinder body bottom shade=blue!30,
cylinder body shade angle=30,
cylinder end fill=blue,text=white,font=\large
] at (0,0){Hello world, how are you doing!};
\end{tikzpicture}
\end{frame}
\end{document} 

enter image description here