我问自己:有没有一种简单的方法可以解决这个问题”球体上的小圆圈“来自@John Kormylo(下面的代码)成锥体, 通过两个角度 theta 和 phi 放置在球体中?
提示:我在这里看到了一些圆锥解;但我认为它们并没有被两个球面角 theta 和 phi 复杂地放置。
提示:我想画这幅图(有 8 个锥体):
可能一个锥体就足够了,以便我可以在必要时完成剩下的工作。
来自@JohnKormylo的MWE:
\documentclass[margin=5mm, tikz]{standalone}
\usepackage{mathtools}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{arrows,calc,backgrounds}
\begin{document}
\pgfmathsetmacro{\R}{3} %
\pgfmathsetmacro{\a}{1.5} %
\pgfmathsetmacro{\r}{sqrt(\R*\R-\a*\a} %
%\pgfmathsetmacro{\Alpha}{atan(\r/\a)}
\pgfmathsetmacro{\Alpha}{acos(\a/\R)} %
\pgfkeys{/tikz/savevalue/.code 2 args={\global\edef#1{#2}}}
\tdplotsetmaincoords{60}{110}
\begin{tikzpicture}[
tdplot_main_coords,
>=latex, font=\footnotesize,
]
\coordinate[label=$Z$] (Z) at (0,0,0);
\pgfmathsetmacro{\Teta}{90} % measured to the z-axis
\pgfmathsetmacro{\Phi}{50} % measured to the x-axis
\tdplotsetrotatedcoords{50}{90}{0}
\begin{scope}[tdplot_rotated_coords]
\coordinate[label=$A$] (A) at (0,0,\R);
\coordinate[label=$M$] (M) at (0,0,\a);
\draw[red, thick] (M) circle[radius=\r];
\end{scope}
\draw[thick] (Z) -- (A);
\draw[red, thick] (Z) -- (M);
% Point P of direction vector p
\pgfmathsetmacro{\xP}{\R*sin(\Teta-\Alpha)*cos(\Phi)} %
\pgfmathsetmacro{\yP}{\R*sin(\Teta-\Alpha)*sin(\Phi)} %
\pgfmathsetmacro{\zP}{\R*cos(\Teta-\Alpha)} %
\coordinate[label=$P$] (P) at (\xP,\yP,\zP);
\draw[thick] (Z) -- (P);
\draw[->] (M) -- (P);
\path let
\p0 = (M), % Center
\p1 = (P),
\n1 = {veclen(\y1-\y0,\x1-\x0)}, \n2={atan2(\y1-\y0,\x1-\x0)}
in [savevalue={\Radius}{\n1}, savevalue={\angle}{\n2}];
\pgfmathsetmacro{\RadiusP}{\Radius/28.4528} % wipe of 'pt'
% Point Q of direction vector q
\pgfmathsetmacro{\xQ}{\R*sin(\Teta)*cos(\Phi-\Alpha)} %
\pgfmathsetmacro{\yQ}{\R*sin(\Teta)*sin(\Phi-\Alpha)} %
\pgfmathsetmacro{\zQ}{\R*cos(\Teta)} %
\coordinate[label=$Q$] (Q) at (\xQ,\yQ,\zQ);
\draw[thick] (Z) -- (Q);
\draw[->] (M) -- (Q);
\path let
\p0 = (M), % Center
\p1 = (Q),
\n1 = {veclen(\y1-\y0,\x1-\x0)}, \n2={atan2(\y1-\y0,\x1-\x0)}
in [savevalue={\Radius}{\n1}, savevalue={\angle}{\n2}];
\pgfmathsetmacro{\RadiusQ}{\Radius/28.4528} % wipe of 'pt'
%OLD
% 3D Small Circle
%\foreach \t in {0,...,360}{
%\pgfmathsetmacro{\rp}{cos(\t)*\r/\RadiusP} %
%\pgfmathsetmacro{\rq}{sin(\t)*\r/\RadiusQ} %
%\coordinate[label=$$] (X) at ($(M)+\rp*(P)-\rp*(M)+\rq*(Q)-\rq*(M)$);
%\draw[red] (X) circle (1pt);
%}
% Sphere
\begin{scope}[tdplot_screen_coords, on background layer]
\fill[ball color= gray!20, opacity = 0.3] (Z) circle (\R);
\end{scope}
\begin{scope}[-latex, shift={(Z)}, xshift=0*2.1*\R cm, yshift=0*0.1*\R cm]
\foreach \P/\s/\Pos in {(5,0,0)/x/right, (0,5,0)/y/below, (0,0,5)/z/right}
\draw[] (0,0,0) -- \P node (\s) [\Pos, pos=0.9,inner sep=2pt]{$\s$};
\node[above=1cm, align=left, font=\normalsize] at (z){Equation of a 3D-circle: \\
$\vec{x} = \vec{m} + r \cos(t) \cdot \vec{p} + r \sin(t) \cdot \vec{q}
~~\text{(with $t = 0\dots 2\pi$)}$
};
\end{scope}
\end{tikzpicture}
\end{document}
答案1
这不是一个完整的答案,因为以下内容对于任意视角都不是“开箱即用的”。圆锥体的底部,即圆圈,是在适当的平面上绘制的,其中相应的旋转角度由宏确定\RotationAnglesForPlaneWithNormal
,这将在下文中解释这里。棘手的部分是找出圆锥的边界与圆相连接的位置。这需要确定交点并区分几种情况,或者进行分析计算。好消息是,人们可以从坐标轴在局部平面中的斜率推断出角度(在范围内确定\pgftransformreset
),坏消息是全自动解决方案需要付出相当大的努力(区分更多情况),所以我只是手动做了一些选择。此外,0,1,2,3
这里的排序“偶然”起作用,如果你过多地改变视角,这不再是合适的排序。但是,对于这种配置,它是有效的。奇怪的列表\LstNormals
只包含四面体的顶点,我从维基百科。
\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{intersections}
\newcommand{\RotationAnglesForPlaneWithNormal}[5]{%\typeout{N=(#1,#2,#3)}
\pgfmathtruncatemacro{\itest}{ifthenelse(abs(#3)==1,0,1)}
\ifnum\itest=0
\xdef#4{0}
\xdef#5{0}
\else
\foreach \XS in {1,-1}
{\foreach \YS in {1,-1}
{\pgfmathsetmacro{\mybeta}{\XS*acos(#3)}
\pgfmathsetmacro{\myalpha}{\YS*acos(#1/sin(\mybeta))}
\pgfmathsetmacro{\ntest}{abs(cos(\myalpha)*sin(\mybeta)-#1)%
+abs(sin(\myalpha)*sin(\mybeta)-#2)+abs(cos(\mybeta)-#3)}
\ifdim\ntest pt<0.1pt
\xdef#4{\myalpha}
\xdef#5{\mybeta}
\fi
}}
\fi
}
\begin{document}
\tdplotsetmaincoords{110}{60}
\begin{tikzpicture}[tdplot_main_coords]
\xdef\LstNormals{{{sqrt(8/9), 0, -1/3},%
{-sqrt(2/9), sqrt(2/3), -1/3},%
{-sqrt(2/9), -sqrt(2/3), -1/3},%
{0, 0, 1}}}
\pgfmathsetmacro{\R}{3} %
\pgfmathsetmacro{\a}{1.5} %
\pgfmathsetmacro{\r}{sqrt(\R*\R-\a*\a} %
\path (0,0,0) coordinate (O);
\foreach \myind in {0,1,2,3}
{\pgfmathsetmacro{\myNx}{\LstNormals[\myind][0]}
\pgfmathsetmacro{\myNy}{\LstNormals[\myind][1]}
\pgfmathsetmacro{\myNz}{\LstNormals[\myind][2]}
\RotationAnglesForPlaneWithNormal{\myNx}{\myNy}{\myNz}{\tmpalpha}{\tmpbeta}
\typeout{\myNx,\tmpalpha,\tmpbeta}
\tdplotsetrotatedcoords{\tmpalpha}{\tmpbeta}{0}
\begin{scope}[tdplot_rotated_coords,canvas is xy plane at z=\r,local bounding
box=loc]
\path[name path=circle] (0,0) circle[radius=\a];
\path[overlay,name path=test] (0,0) -- (O);
\path (1,0) coordinate (Xloc) (0,1) coordinate (Yloc) (0,0) coordinate (Oloc);
\begin{scope}
\pgftransformreset
\path let \p1=($(Xloc)-(Oloc)$),\p2=($(Yloc)-(Oloc)$),
\n1={atan2(\y1,\x1)},\n2={atan2(\y2,\x2)}
in (Xloc) -- (Oloc) -- (Yloc) (Oloc) node{\myind}
\pgfextra{\xdef\myxi{\n1}\xdef\myeta{\n2}};
\end{scope}
\path[name intersections={of=circle and test,total=\iNum}]
\pgfextra{\xdef\iNum{\iNum}};
\ifnum\iNum>0
\ifnum\myind=1
\draw[fill=blue] (-\myxi+90:\a) -- (O) -- (-\myeta-90:\a);
\else
\draw[fill=blue] (-\myxi+90:\a) -- (O) -- (-\myxi-90:\a);
\fi
\draw[fill=blue!30](0,0) circle[radius=\a];
\else
\draw[fill=blue](0,0) circle[radius=\a];
\fi
\end{scope}
}
\path[ball color=gray,opacity=0.2,tdplot_screen_coords] (O) circle[radius=\R];
\end{tikzpicture}
\end{document}
选择:可以让 Ti钾Z 用数值方法找到轮廓,参见这里。
\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{intersections}
\newcommand{\RotationAnglesForPlaneWithNormal}[5]{%\typeout{N=(#1,#2,#3)}
\pgfmathtruncatemacro{\itest}{ifthenelse(abs(#3)==1,0,1)}
\ifnum\itest=0
\xdef#4{0}
\xdef#5{0}
\else
\foreach \XS in {1,-1}
{\foreach \YS in {1,-1}
{\pgfmathsetmacro{\mybeta}{\XS*acos(#3)}
\pgfmathsetmacro{\myalpha}{\YS*acos(#1/sin(\mybeta))}
\pgfmathsetmacro{\ntest}{abs(cos(\myalpha)*sin(\mybeta)-#1)%
+abs(sin(\myalpha)*sin(\mybeta)-#2)+abs(cos(\mybeta)-#3)}
\ifdim\ntest pt<0.1pt
\xdef#4{\myalpha}
\xdef#5{\mybeta}
\fi
}}
\fi
}
\begin{document}
\tdplotsetmaincoords{110}{60}
\begin{tikzpicture}[tdplot_main_coords]
\xdef\LstNormals{{{sqrt(8/9), 0, -1/3},%
{-sqrt(2/9), sqrt(2/3), -1/3},%
{-sqrt(2/9), -sqrt(2/3), -1/3},%
{0, 0, 1}}}
\pgfmathsetmacro{\R}{3} %
\pgfmathsetmacro{\a}{1.5} %
\pgfmathsetmacro{\r}{sqrt(\R*\R-\a*\a} %
\path (0,0,0) coordinate (O);
\foreach \myind in {0,1,2,3}
{\pgfmathsetmacro{\myNx}{\LstNormals[\myind][0]}
\pgfmathsetmacro{\myNy}{\LstNormals[\myind][1]}
\pgfmathsetmacro{\myNz}{\LstNormals[\myind][2]}
\RotationAnglesForPlaneWithNormal{\myNx}{\myNy}{\myNz}{\tmpalpha}{\tmpbeta}
%\typeout{\myNx,\tmpalpha,\tmpbeta}
\tdplotsetrotatedcoords{\tmpalpha}{\tmpbeta}{0}
\begin{scope}[tdplot_rotated_coords,canvas is xy plane at z=\r,local bounding
box=loc]
\path[name path=circle] (0,0) circle[radius=\a];
\path[overlay,name path=test] (0,0) -- (O);
\path (1,0) coordinate (Xloc) (0,1) coordinate (Yloc) (0,0) coordinate (Oloc);
\path[name intersections={of=circle and test,total=\iNum}]
\pgfextra{\xdef\iNum{\iNum}};
\ifnum\iNum>0
\begin{scope}
\pgftransformreset
\path let \p1=($(Oloc)-(O)$),\n1={mod(720+atan2(\y1,\x1),360)} in
\pgfextra{\xdef\oldmax{\n1}\xdef\oldmin{\n1}};
\end{scope}
\typeout{\myind,\oldmax}
\foreach \XX in {0,1,...,359}
{\path ($(\XX:\r)-(O)$) coordinate (aux1) ($(\XX:\r)-(Oloc)$) coordinate
(aux2);
\pgftransformreset
\path let \p1=(aux1),%\p2=(aux2),
\n1={atan2(\y1,\x1)} in
\pgfextra{\pgfmathtruncatemacro{\itest}{ifthenelse(sin(\n1-\oldmin)<0,0,1)}
\ifnum\itest=0
\xdef\oldmin{\n1}
\xdef\oldanA{\XX}
\fi
\pgfmathtruncatemacro{\itest}{ifthenelse(sin(\oldmax-\n1)<0,0,1)}
\ifnum\itest=0
\xdef\oldmax{\n1}
\xdef\oldanB{\XX}
\fi};
}
\draw[fill=blue] (\oldanA:\a) -- (O) -- (\oldanB:\a);
\draw[fill=blue!30](0,0) circle[radius=\a];
\else
%\message{\myind: no intersections}
\draw[fill=blue](0,0) circle[radius=\a];
\fi
\end{scope}
}
\path[ball color=gray,opacity=0.4,tdplot_screen_coords] (O) circle[radius=\R];
\end{tikzpicture}
\end{document}