我基于http://www.texample.net/tikz/examples/spherical-and-cartesian-grids/现在我需要从点 P 到点 Q 添加一条圆弧。目前我能得到的是:
\begin{tikzpicture}[scale=1,every node/.style={minimum size=1cm}]
%% some definitions
\def\R{4} % sphere radius
\def\angEl{25} % elevation angle
\def\angAz{-100} % azimuth angle
\def\angPhiOne{-110} % longitude of point P
\def\angPhiTwo{-45} % longitude of point Q
\def\angBeta{30} % latitude of point P and Q
%% working planes
\pgfmathsetmacro\H{\R*cos(\angEl)} % distance to north pole
\LongitudePlane[xzplane]{\angEl}{\angAz}
\LongitudePlane[pzplane]{\angEl}{\angPhiOne}
\LongitudePlane[qzplane]{\angEl}{\angPhiTwo}
\LongitudePlane[nzplane]{\angEl}{-86}
\LatitudePlane[equator]{\angEl}{0}
\fill[ball color=white!10] (0,0) circle (\R); % 3D lighting effect
\coordinate (O) at (0,0);
\coordinate[mark coordinate] (N) at (0,\H);
\coordinate[mark coordinate] (S) at (0,-\H);
\DrawLongitudeCircle[\R]{\angPhiOne} % pzplane
\DrawLongitudeCircle[\R]{\angPhiTwo} % qzplane
\DrawLatitudeCircle[\R]{\angBeta}
\DrawLatitudeCircle[\R]{0} % equator
%labelling north and south
\node[above=8pt] at (N) {$\mathbf{N}$};
\node[below=8pt] at (S) {$\mathbf{S}$};
\draw[-,dashed, thick] (N) -- (S);
%setup coordinates P and Q
\path[pzplane] (0:\R) coordinate (P);
\draw[->] (O) -- node[above=4pt] {$\overrightarrow{P}$} (P);
\path[qzplane] (\angBeta:\R) coordinate (Q);
\draw[->] (O) -- node[above=2pt] {$\overrightarrow{Q}$} (Q);
\path[nzplane] (153:\R) coordinate (N);
\draw[->,color=red] (O) -- node[right=2pt] {$\overrightarrow{N}$} (N);
\draw (P) arc (-110:-45:\R) (Q);
\end{tikzpicture}
是否有可能以 O 为中心从 P 到 Q 画一条弧?
根据要求,完整的可编译源代码:http://pastebin.com/m809Jwp7
答案1
为了给出正确答案,我们需要定义叉积和向量积(这项工作是在 metapost 中完成的古腾堡手册 48但它是法语的)
我没有足够的时间来定义所有这些宏,但可以找到一种绘制圆弧的方法。首先,我们知道圆弧 PQ(蓝色)位于平面 OPQ 中,是中心为 O、半径为 OP 的圆的一部分。因此,我搜索一个坐标系 xyz,其中 x=OP 和 y=OA'。A 是赤道上经度 = -20 的点。为什么?因为我想要赤道的 OP 和 OA 半径,并且 OP 在 OA 处垂直。然后我需要找到经度为 -20 且纬度 >30 的 A',但我需要计算该值。
更新如何确定 A' 的纬度?
在下面的图片中,H 是 Q 在平面 (OPA) 上的投影。可以用两条边 (OP=1 和 OH=0.866) 计算 PH,我发现 1.001。然后直线 PH 和 OA 在点 I 处相交。现在我计算出 OI=1.238 和 PI=1.591。J 是直线 OA' 上的一个点,I 是 J 在平面 (OPA) 上的投影。P、Q、J 对齐,IJ=0.795。IJ/OI=0.641=tan(32.7)。A' 的纬度是 32.7。现在我可以画一个半径为 1 的圆,该圆通过 P 和 A',以 O 为圆心。
现在我需要画一个以 O 为中心、半径为 1 的圆。圆经过 P 和 A',也经过 Q。我画出直径 POP' 和 QOQ'。
待办事项:微积分正确确定 A' 的纬度,交叉积确定 N'。宏用于放置具有经度和纬度的点。
在我的代码中,我用我正确理解的名称重新定义了个人宏。
\documentclass[11pt]{scrartcl}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzset{%
add/.style args={#1 and #2}{
to path={%
($(\tikztostart)!-#1!(\tikztotarget)$)--($(\tikztotarget)!-#2!(\tikztostart)$)%
\tikztonodes},add/.default={.2 and .2}}
}
\tikzset{%
mark coordinate/.style={inner sep=0pt,outer sep=0pt,minimum size=2pt,
fill=black,circle}%
}
\newcommand\pgfmathsinandcos[3]{%
\pgfmathsetmacro#1{sin(#3)}%
\pgfmathsetmacro#2{cos(#3)}%
}
\newcommand\LongitudePlane[2][current plane]{%
\pgfmathsinandcos\sinEl\cosEl{\Elevation} % elevation
\pgfmathsinandcos\sint\cost{#2} % azimuth
\tikzset{#1/.estyle={cm={\cost,\sint*\sinEl,0,\cosEl,(0,0)}}}
}
\newcommand\LatitudePlane[2][current plane]{%
\pgfmathsinandcos\sinEl\cosEl{\Elevation} % elevation
\pgfmathsinandcos\sint\cost{#2} % latitude
\pgfmathsetmacro\ydelta{\cosEl*\sint}
\tikzset{#1/.estyle={cm={\cost,0,0,\cost*\sinEl,(0,\ydelta)}}} %
}
\newcommand\DrawLongitudeCircle[1]{
\LongitudePlane{#1}
\tikzset{current plane/.prefix style={scale=\R}}
\pgfmathsetmacro\angVis{atan(sin(#1)*cos(\Elevation)/sin(\Elevation))} %
\draw[current plane,thin,black] (\angVis:1) arc (\angVis:\angVis+180:1);
\draw[current plane,thin,dashed] (\angVis-180:1) arc (\angVis-180:\angVis:1);
}%
\newcommand\DrawLatitudeCircle[1]{
\LatitudePlane{#1}
\tikzset{current plane/.prefix style={scale=\R}}
\pgfmathsetmacro\sinVis{sin(#1)/cos(#1)*sin(\Elevation)/cos(\Elevation)}
\pgfmathsetmacro\angVis{asin(min(1,max(\sinVis,-1)))}
\draw[current plane,thin,black] (\angVis:1) arc (\angVis:-\angVis-180:1);
\draw[current plane,thin,dashed] (180-\angVis:1) arc (180-\angVis:\angVis:1);
}%
\newcommand\DrawPointOnSphere[3]{%
\pgfmathsinandcos\sinLoM\cosLoM{#1}
\pgfmathsinandcos\sinLaM\cosLaM{#2}
}
\begin{document}
\null\vfill
\begin{center}
\begin{tikzpicture}
\def\R{4} % sphere radius
\def\Elevation{25} % elevation angle
\def\angleLongitudeP{-110} % longitude of point P
\def\angleLongitudeQ{-45} % longitude of point Q
\def\angleLatitudeQ{30} % latitude Q ; 0 latitude of P
\def\angleLongitudeA{-20} % longitude of point A
\pgfmathsetmacro\H{\R*cos(\Elevation)} % distance to north pole
\LongitudePlane[PLongitudePlane]{\angleLongitudeP}
\LongitudePlane[QLongitudePlane]{\angleLongitudeQ}
\LongitudePlane[ALongitudePlane]{\angleLongitudeA}
\fill[ball color=white!10] (0,0) circle (\R); % 3D lighting effect
\coordinate (O) at (0,0);
\coordinate[] (N) at (0,\H);
\coordinate[] (S) at (0,-\H);
\DrawLongitudeCircle{\angleLongitudeP} % PLongitudePlane
\DrawLongitudeCircle{\angleLongitudeQ} % QLongitudePlane
\DrawLongitudeCircle{\angleLongitudeA}
\DrawLatitudeCircle{\angleLatitudeQ}
\DrawLatitudeCircle{0} % equator
\DrawLongitudeCircle{0}
%setup coordinates P and Q
\path[ALongitudePlane] (0:\R) coordinate (A);
\path[ALongitudePlane] (32.5:\R) coordinate (A');
\path[ALongitudePlane] (122.5:\R) coordinate (N');
\path[PLongitudePlane] (0:\R) coordinate (P);
\draw[dashed,add= 1 and 0] (O) to (P);
\path[QLongitudePlane] (\angleLatitudeQ:\R) coordinate (Q);
\draw[dashed,add= 1 and 0] (O) to (Q) ;
\path[QLongitudePlane] (0:\R) coordinate (B);
\draw [dashed] (O) -- (B) ;
\draw [dashed] (O) -- (N) ;
\foreach \v in {A,O,N,S,P,Q,A',B,N'} {\coordinate[mark coordinate] (v) at (\v);
\node [above] at (\v) {\v};}
\begin{scope}[ x={(P)}, y={(A')}, z={(N')}]
\draw[dashed,fill opacity=.3] circle (1);
\draw[blue] ( 0:1) arc (0:68:1) ;
\draw[] ( 68:1) arc (68:115:1) ;
\draw[] (-55:1) arc (-55:0:1);
\draw[red,->](0,0,0)--(0,0,1);
\draw[red,->](0,0,0)--(0,1,0);
\draw[red,->](0,0,0)--(1,0,0);
\end{scope}
\end{tikzpicture}
\end{center}
\vfill
\end{document}
答案2
诀窍是旋转坐标系。这段代码显示了穿过 P 和 Q 特定值的大圆,以及从 P 到 Q 的蓝色圆弧。
\begin{scope}[rotate around={30:(0,0)}]
\DrawLatitudeCircle[\R]{11}
\draw[current plane,blue,thick] (240:1) arc (240:310:1);
\end{scope}
(我删除了几个绘图命令以使结果更清晰一些。显然,所有参数都是针对这个问题的,而且不太明显的是,是通过视觉选择的。)
答案3
这里有一个不同的算法,它更快,更灵活,因为它使用“\pgfplotfunction”而不是一次绘制每个点。该算法基于以下帖子:
基本上,Rahul 发布的方程式是从
线性插值公式。该公式很容易编码成“\pgfplotfunction”。
我在上面的帖子中使用了与球体上的圆弧相同的测试,但宏不同(重命名为 \myarctwo),它在这里:
\newcommand\myarctwo[9]
{
%center
\def\ox{#1};
\def\oy{#2};
\def\oz{#3};
%start
\def\ax{#4};
\def\ay{#5};
\def\az{#6};
%end
\def\bx{#7}
\def\by{#8}
\def\bz{#9}
% parameter t in [0,1], s is a scale
\pgfmathsetmacro\s{divide(1,\tempa}
% shift coordinates
\pgfmathsetmacro\aox{\ax-\ox}
\pgfmathsetmacro\aoy{\ay-\oy}
\pgfmathsetmacro\aoz{\az-\oz}
\pgfmathsetmacro\boxo{\bx-\ox}
\pgfmathsetmacro\boy{\by-\oy}
\pgfmathsetmacro\boz{\bz-\oz}
\pgfmathsetmacro\bax{\bx-\ax}
\pgfmathsetmacro\bay{\by-\ay}
\pgfmathsetmacro\baz{\bz-\az}
% find radius r, actually we want r^2
\pgfmathsetmacro\r{\aox*\aox+\aoy*\aoy+\aoz*\aoz}
% find angle between the vectors O->A and O->B
\pgfmathsetmacro\dotab{\aox*\boxo + \aoy*\boy + \aox*\boz}
\pgfmathsetmacro\cosphi{\dotab/\r}
\pgfmathsetmacro\sinphi{sqrt(1.0-(\cosphi * \cosphi))}
\pgfmathsetmacro\phia{acos(\cosphi)}
\pgfmathsetmacro\xap{divide(\aox,\sinphi)}
\pgfmathsetmacro\yap{divide(\aoy,\sinphi}
\pgfmathsetmacro\zap{divide(\aoz,\sinphi}
\pgfmathsetmacro\xbp{divide(\boxo,\sinphi}
\pgfmathsetmacro\ybp{divide(\boy,\sinphi}
\pgfmathsetmacro\zbp{divide(\boz,\sinphi}
\begin{scope}[color=\tempb]
\pgfplothandlerlineto
\pgfplotfunction{\t}{0,1,...,\tempa}
{\pgfpointxyz {\ox + \xap*sin((1-\s*\t)*\phia) + \xbp*sin(\s*\t*\phia)}
{\oy + \yap*sin((1-\s*\t)*\phia) + \ybp*sin(\s*\t*\phia)}
{\oz + \zap*sin((1-\s*\t)*\phia) + \zbp*sin(\s*\t*\phia)}}
\pgfusepath{stroke}
\end{scope}
}
以下是包含 200 个点的图:
答案4
arc
为了进行比较,我在模块中添加了一种使用内置的 Asymptote 方法three
。请注意,无需计算弧平面的法线。如果要使用法线进行装饰,只需计算即可n=unit(cross(P,Q));
。
虚线不是用来自然显示图形的。我从未见过需要可见线和不可见线的交点的情况。当然,我们可以通过某种技巧或窍门将隐藏线变成虚线。
// http://asymptote.ualberta.ca/
import three;
unitsize(1cm);
currentprojection=orthographic(2,1,.6,zoom=.9);
real r=3;
draw(scale3(r)*unitsphere,lightyellow+opacity(.2));
// 2 points on the sphere
triple P=r*expi(-30,-30), Q=r*expi(60,70);
// 2 arc on the sphere connecting P and Q
path3 aPQ=arc(O,P,Q);
draw(aPQ,blue,Arrow3);
path3 aPQcw=arc(O,P,Q,CW);
draw(reverse(aPQcw),red,Arrow3);
dot(P^^Q);
dot("$O$",align=plain.S,O);
draw(Label("$x$",EndPoint),O--(r+4)*X);
draw(Label("$y$",EndPoint),O--(r+1)*Y);
draw(Label("$z$",EndPoint),O--(r+1)*Z);