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}

在此輸入影像描述

選擇: 可以讓TikZ 以數值方式求出輪廓,參見這裡

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

在此輸入影像描述

相關內容