我正在使用该tikz-3dplot-circleofsphere
包使用 tikz-3dplot 绘制球体的圆圈。考虑文档中的以下 MWE:
\documentclass{standalone}
\usepackage{tikz-3dplot-circleofsphere}
\begin{document}
\centering
\def\r{3}
\tdplotsetmaincoords{60}{125}
\begin{tikzpicture}[tdplot_main_coords]
\draw[tdplot_screen_coords,thin,black!30] (0,0,0) circle (\r);
\foreach \a in {-75,-60,...,75}
{\tdplotCsDrawLatCircle[thin,black!29]{\r}{\a}}
\foreach \a in {0,15,...,165}
{\tdplotCsDrawLonCircle[thin,black!29]{\r}{\a}}
\tdplotCsDrawGreatCircle[red,thick,/.style={opacity=0}]{4}{105}{-23.5}
\end{tikzpicture}
\end{document}
生成以下图像
如何才能让红色虚线显示出来仅有的在球体后面。也就是说,在这种情况下,我选择的红色圆圈的半径大于球体的半径。
答案1
更新后的版本
我的回答不是最简短的,也许我使用的某些元素已经在库中定义;我不知道。
绘图分为三个步骤:1)3D 视角,2)球体,3)圆(球体上有两圆,第三个圆位于球体小圆的平面上,圆心相同)。现在球体也是通过经线和纬线构造的,也就是圆。
每个圆圈的构建都是为了pic
拥有更清晰的代码。
通过计算观察者向量和点的位置向量的内积来检测球面上的隐藏点。请参阅函数opacityOnS
。
通过内积和范数比较的混合来检测球体内部或球体后面的点。参见函数
behindS
。
这三个步骤中使用了有关元素的更多解释。
在 TikZ 中,坐标平面氧对应于屏幕和盎司 指向屏幕外,朝向观看者。
\tox
观察者由、定义的向量表示\toy
,并\toz
通过带有参数经度和纬度的键引入view
。当两者都为零时,向量为(0,0,1)。各种圆圈具有与
pic
对象类似的代码。我更喜欢根据所需参数的数量重新定义它们。但所有这些函数都会使文件变得tikZSphere.sty
相当长。不透明度及其对立面通过键
unseenS
和来控制seenS
。球体半径通过 键控制
radiusS
。默认值为 1。
评论。我没有解决球体上两个圆如何相交的问题。我设想了一个解决方案,但它很笨拙;我需要将圆(或圆的一部分)定义为整个元素(通过命令\path
),以便能够name path
在之后使用该选项。也许可以进行一些改进,就像用户121799
在
使用 TikZ 在球体上嵌入图形?
会很有用,但是它们超出了我的知识范围。
代码
\documentclass[11pt, border=1.5cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc, math}
\usepackage{tikZSphere}
\begin{document}
\begin{tikzpicture}[view={-35}{27}, radiusS=2.5]
% meridians and parallels
\begin{scope}[black!50, seenS=.7, unseenS=.25, very thin]
\foreach \l in {15, 30, ..., 360}{ \path pic {meridian={\l}}; }
\foreach \l in {-75, -60, ..., 75}{ \path pic {parallel={\l}}; }
\end{scope}
\path[unseenS=.32] pic[magenta, thick] {bigCircleOnS={80:70}};
\path[unseenS=.32] pic[blue, thick] {circleOnS={80:70 at distance -.85}};
\path[unseenS=.25] pic[blue, thick] {circle3d={80:70:4 at distance -.85}};
\path[seenS=.9] pic[orange] {axesForS={1.75}};
\end{tikzpicture}
\end{document}
以及文件tikZsphere.sty
:
\tikzset{%
view/.style 2 args={%
z={({-sin(#1)}, {-cos(#1)*sin(#2)})},
x={({cos(#1)}, {-sin(#1)*sin(#2)})},
y={(0, {cos(#2)})},
evaluate={%
\tox={sin(#1)*cos(#2)};
\toy={sin(#2)};
\toz={cos(#1)*cos(#2)};
}
}
}
\pgfkeys{/tikz/.cd,
seenS/.store in=\seenS,
seenS=1
}
\pgfkeys{/tikz/.cd,
unseenS/.store in=\unseenS,
unseenS=.2
}
\pgfkeys{/tikz/.cd,
radiusS/.store in=\radiusS,
radiusS=1
}
\pgfkeys{/tikz/.cd,
samplesCOnS/.store in=\samplesCOnS,
samplesCOnS=36
}
\tikzmath{% opacities and samples
function opacityOnS(\px, \py, \pz) {%
\res = \px*\tox + \py*\toy + \pz*\toz; % inner product of posV and obsrerver
if \res>0 then {return \seenS;} else {return \unseenS;};
};
function behindS(\px, \py, \pz, \r) {%
\sppo = \px*\tox + \py*\toy + \pz*\toz; % inner product of pos.vect and obsrerver
\npsq = \px*\px + \py*\py + \pz*\pz; % norm of pos.vect^2
\nvsq = \npsq -\sppo*\sppo; % norm of pos,vect's projection^2
if \sppo<0 then {%
if \nvsq -\r*\r<.05 then {return \unseenS;} else {return \seenS;};
} else {%
if \npsq -\r*\r<.05 then {return \unseenS;} else {return \seenS;};
};
};
function stepsCOnS(\r, \k) {return ceil(\r*(\k-6)/\radiusS+6);};
}
\tikzset{
pics/axesForS/.style={%
code={
\tikzmath{%
real \b;
\b = {#1*\radiusS};
}
\foreach \i in {.1, .2, ..., \b}{%
\draw[opacity={behindS(\i-.05, 0, 0, \radiusS)}] (\i-.1, 0, 0) -- (\i, 0, 0);
\path (\b, 0, 0) ++(.4, 0, 0) node[scale=.9] {$x$};
\draw[opacity={behindS(0, \i-.05, 0, \radiusS)}] (0, \i-.1, 0) -- (0, \i, 0);
\path (0, \b, 0) ++(0, .4, 0) node[scale=.9] {$y$};
\draw[opacity={behindS(0, 0, \i-.05, \radiusS)}] (0, 0, \i-.1) -- (0, 0, \i);
\path (0, 0, \b) ++(0, 0, .4) node[scale=.9] {$z$};
}
}
},
pics/meridian/.style = {% longitude, number of points
code={
\tikzmath{
real \pax, \pay, \paz, \pbx, \pby, \pbz, \cosl, \sinl;
integer \N;
\cosl = \radiusS*cos(#1);
\sinl = \radiusS*sin(#1);
\N = int(\samplesCOnS/2);
}
\foreach \k [evaluate=\k as \bz using {180*(\k/\N -.5)},
evaluate=\k as \az using {180*((\k-1)/\N -.5)}] in {1, ..., \N}{
\tikzmath{
\pax = \cosl*cos(\az);
\pay = \radiusS*sin(\az);
\paz = \sinl*cos(\az);
\pbx = \cosl*cos(\bz);
\pby = \radiusS*sin(\bz);
\pbz = \sinl*cos(\bz);
}
\draw[opacity={opacityOnS(\pax, \pay, \paz)}]
(\pax, \pay, \paz) -- (\pbx, \pby, \pbz);
}
}
},
pics/parallel/.style = {% latitude, number of points
code={
\tikzmath{
integer \N;
real \pax, \pay, \paz, \pbx, \pby, \pbz, \cosl, \sinl;
\cosl = \radiusS*cos(#1);
\sinl = \radiusS*sin(#1);
\N = stepsCOnS(\radiusS*cos(#1), \samplesCOnS);
}
\foreach \j [evaluate=\j as \by using {360*(\j/\N)},
evaluate=\j as \ay using {360*((\j-1)/\N)}] in {1, ..., \N}{
\tikzmath{
\pax = cos(\ay)*\cosl;
\paz = sin(\ay)*\cosl;
\pbx = cos(\by)*\cosl;
\pbz = sin(\by)*\cosl;
}
\draw[opacity={opacityOnS(\pbx, \sinl, \pbz)}]
(\pax, \sinl, \paz) -- (\pbx, \sinl, \pbz);
}
}
}
}
%%%% other circles
\tikzmath{
function Cx(\t) {
return \r*\ux*cos(\t) + \r*\vx*sin(\t) + \d*\nx;
};
function Cy(\t) {
return \r*\vy*sin(\t) + \d*\ny;
};
function Cz(\t) {
return \r*\uz*cos(\t) + \r*\vz*sin(\t) + \d*\nz;
};
}
\tikzset{
pics/circle3d/.style args={#1:#2:#3 at distance #4}{%
code={
\tikzmath{
integer \N;
\N = {stepsCOnS(\radiusS, 3*\samplesCOnS)};
\nx = cos(#2)*sin(#1);
\ny = sin(#2);
\nz = cos(#2)*cos(#1);
\ux = cos(#1);
\uz = -sin(#1);
\vx = -sin(#2)*sin(#1);
\vy = cos(#2);
\vz = -sin(#2)*cos(#1);
\d = #4;
\r = #3;
}
\foreach \j [evaluate=\j as \t using {360*(\j/\N)},
evaluate=\j as \s using {360*((\j-1)/\N)}] in {1, ..., \N}{
\tikzmath{
\pax = Cx(\s);
\pay = Cy(\s);
\paz = Cz(\s);
\pbx = Cx(\t);
\pby = Cy(\t);
\pbz = Cz(\t);
}
\draw[opacity={%
behindS((\pax+\pbx)/2, (\pay+\pby)/2, (\paz+\pbz)/2, \radiusS)}]
(\pax, \pay, \paz) -- (\pbx, \pby, \pbz);
}
}
},
pics/bigCircleOnS/.style args={#1:#2}{%
code={
\tikzmath{
integer \N;
\N = {stepsCOnS(\radiusS, \samplesCOnS)};
\nx = cos(#2)*sin(#1);
\ny = sin(#2);
\nz = cos(#2)*cos(#1);
\ux = cos(#1);
\uz = -sin(#1);
\vx = -sin(#2)*sin(#1);
\vy = cos(#2);
\vz = -sin(#2)*cos(#1);
\d = 0;
\r = \radiusS;
}
\foreach \j [evaluate=\j as \t using {360*(\j/\N)},
evaluate=\j as \s using {360*((\j-1)/\N)}] in {1, ..., \N}{
\tikzmath{
\pax = Cx(\s);
\pay = Cy(\s);
\paz = Cz(\s);
\pbx = Cx(\t);
\pby = Cy(\t);
\pbz = Cz(\t);
}
\draw[opacity={opacityOnS((\pax+\pbx)/2, (\pay+\pby)/2, (\paz+\pbz)/2)}]
(\pax, \pay, \paz) -- (\pbx, \pby, \pbz);
}
}
},
pics/bigCircleOnS/.default={0:90},
pics/circleOnS/.style args={#1:#2 at distance#3}{%
code={
\tikzmath{
integer \N;
\N = {stepsCOnS(\radiusS, \samplesCOnS)};
\nx = cos(#2)*sin(#1);
\ny = sin(#2);
\nz = cos(#2)*cos(#1);
\ux = cos(#1);
\uz = -sin(#1);
\vx = -sin(#2)*sin(#1);
\vy = cos(#2);
\vz = -sin(#2)*cos(#1);
\d = #3;
\r = sqrt(\radiusS*\radiusS-\d*\d);
}
\foreach \j [evaluate=\j as \t using {360*(\j/\N)},
evaluate=\j as \s using {360*((\j-1)/\N)}] in {1, ..., \N}{
\tikzmath{
\pax = Cx(\s);
\pay = Cy(\s);
\paz = Cz(\s);
\pbx = Cx(\t);
\pby = Cy(\t);
\pbz = Cz(\t);
}
\draw[opacity={opacityOnS((\pax+\pbx)/2, (\pay+\pby)/2, (\paz+\pbz)/2)}]
(\pax, \pay, \paz) -- (\pbx, \pby, \pbz);
}
}
}
答案2
这只是为了获取球体后面的虚线。我不知道从哪里来的,tikz-3dplot-circleofsphere
所以我无法用它测试。相反,我画了一个球体的轮廓(它是一个椭圆形)并使用它。
这使用spath3
库在轨道路径与边界路径的相交处进行分割,然后以不同的风格渲染各个部分。
\documentclass{article}
%\url{https://tex.stackexchange.com/q/551460/86}
\usepackage{tikz}
\usetikzlibrary{spath3, intersections}
\begin{document}
\begin{tikzpicture}
\path[
rotate=45,
spath/save=boundary
] (0,0) circle[
x radius={3*sqrt(1 + 2*.385^2)},
y radius=3
];
\path[
spath/save=orbital,
y = {(1,0,0)},
x = {(0,0,1)}
] (0,0) circle[radius=5];
\tikzset{
spath/remove empty components={orbital},
spath/split at intersections with={orbital}{boundary},
spath/join components={orbital}{1,4},
spath/get components of={orbital}\cpts
}
\draw[
red,
ultra thick,
dashed,
spath/use=\getComponentOf\cpts{1}
];
\draw[
blue,
ultra thick,
spath/use=boundary];
\draw[
red,
ultra thick,
spath/use=\getComponentOf\cpts{2}
];
\end{tikzpicture}
\end{document}