Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have searched through the internet for a solution, but since I'm not that skilled with pgfplots, I need your help. For several examples I want to draw solids of revolution, but filled ones. I started with this one:

\documentclass{scrartcl}

\usepackage{mathtools}
\usepackage{amssymb}
\usepackage{pgfplots}
\pgfplotsset{width=10cm, compat=1.8}

\begin{document}

\begin{center}
\begin{tikzpicture}
    \begin{axis}[
        title={Rotation um die x-Achse},
        colormap/greenyellow,
        view={15}{30}]    

        \addplot3[
            surf,
            shader=faceted,
            samples=50,
            domain=0:6,y domain=0:3*pi/2,
            z buffer=sort]
        (x,{(((2*x^4)/27) - ((4*x^3)/9)) * cos(deg(y))}, {(((2*x^4)/27) - ((4*x^3)/9)) * sin(deg(y))});
    \end{axis}
\end{tikzpicture}
\end{center}
\end{document}

It's open on the upper side and you can see "into" the shape. Since I need the volume of the shape in my examples, I wanted them cuts to be solid areas, like you cut them away with a knife. In the end, I like this quarter area to be half opaque, so you know it's the full object, but also be able to see if it's solid inside or hollow.

I have seen this question and I have almost the same problem, but those links and other questions here didn't fit.

I also have some examples, where you have to calculate the volume of two rotated functions, one substracted from the other. So there would be a hollow inside.

I'm not quite sure how to explain it, maybe I can create a descent drawing to make it clear. I hope you can help me! Thanks!

sample picture 1

sample picture 2

share|improve this question
    
Welcome to the site! This sounds like a duplicate of the question you have linked..... I can certainly understand the frustration of not seeing an answer, but to keep the site tidy, we try not to have too many repeated questions. The main thing that prevents an answer to linked question is that the parametrization of the solid is quite tricky; perhaps you could ask for help on that aspect on the math.stackexchange.com, which would enable you to move forward –  cmhughes Apr 26 at 15:45
    
Thanks for your quick response. I tried to figure it out on my own, since I just would need to draw two filled 2d-functions of ((2*x^4)/27) - ((4*x^3)/9) into this graph aswell, 90 degrees twisted around x, so it looks like it's "filled". I just can't manage to draw a filled 2d-graph into this 3d-plot –  Cheesey Apr 28 at 16:24
    
Here are 2 pictures, to clarify what I mean. The blue and the red graph are 2 filled plots of the 2D function. They are aligned with the "cut out" of the solid of revolution plot, so they are rotated 90° from each other. The second picture shows a version, where the bubble is not filled. Picture 1 Picture 2 –  Cheesey Apr 28 at 17:11
    
I'll take a look at these at some point - it should be doable. It might not be for a while, though, perhaps someone else will have some luck :) I'll edit them into your question.. Where did you get these images from? You might contact the author... –  cmhughes Apr 28 at 17:24
    
Thank you very much for your effort! Maybe someone here knows how to solve this problem. I made them myself, so there should be no problem. =) –  Cheesey Apr 28 at 19:26

3 Answers 3

up vote 9 down vote accepted

I believe the best way to address the problem of "solid of revolution" would be to use a suitable coordinate system - one in which you can enter the radius, the angle, and the protrusion along the axis.

Here is an attempt to reproduce your first picture:

enter image description here

\documentclass{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=1.9}

% \usetikzlibrary{}
% \usepgfplotslibrary{}


% defines a new value for 'data cs'.
%
% On input, this "data coordinate system" consists of 
% x=generatrix (=radius)
% y=<angle>
% z=distance along axis
%
% On output, it will show the z value on the X axis and the radius on
% the Y axis.
\pgfplotsdefinecstransform{polarrad along x}{cart}{%
    % First, swap axis such that we can apply polarrad->cart.
    % Note that polarrad expects (<angle>,<radius>,Z):
    \pgfkeysgetvalue{/data point/x}\X% copy value of /data point/x into \X
    \pgfkeysgetvalue{/data point/y}\Y
    \pgfkeyslet{/data point/y}\X% copy value of \X into /data point/y
    \pgfkeyslet{/data point/x}\Y
    \pgfplotsaxistransformcs
        {polarrad}
        {cart}%
    %
    % Ok, now we have cartesian. Swap axes such that we have them
    % along X:
    \pgfkeysgetvalue{/data point/x}\X
    \pgfkeysgetvalue{/data point/y}\Y
    \pgfkeysgetvalue{/data point/z}\Z
    \pgfkeyslet{/data point/y}\X
    \pgfkeyslet{/data point/z}\Y
    \pgfkeyslet{/data point/x}\Z
}%


\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        title={Rotation um die x-Achse},
        colormap/greenyellow,
        view={15}{30}]    

        \def\generatrix{(((2*x^4)/27) - ((4*x^3)/9))}

        \addplot3[
            surf,
            shader=faceted,
            samples=25,
            domain=0:6,
            domain y=0:3*pi/2,
            z buffer=sort,
            data cs=polarrad along x]
        ({\generatrix},y,x);

        \addplot3[
            blue,
            fill,
            fill opacity=0.5,
            samples=25,
            samples y=1,
            domain=0:6,
            data cs=polarrad along x]
        ({\generatrix},0,x) --cycle;

        \addplot3[
            orange,
            fill,
            fill opacity=0.5,
            samples=25,
            samples y=1,
            domain=0:6,
            data cs=polarrad along x]
        ({\generatrix},3*pi/2,x) --cycle;

    \end{axis}
\end{tikzpicture}

\end{document}

I have made use of data cs, the feature of pgfplots which allows to provide the data in a different coordinate system than that of the axis. The function pgfplotsdefinecstransform is only documented in the source code of pgfplots at the time of this writing; it defines a transformation from some input system to some output system. Pgfplots tries to use the available transformations whenever it encounters something like data cs=polarrad along x.

I also defined a macro containing your generatrix. The remaining code draws the surface of revolution as a surface plot which resembles yours.

The second two \addplot3 instructions are 3d parametric line plots (due to samples y=1); they use the same input sequence except that they fix y (which is the angle in our custom data cs).


Regarding your second image, you can make use of the fillbetween library which is shipped with pgfplots (as of version 1.10). Its purpose is to fill the area between two other (line) plots, compare Fill the area between two curves calculated by pgfplots or Fill between two curves in pgfplots. for simple applications.

If I understand correctly, you have some inner generating function and some outer generating function and the inner one defines the hole.

My idea would be to "plot" both with draw=none, name path=<some name> in order to label the resulting paths. Then we can fill the area between them.

Here is that approach:

enter image description here

\documentclass{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=1.10}

% \usetikzlibrary{}
\usepgfplotslibrary{fillbetween}


% defines a new value for 'data cs'.
%
% On input, this "data coordinate system" consists of 
% x=generatrix (=radius)
% y=<angle>
% z=distance along axis
%
% On output, it will show the z value on the X axis and the radius on
% the Y axis.
\pgfplotsdefinecstransform{polarrad along x}{cart}{%
    % First, swap axis such that we can apply polarrad->cart.
    % Note that polarrad expects (<angle>,<radius>,Z):
    \pgfkeysgetvalue{/data point/x}\X% copy value of /data point/x into \X
    \pgfkeysgetvalue{/data point/y}\Y
    \pgfkeyslet{/data point/y}\X% copy value of \X into /data point/y
    \pgfkeyslet{/data point/x}\Y
    \pgfplotsaxistransformcs
        {polarrad}
        {cart}%
    %
    % Ok, now we have cartesian. Swap axes such that we have them
    % along X:
    \pgfkeysgetvalue{/data point/x}\X
    \pgfkeysgetvalue{/data point/y}\Y
    \pgfkeysgetvalue{/data point/z}\Z
    \pgfkeyslet{/data point/y}\X
    \pgfkeyslet{/data point/z}\Y
    \pgfkeyslet{/data point/x}\Z
}%


\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        title={Rotation um die x-Achse},
        colormap/greenyellow,
        view={15}{30}]    

        \def\generatrix{(((2*x^4)/27) - ((4*x^3)/9))}

        \addplot3[
            surf,
            shader=faceted,
            samples=25,
            domain=0:6,
            domain y=0:3*pi/2,
            z buffer=sort,
            data cs=polarrad along x]
        ({\generatrix},y,x);

        % A Helper macro such that we do not need to repeat outselfes.
        %
        % It can be invoked with
        % \generatrix[<draw/fill options>]{<angle which defines slice>}{some unique text label}
        \newcommand\generateSlice[3][]{%
            \addplot3[
                draw=none,
                %blue, fill, fill opacity=0.5,
                name path=outline_y#3,
                samples=25,
                samples y=1,
                domain=0:6,
                data cs=polarrad along x]
            ({\generatrix},#2,x);

            \addplot3[
                smooth,
                draw=none,
                %red, fill, fill opacity=0.5,
                name path=inner_y#3,
                samples=25,
                samples y=1,
                domain=0:6,
                data cs=polarrad along x]
            coordinates {
                (0,#2,2)    (-2,#2,3) 
                (-2.5,#2,4.2) (0,#2,5.2)
            };

            \addplot[#1] fill between[
                % typically, the 'fill between' library tries to draw
                % its paths in a background layer. Avoid that:
                on layer=main,
                of=outline_y#3 and inner_y#3];
        }

        \generateSlice[draw,blue,fill opacity=0.5]{0}{first}

        \generateSlice[draw,orange,fill opacity=0.5]{3*pi/2}{second}

    \end{axis}
\end{tikzpicture}

\end{document}

In order to avoid repetitions, I used some helper macro for the two slices. I only provide the angle which defines the slice, the draw options, and the unique label on input.

Note that I provided the inner function by means of \addplot3 coordinates {<list>} which is perfectly valid in this context (as is any other 3d input).

Note that this fillbetween stuff is essentially unrelated to solids of revolution as indicated by the links above - but it works seamlessly.


There might be a further useful modification in order to visualize the hole: we could add a second solid of revolution in the middle. To this end, I took my last solution, replaced \addplot3 coordinates by some random inner generatrix and arrived at

enter image description here

\documentclass{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=1.9}

% \usetikzlibrary{}
\usepgfplotslibrary{fillbetween}


% defines a new value for 'data cs'.
%
% On input, this "data coordinate system" consists of 
% x=generatrix (=radius)
% y=<angle>
% z=distance along axis
%
% On output, it will show the z value on the X axis and the radius on
% the Y axis.
\pgfplotsdefinecstransform{polarrad along x}{cart}{%
    % First, swap axis such that we can apply polarrad->cart.
    % Note that polarrad expects (<angle>,<radius>,Z):
    \pgfkeysgetvalue{/data point/x}\X
    \pgfkeysgetvalue{/data point/y}\Y
    \pgfkeyslet{/data point/y}\X
    \pgfkeyslet{/data point/x}\Y
    \pgfplotsaxistransformcs
        {polarrad}
        {cart}%
    %
    % Ok, now we have cartesian. Swap axes such that we have them
    % along X:
    \pgfkeysgetvalue{/data point/x}\X
    \pgfkeysgetvalue{/data point/y}\Y
    \pgfkeysgetvalue{/data point/z}\Z
    \pgfkeyslet{/data point/y}\X
    \pgfkeyslet{/data point/z}\Y
    \pgfkeyslet{/data point/x}\Z
}%


\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        title={Rotation um die x-Achse},
        colormap/greenyellow,
        view={15}{30}]    

        \def\generatrix{(((2*x^4)/27) - ((4*x^3)/9))}

        \addplot3[
            surf,
            shader=faceted,
            samples=25,
            domain=0:6,
            domain y=0:3*pi/2,
            z buffer=sort,
            data cs=polarrad along x]
        ({\generatrix},y,x);

        \def\innergeneratrix{-10*(x-2)/2*(1-(x-2)/2)}
        \addplot3[
            surf,
            colormap/violet,
            shader=faceted,
            samples=7,
            domain=2:4,
            domain y=0:3*pi/2,
            z buffer=sort,
            data cs=polarrad along x]
        ({\innergeneratrix},y,x);

        % A Helper macro such that we do not need to repeat outselfes.
        %
        % It can be invoked with
        % \generatrix[<draw/fill options>]{<angle which defines slice>}{some unique text label}
        \newcommand\generateSlice[3][]{%
            \addplot3[
                draw=none,
                %blue, fill, fill opacity=0.5,
                name path=outline_y#3,
                samples=25,
                samples y=1,
                domain=0:6,
                data cs=polarrad along x]
            ({\generatrix},#2,x);

            \addplot3[
                draw=none,
                %red, fill, fill opacity=0.5,
                name path=inner_y#3,
                samples=7,
                samples y=1,
                domain=2:4,
                data cs=polarrad along x]
            ({\innergeneratrix},#2,x);

            \addplot[#1] fill between[
                % typically, the 'fill between' library tries to draw
                % its paths in a background layer. Avoid that:
                on layer=main,
                of=outline_y#3 and inner_y#3];
        }

        \generateSlice[draw,blue,fill opacity=0.5]{0}{first}

        \generateSlice[draw,orange,fill opacity=0.5]{3*pi/2}{second}

    \end{axis}
\end{tikzpicture}

\end{document}
share|improve this answer
    
This is exactly what I wanted! Thank you so much for your answer! It's a pity there is no easier way to do this, but it's not that complex aswell. Thank you, I'll use that! –  Cheesey Apr 29 at 7:44
1  
I'm glad it addresses your use-case. I agree that the definition on top looks frightening unless one is used to such definitions... one could, of course omit the special coordinate system and stick with cartesian coordinates. –  Christian Feuersänger Apr 30 at 7:59
1  
In order to answer your question completely and in order to advertise the relatively new fillbetween library, I added a solution for your second image as well. –  Christian Feuersänger Apr 30 at 7:59

With PSTricks and pst-solides3d. Run it with xelatex or the sequence latex->dvips->ps2pdf (is faster)

\documentclass{article}
\usepackage{pst-solides3d}

\begin{document}
\psset{linewidth=0.5\pslinewidth,viewpoint=80 -75 0 rtp2xyz,lightsrc=viewpoint,Decran=30}
\begin{pspicture}(-1,-5)(5,5)
  \defFunction[algebraic]{func}(x,y)
      { x }
      { (x^4 * 2/27 - x^3 * 4/9) * cos(y)} 
      { (x^4 * 2/27 - x^3 * 4/9) * sin(y)}
  \psSolid[
    object=surfaceparametree,
    base=0 6 0 Pi 1.5 mul,
    hue=0 1,
    incolor=yellow,
    ngrid=0.2 0.2,
    function=func]
  \gridIIID[Zmin=-10,Zmax=10,stepX=2,stepY=4,stepZ=2](0,10)(-10,10)
\end{pspicture}
%
\psset{viewpoint=80 -60 0 rtp2xyz}
\begin{pspicture}(-1,-5)(5,5)
  \defFunction[algebraic]{func}(x,y)
      { x }
      { (x^4 * 2/27 - x^3 * 4/9) * cos(y)} 
      { (x^4 * 2/27 - x^3 * 4/9) * sin(y)}
  \psSolid[
    object=surfaceparametree,
    base=0 6 0 Pi 1.5 mul,
    hue=0 1,
    incolor=yellow,
    ngrid=0.2 0.2,
    function=func]
% \gridIIID[Zmin=-10,Zmax=10,stepX=2,stepY=4,stepZ=4](0,10)(-10,10)
\end{pspicture}

\end{document}

enter image description here

share|improve this answer
    
Thank you for solution, but it's not quite what I was looking for. I want the reader to see this solid of revolution is "filled" (because you have to calculate the volume of this function). –  Cheesey Apr 29 at 7:40
1  
That is no problem. Draw it again with z=0 and then y=0 that's all. –  Herbert Apr 29 at 7:46
    
Oh, I see. I'll look into that as well, thank you! –  Cheesey Apr 29 at 7:50

Thanks to Christian Feuersänger I could solve my problem like I wanted to. I post this answer so everybody who wants to do the same thing or something similar can use this code as a basis. Please give Christan credit for his solution!

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}

% \usetikzlibrary{}
% \usepgfplotslibrary{}
%
% defines a new value for 'data cs'.
%
% On input, this "data coordinate system" consists of 
% x=generatrix (=radius)
% y=<angle>
% z=distance along axis
%
% On output, it will show the z value on the X axis and the radius on
% the Y axis.
\pgfplotsdefinecstransform{polarrad along x}{cart}{%
    % First, swap axis such that we can apply polarrad->cart.
    % Note that polarrad expects (<angle>,<radius>,Z):
    \pgfkeysgetvalue{/data point/x}\X
    \pgfkeysgetvalue{/data point/y}\Y
    \pgfkeyslet{/data point/y}\X
    \pgfkeyslet{/data point/x}\Y
    \pgfplotsaxistransformcs
        {polarrad}
        {cart}%
    %
    % Ok, now we have cartesian. Swap axes such that we have them
    % along X:
    \pgfkeysgetvalue{/data point/x}\X
    \pgfkeysgetvalue{/data point/y}\Y
    \pgfkeysgetvalue{/data point/z}\Z
    \pgfkeyslet{/data point/y}\X
    \pgfkeyslet{/data point/z}\Y
    \pgfkeyslet{/data point/x}\Z
}%

\begin{document}
\begin{tikzpicture}
    % This creates a color gradient for the filled area of the two functions
    \pgfdeclareverticalshading{brighter}{100bp}{
        rgb(0bp)=(0.1,0.55,0);
        rgb(100bp)=(0.8,0.9,0)
    }
    %
    \pgfdeclareverticalshading{darker}{100bp}{
        rgb(0bp)=(0.5,0.75,0);
        rgb(100bp)=(0,0.5,0)
    }
    %
    \begin{axis}[
        title={Rotation um die x-Achse},
        colormap/greenyellow,
        view={12}{30}]

        \def\generatrix{(((2*x^4)/27) - ((4*x^3)/9))}

        \addplot3[
            surf,
            shader=faceted interp,
            samples=30,
            domain=0:6,
            domain y=0:3*pi/2,
            z buffer=sort,
            data cs=polarrad along x]
        ({\generatrix},y,x);

        \addplot3[
            draw=none,
            shading=darker,
            fill opacity=1.0,
            samples=30,
            samples y=1,
            domain=0:6,
            data cs=polarrad along x]
        ({\generatrix},0,x) --cycle;

        \addplot3[
            draw=none,
            shading=brighter,
            fill opacity=1.0,
            samples=30,
            samples y=1,
            domain=0:6,
            data cs=polarrad along x]
        ({\generatrix},3*pi/2,x) --cycle;

        \addplot3[
            surf,
            opacity = 0.1,
            shader=faceted interp,
            samples=30,
            samples y = 10,
            domain=0:6,
            domain y=3*pi/2:2*pi,
            z buffer=sort,
            data cs=polarrad along x]
        ({\generatrix},y,x);
    \end{axis}
\end{tikzpicture}
\end{document}

And that's what it looks like:

Filled solid of revolution

share|improve this answer
    
How can we give credit to the pgfplots author? :) –  percusse Apr 29 at 18:05
    
Isn't your answer exactly the same as Christians but you have different shading? –  dustin Apr 29 at 18:50
    
Different shading (or shading at all) and the almost opaque quarter piece at the end creating the mesh. I posted it because that's what I wanted it to look like and I hope everyone with similar things in mind will be able to use it for their advance =) –  Cheesey Apr 29 at 19:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.