如何在 TikZ 中的 3D 球体上从点 A -> B 绘制圆弧?

如何在 TikZ 中的 3D 球体上从点 A -> B 绘制圆弧?

我基于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”而不是一次绘制每个点。该算法基于以下帖子:

3D 中矢量两个端点之间的圆弧

基本上,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 个点的图:

3D 中两点之间的圆弧

答案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);

相关内容