7

I want to draw a 3D shape as shown in the image, but I cannot seem to get the circle/ellipse base of the cones to fit within the lines. The sides should be a tangent to the bottom circle/ellipse. The problem seems to get slightly better if I decrease the p-variable, but then the base starts losing its circular form, which makes the shapes look completely off.

Is there a way to fix this?

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}

\begin{tikzpicture}

    \def\h{2}
    \def\r{2}
    \def\p{0.5}

    \draw[line width = 0.6pt] (-\r,\h) arc (180:360:\r cm and \p cm) -- (0,0) -- cycle;
    \draw[dashed][line width = 0.6pt] (\r,\h) arc (0:180:\r cm and \p cm);

    \draw[line width = 0.6pt] (-\r,\h) -- (-\r,3*\h);
    \draw[line width = 0.6pt] (\r,\h) -- (\r,3*\h);

    \draw[line width = 0.6pt] (-\r,3*\h) arc (180:360:\r cm and \p cm) -- (0,4*\h) -- cycle;
    \draw[dashed][line width = 0.6pt] (\r,3*\h) arc (0:180:\r cm and \p cm);

    \draw[|-|] (\r+0.3,0) -- node[right] {\normalsize$1.5$} (\r+0.3,\h);
    \draw[|-|] (-\r-0.3,\h) -- node[left] {\normalsize$3.0$} (-\r-0.3,3*\h);
    \draw[|-|] (\r+0.3,3*\h) -- node[right] {\normalsize$1.5$} (\r+0.3,4*\h);
    \draw[dashed] (0,3*\h) -- node[above=-1.5pt] {\normalsize$1.5$} (\r,3*\h);
    \fill[fill=black] (0,3*\h) circle (1.2pt);


    \fill[left color=gray!50!black, right color=gray!50!black, middle color=gray!50, shading=axis, opacity=0.1] (-\r,\h) arc (180:360:\r cm and \p cm) -- (0,0) -- cycle;
    \fill[left color=gray!50!black, right color=gray!50!black, middle color=gray!50, shading=axis, opacity=0.1] (\r,\h) arc (0:-180:\r cm and \p cm);

    \fill[left color=gray!50!black, right color=gray!50!black, middle color=gray!50, shading=axis, opacity=0.1] (-\r,\h) -- (\r,\h) -- (\r,3*\h) -- (-\r,3*\h);

    \fill[left color=gray!50!black, right color=gray!50!black, middle color=gray!50, shading=axis, opacity=0.1] (-\r,3*\h) arc (180:0:\r cm and \p cm) -- (0,4*\h) -- cycle;
    \fill[left color=gray!50!black, right color=gray!50!black, middle color=gray!50, shading=axis, opacity=0.1] (\r,3*\h) arc (0:180:\r cm and \p cm);

    \fill[left color=gray!50!black, right color=gray!50!black, middle color=gray!50, shading=axis, opacity=0.1] (\r,\h) arc (0:360:\r cm and \p cm);
    \fill[left color=gray!50!black, right color=gray!50!black, middle color=gray!50, shading=axis, opacity=0.1] (\r,3*\h) arc (0:360:\r cm and \p cm);

\end{tikzpicture}\end{document}

Current code result

3 Answers 3

6

It is not too difficult to compute the angle of the intersection from your inputs.

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[fill opacity=0.2,text opacity=1]
    \def\h{2}
    \def\r{2}
    \def\p{0.5}
    % compute the aspect of the cylinder/cone
    \pgfmathsetmacro{\mytheta}{atan2(\p,\r)}
    % compute the critical angle at which the mantle intersects the base
    \pgfmathsetmacro{\alphacrit}{90-acos(\p/\h)}%
    % lower cone
    \path (0,\h) + (-\alphacrit:\r cm and \p cm) coordinate (br)
    (0,\h) + (180+\alphacrit:\r cm and \p cm) coordinate (bl);
    \draw[left color=gray!50!black, right color=gray!50!black, middle color=gray!50,
      line width = 0.6pt] 
      (bl) arc[start angle=180+\alphacrit,end angle=360-\alphacrit,
        x radius=\r*1cm,y radius=\p*1cm]
     -- (0,0) -- cycle;
    % cylinder base
    \fill[gray] (0,\h) circle[x radius=\r,y radius=\p];
    \draw[dashed,line width = 0.6pt] (\r,\h) 
    arc[start angle=0,end angle=180,x radius=\r*1cm,y radius=\p*1cm];
    \fill[fill=black,fill opacity=1] (0,\h) circle[radius=1.2pt];
    % cylinder mantle
    \draw[line width = 0.6pt,left color=gray!50!black, right
        color=gray!50!black, middle color=gray!50]
     (\r,\h) arc[start angle=0,end angle=-180,x radius=\r*1cm,y radius=\p*1cm]
     -- (-\r,3*\h)  arc[start angle=180,end angle=360,x radius=\r*1cm,y radius=\p*1cm] 
     -- cycle;
    % cylinder top
    \fill[gray] (0,3*\h) circle[x radius=\r,y radius=\p];
    \draw[dashed,line width = 0.6pt] (\r,3*\h) 
     arc[start angle=0,end angle=180,x radius=\r*1cm,y radius=\p*1cm];
    \fill[fill=black,fill opacity=1] (0,3*\h) circle[radius=1.2pt];
    % upper cone
    \path (0,3*\h) + (\alphacrit:\r cm and \p cm) coordinate (tr)
    (0,3*\h) + (180-\alphacrit:\r cm and \p cm) coordinate (tl);
    \draw[left color=gray!50!black, right color=gray!50!black, middle color=gray!50,
      line width = 0.6pt] 
      (tl) arc[start angle=180-\alphacrit,end angle=360+\alphacrit,
      x radius=\r*1cm,y radius=\p*1cm]
     -- (0,4*\h) -- cycle;
    % annotations 
    \draw[|-|] (\r+0.3,0) -- node[right] {$1.5$} (\r+0.3,\h);
    \draw[|-|] (-\r-0.3,\h) -- node[left] {$3.0$} (-\r-0.3,3*\h);
    \draw[|-|] (\r+0.3,3*\h) -- node[right] {$1.5$} (\r+0.3,4*\h);
    \draw[dashed] (0,3*\h) -- node[above=-1.5pt] {$1.5$} (\r,3*\h);
\end{tikzpicture}
\end{document}

enter image description here

There is a chance that my other post on this is wrong...

4
  • Schrödinger's cat it looks better now. Can it be drawn in 3D? Apr 24, 2020 at 5:39
  • 2
    @minhthien_2016 Yes, sure.
    – user194703
    Apr 24, 2020 at 5:50
  • It looks really smooth and code is well structured, thanks a lot Schrödinger's cat!
    – Amer
    Apr 24, 2020 at 14:10
  • 1
    @minhthien_2016 See tex.stackexchange.com/a/539871/194703.
    – user194703
    Apr 24, 2020 at 17:41
2

It's quite flexible to make pic with the following kind of pgfkeys code (credit to whom? Schrodinger's cat?)

\tikzset{pics/ZZZZZ/.style={code={
\tikzset{ZZZZZ/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/ZZZZZ/##1}}%
 .....

This is my first try. The code for pic cylinder is straight.

\begin{tikzpicture}[thick]
\path 
(0,0) pic[brown]{cylinder}
(7,0) pic[cyan]{cylinder={major=3,minor=.75,height=4}};
\end{tikzpicture}

enter image description here

For pic cone, I add the boolean key upside down via boolean comparison\newif\ifupsidedown with setting

upside down/.initial=false, % Initially, cylinder is upside
upside down/.is if=upsidedown

enter image description here

\begin{tikzpicture}[thick]
\path 
(0,0) pic[blue]{cone}
(7,0) pic[red]{cone={major=3,minor=.75,height=2.5,upside down=true}};
\end{tikzpicture}

Here is the final picture.

enter image description here

Full code is as follows.

\documentclass[tikz,border=5mm]{standalone}
\begin{document}
%%%%%%%% CYLINDER %%%%%%%%%%%%%%%%%%%%%
\tikzset{pics/cylinder/.style={code={
\tikzset{cylinder/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/cylinder/##1}}%
\draw[fill=white] 
(\pv{major},\pv{height})--(\pv{major},0) 
arc(0:-180:{\pv{major}} and {\pv{minor}})
--(-\pv{major},\pv{height}) 
arc(180:-180:{\pv{major}} and {\pv{minor}});
\draw[dashed] 
(\pv{major},0) arc(0:180:{\pv{major}} and {\pv{minor}});
}},
cylinder/.cd,
major/.initial=1.5,
minor/.initial=.7,
height/.initial=3,
}% end of the pic: cylinder 
%%%%%%%% CONE %%%%%%%%%%%%%%%%%%%%%%%%%
\newif\ifupsidedown
\tikzset{pics/cone/.style={code={
\tikzset{cone/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/cone/##1}}%
\pgfmathsetmacro{\t}{asin(\pv{minor}/\pv{height})}
\ifupsidedown
\draw 
(-\t:{\pv{major}} and {\pv{minor}})--(0,-\pv{height})--(180+\t:{\pv{major}} and {\pv{minor}})
(\pv{major},0) arc(0:360:{\pv{major}} and {\pv{minor}});
\else
\draw[fill=white] 
(\t:{\pv{major}} and {\pv{minor}})--(0,\pv{height})--(180-\t:{\pv{major}} and {\pv{minor}})
arc(180-\t:360+\t:{\pv{major}} and {\pv{minor}});
\draw[dashed] 
(\t:{\pv{major}} and {\pv{minor}}) arc(\t:180-\t:{\pv{major}} and {\pv{minor}});
\fi
}},
cone/.cd,
major/.initial=3,
minor/.initial=1,
height/.initial=3,
upside down/.initial=false,
upside down/.is if=upsidedown
} % end of the pic: cone
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{tikzpicture}[thick]
\path 
(0,0) pic[brown]{cylinder}
(7,0) pic[cyan]{cylinder={major=3,minor=.75,height=4}}
;
\end{tikzpicture}
\begin{tikzpicture}[thick]
\path 
(0,0) pic[blue]{cone}
(7,0) pic[red]{cone={major=3,minor=.75,height=2.5,upside down=true}}
;
\end{tikzpicture}
\begin{tikzpicture}
\def\a{1.5} \def\b{.5} \def\hcy{3} \def\hco{1.5}
\path[thick] 
(0,0)
pic{cone={major=\a,minor=\b,height=\hco,upside down=true}}
pic{cylinder={major=\a,minor=\b,height=\hcy}}
(0,3)
pic{cone={major=\a,minor=\b,height=\hco}}
;

% for legends
\begin{scope}[magenta,nodes={midway,scale=.8}]
\draw[dashed] (\a,\hcy)--(0,\hcy) node[above]{1.5};
\draw[|-|] (\a+.3,\hcy)--+(90:\hco) node[right]{1.5};
\draw[|-|] (\a+.3,0)--+(-90:\hco) node[right]{1.5};
\draw[|-|] (-\a-.3,0)--+(90:\hcy) node[left]{3};
\fill (0,0) circle(1.5pt) (0,\hcy) circle(1.5pt);       
\end{scope}
\end{tikzpicture}
\end{document}
2

You can try this code

\documentclass[12pt,a4paper,border=2mm]{standalone}
\usepackage{tikz, tikz-3dplot}
\usetikzlibrary{calc,backgrounds}
\usepackage{pgfplots}
\begin{document}
    \pgfmathsetmacro\th{70}
    \pgfmathsetmacro\az{70}
    \tdplotsetmaincoords{\th}{\az}
\pgfmathsetmacro\h{3} %height of cylinder
    \pgfmathsetmacro\R{3} %radius of base
    \pgfmathsetmacro\v{\h + 3} 
    \pgfmathsetmacro\t{-\h} 
    \begin{tikzpicture} [scale=1, tdplot_main_coords, axis/.style={blue,thick}]
        \path
    (0,0,0) coordinate (O) 
    (0,0,\v) coordinate (B) 
    (0,0,\t) coordinate (A);
    \pgfmathsetmacro\cott{{cot(\th)}}
    \pgfmathsetmacro\fraction{\R*\cott/(\v-\h)}
    \pgfmathsetmacro\fractionTwo{\R*\cott/\t}
    \pgfmathsetmacro\fraction{\fraction<1 ? \fraction : 1}
    \pgfmathsetmacro\angle{{acos(\fraction)}}
    \pgfmathsetmacro\angleTwo{{acos(\fractionTwo)}}
    \pgfmathsetmacro\PhiOne{180+(\az-90)+\angle}
    \pgfmathsetmacro\PhiTwo{180+(\az-90)-\angle}
    \pgfmathsetmacro\PhiOneBis{180+(\az-90)+\angleTwo}
    \pgfmathsetmacro\PhiTwoBis{180+(\az-90)-\angleTwo}
    \pgfmathsetmacro\sinPhiOne{{sin(\PhiOne)}}
    \pgfmathsetmacro\cosPhiOne{{cos(\PhiOne)}}
    \pgfmathsetmacro\sinPhiTwo{{sin(\PhiTwo)}}
    \pgfmathsetmacro\cosPhiTwo{{cos(\PhiTwo)}}
    \pgfmathsetmacro\sinPhiOneBis{{sin(\PhiOneBis)}}
    \pgfmathsetmacro\cosPhiOneBis{{cos(\PhiOneBis)}}
    \pgfmathsetmacro\sinPhiTwoBis{{sin(\PhiTwoBis)}}
    \pgfmathsetmacro\cosPhiTwoBis{{cos(\PhiTwoBis)}}
    \pgfmathsetmacro\sinazp{{sin(\az-90)}}
    \pgfmathsetmacro\cosazp{{cos(\az-90)}}
    \pgfmathsetmacro\sinazm{{sin(90-\az)}}
    \pgfmathsetmacro\cosazm{{cos(90-\az)}}
    %\tdplotdrawarc[tdplot_main_coords,thick]{(O)}{\R}{\PhiOne}{360+\PhiTwo}{anchor=north}{}
        \draw[dashed] (\tdplotmainphi:\R) arc(\tdplotmainphi:\tdplotmainphi+180:\R);

        \draw[thick] (\tdplotmainphi:\R)  arc(\tdplotmainphi:\tdplotmainphi-180:\R);

    \tdplotdrawarc[tdplot_main_coords,thick]{(0,0,\h)}{\R}{\PhiOne}{360+\PhiTwo}{anchor=north}{}
\tdplotdrawarc[tdplot_main_coords,dashed]{(0,0,\h)}{\R}{\PhiTwo}{\PhiOne}{anchor=north}{}
\draw[thick]  ({\R*cos(\tdplotmainphi)},{\R*sin(\tdplotmainphi)},0 ) -- ({\R*cos(\tdplotmainphi)},{\R*sin(\tdplotmainphi)},\h );
    \draw[thick]  ({\R*cos(\tdplotmainphi-180)},{\R*sin(\tdplotmainphi-180)},0 ) -- ({\R*cos(\tdplotmainphi-180)},{\R*sin(\tdplotmainphi-180)},\h );
    \draw[thick] (B) -- (\R*\cosPhiOne,\R*\sinPhiOne,\h);
    \draw[thick] (B) -- (\R*\cosPhiTwo,\R*\sinPhiTwo,\h);
    \draw[thick] (A) -- (\R*\cosPhiOneBis,\R*\sinPhiOneBis,0);
\draw[thick] (A) -- (\R*\cosPhiTwoBis,\R*\sinPhiTwoBis,0);
    \foreach \p in {O,B,A}
    \draw[fill=black] (\p) circle (1pt);
    \foreach \p/\g in {O/-45,B/90,A/-90}
    \path (\p)+(\g:3mm) node{$\p$};
    \draw[dashed]  (A)--(B)    (-\R*\sinazm,-\R*\cosazm,0) -- (-\R*\sinazp,+\R*\cosazp,0) ;
    \end{tikzpicture}
    \end{document} 

enter image description here

You can try

\documentclass[12pt,a4paper,border=2mm]{standalone}
\usepackage{tikz, tikz-3dplot}
\usetikzlibrary{calc,backgrounds}
\usepackage{pgfplots}
\begin{document}
    \pgfmathsetmacro\th{80}
    \pgfmathsetmacro\az{70}
    \tdplotsetmaincoords{\th}{\az}
\pgfmathsetmacro\h{3} %height of cylinder
    \pgfmathsetmacro\R{8} %radius of base
    \pgfmathsetmacro\v{\h + 3} 
    \pgfmathsetmacro\t{-8} 
    \begin{tikzpicture} [scale=1, tdplot_main_coords, axis/.style={blue,thick}]
        \path
    (0,0,0) coordinate (O) 
    (0,0,\v) coordinate (B) 
    (0,0,\t) coordinate (A);
    \pgfmathsetmacro\cott{{cot(\th)}}
    \pgfmathsetmacro\fraction{\R*\cott/(\v-\h)}
    \pgfmathsetmacro\fractionTwo{\R*\cott/\t}
    \pgfmathsetmacro\fraction{\fraction<1 ? \fraction : 1}
    \pgfmathsetmacro\angle{{acos(\fraction)}}
    \pgfmathsetmacro\angleTwo{{acos(\fractionTwo)}}
    \pgfmathsetmacro\PhiOne{180+(\az-90)+\angle}
    \pgfmathsetmacro\PhiTwo{180+(\az-90)-\angle}
    \pgfmathsetmacro\PhiOneBis{180+(\az-90)+\angleTwo}
    \pgfmathsetmacro\PhiTwoBis{180+(\az-90)-\angleTwo}
    \pgfmathsetmacro\sinPhiOne{{sin(\PhiOne)}}
    \pgfmathsetmacro\cosPhiOne{{cos(\PhiOne)}}
    \pgfmathsetmacro\sinPhiTwo{{sin(\PhiTwo)}}
    \pgfmathsetmacro\cosPhiTwo{{cos(\PhiTwo)}}
    \pgfmathsetmacro\sinPhiOneBis{{sin(\PhiOneBis)}}
    \pgfmathsetmacro\cosPhiOneBis{{cos(\PhiOneBis)}}
    \pgfmathsetmacro\sinPhiTwoBis{{sin(\PhiTwoBis)}}
    \pgfmathsetmacro\cosPhiTwoBis{{cos(\PhiTwoBis)}}
    \pgfmathsetmacro\sinazp{{sin(\az-90)}}
    \pgfmathsetmacro\cosazp{{cos(\az-90)}}
    \pgfmathsetmacro\sinazm{{sin(90-\az)}}
    \pgfmathsetmacro\cosazm{{cos(90-\az)}}
            \draw[dashed] (\tdplotmainphi:\R) arc(\tdplotmainphi:\tdplotmainphi+180:\R);

        \draw[thick] (\tdplotmainphi:\R)  arc(\tdplotmainphi:\tdplotmainphi-180:\R);

    \tdplotdrawarc[tdplot_main_coords,thick]{(0,0,\h)}{\R}{\PhiOne}{360+\PhiTwo}{anchor=north}{}
\tdplotdrawarc[tdplot_main_coords,dashed]{(0,0,\h)}{\R}{\PhiTwo}{\PhiOne}{anchor=north}{}
\draw[thick]  ({\R*cos(\tdplotmainphi)},{\R*sin(\tdplotmainphi)},0 ) -- ({\R*cos(\tdplotmainphi)},{\R*sin(\tdplotmainphi)},\h );
    \draw[thick]  ({\R*cos(\tdplotmainphi-180)},{\R*sin(\tdplotmainphi-180)},0 ) -- ({\R*cos(\tdplotmainphi-180)},{\R*sin(\tdplotmainphi-180)},\h );
    \draw[thick] (B) -- (\R*\cosPhiOne,\R*\sinPhiOne,\h);
    \draw[thick] (B) -- (\R*\cosPhiTwo,\R*\sinPhiTwo,\h);
    \draw[thick] (A) -- (\R*\cosPhiOneBis,\R*\sinPhiOneBis,0);
\draw[thick] (A) -- (\R*\cosPhiTwoBis,\R*\sinPhiTwoBis,0);
    \foreach \p in {O,B,A}
    \draw[fill=black] (\p) circle (1pt);
    \foreach \p/\g in {O/-45,B/90,A/-90}
    \path (\p)+(\g:3mm) node{$\p$};
    \draw[dashed]  (A)--(B)    (-\R*\sinazm,-\R*\cosazm,0) -- (-\R*\sinazp,+\R*\cosazp,0) ;

    \end{tikzpicture}
    \end{document} 

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .