Я спросил себя: есть ли простой способ преобразовать решение?маленькие круги сферы" от @John Kormylo (код ниже) в конусы, помещенный в сферу двумя углами тета и фи?
Подсказка: я видел здесь несколько решений с конусами; но я думаю, что они не были усложнены двумя сферическими углами тета и фи.
Подсказка: Я хочу нарисовать эту картинку (с 8 конусами):
Вероятно, одного конуса будет достаточно, а остальное я смогу сделать при необходимости.
MWE от @JohnKormylo:
\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}
Альтернатива: Можно позволить Тик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}