我正在使用基于 Tomas M. Trzeciak 的代码立体和圆柱地图投影示例绘制球体。
我在球体上添加了三个大圆:赤道和两个经度圆。我想用点标记赤道和另外两个大圆的(正面)交点(就像我对天顶和天底所做的那样),并将它们标记为 A 和 B。为此,我可能需要以某种方式使用圆的交点坐标。我该怎么做?
这是 MWE。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,fadings,decorations.pathreplacing}
\usepackage{verbatim}
%% Helper macros
\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/.estyle={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/.estyle={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][2]{
\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);
}
%% Document-wide tikz options and styles
\tikzset{%
>=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}%
}
\begin{document}
\begin{tikzpicture} % "THE GLOBE" showcase
\def\R{2.5} % sphere radius
\def\angEl{25} % elevation angle
\filldraw[ball color=white] (0,0) circle (\R);
\DrawLatitudeCircle[\R]{0}
\DrawLongitudeCircle[\R]{-110}
\DrawLongitudeCircle[\R]{-50}
\pgfmathsetmacro\H{\R*cos(\angEl)} % distance to north pole
\coordinate (O) at (0,0);
\coordinate[mark coordinate] (Z) at (0,\H);
\coordinate[mark coordinate] (N) at (0,-\H);
\draw[->] (0,-\H) -- (0,1.2*\R) node[above] {Zenith};
\draw[dashed] (0,-\H) -- (0,-\R);
\draw (0,-\R) -- (0,-1.2*\R) node[below] {Nadir};
\end{tikzpicture}
\end{document}
它生成下面的图像(没有明显的修改):
答案1
以下是使用该库的可能性intersections
:
我重新定义了\DrawLongitudeCircle
并\DrawLatitudeCircle
增加了一个强制参数,用于命名路径;命名完成后,intersections
将使用该库来获取路径之间的交点。
代码:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{intersections,calc,fadings,decorations.pathreplacing}
\usepackage{verbatim}
\usepackage{xparse}
%% Helper macros
\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[3][1]{
\LongitudePlane{\angEl}{#2}
\tikzset{current plane/.prefix style={scale=#1}}
% angle of "visibility"
\pgfmathsetmacro\angVis{atan(sin(#2)*cos(\angEl)/sin(\angEl))} %
\draw[name path=#3,current plane] (\angVis:1) arc (\angVis:\angVis+180:1);
\draw[name path=dashed#3,current plane,dashed] (\angVis-180:1) arc (\angVis-180:\angVis:1);
}
\newcommand\DrawLatitudeCircle[3][2]{
\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[name path=#3,current plane] (\angVis:1) arc (\angVis:-\angVis-180:1);
\draw[name path=dashed#3,current plane,dashed] (180-\angVis:1) arc (180-\angVis:\angVis:1);
}
%% Document-wide tikz options and styles
\tikzset{%
>=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},%
smalldot/.style={
fill,
circle,
inner sep=1.5pt
}
}
\begin{document}
\begin{tikzpicture} % "THE GLOBE" showcase
\def\R{2.5} % sphere radius
\def\angEl{25} % elevation angle
\filldraw[ball color=white] (0,0) circle (\R);
\DrawLatitudeCircle[\R]{0}{lat}
\DrawLongitudeCircle[\R]{-110}{lon1}
\DrawLongitudeCircle[\R]{-50}{lon2}
% We find the intersection points and then draw little filled circles at them
\path[name intersections={of= lat and lon1,by={a}}];
\path[name intersections={of= lat and lon2,by={b}}];
\node[smalldot,label={above right:$A$}] at (a) {};
\node[smalldot,label={above left:$B$}] at (b) {};
\pgfmathsetmacro\H{\R*cos(\angEl)} % distance to north pole
\coordinate (O) at (0,0);
\coordinate[mark coordinate] (Z) at (0,\H);
\coordinate[mark coordinate] (N) at (0,-\H);
\draw[->] (0,-\H) -- (0,1.2*\R) node[above] {Zenith};
\draw[dashed] (0,-\H) -- (0,-\R);
\draw (0,-\R) -- (0,-1.2*\R) node[below] {Nadir};
\end{tikzpicture}
\end{document}
评论
对于 PGF/TikZ 版本 3.0,必须修改原始问题中给出的代码,通过更改(如我的示例代码中所示)以产生所需的estyle
结果style
\tikzset{#1/.estyle={cm={\cost,\sint*\sinEl,0,\cosEl,(0,0)}}}
和
\tikzset{#1/.estyle={cm={\cost,0,0,\cost*\sinEl,(0,\yshift)}}} %
无论如何,我的解决方案适用于任何版本 > 2.10。
答案2
值得一提的是,这是一个版本元帖子。
使用构造很容易找到交点intersectionpoint
。但正如您所看到的,我有点作弊,将北极和南极保持在顶部和底部。要像您的示例一样自由旋转图形,需要计算出所有投影,这在普通 MP 中会有点繁琐(但并非不可能)。
prologues := 3;
outputtemplate := "%j%c.eps";
beginfig(1);
path outline, equator, prime_meridian, ninety_meridian;
r := 100;
outline := fullcircle scaled 2r;
n := 40;
for i = 0 upto n:
fill outline scaled (1-3i/4n) shifted (-i*r/2.8n,i*r/2.8n) withcolor (0.5+i/1.6n)*white;
endfor
equator = outline yscaled 0.14;
prime_meridian = outline xscaled 0.54;
ninety_meridian = outline xscaled 0.84;
drawoptions(dashed withdots withcolor .3 white);
draw subpath(0,4) of equator;
draw subpath(-2,2) of prime_meridian;
draw subpath(2,6) of ninety_meridian;
drawoptions(dashed evenly withcolor .3 white);
draw r*down -- r*up;
drawoptions();
draw subpath(4,8) of equator;
draw subpath(2,6) of prime_meridian;
draw subpath(-2,2) of ninety_meridian;
dotlabel.urt ("A",subpath (3,5) of prime_meridian intersectionpoint subpath (4,6) of equator);
dotlabel.ulft("B",subpath (-1,1) of ninety_meridian intersectionpoint subpath (6,8) of equator);
drawarrow r*up -- 1.2r*up;
draw r*down -- 1.2r*down;
label.top("Zenith",1.2r*up);
label.bot("Nadir", 1.2r*down);
endfig;
end.
enter code here