我真的很惊讶我找不到这个问题的答案,但问题是:如何使用 tikz 和 tikz-3dplots 绘制与球体相交的平面?
但我真正想要的是这样的(真遗憾,我完全不明白为什么 Geogebra 不将 3D 图形转换为 tikz):
显然,我快到了。但阴影是错误的:平面被绘制成好像覆盖了球体,而不是与球体相交。我发现这里显然没有办法自动进行着色,但我可以手动进行。唯一的问题是,我不知道该怎么做。我花了一天多的时间试图理解前面提到的答案的代码中发生了什么,因为它们是针对特定情况制作的,我需要将它们转换为与随机平面相交的随机球体。我用收集到的信息在代码中添加了一些注释。但我仍然不确定所有这些命令是如何工作的,所以我无法正确识别应该在哪里结束和开始一个弧线,以便在平面绘图的顶部用一些深灰色填充。
我知道使用外部程序来生成图像是可行的(这里是一个使用 Asymptote 的好例子,但我必须向我的文件中添加许多与不同平面相交的不同球体,并且我希望能够使用 tikz 直接在 Latex 中生成它们,而不是使用多个图形。
所以我的问题简化为:如何在我的图中手动添加适当的阴影?(请注意,需要两种阴影:一种用于球体的盖子,一种较暗的用于球体盖子的后部。)当然,可以轻松修改不同球体和平面(特别是不平行于 xy 的平面)的替代代码也非常受欢迎。
我目前拥有的:
\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{backgrounds, intersections}
%I don't have a clear idea of what is happening here, but they are used for the plane construction
\newcommand\pgfmathsinandcos[3]{%
\pgfmathsetmacro#1{sin(#3)}%
\pgfmathsetmacro#2{cos(#3)}%
}
\newcommand\LongitudePlane[3][current plane]{%
\pgfmathsinandcos\sinEl\cosEl{#2} % elevation
\pgfmathsinandcos\sint\cost{#3} % azimuth
\tikzset{#1/.style={cm={\cost,\sint*\sinEl,0,\cosEl,(0,0)}}}
}
\newcommand\LatitudePlane[3][current plane]{%
\pgfmathsinandcos\sinEl\cosEl{#2} % elevation
\pgfmathsinandcos\sint\cost{#3} % latitude
\pgfmathsetmacro\yshift{\cosEl*\sint}
\tikzset{#1/.style={cm={\cost,0,0,\cost*\sinEl,(0,\yshift)}}} %
}
\newcommand\DrawLongitudeCircle[2][1]{
\LongitudePlane{\angEl}{#2}
\tikzset{current plane/.prefix style={scale=#1}}
% angle of "visibility"
\pgfmathsetmacro\angVis{atan(sin(#2)*cos(\angEl)/sin(\angEl))} %
\draw[current plane] (\angVis:1) arc (\angVis:\angVis+180:1);
\draw[current plane,dashed] (\angVis-180:1) arc (\angVis-180:\angVis:1);
}
\newcommand\DrawLatitudeCircle[2][1]{
\LatitudePlane{\angEl}{#2}
\tikzset{current plane/.prefix style={scale=#1}}
\pgfmathsetmacro\sinVis{sin(#2)/cos(#2)*sin(\angEl)/cos(\angEl)}
% angle of "visibility"
\pgfmathsetmacro\angVis{asin(min(1,max(\sinVis,-1)))}
\draw[current plane] (\angVis:1) arc (\angVis:-\angVis-180:1);
\draw[current plane,dashed] (180-\angVis:1) arc (180-\angVis:\angVis:1);
}
\begin{document}
\begin{figure}
\centering
\tdplotsetmaincoords{60}{110}
\begin{tikzpicture}[tdplot_main_coords,
declare function={dicri(\t,\th,\ph,\R)=sin(\th)*sin(\ph)*(\R*cos(\t)) - sin(\th)*cos(\ph)*(\R*sin(\t))+ cos(\th)*(1);}] %dicri is defined according to a parametrization n+r*cos(t)*u+r*sen(t)*v, being u and v orthonormal vectors in the intersecting plane
\pgfmathsetmacro{\R}{5}%
\path coordinate (T) at (0,0,3) %center of circle defined by the intersection
coordinate (I) at (0,0,0);
\path[tdplot_screen_coords,shift={(I)},use as bounding box] (-1.2*\R,-1.2*\R)rectangle (1.2*\R,1.2*\R);%this limits the image position
%draws dot+label for coordinates T and I
\foreach \v/\position in {T/above,I/below} {
\draw[fill=black] (\v) circle (0.7pt) node [\position=0.2mm] {$\v$};
}
\begin{scope}[tdplot_screen_coords, on background layer]
\fill[ball color=white, opacity=0.8] (I) circle (\R);
% determine the zeros of dicri
\path[overlay,name path=dicri] plot[variable=\x,domain=0:360,samples=73]
({\x*1pt},{dicri(\x,\tdplotmaintheta,\tdplotmainphi,4)});
\path[overlay,name path=zero] (0,0) -- (360pt,0);
\path[name intersections={of=dicri and zero,total=\t}]
let \p1=(intersection-1),\p2=(intersection-2) in
\pgfextra{\xdef\tmin{\x1}\xdef\tmax{\x2}};
\end{scope} %this has to do with finding the equation of the intersection circle, I believe
\pgfmathsetmacro{\SmallR}{4} %the radius of the intersection circle is supposed as known
% Draw dashed part of intersecting circle
\draw[dashed] plot[variable=\t,domain=\tmin:\tmax,samples=50,smooth]
({\SmallR*cos(\t)},
{\SmallR*sin(\t)},
{3});
% Draw continuous part of intersecting circle
\draw[thick,save path=\pathA] plot[variable=\t,domain=\tmax:\tmin+360,samples=50,smooth]
({\SmallR*cos(\t)},
{\SmallR*sin(\t)},
{3}); %same parametrization used in dicri.
%Plane construction
%% some definitions
\def\angEl{35} % elevation angle
\def\angAz{-105} % azimuth angle
\def\angPhi{-40} % longitude of point P
\def\angBeta{19} % latitude of point P
%% working planes
\pgfmathsetmacro\H{\R*cos(\angEl)} % distance to north pole
\tikzset{xyplane/.style={
cm={cos(\angAz),sin(\angAz)*sin(\angEl),-sin(\angAz),cos(\angAz)*sin(\angEl),(0,-\H)}
}, >=latex, % option for nice arrows
inner sep=0pt,%
outer sep=2pt,%
mark coordinate/.style={inner sep=0pt,outer sep=0pt,minimum size=3pt,
fill=black,circle}
}
\LatitudePlane[equator]{\angEl}{0}
%% draw xy shifted plane
\filldraw[xyplane,shift={(0,0,3)},fill=gray!10,opacity=0.2]
(-1.8*\R,-2.6*\R) rectangle (2.2*\R,2*\R);
\end{tikzpicture}
\end{figure}
\end{document}
编辑:我设法使用以下命令找到连续圆变成虚线圆的点:
\path ({\SmallR*cos(\tmin)},
{\SmallR*sin(\tmin)},
{3}) coordinate (pmin)
({\SmallR*cos(\tmax)},
{\SmallR*sin(\tmax)},
{3}) coordinate (pmax);
这些点是新阴影的开始位置,现在我只需要知道如何找到虚线圆和上球面的圆弧。
答案1
在这种情况下,很容易满足您的要求,但我不确定这是否会对您有长期帮助。以下是一些最小的损坏变化。
\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{backgrounds, intersections}
%I don't have a clear idea of what is happening here, but they are used for the plane construction
\newcommand\pgfmathsinandcos[3]{%
\pgfmathsetmacro#1{sin(#3)}%
\pgfmathsetmacro#2{cos(#3)}%
}
\newcommand\LongitudePlane[3][current plane]{%
\pgfmathsinandcos\sinEl\cosEl{#2} % elevation
\pgfmathsinandcos\sint\cost{#3} % azimuth
\tikzset{#1/.style={cm={\cost,\sint*\sinEl,0,\cosEl,(0,0)}}}
}
\newcommand\LatitudePlane[3][current plane]{%
\pgfmathsinandcos\sinEl\cosEl{#2} % elevation
\pgfmathsinandcos\sint\cost{#3} % latitude
\pgfmathsetmacro\yshift{\cosEl*\sint}
\tikzset{#1/.style={cm={\cost,0,0,\cost*\sinEl,(0,\yshift)}}} %
}
\newcommand\DrawLongitudeCircle[2][1]{
\LongitudePlane{\angEl}{#2}
\tikzset{current plane/.prefix style={scale=#1}}
% angle of "visibility"
\pgfmathsetmacro\angVis{atan(sin(#2)*cos(\angEl)/sin(\angEl))} %
\draw[current plane] (\angVis:1) arc (\angVis:\angVis+180:1);
\draw[current plane,dashed] (\angVis-180:1) arc (\angVis-180:\angVis:1);
}
\newcommand\DrawLatitudeCircle[2][1]{
\LatitudePlane{\angEl}{#2}
\tikzset{current plane/.prefix style={scale=#1}}
\pgfmathsetmacro\sinVis{sin(#2)/cos(#2)*sin(\angEl)/cos(\angEl)}
% angle of "visibility"
\pgfmathsetmacro\angVis{asin(min(1,max(\sinVis,-1)))}
\draw[current plane] (\angVis:1) arc (\angVis:-\angVis-180:1);
\draw[current plane,dashed] (180-\angVis:1) arc (180-\angVis:\angVis:1);
}
\begin{document}
\begin{figure}
\centering
\tdplotsetmaincoords{60}{110}
\begin{tikzpicture}[tdplot_main_coords,
declare function={dicri(\t,\th,\ph,\R)=sin(\th)*sin(\ph)*(\R*cos(\t)) - sin(\th)*cos(\ph)*(\R*sin(\t))+ cos(\th)*(1);}] %dicri is defined according to a parametrization n+r*cos(t)*u+r*sen(t)*v, being u and v orthonormal vectors in the intersecting plane
\pgfmathsetmacro{\R}{5}%
\path coordinate (T) at (0,0,3) %center of circle defined by the intersection
coordinate (I) at (0,0,0);
\path[tdplot_screen_coords,shift={(I)},use as bounding box] (-1.2*\R,-1.2*\R)rectangle (1.2*\R,1.2*\R);%this limits the image position
%draws dot+label for coordinates T and I
\foreach \v/\position in {T/above,I/below} {
\draw[fill=black] (\v) circle (0.7pt) node [\position=0.2mm] {$\v$};
}
\begin{scope}[tdplot_screen_coords, on background layer]
\fill[ball color=white] (I) circle[radius=\R];
% determine the zeros of dicri
\path[overlay,name path=dicri] plot[variable=\x,domain=0:360,samples=73]
({\x*1pt},{dicri(\x,\tdplotmaintheta,\tdplotmainphi,4)});
\path[overlay,name path=zero] (0,0) -- (360pt,0);
\path[name intersections={of=dicri and zero,total=\t}]
let \p1=(intersection-1),\p2=(intersection-2) in
\pgfextra{\xdef\tmin{\x1}\xdef\tmax{\x2}};
\end{scope} %this has to do with finding the equation of the intersection circle, I believe
\pgfmathsetmacro{\SmallR}{4} %the radius of the intersection circle is supposed as known
% Draw continuous part of intersecting circle
\draw[thick,save path=\pathA] plot[variable=\t,domain=\tmax:\tmin+360,samples=50,smooth]
({\SmallR*cos(\t)},
{\SmallR*sin(\t)},
{3}); %same parametrization used in dicri.
%Plane construction
%% some definitions
\def\angEl{35} % elevation angle
\def\angAz{-105} % azimuth angle
\def\angPhi{-40} % longitude of point P
\def\angBeta{19} % latitude of point P
%% working planes
\pgfmathsetmacro\H{\R*cos(\angEl)} % distance to north pole
\tikzset{xyplane/.style={
cm={cos(\angAz),sin(\angAz)*sin(\angEl),-sin(\angAz),cos(\angAz)*sin(\angEl),(0,-\H)}
}, >=latex, % option for nice arrows
inner sep=0pt,%
outer sep=2pt,%
mark coordinate/.style={inner sep=0pt,outer sep=0pt,minimum size=3pt,
fill=black,circle}
}
\LatitudePlane[equator]{\angEl}{0}
%% draw xy shifted plane
\filldraw[xyplane,shift={(0,0,3)},fill=gray!20,opacity=0.4]
(-1.8*\R,-2.6*\R) rectangle (2.2*\R,2*\R);
% added
\clip ({\SmallR*cos(\tmax)},{\SmallR*sin(\tmax)},{3})
coordinate (auxA)
plot[variable=\t,domain=\tmax:\tmin+360,samples=50,smooth]
({\SmallR*cos(\t)},{\SmallR*sin(\t)},{3})
coordinate (auxB) -- ($(auxB)!\R*1cm!-90:(auxA)$)
-- ($(auxA)!\R*1cm!90:(auxB)$) -- cycle;
\fill[ball color=white,tdplot_screen_coords] (I) circle[radius=\R];
% moved
% Draw dashed part of intersecting circle
\draw[dashed] plot[variable=\t,domain=\tmin:\tmax,samples=50,smooth]
({\SmallR*cos(\t)},
{\SmallR*sin(\t)},
{3});
\end{tikzpicture}
\end{figure}
\end{document}
到目前为止一切顺利。但您的代码是各种代码的组合,这些代码可能有也可能没有合理的解释。如果您将它们混合在一起并且不真正理解它们,那么在保持理智的情况下在您的 LaTeX 文档中添加其中几个代码可能并不是一件容易的事。(抱歉措辞。)在我看来,一个更好的方法是想出一个简化的代码,您只在其中指定平面的法线和高度。您链接到了各种帖子,也许它们允许您以更结构化的方式将事情拼凑在一起。