我想在圆柱体上绘制测地线。这些是直线、圆或螺旋线。我可以绘制前两种,但我不知道如何绘制螺旋线。
准确地说,我想知道如何在这个圆柱体上画一个螺旋线(经过两个点 A 和 B,但这两点的位置无关紧要),TikZ
只使用(可能使用pgfplots
,但不使用pstricks
):
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\begin{document}
\begin{tikzpicture}
\node [cylinder,rotate=90,draw,aspect=2,minimum width=2cm,minimum height=3.5cm](C){};
\draw[fill] (-0.5,-0.5) circle [radius=0.045]node[below]{$A$};
\draw[fill] (0.5,0.75) circle [radius=0.045]node[below]{$B$};
\end{tikzpicture}
\end{document}
答案1
我喜欢 @Gromolatto 的想法。但是我认为绘制数百个线段有点过头了。这是他/她使用“\pgfplotfunction”的代码,它简化了代码并提高了精度,因为所有点都按原样绘制,而无需定义数百个子线段。
我保留了原始代码并注释了被替换的行。
\documentclass{standalone}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usepackage{pgfplots}
\usetikzlibrary{shapes}
\tdplotsetmaincoords{60}{110}
\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\node [cylinder,rotate=90,draw,aspect=2,minimum width=2cm,minimum height=3.5cm](C){};
%\foreach \t in {-90,-75,...,0}{%
% \draw ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.23+\t/360});
%}
\begin{scope}[color=black, dashed]
\pgfplothandlerlineto
\pgfplotfunction{\t}{-90,-89,...,15}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}
% \foreach \t in {15,16,...,98}{%
% \draw[line width=1.5pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+1)},{sin(\t +1)},{-0.22+\t/360});
% }
\begin{scope}[color=red]
\pgfplothandlerlineto
\pgfplotfunction{\t}{15,16,...,110}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}
%\foreach \t in {110,125,...,280}{%
% \draw[line width=1pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.22+\t/360});
%}
\begin{scope}[color=red, dashed]
\pgfplothandlerlineto
\pgfplotfunction{\t}{110,111,...,303}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}
% \foreach \t in {303,304,...,340}{%
% \draw[line width=1.6pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+1)},{sin(\t +1)},{-0.19+\t/360});
% }
\begin{scope}[color=red]
\pgfplothandlerlineto
\pgfplotfunction{\t}{303,304,...,340}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}
%\foreach \t in {355,370}{%
% \draw ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.23+\t/360});
%}
\begin{scope}[color=black, dashed]
\pgfplothandlerlineto
\pgfplotfunction{\t}{340,341,...,370}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}
\def\ang{340}
\pgfmathsetmacro\bx{cos(\ang)}
\pgfmathsetmacro\by{sin(\ang)}
\pgfmathsetmacro\bz{-0.24+ \ang/360}
\coordinate (B) at (\bx,\by,\bz);
\draw[fill] (0.9922,0.25,-0.2) circle [x=1cm,y=1cm,radius=0.045]node[below]{$A$};
\draw[fill] (B) circle [x=1cm,y=1cm,radius=0.045]node[below]{$B$};
\end{tikzpicture}
\end{document}
得到的数据如下:
如果您进行“放大”,您将看到这个图形如何提高精度。
答案2
这里有一个tikz-3dplot
解决方案。如果人们有兴趣在圆柱体的两个点之间绘制更通用的螺旋线(而不仅仅是测地线),我添加了一个宏,用于\n
指定圆柱体周围的额外圈数。
编辑:感谢 Qrrbrbirlbel 的非常有用的评论。
\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\begin{document}
\tdplotsetmaincoords{70}{15}
\tikzset{every circle/.append style={x=1cm, y=1cm}}
\begin{tikzpicture}[tdplot_main_coords]
% --- Independent parameters ---
\def\h{3} % cylinder height
\pgfmathtruncatemacro\tA{350} % A angle
\def\zA{1} % A applicate
\pgfmathtruncatemacro\tB{150} % B angle
\def\zB{2} % B applicate
\pgfmathtruncatemacro\n{0} % number of additional turns
\pgfmathtruncatemacro\NbPt{51} % number of dots for drawing the helix portion
\def\rhelixdots{0.02} % radius of dots forming helix
\def\rAB{0.05} % radius of A and B dots
% --- Draw cylinder ---
% peripheral spokes
\foreach \t in {20,40,...,360}
{
\draw[gray,very thin,dashed] ({cos(\t)},{sin(\t)},0)
--({cos(\t)},{sin(\t)},\h);
}
% lower circle
\draw[black,very thin] (1,0,0)
\foreach \t in {2,3,...,360}
{
--({cos(\t)},{sin(\t)},0)
}
--cycle;
% upper circle
\draw[black,very thin] (1,0,\h)
\foreach \t in {2,4,...,360}
{
--({cos(\t)},{sin(\t)},\h)
}
--cycle;
% --- Draw helix ---
\pgfmathsetmacro\tone{\tA}
\pgfmathsetmacro\tlast{\tB+\n*360}
\pgfmathsetmacro\ttwo{\tone+(\tlast-\tone)/(\NbPt-1)}
\pgfmathsetmacro\p{360*(\zB-\zA)/(\tB-\tA+360*\n)}
\foreach \t in {\tone,\ttwo,...,\tlast}{%
\fill[red] ({cos(\t)},{sin(\t)},{\p*(\t-\tA)/360+\zA}) circle[radius=\rhelixdots];
}
% --- Draw A and B ---
\fill[blue] ({cos(\tA)},{sin(\tA)},\zA) circle [radius=\rAB]node[right]{$A$};
\fill[blue] ({cos(\tB)},{sin(\tB)},\zB) circle [radius=\rAB]node[left]{$B$};
\end{tikzpicture}
\end{document}
答案3
以下是我完全想要的解决方案(它基于 Jubobs 和 Qrrbrbirlbel 的回复,但形式更简化)。根据颜色和线的类型(虚线或非虚线),有 5 个不同的扇区。计算点坐标,使它们位于螺旋线上:
\documentclass{standalone}
\usepackage{tikz}
\usepackage{3dplot}
\usetikzlibrary{shapes.geometric}
\tdplotsetmaincoords{60}{110}
\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\node [cylinder,rotate=90,draw,aspect=2,minimum width=2cm,minimum height=3.5cm](C){};
\foreach \t in {-90,-75,...,0}{%
\draw ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.23+\t/360});
}
\foreach \t in {15,16,...,98}{%
\draw[line width=1.5pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+1)},{sin(\t +1)},{-0.22+\t/360});
}
\foreach \t in {110,125,...,280}{%
\draw[line width=1pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.22+\t/360});
}
\foreach \t in {303,304,...,340}{%
\draw[line width=1.6pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+1)},{sin(\t +1)},{-0.19+\t/360});
}
\foreach \t in {355,370}{%
\draw ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.23+\t/360});
}
\draw[fill] (0.9922,0.25,-0.2) circle [x=1cm,y=1cm,radius=0.045]node[below]{$A$};
\draw[fill] (0.2739,-0.5,0.32) circle [x=1cm,y=1cm,radius=0.045]node[below]{$B$};
\end{tikzpicture}
\end{document}
转折点附近的线条密度存在一些问题,但这些问题可以轻松手动调整。打印后,这是可以的:
答案4
这只是提到了弗里茨的精彩回答也可以在这里使用。对于圆柱体来说,数学运算甚至更简单。这允许人们让 pgfplots 决定某些拉伸是在前面还是在后面,并且 pgfplots 还允许我们通过拨打适当的 来根据需要对事物进行阴影处理point meta
。
\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\begin{document}
% very much like https://tex.stackexchange.com/a/199715/121799
\pgfplotsset{visible stretch/.style={restrict expr to
domain={sin(atan2(rawy,rawx)-\pgfkeysvalueof{/pgfplots/view/az})}{-1.1:0}},hidden
stretch/.style={restrict expr to
domain={sin(atan2(rawy,rawx)-\pgfkeysvalueof{/pgfplots/view/az})}{0:1.1}}}
\def\addFGBGplot[#1]#2;{
\addplot3[#1,hidden stretch, opacity=0.25] #2;
\addplot3[#1,visible stretch] #2;
}
\begin{tikzpicture}[declare function={R=1;H=3;}]
\begin{axis}[hide axis]
\addplot3[surf,shader=interp,domain y=0:H,opacity=0.5,domain=
\pgfkeysvalueof{/pgfplots/view/az}:\pgfkeysvalueof{/pgfplots/view/az}-180,
colormap/blackwhite,point meta={sin(atan2(y,x)+40)}]
({R*cos(x)},
{R*sin(x)},{y});
\addplot3[samples y=0,domain=0:360,smooth,fill=gray!30,draw=black] ({R*cos(x)},{R*sin(x)},{H});
\addFGBGplot[samples y=0,color=blue,domain=0:1440,smooth,samples=251]
({R*cos(x)},{R*sin(x)},{0.75*x/360});
\addplot3[samples y=0,domain=\pgfkeysvalueof{/pgfplots/view/az}:\pgfkeysvalueof{/pgfplots/view/az}-180,smooth,color=black]
({R*cos(x)},{R*sin(x)},{0});
\draw ({R*cos(\pgfkeysvalueof{/pgfplots/view/az})},{R*sin(\pgfkeysvalueof{/pgfplots/view/az})
},{0}) -- ({R*cos(\pgfkeysvalueof{/pgfplots/view/az})},{R*sin(\pgfkeysvalueof{/pgfplots/view/az})},{H})
({R*cos(\pgfkeysvalueof{/pgfplots/view/az}-180)},{R*sin(\pgfkeysvalueof{/pgfplots/view/az}-180)
},{0}) -- ({R*cos(\pgfkeysvalueof{/pgfplots/view/az}-180)},{R*sin(\pgfkeysvalueof{/pgfplots/view/az}-180)},{H});
\end{axis}
\end{tikzpicture}
\end{document}