答案1
在原则使用 fillbetween 库可以做到这一点。技术挑战在于 Ti钾Z 会发现太多交点,而交点的数量取决于绘制球体路径所用的样本数量。因此,原则上,您可以在球体上绘制任意形状(不仅仅是弧线!),并区分隐藏和可见的线和表面。虽然对于线条,它只需使用样式即可spherical smooth
,但对于表面,不幸的是,必须手动摆弄。以下是一个例子:
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{intersections}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usepgfplotslibrary{fillbetween}
\usepackage{tikz-3dplot}
\pgfkeys{/tikz/.cd,
hidden opacity/.store in=\HiddenOpacity,
hidden opacity=0.3,
}
\makeatletter
% from https://tex.stackexchange.com/a/375604/121799
%along z axis
\define@key{z sphericalkeys}{radius}{\def\myradius{#1}}
\define@key{z sphericalkeys}{theta}{\def\mytheta{#1}}
\define@key{z sphericalkeys}{phi}{\def\myphi{#1}}
\tikzdeclarecoordinatesystem{z spherical}{%
\setkeys{z sphericalkeys}{#1}%
\pgfmathsetmacro{\Xtest}{cos(90-\tdplotmaintheta)*cos(\tdplotmainphi-90)*cos(\mytheta)*cos(\myphi)
+cos(90-\tdplotmaintheta)*sin(\tdplotmainphi-90)*cos(\mytheta)*sin(\myphi)
+sin(90-\tdplotmaintheta)*sin(\mytheta)}
% \Xtest is the projection of the coordinate on the normal vector of the visible plane
\pgfmathsetmacro{\ntest}{ifthenelse(\Xtest<0,0,1)}
\ifnum\ntest=0
\xdef\MCheatOpa{\HiddenOpacity}
\else
\xdef\MCheatOpa{1}
\fi
%\typeout{\mytheta,\tdplotmaintheta;\myphi,\tdplotmainphi:\ntest}
\pgfpointxyz{\myradius*cos(\mytheta)*cos(\myphi)}{%
\myradius*cos(\mytheta)*sin(\myphi)}{\myradius*sin(\mytheta)}}
%%%%%%%%%%%%%%%%%
% define "new" plot handler
\tikzoption{spherical smooth}[]{\let\tikz@plot@handler=\pgfplothandlersphericalcurveto}
\pgfdeclareplothandler{\pgfplothandlersphericalcurveto}{}{%
point macro=\pgf@plot@curveto@handler@spherical@initial,
jump macro=\pgf@plot@smooth@next@spherical@moveto,
end macro=\pgf@plot@curveto@handler@spherical@finish
}
\def\pgf@plot@smooth@next@spherical@moveto{%
\pgf@plot@curveto@handler@spherical@finish%
\global\pgf@plot@startedfalse%
\global\let\pgf@plotstreampoint\pgf@plot@curveto@handler@spherical@initial%
}
\def\pgf@plot@curveto@handler@spherical@initial#1{%
\pgf@process{#1}%
\ifx\tikz@textcolor\pgfutil@empty%
\else
\pgfsetstrokecolor{\tikz@textcolor}
\fi
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@plot@first@action{\pgfqpoint{\pgf@xa}{\pgf@ya}}%
\xdef\pgf@plot@curveto@first{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%
\global\let\pgf@plot@curveto@first@support=\pgf@plot@curveto@first%
\global\let\pgf@plotstreampoint=\pgf@plot@curveto@handler@spherical@second%
}
\def\pgf@plot@curveto@handler@spherical@second#1{%
\pgf@process{#1}%
\xdef\pgf@plot@curveto@second{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
\global\let\pgf@plotstreampoint=\pgf@plot@curveto@handler@spherical@third%
\global\pgf@plot@startedtrue%
}
\def\pgf@plot@curveto@handler@spherical@third#1{%
\pgf@process{#1}%
\xdef\pgf@plot@curveto@current{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
% compute difference vector:
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\pgf@plot@curveto@first}
\advance\pgf@xa by-\pgf@x%
\advance\pgf@ya by-\pgf@y%
% compute support directions:
\pgf@xa=\pgf@plottension\pgf@xa%
\pgf@ya=\pgf@plottension\pgf@ya%
% first marshal:
\pgf@process{\pgf@plot@curveto@second}%
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\pgf@xc=\pgf@x%
\pgf@yc=\pgf@y%
\advance\pgf@xb by-\pgf@xa%
\advance\pgf@yb by-\pgf@ya%
\advance\pgf@xc by\pgf@xa%
\advance\pgf@yc by\pgf@ya%
\@ifundefined{MCheatOpa}{}{%
\pgf@plotstreamspecial{\pgfsetstrokeopacity{\MCheatOpa}}}
\edef\pgf@marshal{\noexpand\pgfsetstrokeopacity{\noexpand\MCheatOpa}
\noexpand\pgfpathcurveto{\noexpand\pgf@plot@curveto@first@support}%
{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgf@plot@curveto@second}
\noexpand\pgfusepathqstroke
\noexpand\pgfpathmoveto{\noexpand\pgf@plot@curveto@second}}%
{\pgf@marshal}%
%\pgfusepathqstroke%
% Prepare next:
\global\let\pgf@plot@curveto@first=\pgf@plot@curveto@second%
\global\let\pgf@plot@curveto@second=\pgf@plot@curveto@current%
\xdef\pgf@plot@curveto@first@support{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}%
}
\def\pgf@plot@curveto@handler@spherical@finish{%
\ifpgf@plot@started%
\pgfpathcurveto{\pgf@plot@curveto@first@support}{\pgf@plot@curveto@second}{\pgf@plot@curveto@second}%
\fi%
}
\makeatother
\begin{document}
\pgfmathsetmacro{\RadiusSphere}{3}
\begin{tikzpicture}
\shade[name path=sphere,ball color = gray!40, opacity = 0.5]
plot[smooth,domain=-180:180] ({\RadiusSphere*cos(\x)},{\RadiusSphere*sin(\x)});
\tdplotsetmaincoords{42}{205}
\begin{scope}[tdplot_main_coords,samples=60]
%
% \draw[-latex,orange] (0,0,0) -- (z spherical cs: radius=\RadiusSphere,
% phi={\tdplotmainphi-90},theta={90-\tdplotmaintheta});
% \draw[-latex] (0,0,0) -- (\RadiusSphere,0,0) node[below]{$x$};
% \draw[-latex] (0,0,0) -- (0,\RadiusSphere,0) node[left]{$y$};
% \draw[-latex] (0,0,0) -- (0,0,\RadiusSphere) node[left]{$z$};
\draw plot[spherical smooth,variable=\x,domain=-180:180]
(z spherical cs: radius=\RadiusSphere,phi={50*sin(\x)},theta={40*cos(\x)});
% I modified the plot handler in order to change the opacity along the paths
% therefore I need to redraw it if I want to use it in fills :-(
\path[name path=circle,fill=blue,opacity=0.2] plot[smooth,variable=\x,domain=-180:180]
(z spherical cs: radius=\RadiusSphere,phi={50*sin(\x)},theta={40*cos(\x)});
% main technical challenge: TikZ finds tons of intersections instead of 2
% \draw[red, name intersections={of=sphere and circle,name=i, total=\t}]
% \foreach \s in {1,...,\t}{node[fill,circle,scale=0.3,label=above:\s] at (i-\s) {}}
% \pgfextra{\typeout{\t}};
%
\path [%draw,yellow,ultra thick,opacity=1,
fill=blue,opacity=0.4,
name path=visible surface,
intersection segments={
of=circle and sphere,
sequence={A5--B0[reverse]--B7[reverse]}
}];
\end{scope}
\end{tikzpicture}
\end{document}
你可以增加样本并改变视角,但这样做的代价是交叉点的数量会发生变化,你必须重新找到相关的路径。例如,对于
\shade[name path=sphere,ball color = gray!40, opacity = 0.5]
plot[smooth,domain=-180:180,samples=120] ({\RadiusSphere*cos(\x)},{\RadiusSphere*sin(\x)}); % now 120 samples
\tdplotsetmaincoords{52}{200}
Ti 发现的交叉点数量钾Z 是 5,你需要做
\path [%draw,yellow,ultra thick,opacity=1,
fill=blue,opacity=0.4,
name path=visible surface,
intersection segments={
of=circle and sphere,
sequence={A4--B0[reverse]--B5[reverse]}
}];
要得到
如果你厌倦了手动调整这些内容,请切换到渐近线;-)
小更新:第一个版本没有填充。
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{intersections,decorations.markings}
\usepackage{tikz-3dplot}
\tikzset{endmark/.style={postaction={decorate,decoration={markings,
mark=at position 0 with {\coordinate (X0); },
mark=at position 1 with {\coordinate (X1); }}}}}
\pgfkeys{/tikz/.cd,
hidden opacity/.store in=\HiddenOpacity,
hidden opacity=0.3,
}
\makeatletter
\xdef\prevhidden@toggle{0}
\xdef\spherical@plot@start{0}
% the spherical coordinates are from https://tex.stackexchange.com/a/375604/121799
% but the routine got modified to
% (i) decide whether a point is "visible" or "hidden"
% (ii)
%along z axis
\define@key{z sphericalkeys}{radius}{\def\myradius{#1}}
\define@key{z sphericalkeys}{theta}{\def\mytheta{#1}}
\define@key{z sphericalkeys}{phi}{\def\myphi{#1}}
\tikzdeclarecoordinatesystem{z spherical}{%
\setkeys{z sphericalkeys}{#1}%
\pgfmathsetmacro{\Xtest}{cos(90-\tdplotmaintheta)*cos(\tdplotmainphi-90)*cos(\mytheta)*cos(\myphi)
+cos(90-\tdplotmaintheta)*sin(\tdplotmainphi-90)*cos(\mytheta)*sin(\myphi)
+sin(90-\tdplotmaintheta)*sin(\mytheta)}
% \Xtest is the projection of the coordinate on the normal vector of the visible plane
\pgfmathsetmacro{\ntest}{ifthenelse(\Xtest<0,0,1)}
\ifnum\ntest=0
\xdef\MCheatOpa{\HiddenOpacity}
%\typeout{point\space hidden}
\ifnum\prevhidden@toggle=1 % previous point was also hidden
\xdef\hid@path{\hid@path (z spherical cs: radius={\myradius},phi={\myphi},theta={\mytheta})}
\else % finish visible path
\ifnum\spherical@plot@start=1 % this is the first point of the plot
%\typeout{start}
\else
\ifnum\thevis@paths=0
\xdef\lst@vis@paths{{\vis@path}}
\else
\xdef\lst@vis@paths{\lst@vis@paths,{\vis@path}}
\fi
\stepcounter{vis@paths}
\fi % and start a new hidden path
\xdef\hid@path{(z spherical cs: radius={\myradius},phi={\myphi},theta={\mytheta})}
\fi
\xdef\prevhidden@toggle{1}
\else
\xdef\MCheatOpa{1}
%\typeout{point\space visible}
\ifnum\prevhidden@toggle=0 % previous point was also visible
\xdef\vis@path{\vis@path (z spherical cs: radius={\myradius},phi={\myphi},theta={\mytheta})}
\else % finish hidden path
\ifnum\spherical@plot@start=1
%\typeout{start}
\else
\ifnum\thehid@paths=0
\xdef\lst@hid@paths{{\hid@path}}
\else
\xdef\lst@hid@paths{\lst@hid@paths,{\hid@path}}
\fi
\stepcounter{hid@paths}
\fi % and start a new visible path
\xdef\vis@path{(z spherical cs: radius={\myradius},phi={\myphi},theta={\mytheta})}
\fi
\xdef\prevhidden@toggle{0}
\fi
%\typeout{\mytheta,\tdplotmaintheta;\myphi,\tdplotmainphi:\ntest}
\pgfpointxyz{\myradius*cos(\mytheta)*cos(\myphi)}{%
\myradius*cos(\mytheta)*sin(\myphi)}{\myradius*sin(\mytheta)}}
%%%%%%%%%%%%%%%%%
% define "new" plot handler
\newcounter{vis@paths}
\newcounter{hid@paths}
\tikzoption{spherical smooth}[]{\xdef\lst@vis@paths{}
\xdef\lst@hid@paths{}
\xdef\hid@path{}
\xdef\vis@path{}
\let\tikz@plot@handler=\pgfplothandlersphericalcurveto}
\pgfdeclareplothandler{\pgfplothandlersphericalcurveto}{}{%
point macro=\pgf@plot@curveto@handler@spherical@initial,
jump macro=\pgf@plot@smooth@next@spherical@moveto,
end macro=\pgf@plot@curveto@handler@spherical@finish
}
\def\pgf@plot@smooth@next@spherical@moveto{%
\pgf@plot@curveto@handler@spherical@finish%
\global\pgf@plot@startedfalse%
\global\let\pgf@plotstreampoint\pgf@plot@curveto@handler@spherical@initial%
}
\def\pgf@plot@curveto@handler@spherical@initial#1{%
\pgf@process{#1}%
\ifx\tikz@textcolor\pgfutil@empty%
\else
\pgfsetstrokecolor{\tikz@textcolor}
\fi
\setcounter{vis@paths}{0}
\setcounter{hid@paths}{0}
\xdef\spherical@plot@start{1}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@plot@first@action{\pgfqpoint{\pgf@xa}{\pgf@ya}}%
\xdef\pgf@plot@curveto@first{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%
\global\let\pgf@plot@curveto@first@support=\pgf@plot@curveto@first%
\global\let\pgf@plotstreampoint=\pgf@plot@curveto@handler@spherical@second%
}
\def\pgf@plot@curveto@handler@spherical@second#1{%
\xdef\spherical@plot@start{0}
\pgf@process{#1}%
\xdef\pgf@plot@curveto@second{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
\global\let\pgf@plotstreampoint=\pgf@plot@curveto@handler@spherical@third%
\global\pgf@plot@startedtrue%
}
\def\pgf@plot@curveto@handler@spherical@third#1{%
\pgf@process{#1}%
\xdef\pgf@plot@curveto@current{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
% compute difference vector:
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\pgf@plot@curveto@first}
\advance\pgf@xa by-\pgf@x%
\advance\pgf@ya by-\pgf@y%
% compute support directions:
\pgf@xa=\pgf@plottension\pgf@xa%
\pgf@ya=\pgf@plottension\pgf@ya%
% first marshal:
\pgf@process{\pgf@plot@curveto@second}%
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\pgf@xc=\pgf@x%
\pgf@yc=\pgf@y%
\advance\pgf@xb by-\pgf@xa%
\advance\pgf@yb by-\pgf@ya%
\advance\pgf@xc by\pgf@xa%
\advance\pgf@yc by\pgf@ya%
\edef\pgf@marshal{\noexpand\pgfsetstrokeopacity{\noexpand\MCheatOpa}
\noexpand\pgfpathcurveto{\noexpand\pgf@plot@curveto@first@support}%
{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgf@plot@curveto@second}
\noexpand\pgfusepathqstroke
\noexpand\pgfpathmoveto{\noexpand\pgf@plot@curveto@second}}%
{\pgf@marshal}%
%\pgfusepathqstroke%
% Prepare next:
\global\let\pgf@plot@curveto@first=\pgf@plot@curveto@second%
\global\let\pgf@plot@curveto@second=\pgf@plot@curveto@current%
\xdef\pgf@plot@curveto@first@support{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}%
}
\def\pgf@plot@curveto@handler@spherical@finish{%
\ifpgf@plot@started%
\pgfpathcurveto{\pgf@plot@curveto@first@support}{\pgf@plot@curveto@second}{\pgf@plot@curveto@second}%
\fi%
\ifnum\prevhidden@toggle=1
\xdef\lstvispaths{\lst@vis@paths}
\ifx\hid@path\empty
\else
%\typeout{closing\space hidden}
\ifx\lst@hid@paths\empty
\xdef\lst@hid@paths{{\hid@path}}
\else
\xdef\lst@hid@paths{\lst@hid@paths,{\hid@path}}
\fi
\foreach \X [count=\Y] in \lst@hid@paths
{\xdef\my@len{\Y}}
%\typeout{\my@len\space hidden\space patches}
\xdef\lsthidpaths{}
\foreach \X [count=\Y] in \lst@hid@paths
{\ifnum\Y=1 % save the first stretch
\xdef\tmppath{\X}
\ifnum\my@len=1
\xdef\lsthidpaths{{\X}}
\fi
\else
\ifnum\Y=\my@len
\ifnum\Y=2
\xdef\lsthidpaths{{\X\tmppath}}
\else
\xdef\lsthidpaths{\lsthidpaths,{\X\tmppath}}
\fi
%\typeout{adding:{\tmppath\X}}
%\typeout{result:\lsthidpaths}
\else
\xdef\lsthidpaths{\lsthidpaths,{\X}}
\fi
\fi}
%\typeout{hidden\space paths:\lst@hid@paths}
\fi
\else
\xdef\lsthidpaths{\lst@hid@paths}
\ifx\vis@path\empty
\else
%\typeout{closing\space visible}
\xdef\lst@vis@paths{\lst@vis@paths,{\vis@path}}
\foreach \X [count=\Y] in \lst@vis@paths
{\xdef\my@len{\Y}}
%\typeout{\my@len\space hidden\space coordinates:\vis@path}
\xdef\lstvispaths{}
\foreach \X [count=\Y] in \lst@vis@paths
{\ifnum\Y=1 % save the first stretch
\xdef\tmppath{\X}
\ifnum\my@len=1
\xdef\lstvispaths{{\X}}
\fi
\else
\ifnum\Y=\my@len
\ifnum\my@len=1
\xdef\lstvispaths{{\X}}
\else
\ifnum\Y=2
\xdef\lstvispaths{{\X\tmppath}}
\else
\xdef\lstvispaths{\lstvispaths,{\X\tmppath}}
\fi
%\typeout{adding:{\tmppath\X}}
%\typeout{result:\lstvispaths}
\fi
\else
\xdef\lstvispaths{\lstvispaths,{\X}}
\fi
\fi}
\fi
\fi
}
\makeatother
\newcommand{\FillVisibleSurfaces}[1][]{\xdef\numvis{0}
\foreach \X [count=\Y] in \lstvispaths
{\ifx\X\empty
\else
\xdef\numvis{\Y}
\fi}
\ifnum\numvis=0%
\else
\foreach \X [count=\Y] in \lstvispaths
{%\typeout{processing\space \X}
\path[endmark] plot[tdplot_main_coords,samples=60] coordinates {\X};
\fill[#1] let
\p1=(X0),\p2=(X1),\n1={mod(atan2(\y1,\x1)+720,360)},\n2={mod(atan2(\y2,\x2)+720,360)}
in % \pgfextra{\typeout{visible:\space start:\n1,end:\n2}}
plot[tdplot_main_coords,samples=60] coordinates {\X} -- (X1) arc(\n2:\n1:\RadiusSphere);
}
\fi
}
\newcommand{\FillHiddenSurfaces}[1][]{\xdef\numhid{0}
\foreach \X [count=\Y] in \lsthidpaths
{\ifx\X\empty
\else
\xdef\numhid{\Y}
\fi}
\ifnum\numhid=0%
\else
\foreach \X [count=\Y] in \lsthidpaths
{
\path[endmark] plot[tdplot_main_coords,samples=60] coordinates {\X};
\fill[#1] let
\p1=(X0),\p2=(X1),\n1={mod(atan2(\y1,\x1)+720,360)},\n2={mod(atan2(\y2,\x2)+720,360)}
in %\pgfextra{\typeout{hidden\space start:\n1,end:\n2}}
plot[tdplot_main_coords,samples=60] coordinates {\X} -- (X1) arc(\n2:\n1:\RadiusSphere)
--cycle;
}
\fi
}
\begin{document}
\pgfmathsetmacro{\RadiusSphere}{3}
\foreach \X in {0,10,...,350}
{\begin{tikzpicture}
\shade[name path=sphere,ball color = gray!40, opacity = 0.5]
plot[smooth,domain=-180:180,samples=120] ({\RadiusSphere*cos(\x)},{\RadiusSphere*sin(\x)});
\tdplotsetmaincoords{110}{\X}
\begin{scope}[tdplot_main_coords,samples=60]
%
% \draw[-latex,orange] (0,0,0) -- (z spherical cs: radius=\RadiusSphere,
% phi={\tdplotmainphi-90},theta={90-\tdplotmaintheta});
% \draw[-latex] (0,0,0) -- (\RadiusSphere,0,0) node[below]{$x$};
% \draw[-latex] (0,0,0) -- (0,\RadiusSphere,0) node[left]{$y$};
% \draw[-latex] (0,0,0) -- (0,0,\RadiusSphere) node[left]{$z$};
\draw plot[spherical smooth,variable=\x,domain=-180:180]
(z spherical cs: radius=\RadiusSphere,phi={50*sin(\x)},theta={40*cos(\x)});
\end{scope}
% note that these commands need to be placed *outside* the tdplot_main_coords scope
\FillHiddenSurfaces[blue,opacity=0.2]
\FillVisibleSurfaces[blue,opacity=0.5]
\end{tikzpicture}
}
\end{document}
我相信已经用大量的\if
语句解决了几个问题。但是,上面的动画显然看起来不对。(请注意,底部和右侧出现的额外位是由于转换为 gif 造成的,它们在 pdf 中不存在。)但这是因为在球体上,封闭曲面的“内部”定义不明确,而是有两个选项。而且总是填充较小的区域似乎也不对,因为人们可能想要填充较大的区域。读过这篇文章的人知道如何在数学上甚至在 Ti 中定义它吗?钾Z?
最后,我想提出一个“作弊”解决方案,它几乎与上面的解决方案一样强大,但不需要修改绘图处理程序,并且可以与任何\draw
命令一起使用,而不仅仅是plot
。只需绘制两次,让坐标系决定该点是否可见。如果不可见,则返回定义球体的圆边界上的一个点。
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{intersections,decorations.markings}
\usepackage{tikz-3dplot}
\makeatletter
%along z axis
\define@key{z sphericalkeys}{radius}{\def\myradius{#1}}
\define@key{z sphericalkeys}{theta}{\def\mytheta{#1}}
\define@key{z sphericalkeys}{phi}{\def\myphi{#1}}
\tikzdeclarecoordinatesystem{z spherical visible}{%
\setkeys{z sphericalkeys}{#1}%
\pgfmathsetmacro{\Xtest}{cos(90-\tdplotmaintheta)*cos(\tdplotmainphi-90)*cos(\mytheta)*cos(\myphi)
+cos(90-\tdplotmaintheta)*sin(\tdplotmainphi-90)*cos(\mytheta)*sin(\myphi)
+sin(90-\tdplotmaintheta)*sin(\mytheta)}
% \Xtest is the projection of the coordinate on the normal vector of the visible plane
\pgfmathsetmacro{\ntest}{ifthenelse(\Xtest<0,0,1)}
\ifnum\ntest=0
\pgfmathsetmacro{\myx}{\myradius*cos(\mytheta)*cos(\myphi)*\raarot
+\myradius*cos(\mytheta)*sin(\myphi)*\rabrot+\myradius*sin(\mytheta*\racrot}
\pgfmathsetmacro{\myy}{\myradius*cos(\mytheta)*cos(\myphi)*\rbarot
+\myradius*cos(\mytheta)*sin(\myphi)*\rbbrot+\myradius*sin(\mytheta*\rbcrot}
\pgfpoint{\RadiusSphere*cos(atan2(\myy,\myx))*1cm}{\RadiusSphere*sin(atan2(\myy,\myx))*1cm}
\else
\pgfpointxyz{\myradius*cos(\mytheta)*cos(\myphi)}{%
\myradius*cos(\mytheta)*sin(\myphi)}{\myradius*sin(\mytheta)}
\fi
}
\tikzdeclarecoordinatesystem{z spherical invisible}{%
\setkeys{z sphericalkeys}{#1}%
\pgfmathsetmacro{\Xtest}{cos(90-\tdplotmaintheta)*cos(\tdplotmainphi-90)*cos(\mytheta)*cos(\myphi)
+cos(90-\tdplotmaintheta)*sin(\tdplotmainphi-90)*cos(\mytheta)*sin(\myphi)
+sin(90-\tdplotmaintheta)*sin(\mytheta)}
% \Xtest is the projection of the coordinate on the normal vector of the visible plane
%\typeout{\raarot,\rbarot,\rabrot,\rbbrot,\racrot, \rbcrot}
\pgfmathsetmacro{\ntest}{ifthenelse(\Xtest<0,0,1)}
\ifnum\ntest=1
\pgfmathsetmacro{\myx}{\myradius*cos(\mytheta)*cos(\myphi)*\raarot
+\myradius*cos(\mytheta)*sin(\myphi)*\rabrot+\myradius*sin(\mytheta*\racrot}
\pgfmathsetmacro{\myy}{\myradius*cos(\mytheta)*cos(\myphi)*\rbarot
+\myradius*cos(\mytheta)*sin(\myphi)*\rbbrot+\myradius*sin(\mytheta*\rbcrot}
\pgfpoint{\RadiusSphere*cos(atan2(\myy,\myx))*1cm}{\RadiusSphere*sin(atan2(\myy,\myx))*1cm}
\else
\pgfpointxyz{\myradius*cos(\mytheta)*cos(\myphi)}{%
\myradius*cos(\mytheta)*sin(\myphi)}{\myradius*sin(\mytheta)}
\fi
}
%%%%%%%%%%%%%%%%%
\makeatother
% decoration
\begin{document}
\pgfmathsetmacro{\RadiusSphere}{3}
\foreach \X in {0,10,...,350}
{\begin{tikzpicture}
\path[use as bounding box] ({-1.2*\RadiusSphere},{-1.2*\RadiusSphere}) rectangle
({1.2*\RadiusSphere},{1.2*\RadiusSphere});
\shade[ball color = gray!40, opacity = 0.5] (0,0) circle (\RadiusSphere);
\tdplotsetmaincoords{110}{\X}
\begin{scope}[tdplot_main_coords,samples=60]
%
% \draw[-latex,orange] (0,0,0) -- (z spherical cs: radius=\RadiusSphere,
% phi={\tdplotmainphi-90},theta={90-\tdplotmaintheta});
% \draw[-latex] (0,0,0) -- (\RadiusSphere,0,0) node[below]{$x$};
% \draw[-latex] (0,0,0) -- (0,\RadiusSphere,0) node[left]{$y$};
% \draw[-latex] (0,0,0) -- (0,0,\RadiusSphere) node[left]{$z$};
\pgfmathtruncatemacro{\Dis}{ifthenelse(\X<50,1,0)+ifthenelse(\X>130,1,0)}
\ifnum\Dis=0
\else
\draw[opacity=0.3,fill opacity=0.2,fill=blue] plot[smooth,variable=\x,domain=-180:180]
(z spherical invisible cs: radius=\RadiusSphere,phi={50*sin(\x)},theta={40*cos(\x)});
\fi
\pgfmathtruncatemacro{\Dis}{ifthenelse(\X<230,1,0)+ifthenelse(\X>320,1,0)}
\ifnum\Dis=0
\else
\draw[fill opacity=0.5,fill=blue] plot[smooth,variable=\x,domain=-180:180]
(z spherical visible cs: radius=\RadiusSphere,phi={50*sin(\x)},theta={40*cos(\x)});
\fi
%(z spherical cs: {\RadiusSphere},{50*sin(\x)},{40*cos(\x)});
\end{scope}
\end{tikzpicture}
}
\end{document}
这很好用除非隐藏的表面包含圆心。在这种情况下,应该不绘制该表面。也许有一种方法可以避免手动删除这些表面。