# How to draw a double napped cone with TikZ

I would like to reproduce something like this in black and white using TikZ (just the figure not the writing) :

Here is the code I have so far, but I don't know how to draw the three planes properly :

\documentclass[tikz, border=3pt]{standalone}
\usepackage{tikz,tikz-3dplot}
\tdplotsetmaincoords{80}{45}
\tdplotsetrotatedcoords{-90}{180}{-90}

%% style for surfaces
\tikzset{surface/.style={draw=black, fill=white, fill opacity=.6}}

%% macros to draw back and front of cones
%% optional first argument is styling; others are z, radius, side offset (in degrees)
\newcommand{\coneback}[4][]{
%% start at the correct point on the circle, draw the arc, then draw to the origin of the diagram, then close the path
\draw[canvas is xy plane at z=#2, #1] (45-#4:#3) arc (45-#4:225+#4:#3) -- (O) --cycle;
}
\newcommand{\conefront}[4][]{
\draw[canvas is xy plane at z=#2, #1] (45-#4:#3) arc (45-#4:-135+#4:#3) -- (O) --cycle;
}

\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\coordinate (O) at (0,0,0);

%% make sure to draw everything from back to front
\coneback[surface]{-3}{2}{-10}
\draw (0,0,-5) -- (O);
\conefront[surface]{-3}{2}{-10}
\draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
\draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
\coneback[surface]{3}{2}{10}
\draw[->] (O) -- (0,0,5) node[above] {$z$};
\conefront[surface]{3}{2}{10}
\end{tikzpicture}
\end{document}


Update : Here is the result thanks to these two posts (@Schrödinger's cat's answer / The fix from another question). The code contains a fix to cope with outdated tikz 3d library.

\documentclass[tikz, border=3pt]{standalone}
\usepackage{tikz,tikz-3dplot}
\tdplotsetmaincoords{80}{110}

%This piece of code fixes the bug%
\usetikzlibrary{3d}
\makeatletter
\tikzoption{canvas is xy plane at z}[]{%
\def\tikz@plane@origin{\pgfpointxyz{0}{0}{#1}}%
\def\tikz@plane@x{\pgfpointxyz{1}{0}{#1}}%
\def\tikz@plane@y{\pgfpointxyz{0}{1}{#1}}%
\tikz@canvas@is@plane
}
\makeatother
%%%%%%%%%%%%

%% style for surfaces
\tikzset{surface/.style={draw=black, left color=orange,right color=orange,middle
color=orange!60!#1, fill opacity=1},surface/.default=white}

%% macros to draw back and front of cones
%% optional first argument is styling; others are z, radius, side offset (in degrees)
\newcommand{\coneback}[4][]{
%% start at the correct point on the circle, draw the arc, then draw to the origin of the diagram, then close the path
\draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3)
arc(\tdplotmainphi-#4:\tdplotmainphi+180+#4:#3) -- (O) --cycle;
}
\newcommand{\conefront}[4][]{
\draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3) arc
(\tdplotmainphi-#4:\tdplotmainphi-180+#4:#3) -- (O) --cycle;
}

\newcommand{\conetruncback}[6][]{
\draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi+180+#4]
({#3*cos(\t)},{#3*sin(\t)},#2)
-- plot[variable=\t,domain=\tdplotmainphi+180-#4:\tdplotmainphi+#4]
({#6*cos(\t)},{#6*sin(\t)},#5)
--cycle;
}

\newcommand{\conetruncfront}[6][]{
\draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi-180+#4]
({#3*cos(\t)},{#3*sin(\t)},#2)
-- plot[variable=\t,domain=\tdplotmainphi-180-#4:\tdplotmainphi+#4]
({#6*cos(\t)},{#6*sin(\t)},#5)
--cycle;
}

\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\coordinate (O) at (0,0,0);
\conetruncback[surface=black]{-2}{4/3}{0}{-3}{2}
\draw (0,0,-5) -- (0,0,-2);
\conetruncfront[surface]{-2}{4/3}{0}{-3}{2}
\draw[canvas is xy plane at z=-2,fill=green!40!black,fill opacity=1] (-3,-3) rectangle (3,3);
\coneback[surface=black]{-2}{4/3}{-10}
\draw (0,0,-2) -- (O);
\conefront[surface]{-2}{4/3}{-10}
\draw[canvas is xy plane at z=0,fill=teal,fill opacity=1] (-3,-3) rectangle (3,3);
\draw[->] (-6,0,0) -- (7,0,0) node[below] {$x$};
\draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
\coneback[surface=white]{2}{4/3}{10}
\draw[-] (O) -- (0,0,2);
\conefront[surface=black]{2}{4/3}{10}
\draw[canvas is xy plane at z=2,fill=pink,fill opacity=1] (-3,-3) rectangle (3,3);
\conetruncback[surface=white]{2}{4/3}{0}{3}{2}
\draw[->] (0,0,2) -- (0,0,5) node[above] {$z$};
\conetruncfront[surface=black]{2}{4/3}{0}{3}{2}
\end{tikzpicture}
\end{document}


And the result :

• I recommend asymptote for 3d drawings. Nov 3 '19 at 19:51
• @Schrödinger'scat Done ;-) Nov 4 '19 at 18:45
• The cross hatching on the cone on the original book cover is nice. I wish we had a good way to do that in TikZ or asymptote. Nov 8 '19 at 12:52
• Yes, maybe I'll look into adding this during the week-end Nov 8 '19 at 18:44

You were almost there. Drawing a plane is as simple as saying

\draw[canvas is xy plane at z=2,fill=blue,fill opacity=0.6] (-4,-4) rectangle (4,4);


Other than that you need to draw the parts of the cone below and above the planes separately, which is why I added a macro for the truncated cone, \conetruncfront. I also replaced the hardcoded 45 with \tdplotmainphi.

\documentclass[tikz, border=3pt]{standalone}
\usepackage{tikz,tikz-3dplot}
\tdplotsetmaincoords{80}{45}

%% style for surfaces
\tikzset{surface/.style={draw=black, fill=white, fill opacity=.6}}

%% macros to draw back and front of cones
%% optional first argument is styling; others are z, radius, side offset (in degrees)
\newcommand{\coneback}[4][]{
%% start at the correct point on the circle, draw the arc, then draw to the origin of the diagram, then close the path
\draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3)
arc(\tdplotmainphi-#4:\tdplotmainphi+180+#4:#3) -- (O) --cycle;
}
\newcommand{\conefront}[4][]{
\draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3) arc
(\tdplotmainphi-#4:\tdplotmainphi-180+#4:#3) -- (O) --cycle;
}

\newcommand{\conetruncfront}[6][]{
\draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi-180+#4]
({#3*cos(\t)},{#3*sin(\t)},#2)
-- plot[variable=\t,domain=\tdplotmainphi-180-#4:\tdplotmainphi+#4]
({#6*cos(\t)},{#6*sin(\t)},#5)
--cycle;
}

\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\coordinate (O) at (0,0,0);

%% make sure to draw everything from back to front
\coneback[surface]{-3}{2}{-10}
\draw (0,0,-5) -- (O);
\conefront[surface]{-3}{2}{-10}
\draw[canvas is xy plane at z=-2,fill=green!60!black,fill opacity=0.6] (-4,-4) rectangle (4,4);
\coneback[surface]{-2}{4/3}{-10}
\draw (0,0,-2) -- (O);
\conefront[surface]{-2}{4/3}{-10}
\draw[canvas is xy plane at z=0,fill=blue,fill opacity=0.6] (-4,-4) rectangle (4,4);
\draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
\draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
\coneback[surface]{3}{2}{10}
\draw[->] (O) -- (0,0,5) node[above] {$z$};
\conefront[surface]{3}{2}{10}
\draw[canvas is xy plane at z=2,fill=purple,fill opacity=0.6] (-4,-4) rectangle (4,4);
\draw[->] (0,0,2) -- (0,0,5) node[above] {$z$};
\conetruncfront[surface]{2}{4/3}{0}{3}{2}
\end{tikzpicture}
\end{document}


However, I'd slightly change things to get

 \documentclass[tikz, border=3pt]{standalone}
\usepackage{tikz,tikz-3dplot}
\tdplotsetmaincoords{80}{45}

%% style for surfaces
\tikzset{surface/.style={draw=black, left color=yellow,right color=yellow,middle
color=yellow!60!#1, fill opacity=.6},surface/.default=white}

%% macros to draw back and front of cones
%% optional first argument is styling; others are z, radius, side offset (in degrees)
\newcommand{\coneback}[4][]{
%% start at the correct point on the circle, draw the arc, then draw to the origin of the diagram, then close the path
\draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3)
arc(\tdplotmainphi-#4:\tdplotmainphi+180+#4:#3) -- (O) --cycle;
}
\newcommand{\conefront}[4][]{
\draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3) arc
(\tdplotmainphi-#4:\tdplotmainphi-180+#4:#3) -- (O) --cycle;
}

\newcommand{\conetruncback}[6][]{
\draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi+180+#4]
({#3*cos(\t)},{#3*sin(\t)},#2)
-- plot[variable=\t,domain=\tdplotmainphi+180-#4:\tdplotmainphi+#4]
({#6*cos(\t)},{#6*sin(\t)},#5)
--cycle;
}

\newcommand{\conetruncfront}[6][]{
\draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi-180+#4]
({#3*cos(\t)},{#3*sin(\t)},#2)
-- plot[variable=\t,domain=\tdplotmainphi-180-#4:\tdplotmainphi+#4]
({#6*cos(\t)},{#6*sin(\t)},#5)
--cycle;
}

\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\coordinate (O) at (0,0,0);
\conetruncback[surface=black]{-2}{4/3}{0}{-3}{2}
\draw (0,0,-5) -- (0,0,-2);
\conetruncfront[surface]{-2}{4/3}{0}{-3}{2}
\draw[canvas is xy plane at z=-2,fill=green!60!black,fill opacity=0.6] (-4,-4) rectangle (4,4);
\coneback[surface=black]{-2}{4/3}{-10}
\draw (0,0,-2) -- (O);
\conefront[surface]{-2}{4/3}{-10}
\draw[canvas is xy plane at z=0,fill=blue,fill opacity=0.6] (-4,-4) rectangle (4,4);
\draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
\draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
\coneback[surface=white]{2}{4/3}{10}
\draw[-] (O) -- (0,0,2);
\conefront[surface=black]{2}{4/3}{10}
\draw[canvas is xy plane at z=2,fill=purple,fill opacity=0.6] (-4,-4) rectangle (4,4);
\conetruncback[surface=white]{2}{4/3}{0}{3}{2}
\draw[->] (0,0,2) -- (0,0,5) node[above] {$z$};
\conetruncfront[surface=black]{2}{4/3}{0}{3}{2}
\end{tikzpicture}
\end{document}


Or with slightly different view angles and opacity set to 1, and adjustments suggested by minhthien_2016.

\documentclass[tikz, border=3pt]{standalone}
\usepackage{tikz,tikz-3dplot}
\tdplotsetmaincoords{80}{60}

%% style for surfaces
\tikzset{surface/.style={draw=black, left color=yellow,right color=yellow,middle
color=yellow!60!#1, fill opacity=1},surface/.default=white}

%% macros to draw back and front of cones
%% optional first argument is styling; others are z, radius, side offset (in degrees)
\newcommand{\coneback}[4][]{
%% start at the correct point on the circle, draw the arc, then draw to the origin of the diagram, then close the path
\draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3)
arc(\tdplotmainphi-#4:\tdplotmainphi+180+#4:#3) -- (O) --cycle;
}
\newcommand{\conefront}[4][]{
\draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3) arc
(\tdplotmainphi-#4:\tdplotmainphi-180+#4:#3) -- (O) --cycle;
}

\newcommand{\conetruncback}[7][]{
\draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi+180+#4]
({#3*cos(\t)},{#3*sin(\t)},#2)
-- plot[variable=\t,domain=\tdplotmainphi+180-#7:\tdplotmainphi+#7]
({#6*cos(\t)},{#6*sin(\t)},#5)
--cycle;
}

\newcommand{\conetruncfront}[7][]{
\draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi-180+#4]
({#3*cos(\t)},{#3*sin(\t)},#2)
-- plot[variable=\t,domain=\tdplotmainphi-180-#7:\tdplotmainphi+#7]
({#6*cos(\t)},{#6*sin(\t)},#5)
--cycle;
}

\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\coordinate (O) at (0,0,0);
\conetruncback[surface=black]{-2}{4/3}{-5}{-3}{2}{5}
\draw (0,0,-5) -- (0,0,-2);
\conetruncfront[surface]{-2}{4/3}{-5}{-3}{2}{5}
\draw[canvas is xy plane at z=-2,fill=green!60!black,fill opacity=1] (-4,-4) rectangle (4,4);
\coneback[surface=black]{-2}{4/3}{-10}
\draw (0,0,-2) -- (O);
\conefront[surface]{-2}{4/3}{-10}
\draw[canvas is xy plane at z=0,fill=blue,fill opacity=1] (-4,-4) rectangle (4,4);
\draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
\draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
\coneback[surface=white]{2}{4/3}{10}
\draw[-] (O) -- (0,0,2);
\conefront[surface=black]{2}{4/3}{10}
\draw[canvas is xy plane at z=2,fill=purple,fill opacity=1] (-4,-4) rectangle (4,4);
\conetruncback[surface=white]{2}{4/3}{5}{3}{2}{-5}
\draw[->] (0,0,2) -- (0,0,5) node[above] {$z$};
\conetruncfront[surface=black]{2}{4/3}{5}{3}{2}{-5}
\end{tikzpicture}
\end{document}


• Thanks for your answer, however I tested the second version of your code and even after trying different values for \tdplotsetmaincoords{80}{60}, I can't get the same output as you. I've updated my post with a screenshot Nov 3 '19 at 20:25
• @Emperor_Udan You might have an old version of the 3d library on your machine, in which the xy plane had a bug. The cleanest solution will be to update your installation. Alternatively you could use yx plane for the planes. Please add the very precise code that you run, and indicate the compiler you are using.
– user194703
Nov 3 '19 at 20:28
• @Emperor_Udan You can also try using this fix.
– user194703
Nov 3 '19 at 20:32
• @Emperor_Udan This is up to you. Anyway, I am glad it worked. ;-)
– user194703
Nov 3 '19 at 20:37
• @minhthien_2016 Thanks! I tried to fix it. (To be honest, is this the answer that has problems with not everything being smooth? ;-)
– user194703
Nov 4 '19 at 16:34

Run with xelatex:

\documentclass[border=10pt,pstricks]{standalone}
\usepackage{pst-solides3d}
\begin{document}

\psset{unit=0.5}
\begin{pspicture}[linewidth=0.1pt](-7,-7)(7,7)
\psset[pst-solides3d]{viewpoint=20 10 20 rtp2xyz,Decran=50,lightsrc=20 10 5,solidmemory}
\psSolid[object=grille,base=-2 2 -2 2,ngrid=30,name=A](0,0,-1.5)
\psSolid[object=grille,base=-2 2 -2 2,ngrid=30,name=B](0,0,0)
\psSolid[object=grille,base=-2 2 -2 2,ngrid=30,name=C](0,0,1.5)
\defFunction{cone}(u,v){u v Cos mul}{u v Sin mul}{u}
\psSolid[object=surfaceparametree,base=-2 2 0 2 pi mul,
inhue=0.8 0.2,hue=0.8 0.2,function=cone,linewidth=0.1pt,ngrid=25 40,name=D]
\psSolid[object=fusion,base=A B C D,linecolor=black!10]
\axesIIID(0,0,1.5)(2,2,3)
\end{pspicture}

\end{document}


• That was not exactly what I was looking for, but it looks good. I could use it in the future thanks Nov 4 '19 at 18:47