4

I used the result in this post to achieve a rotation of a cone about an 3D axis. I am unsure on how to implement the following to this image:

Rotated cone.

I would like the imaginary lines that run along the 'volume of the cone' to be dashed to promote a better sense of the 3D nature of the image. I also need to draw an arc between the central lines of both cones to label the rotation angle $\vartheta$. Also is there any advice to make it look more '3D-like'?

MWE

\documentclass[tikz]{standalone}
\usepackage{pgfplots} 
\usepackage{filecontents}           
\usetikzlibrary{arrows,shapes,backgrounds,fit,decorations.pathreplacing,chains,snakes,positioning,angles,quotes}  


\newcommand{\savedx}{0}
\newcommand{\savedy}{0}
\newcommand{\savedz}{0}

\tikzset{
pics/tester/.style n args={3}{
code = {%   

\def\x{1}
\def\y{3.4}
\def\R{\x+0.009}
\def\yc{\y+0.08}
\def\e{0.6}


\shade[right color=white,left color=blue,opacity=#1]
(-\x,\y) -- (-\x,\yc) arc (180:360:{\R} and \e) -- (\x,\y) -- (0,0) -- cycle;
\draw[fill=#2,#3]
(0,\yc) circle ({\R} and \e);
\draw[#3]
(-\x,\y) -- (0,0) -- (\x,\y);
\draw[#3]
(0,\yc) circle ({\R} and \e);

\draw[line width=1pt] (0,0,0) -- (0,4,0);

}}}



\newcommand{\rotateRPY}[4][0/0/0]% point to be saved to \savedxyz, roll, pitch, yaw
{   \pgfmathsetmacro{\rollangle}{#2}
\pgfmathsetmacro{\pitchangle}{#3}
\pgfmathsetmacro{\yawangle}{#4}

% to what vector is the x unit vector transformed, and which 2D vector is this?
\pgfmathsetmacro{\newxx}{cos(\yawangle)*cos(\pitchangle)}% a
\pgfmathsetmacro{\newxy}{sin(\yawangle)*cos(\pitchangle)}% d
\pgfmathsetmacro{\newxz}{-sin(\pitchangle)}% g
\path (\newxx,\newxy,\newxz);
\pgfgetlastxy{\nxx}{\nxy};

% to what vector is the y unit vector transformed, and which 2D vector is this?
\pgfmathsetmacro{\newyx}{cos(\yawangle)*sin(\pitchangle)*sin(\rollangle)-sin(\yawangle)*cos(\rollangle)}% b
\pgfmathsetmacro{\newyy}{sin(\yawangle)*sin(\pitchangle)*sin(\rollangle)+ cos(\yawangle)*cos(\rollangle)}% e
\pgfmathsetmacro{\newyz}{cos(\pitchangle)*sin(\rollangle)}% h
\path (\newyx,\newyy,\newyz);
\pgfgetlastxy{\nyx}{\nyy};

% to what vector is the z unit vector transformed, and which 2D vector is this?
\pgfmathsetmacro{\newzx}{cos(\yawangle)*sin(\pitchangle)*cos(\rollangle)+ sin(\yawangle)*sin(\rollangle)}
\pgfmathsetmacro{\newzy}{sin(\yawangle)*sin(\pitchangle)*cos(\rollangle)-cos(\yawangle)*sin(\rollangle)}
\pgfmathsetmacro{\newzz}{cos(\pitchangle)*cos(\rollangle)}
\path (\newzx,\newzy,\newzz);
\pgfgetlastxy{\nzx}{\nzy};

% transform the point given by #1
\foreach \x/\y/\z in {#1}
{   \pgfmathsetmacro{\transformedx}{\x*\newxx+\y*\newyx+\z*\newzx}
    \pgfmathsetmacro{\transformedy}{\x*\newxy+\y*\newyy+\z*\newzy}
    \pgfmathsetmacro{\transformedz}{\x*\newxz+\y*\newyz+\z*\newzz}
    \xdef\savedx{\transformedx}
    \xdef\savedy{\transformedy}
    \xdef\savedz{\transformedz}     
}
}

\tikzset{RPY/.style={x={(\nxx,\nxy)},y={(\nyx,\nyy)},z={(\nzx,\nzy)}}}

\pgfplotsset{compat=newest}

\begin{document}

\begin{tikzpicture}
\pic {tester={0.08}{black!6!white}{densely dashed}};
\rotateRPY{0}{0}{91}
\begin{scope}[RPY]
\pic {tester={0.2}{blue!14!white}{}};
\end{scope}
\end{tikzpicture}


\end{document}

I would like then like to overlay both of the cones with a similar one that is squashed in one direction, but stretched by an equivalent factor in the other direction. The above MWE has a few flaws in achieving this which shows for one of the cones:

Second objective

Namely, bases of the cones are not in the same plane. The red cone is stretched in one direction, but is not squeezed in the other direction.

1 Answer 1

6

I would like to argue that such things are drawn much more conveniently with the tikz-3dplot package and the 3d library.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot} 
\usetikzlibrary{3d,shadings}
\makeatletter
% small fix for canvas is xy plane at z % https://tex.stackexchange.com/a/48776/121799
 \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

\begin{document}

\tdplotsetmaincoords{110}{-165} % - because of difference between active and passive transformations...
\begin{tikzpicture}
 %\draw (-5,-2.5) rectangle (1.5,5);
 \begin{scope}[tdplot_main_coords,thick]
  % just in case you want to get an intuition for the coordinates/projections
  %  \draw[-latex] (0,0,0) -- (1,0,0) coordinate (X) node[below]{$x$};
  %  \draw[-latex] (0,0,0) -- (0,1,0) coordinate (Y) node[right]{$y$};
  %  \draw[-latex] (0,0,0) -- (0,0,1) coordinate (Z) node[left]{$z$};
  % origin
  \coordinate (O) at (0,0,0);
  % top
  \begin{scope}[canvas is xy plane at z=4,dashed]
   \draw[thick,solid] (O) -- (0,0);
   \shadedraw[fill opacity=0.3,left color=blue,right color=white] (\tdplotmainphi:1) 
   arc(\tdplotmainphi:\tdplotmainphi+180:1) -- (O) -- cycle;
   \draw[fill opacity=0.3,fill=gray!80] circle (1);
  \end{scope}
  % left
  \begin{scope}[canvas is yz plane at x=4]
   \draw[thick] (O) -- (0,0);
   \pgfmathsetmacro{\MyThetaMax}{atan(tan(\tdplotmaintheta)*sin(90+\tdplotmainphi))}
   \shadedraw[line join=bevel,fill opacity=0.3,upper right=white,lower  left=blue] 
   (\MyThetaMax:1) 
   arc(\MyThetaMax:\MyThetaMax+180:1) -- (O) -- cycle;
       \draw[fill opacity=0.3,fill=gray] circle (1);
      \end{scope}
      % arc
      \begin{scope}[canvas is xz plane at y=0,xscale=-1]
       \draw[-latex] (0,1) arc(90:180:1) node[midway,above left]{$\vartheta$};
  \end{scope}
 \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

The advantage is that you can change the view angles at will.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot} 
\usetikzlibrary{3d,shadings}
\makeatletter
% small fix for canvas is xy plane at z % https://tex.stackexchange.com/a/48776/121799
 \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

\begin{document}
\foreach \X in {5,15,...,355}
{\tdplotsetmaincoords{120+20*sin(\X)}{\X} % - because of difference between active and passive transformations...
\begin{tikzpicture}
 \path[use as bounding box] (-5,-2.5) rectangle (5,5);
 \begin{scope}[tdplot_main_coords,thick]
  % just in case you want to get an intuition for the coordinates/projections
  %  \draw[-latex] (0,0,0) -- (1,0,0) coordinate (X) node[below]{$x$};
  %  \draw[-latex] (0,0,0) -- (0,1,0) coordinate (Y) node[right]{$y$};
  %  \draw[-latex] (0,0,0) -- (0,0,1) coordinate (Z) node[left]{$z$};
  % origin
  \coordinate (O) at (0,0,0);
  % left
  \begin{scope}[canvas is yz plane at x=4]
   \pgfmathtruncatemacro{\ttest}{sign(cos(\tdplotmainphi+90))}
   \ifnum\ttest=1
    \pgfmathsetmacro{\MyThetaMax}{atan(tan(\tdplotmaintheta)*sin(90+\tdplotmainphi))}
    \shadedraw[line join=bevel,fill opacity=0.3,upper right=white,lower  left=blue] 
    (\MyThetaMax:1) 
    arc(\MyThetaMax:\MyThetaMax+180:1) -- (O) -- cycle;
    \draw[fill=gray!30] circle (1);
    \draw[thick] (O) -- (0,0);
   \else
    \draw[fill=gray!30] circle (1);
    \draw[thick] (O) -- (0,0);
    \pgfmathsetmacro{\MyThetaMax}{atan(tan(\tdplotmaintheta)*sin(90+\tdplotmainphi))}
    \shadedraw[line join=bevel,fill opacity=0.3,upper right=white,lower  left=blue] 
    (\MyThetaMax:1) 
    arc(\MyThetaMax:\MyThetaMax+180:1) -- (O) -- cycle;
   \fi  
  \end{scope}
  % top
  \begin{scope}[canvas is xy plane at z=4,dashed]
   \draw[thick,solid] (O) -- (0,0);1
   \shadedraw[fill opacity=0.3,left color=blue,right color=white] (\tdplotmainphi:1) 
   arc(\tdplotmainphi:\tdplotmainphi+180:1) -- (O) -- cycle;
   \draw[fill opacity=0.3,fill=gray!80] circle (1);
  \end{scope}
  % arc
%   \begin{scope}[canvas is xz plane at y=0,xscale=-1]
%    \draw[-latex] (0,1) arc(90:180:1) node[midway,above left]{$\vartheta$};
%   \end{scope}
 \end{scope}
\end{tikzpicture}}
\end{document}

enter image description here

As for the "squashed" shape: it took me some time to derive the (hopefully) correct formula for the visibility angle \MyThetaMax. Other than that it is almost trivial: draw ellipses in the respective planes and then repeat the above.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot} 
\usetikzlibrary{3d,shadings}

\makeatletter
% small fix for canvas is xy plane at z % https://tex.stackexchange.com/a/48776/121799
 \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

\begin{document}

\tdplotsetmaincoords{110}{-165} % - because of difference between active and passive transformations...
\begin{tikzpicture}
 %\draw (-5,-2.5) rectangle (1.5,5);
 \begin{scope}[tdplot_main_coords,thick]
  % just in case you want to get an intuition for the coordinates/projections
  %  \draw[-latex] (0,0,0) -- (1,0,0) coordinate (X) node[below]{$x$};
  %  \draw[-latex] (0,0,0) -- (0,1,0) coordinate (Y) node[right]{$y$};
  %  \draw[-latex] (0,0,0) -- (0,0,1) coordinate (Z) node[left]{$z$};
  % origin
  \coordinate (O) at (0,0,0);
  % top
  \begin{scope}[canvas is xy plane at z=4,dashed]
   \draw[thick,solid] (O) -- (0,0);
   \shadedraw[fill opacity=0.3,left color=blue,right color=white] (\tdplotmainphi:1) 
   arc(\tdplotmainphi:\tdplotmainphi+180:1) -- (O) -- cycle;
   \draw[fill opacity=0.3,fill=gray!80] circle (1);
   % squashed shape
   \shadedraw[fill opacity=0.1,left color=red,right color=white] 
   (\tdplotmainphi:2 and 1) 
   arc(\tdplotmainphi:\tdplotmainphi+180:2 and 1) -- (O) -- cycle;
   \draw[fill opacity=0.1,fill=gray!80] circle (2 and 1);
  \end{scope}
  % left
  \begin{scope}[canvas is yz plane at x=4]
   \draw[thick] (O) -- (0,0);
   \pgfmathsetmacro{\MyThetaMax}{atan(tan(\tdplotmaintheta)*sin(90+\tdplotmainphi))}
   \shadedraw[line join=bevel,fill opacity=0.3,upper right=white,lower  left=blue] 
   (\MyThetaMax:1) 
   arc(\MyThetaMax:\MyThetaMax+180:1) -- (O) -- cycle;
   \draw[fill opacity=0.3,fill=gray] circle (1);
   % squash again
   \pgfmathsetmacro{\MyThetaMax}{atan(tan(\tdplotmaintheta)*sin(90+\tdplotmainphi)*2)}
   \shadedraw[line join=bevel,fill opacity=0.1,upper right=white,
   lower  left=red] 
   (\MyThetaMax:1 and 2) 
   arc(\MyThetaMax:\MyThetaMax+180:1 and 2) -- (O) -- cycle;
   \draw[fill opacity=0.1,fill=gray] circle (1 and 2);
  \end{scope}
  % arc
  \begin{scope}[canvas is xz plane at y=0,xscale=-1]
    \draw[-latex] (0,1) arc(90:180:1) node[midway,above left]{$\vartheta$};
  \end{scope}
 \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

Here's another attempt. I thought the above one would match your description.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot} 
\usetikzlibrary{3d,shadings}

\makeatletter
% small fix for canvas is xy plane at z % https://tex.stackexchange.com/a/48776/121799
 \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

\begin{document}

\tdplotsetmaincoords{110}{-165} % - because of difference between active and passive transformations...
\begin{tikzpicture}
 %\draw (-5,-2.5) rectangle (1.5,5);
 \begin{scope}[tdplot_main_coords,thick]
  % just in case you want to get an intuition for the coordinates/projections
  %  \draw[-latex] (0,0,0) -- (1,0,0) coordinate (X) node[below]{$x$};
  %  \draw[-latex] (0,0,0) -- (0,1,0) coordinate (Y) node[right]{$y$};
  %  \draw[-latex] (0,0,0) -- (0,0,1) coordinate (Z) node[left]{$z$};
  % origin
  \coordinate (O) at (0,0,0);
  % top
  \begin{scope}[canvas is xy plane at z=4,dashed]
   \draw[thick,solid] (O) -- (0,0);
   % squashed shape
   \pgfmathsetmacro{\MyPhiMax}{atan(tan(\tdplotmainphi)*sin(90+\tdplotmaintheta))}
   \shadedraw[fill opacity=0.1,left color=red,right color=white] 
   (\MyPhiMax:2 and 0.5) 
   arc(\MyPhiMax:\MyPhiMax+180:2 and 0.5) -- (O) -- cycle;
   \draw[fill opacity=0.1,fill=gray!80] circle (2 and 0.5);
   % unsquashed
   \shadedraw[fill opacity=0.3,left color=blue,right color=white] (\tdplotmainphi:1) 
   arc(\tdplotmainphi:\tdplotmainphi+180:1) -- (O) -- cycle;
   \draw[fill opacity=0.3,fill=gray!80] circle (1);
  \end{scope}
  % left
  \begin{scope}[canvas is yz plane at x=4]
   \draw[thick] (O) -- (0,0);
   % squash again
   \pgfmathsetmacro{\MyThetaMax}{atan(tan(\tdplotmaintheta)*sin(90+\tdplotmainphi)*4)}
   \shadedraw[line join=bevel,fill opacity=0.1,upper right=white,
   lower  left=red] 
   (\MyThetaMax:0.5 and 2) 
   arc(\MyThetaMax:\MyThetaMax+180:0.5 and 2) -- (O) -- cycle;
   \draw[fill opacity=0.1,fill=gray] circle (0.5 and 2);
   % unsquashed
   \pgfmathsetmacro{\MyThetaMax}{atan(tan(\tdplotmaintheta)*sin(90+\tdplotmainphi))}
   \shadedraw[line join=bevel,fill opacity=0.3,upper right=white,lower  left=blue] 
   (\MyThetaMax:1) 
   arc(\MyThetaMax:\MyThetaMax+180:1) -- (O) -- cycle;
   \draw[fill opacity=0.3,fill=gray] circle (1);
  \end{scope}
  % arc
  \begin{scope}[canvas is xz plane at y=0,xscale=-1]
    \draw[-latex] (0,1) arc(90:180:1) node[midway,above left]{$\vartheta$};
  \end{scope}
 \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

12
  • We keep crossing paths ;) Great answer. How could I change the lines running along the volume of the cone to be dashed?
    – Sid
    Aug 28, 2018 at 22:00
  • Also the animation example has the function sign that isn't recognised?
    – Sid
    Aug 28, 2018 at 22:02
  • @Sid In the "top" scope I just added dashed to the scope options. Does adding dashed to the left scope give you want you want? (Probably I just do not understand.) And what do you mean by sign is not recognized? On my TeXLive installation the code gives me a multipage pdf without any problems which I convert using convert to the animated gif.
    – user121799
    Aug 28, 2018 at 22:05
  • I got the 'unknown function sign' on the console. On a related question, I wanted to overlay another cone over both the dashed and non-dashed cones, but which is stretched along one of the axes and red in colour. This was why I originally had the \tikzset approach. How could I do this?
    – Sid
    Aug 28, 2018 at 22:13
  • 1
    For the record: Jake's patch is now incorporated in v3.1 of TikZ. Jan 15, 2019 at 19:19

You must log in to answer this question.

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