答案1
这只是为了好玩。关于在屏幕上投影 3d 锥体的一些考虑。主要目的是解释为什么我认为来自尖端的极值射线一般与从投影底面圆到屏幕上而出现的椭圆的切线有关。锥体的投影是一个三角形。可以通过分析计算锥体与底面的交点来获得
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{shadings}
\tikzset{pics/3d cone/.style={code={
\tikzset{3d cone/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/3d cone/##1}}%
% \itest determines whether the projection of the tip of the cone is inside
% the projection of the base circle, in which case \itest=1
\pgfmathtruncatemacro{\itest}{-1*sign(\pv{h}*abs(cos(\pv{theta}))-\pv{r}*abs(sin(\pv{theta})))}
% \ttest checks whether we look at the cone from the bottom or top,
% in the latter case \ttest=1
\pgfmathtruncatemacro{\ttest}{sign(sin(\pv{theta}))}%
% alpha crit
\pgfmathsetmacro{\alphacrit}{90-atan2((2*\pv{h}*\pv{r}*sin(\pv{theta})*cos(\pv{theta}))/(pow(\pv{h}*cos(\pv{theta}),2) + pow(\pv{r}*sin(\pv{theta}),2)),
(pow(\pv{h}*cos(\pv{theta}),2) - pow(\pv{r}*sin(\pv{theta}),2))/(pow(\pv{h}*cos(\pv{theta}),2) +
pow(\pv{r}*sin(\pv{theta}),2))}%
\begin{scope}[rotate=\pv{phi}]
\ifnum\itest=1
\ifnum\ttest=1
\path[3d cone/base] (0,0)
circle[x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}];
\path[3d cone/mantle]
circle[x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}];
\else
\path[3d cone/mantle]
circle[x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}];
\path[3d cone/base] (0,0)
circle[x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}];
\fi
\else
\ifnum\ttest=1
\path[3d cone/base] (0,0)
circle[x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}];
\path[3d cone/mantle]
plot[variable=\t,domain=\alphacrit:360-\alphacrit,smooth,samples=51]
({\pv{r}*sin(\pv{theta})*cos(\t)},{\pv{r}*sin(\t)})
-- ({\pv{h}*cos(\pv{theta})},0) -- cycle;
\else
\path[3d cone/mantle]
plot[variable=\t,domain=\alphacrit:360-\alphacrit,smooth,samples=51]
({\pv{r}*sin(\pv{theta})*cos(\t)},{\pv{r}*sin(\t)})
-- ({\pv{h}*cos(\pv{theta})},0) -- cycle;
\path[3d cone/base] (0,0)
circle[x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}];
\fi
\fi
\end{scope}
}},3d cone/.cd,h/.initial=1,r/.initial=1,theta/.initial=0,phi/.initial=90,
base/.style={fill=gray},
mantle/.style={shading=bilinear interpolation,
lower left=gray, upper left=gray!60!black, upper right=gray, lower
right=white,shading angle=\pv{phi}-135,opacity=0.7,
postaction={left color=gray,right color=gray,middle color=gray!20,
shading angle=\pv{phi},opacity=0.7}},
mantle contour/.style={draw=gray,very thin},
from top/.style={inner color=gray!20,outer color=gray,opacity=0.7}}
\begin{document}
\foreach \Angle in {5,15,...,355}
{\begin{tikzpicture}
\path[use as bounding box] (-4,-4) rectangle (4,4);
\path (0,0) pic{3d cone={theta=\Angle,phi={90+30*sin(\Angle)},h=3,r=2}};
\end{tikzpicture}}
\end{document}
这可以用来构造箭头。阴影是从这里。
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{shadings}
\tikzset{pics/3d arrow/.style={code={
\tikzset{3d arrow/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/3d arrow/##1}}%
% \itest determines whether the projection of the tip of the cone is inside
% the projection of the base circle, in which case \itest=1
\pgfmathtruncatemacro{\itest}{-1*sign(\pv{h}*abs(cos(\pv{theta}))-\pv{R}*abs(sin(\pv{theta})))}
% \ttest checks whether we look at the cone from the bottom or top,
% in the latter case \ttest=1
\pgfmathtruncatemacro{\ttest}{sign(sin(\pv{theta}))}%
% alpha crit
\pgfmathsetmacro{\alphacrit}{90-atan2((2*\pv{h}*\pv{R}*sin(\pv{theta})*cos(\pv{theta}))/(pow(\pv{h}*cos(\pv{theta}),2) + pow(\pv{R}*sin(\pv{theta}),2)),
(pow(\pv{h}*cos(\pv{theta}),2) - pow(\pv{R}*sin(\pv{theta}),2))/(pow(\pv{h}*cos(\pv{theta}),2) +
pow(\pv{R}*sin(\pv{theta}),2))}%
%\pgfmathsetmacro{\alphacrit}{min(\alphacrit,180-\alphacrit)}
% \path (-4,4) node[below right]
% {$t=\ttest,i=\itest,\alpha_\mathrm{crit}=\alphacrit,\theta=\pv{theta},\phi=\pv{phi}$};
\begin{scope}[rotate=\pv{phi}]
\path ({\pv{h}*cos(\pv{theta})},0) coordinate (tip);
\ifnum\itest=1
\ifnum\ttest=1
\tikzset{3d arrow/shaft}
\path[3d arrow/base] (0,0)
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\path[3d arrow/mantle]
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\tikzset{3d arrow/mantle extra}
\else
\path[3d arrow/mantle]
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\tikzset{3d arrow/mantle extra}
\path[3d arrow/base] (0,0)
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\tikzset{3d arrow/shaft}
\fi
\else
\ifnum\ttest=1
\tikzset{3d arrow/shaft}
\path[3d arrow/base] (0,0)
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\pgfmathsetmacro{\alphamax}{(\alphacrit<90 ? 360-\alphacrit :-\alphacrit)}
\path[3d arrow/mantle]
plot[variable=\t,domain=\alphacrit:\alphamax,smooth,samples=51]
({\pv{R}*sin(\pv{theta})*cos(\t)},{\pv{R}*sin(\t)})
-- ({\pv{h}*cos(\pv{theta})},0) -- cycle;
\tikzset{3d arrow/mantle extra}
\else
\path[3d arrow/mantle]
plot[variable=\t,domain=\alphacrit:360-\alphacrit,smooth,samples=51]
({\pv{R}*sin(\pv{theta})*cos(\t)},{\pv{R}*sin(\t)})
-- ({\pv{h}*cos(\pv{theta})},0) -- cycle;
\tikzset{3d arrow/mantle extra}
\path[3d arrow/base] (0,0)
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\tikzset{3d arrow/shaft}
\fi
\fi
\end{scope}
}},3d arrow/.cd,h/.initial=1,% height of cone
R/.initial=1,% radius of cone
r/.initial=0.5,% radius of shaft
L/.initial=2,% length of shaft
theta/.initial=0,phi/.initial=90,
base/.style={fill=gray!70},
mantle/.style={fill=gray!20},
mantle contour/.style={draw=gray,very thin},
from top/.style={inner color=gray!20,outer color=gray,opacity=0.7},
mantle extra/.code={
\ifnum\itest=1
\foreach \XX in {-45,45,135,225}
{\foreach \YY [evaluate = {\ZZ=30;}] in {0,2,...,30}
{\fill [black, fill opacity = 1/50]
(tip) --
plot[variable=\t,domain=-\ZZ:\ZZ]
({\pv{R}*sin(\pv{theta})*cos(\XX-\YY+\t)},{\pv{R}*sin(\XX-\YY+\t)})
-- cycle;}}
\else
\pgfmathsetmacro{\pft}{(cos(\pv{theta})>0 ? 0 :180)}
\foreach \XX in {135,225}
{\foreach \YY [evaluate = {\ZZ=30;}] in {0,2,...,30}
{\fill [black, fill opacity = 1/50]
(tip) --
plot[variable=\t,domain=-\ZZ:\ZZ]
({\pv{R}*sin(\pv{theta})*cos(\pft+\XX-\YY+\t)},{\pv{R}*sin(\pft+\XX-\YY+\t)})
-- cycle;}}
\fi
},
shaft/.code={
\pgfmathsetmacro{\betamax}{(cos(\pv{theta})>0 ? 270 :-90)}
\path[top color=gray!80,bottom color=black,middle color=gray!10,
shading angle=\pv{phi}] (0,\pv{r}) arc[start angle=90,end angle=\betamax,
x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}] --
({-\pv{L}*cos(\pv{theta})},-\pv{r})
arc[start angle=\betamax,end angle=90,
x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}] -- cycle;
\ifnum\ttest=-1
\fill[gray] ({-\pv{L}*cos(\pv{theta})},0) circle[x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}];
\fi
}}
\begin{document}
\foreach \Angle in {5,15,...,355}
{\begin{tikzpicture}
\path[use as bounding box] (-4,-4) rectangle (4,4);
\path (0,0) pic{3d arrow={theta=\Angle,phi={90+30*sin(\Angle)},h=3,R=2}};
\end{tikzpicture}}
\end{document}
这可以按照通常的方式用来创建符号。
\documentclass{article}
\usepackage{tikz}
\usepackage{scalerel}
\tikzset{pics/3d arrow/.style={code={
\tikzset{3d arrow/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/3d arrow/##1}}%
% \itest determines whether the projection of the tip of the cone is inside
% the projection of the base circle, in which case \itest=1
\pgfmathtruncatemacro{\itest}{-1*sign(\pv{h}*abs(cos(\pv{theta}))-\pv{R}*abs(sin(\pv{theta})))}
% \ttest checks whether we look at the cone from the bottom or top,
% in the latter case \ttest=1
\pgfmathtruncatemacro{\ttest}{sign(sin(\pv{theta}))}%
% alpha crit
\pgfmathsetmacro{\alphacrit}{90-atan2((2*\pv{h}*\pv{R}*sin(\pv{theta})*cos(\pv{theta}))/(pow(\pv{h}*cos(\pv{theta}),2) + pow(\pv{R}*sin(\pv{theta}),2)),
(pow(\pv{h}*cos(\pv{theta}),2) - pow(\pv{R}*sin(\pv{theta}),2))/(pow(\pv{h}*cos(\pv{theta}),2) +
pow(\pv{R}*sin(\pv{theta}),2))}%
%\pgfmathsetmacro{\alphacrit}{min(\alphacrit,180-\alphacrit)}
% \path (-4,4) node[below right]
% {$t=\ttest,i=\itest,\alpha_\mathrm{crit}=\alphacrit,\theta=\pv{theta},\phi=\pv{phi}$};
\begin{scope}[rotate=\pv{phi}]
\path ({\pv{h}*cos(\pv{theta})},0) coordinate (tip);
\ifnum\itest=1
\ifnum\ttest=1
\tikzset{3d arrow/shaft}
\path[3d arrow/base] (0,0)
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\path[3d arrow/mantle]
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\tikzset{3d arrow/mantle extra}
\else
\path[3d arrow/mantle]
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\tikzset{3d arrow/mantle extra}
\path[3d arrow/base] (0,0)
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\tikzset{3d arrow/shaft}
\fi
\else
\ifnum\ttest=1
\tikzset{3d arrow/shaft}
\path[3d arrow/base] (0,0)
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\pgfmathsetmacro{\alphamax}{(\alphacrit<90 ? 360-\alphacrit :-\alphacrit)}
\path[3d arrow/mantle]
plot[variable=\t,domain=\alphacrit:\alphamax,smooth,samples=51]
({\pv{R}*sin(\pv{theta})*cos(\t)},{\pv{R}*sin(\t)})
-- ({\pv{h}*cos(\pv{theta})},0) -- cycle;
\tikzset{3d arrow/mantle extra}
\else
\path[3d arrow/mantle]
plot[variable=\t,domain=\alphacrit:360-\alphacrit,smooth,samples=51]
({\pv{R}*sin(\pv{theta})*cos(\t)},{\pv{R}*sin(\t)})
-- ({\pv{h}*cos(\pv{theta})},0) -- cycle;
\tikzset{3d arrow/mantle extra}
\path[3d arrow/base] (0,0)
circle[x radius={\pv{R}*sin(\pv{theta})},y radius=\pv{R}];
\tikzset{3d arrow/shaft}
\fi
\fi
\end{scope}
}},3d arrow/.cd,h/.initial=1,% height of cone
R/.initial=1,% radius of cone
r/.initial=0.5,% radius of shaft
L/.initial=2,% length of shaft
theta/.initial=0,phi/.initial=90,
base/.style={fill=gray!70},
mantle/.style={fill=gray!20},
mantle contour/.style={draw=gray,very thin},
from top/.style={inner color=gray!20,outer color=gray,opacity=0.7},
mantle extra/.code={
\ifnum\itest=1
\foreach \XX in {-45,45,135,225}
{\foreach \YY [evaluate = {\ZZ=30;}] in {0,2,...,30}
{\fill [black, fill opacity = 1/50]
(tip) --
plot[variable=\t,domain=-\ZZ:\ZZ]
({\pv{R}*sin(\pv{theta})*cos(\XX-\YY+\t)},{\pv{R}*sin(\XX-\YY+\t)})
-- cycle;}}
\else
\pgfmathsetmacro{\pft}{(cos(\pv{theta})>0 ? 0 :180)}
\foreach \XX in {135,225}
{\foreach \YY [evaluate = {\ZZ=30;}] in {0,2,...,30}
{\fill [black, fill opacity = 1/50]
(tip) --
plot[variable=\t,domain=-\ZZ:\ZZ]
({\pv{R}*sin(\pv{theta})*cos(\pft+\XX-\YY+\t)},{\pv{R}*sin(\pft+\XX-\YY+\t)})
-- cycle;}}
\fi
},
shaft/.code={
\pgfmathsetmacro{\betamax}{(cos(\pv{theta})>0 ? 270 :-90)}
\path[top color=gray!80,bottom color=black,middle color=gray!10,
shading angle=\pv{phi}] (0,\pv{r}) arc[start angle=90,end angle=\betamax,
x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}] --
({-\pv{L}*cos(\pv{theta})},-\pv{r})
arc[start angle=\betamax,end angle=90,
x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}] -- cycle;
\ifnum\ttest=-1
\fill[gray] ({-\pv{L}*cos(\pv{theta})},0) circle[x radius={\pv{r}*sin(\pv{theta})},y radius=\pv{r}];
\fi
}}
\newsavebox\SBTikzTDrightarrow
\newsavebox\SBTikzTDleftarrow
\sbox\SBTikzTDrightarrow{\begin{tikzpicture}
\pic{3d arrow={theta=-20,phi=0,h=3,R=2,L=8}};
\end{tikzpicture}}
\sbox\SBTikzTDleftarrow{\begin{tikzpicture}
\pic{3d arrow={theta=20,phi=180,h=3,R=2,L=8}};
\end{tikzpicture}}
\newcommand{\TDrightarrow}{\mathrel{\scalerel*{\usebox\SBTikzTDrightarrow}{\rightarrow}}}
\newcommand{\TDleftarrow}{\mathrel{\scalerel*{\usebox\SBTikzTDleftarrow}{\leftarrow}}}
\begin{document}
$a\TDrightarrow b\TDleftarrow c$
$a\rightarrow b\leftarrow c$
\end{document}