tikz-3dplot:球体中按角度放置的锥体

tikz-3dplot:球体中按角度放置的锥体

我问自己:有没有一种简单的方法可以解决这个问题”球体上的小圆圈“来自@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}

在此处输入图片描述

选择:可以让 TiZ 用数值方法找到轮廓,参见这里

\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}

在此处输入图片描述

相关内容