如果我们以地心模型俯视太阳系,太阳和所有行星都将围绕地球运行。在这个模型中,地球是宇宙的中心。让我们关注地球以外的两个天体:太阳和金星。如果我们假设地球是固定的,那么太阳绕地球公转 8 次,金星将绕地球公转 13 次。这将创建一个美丽的图表,称为金星五角星(实际上,该比例为 8:13.004,非整数系数将产生摆动)。马修·亨德森在他的网站上发布了这张金星和地球宇宙舞蹈的简化图像Tumblr 网页:
编辑。上图展示了金星从日心角度的舞蹈,而不是我解释过的地心角度。我错过了它,因为我在浏览器中打开了几张日心和地心金星五角星的图片,显然我复制了错误的一张。感谢 Keks Dose 提到这一点。这里是链接观看一段精彩的视频,其中展示了金星以地球为中心翩翩起舞。
我想知道我是否可以使用 TikZ/PGF 绘制此图。我见过类似主题在 Mathematica Stack Exchange 上,但我想使用 LaTeX。我最近找到了包pst-solarsystem
和tikz-planets
如果可能的话,使用它们的功能会很酷。我不需要动画,任何帮助创建最终静态图像的帮助都会很感激。
答案1
非常有趣。基本上是一句话:
\documentclass{article}
\usepackage[halfletter,margin=0.6in]{geometry}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\foreach \x in {0,5,...,2880}{
\draw[help lines] (\x:5) -- ({(\x/8)*13}:4);%% <<<--- avoids arithmetic overflow
}
\end{tikzpicture}
\end{document}
得到这张美丽的图形:
更新
好吧,这必须发生。这是一个可以进行绘图的宏,并且能够使用参数:
\documentclass[tikz,border=20pt]{standalone}
\usepackage{keyval}
\newlength{\outerlength}
\setlength{\outerlength}{4in}
\newlength{\innerlength}
\setlength{\innerlength}{3in}
\def\outerrate{8}
\def\innerrate{13}
\def\maxtimes{2880}
\def\increment{2}
\makeatletter
\define@key{venus}{outerlength}{\setlength{\outerlength}{#1}}
\define@key{venus}{innerlength}{\setlength{\innerlength}{#1}}
\define@key{venus}{outerrate}{\def\outerrate{#1}}
\define@key{venus}{innerrate}{\def\innerrate{#1}}
\define@key{venus}{maxtimes}{\def\maxtimes{#1}}
\define@key{venus}{increment}{\def\increment{#1}}
\newcommand{\makevenus}[1][]{%
\setkeys{venus}{#1}
\begin{tikzpicture}
\foreach \x in {0,\increment,...,\maxtimes}{%
\draw[help lines] (\x:\outerlength) --
({(\x/\outerrate)*\innerrate}:\innerlength);%% <<<--- avoids arithmetic overflow
}%
\end{tikzpicture}%
}
\begin{document}
\makevenus[innerrate=7,innerlength=2.25in,increment=3]
\end{document}
生成结果:
同时\makevenus[outerrate=5,innerrate=13,innerlength=3.75in,increment=1]
生产(我喜欢我的新玩具!):
更新 2
我很好奇如果显示每条线的中心点会发生什么。有趣的是,正如宏\newmakevenus
所示,它追踪了线条交叉点形成的形状。
\RequirePackage[rgb]{xcolor}
\documentclass[tikz,border=20pt]{standalone}
\usepackage{xparse}
\usepackage{keyval}
\usepackage{fp}
\newlength{\outerlength}
\setlength{\outerlength}{4in}
\newlength{\innerlength}
\setlength{\innerlength}{2.8933in}
\def\outerrate{8}
\def\innerrate{13}
\def\maxtimes{2880}
\def\increment{2}
\colorlet{mycolor}{black}
\makeatletter
\define@key{venus}{outerlength}{\setlength{\outerlength}{#1}}
\define@key{venus}{innerlength}{\setlength{\innerlength}{#1}}
\define@key{venus}{outerrate}{\def\outerrate{#1}}
\define@key{venus}{innerrate}{\def\innerrate{#1}}
\define@key{venus}{maxtimes}{\def\maxtimes{#1}}
\define@key{venus}{increment}{\def\increment{#1}}
\define@key{venus}{venuscolor}{\colorlet{mycolor}{#1}}
\makeatother
\NewDocumentCommand{\makevenus}{sO{}}{%
\setkeys{venus}{#2}
\begin{tikzpicture}
\foreach \x in {0,\increment,...,\maxtimes}{%
\IfBooleanT{#1}{%
\pgfmathsetmacro{\huenum}{\x/\maxtimes}
\definecolor{mycolor}{hsb}{\huenum,0.5,1}
}%
\draw[help lines,mycolor] (\x:\outerlength) --
({(\x/\outerrate)*\innerrate}:\innerlength);%% <<<--- avoids arithmetic overflow
}%
\end{tikzpicture}%
}
\NewDocumentCommand{\newmakevenus}{sO{}}{%
\setkeys{venus}{#2}
\begin{tikzpicture}
\foreach \x in {0,\increment,...,\maxtimes}{%
\IfBooleanT{#1}{%
\pgfmathsetmacro{\huenum}{\x/\maxtimes}
\definecolor{mycolor}{hsb}{\huenum,0.5,1}
}%
\draw(\x:\outerlength) --node[circle,fill=orange,pos=.5]{}
({(\x/\outerrate)*\innerrate}:\innerlength);%% <<<--- avoids arithmetic overflow
}%
\end{tikzpicture}%
}
\begin{document}
%%\makevenus*[outerrate=8,innerrate=13,increment=2,maxtimes=2880,innerlength=2.9in]
\newmakevenus[outerrate=8,innerrate=13,increment=3,innerlength=2.9in,maxtimes=2880]
\end{document}
可选的*
是对图形进行着色,以便\makevenus*[outerrate=8,innerrate=13,increment=2,maxtimes=2880,innerlength=2.9in]
产生:
2880就是8*360。
节日更新
给图形上色很简单:使用hsb
颜色空间,并在绘制每条线时改变其色调(需要\RequirePackage[rgb]{xcolor}
前 \documentclass
命令)。虽然很有趣,但我想知道如果颜色循环次数(红黄->绿->蓝->紫->红)与生成的图案叶瓣循环的次数相同会发生什么——事实证明这很简单abs(\innerrate-\outerrate)
——如果或\innerrate
或\outerrate
都是素数,则效果最佳。我对它的有效性感到震惊:
\RequirePackage[rgb]{xcolor}
\documentclass[tikz,border=20pt]{standalone}
\usepackage{xparse}
\usepackage{keyval}
\newlength{\outerlength}
\setlength{\outerlength}{4in}
\newlength{\innerlength}
\setlength{\innerlength}{2.8933in}
\def\outerrate{8}
\def\innerrate{13}
\def\maxtimes{2880}
\def\increment{2}
\def\changephase{0}
\colorlet{mycolor}{black}
\makeatletter
\define@key{venus}{outerlength}{\setlength{\outerlength}{#1}}
\define@key{venus}{innerlength}{\setlength{\innerlength}{#1}}
\define@key{venus}{outerrate}{\def\outerrate{#1}}
\define@key{venus}{innerrate}{\def\innerrate{#1}}
\define@key{venus}{increment}{\def\increment{#1}}
\define@key{venus}{changephase}{\def\changephase{#1}}
\define@key{venus}{venuscolor}{\colorlet{mycolor}{#1}}
\makeatother
\NewDocumentCommand{\makevenus}{sO{}}{%
\setkeys{venus}{#2}
\begin{tikzpicture}
\pgfmathsetmacro{\nmaxtimes}{360*\outerrate}
\foreach \x in {0,\increment,...,\nmaxtimes}{%
\IfBooleanT{#1}{%
\pgfmathsetmacro{\huenum}{%
abs(sin((360/\nmaxtimes)*\x*abs(\innerrate-\outerrate)+\changephase))
}%
\definecolor{mycolor}{hsb}{\huenum,1,1}
}%
\draw[help lines,mycolor] (\x:\outerlength) --
({(\x/\outerrate)*\innerrate}:\innerlength);%% <<<--- avoids arithmetic overflow
}%
\end{tikzpicture}%
}
\begin{document}
\makevenus*[outerrate=8,innerrate=17,increment=2,innerlength=3.5in,changephase=60]
\end{document}
也可以使用以下方法改变颜色循环的阶段,changephase
从而
\makevenus*[outerrate=8,innerrate=13,increment=2,innerlength=3.5in,changephase=60]
产生:
希望你能从中得到乐趣——我知道我做到了。
新年烟花盛况
最重要的是,要从两个方面对@Thruston 表示衷心的感谢:首先,感谢他编写的优雅的单行绘图代码;其次,感谢他编写的将 HSL 转换为 RGB 的精彩 MP 代码。
以下代码输出三种样式的图形:1:单色版本;2:Thruston 的原始着色版本;3:重复光谱(内部速率 - 外部速率)次的分阶段着色。请注意,我绝不是 MP 专家,因此,毫无疑问,可以对此代码进行各种改进。
\documentclass[border=10pt]{standalone}
\usepackage{luamplib}
\usepackage{xparse}
\usepackage{graphicx}
\mplibnumbersystem{double}
%% TO DO: use keyval.sty
%% [#1 step delta]; #2 inner r; #3 outer r;
%% #4 [cycle offset]
%% #5 inner rate; #6 outer rate;
%% #7[pen scale]; #8*=color (& #9* phased color)
%% #3 (outer r) is the radius of the finished graphic, assuming that it is
%% greater than #2 (inner r).
\NewDocumentCommand{\makevenusL}{O{1} m m O{0} m m O{.125} s s}{%
\begin{mplibcode}
vardef hsv_color_cyc(expr h,s,v) = % HSB->rgb following wikipedia article on "HSL and HSV"
save chroma, hh, x, m;
chroma = v*s;
%% The following cycles through color spectrum (\innerrate-\outerrate) times
%% a constant can be added to shift the cycle.
hh = (((#6-#5)*h + #4) mod 360)/60;
x = chroma * (1-abs(hh mod 2 - 1));
m = v - chroma;
if hh < 1: (chroma,x,0)+(m,m,m)
elseif hh < 2: (x,chroma,0)+(m,m,m)
elseif hh < 3: (0,chroma,x)+(m,m,m)
elseif hh < 4: (0,x,chroma)+(m,m,m)
elseif hh < 5: (x,0,chroma)+(m,m,m)
else: (chroma,0,x)+(m,m,m)
fi
enddef;
vardef hsv_color(expr h,s,v) = % HSB->rgb following wikipedia article on "HSL and HSV"
save chroma, hh, x, m;
chroma = v*s;
%% The following cycles through color range once
hh = h/60;
x = chroma * (1-abs(hh mod 2 - 1));
m = v - chroma;
if hh < 1: (chroma,x,0)+(m,m,m)
elseif hh < 2: (x,chroma,0)+(m,m,m)
elseif hh < 3: (0,chroma,x)+(m,m,m)
elseif hh < 4: (0,x,chroma)+(m,m,m)
elseif hh < 5: (x,0,chroma)+(m,m,m)
else: (chroma,0,x)+(m,m,m)
fi
enddef;
\IfBooleanTF{#8}
{%
\IfBooleanTF{#9}
{% cycle through spectrum multiple times
beginfig(1);
for t=0 step #1 until 360:
draw #2 dir #5t -- #3 dir #6t
withpen pencircle scaled #7 withcolor hsv_color_cyc(t, 1, 1);
endfor;
draw (288,0) .. (0,288) .. (-288,0) .. (0,-288) .. cycle;
endfig;
}%
{% cycle through spectrum once
beginfig(1);
for t=0 step #1 until 360:
draw #2 dir #5t -- #3 dir #6t
withpen pencircle scaled #7 withcolor hsv_color(t, 1, 1);
endfor;
draw (288,0) .. (0,288) .. (-288,0) .. (0,-288) .. cycle;
endfig;
}%
}%
{% one color
beginfig(1);
for t=0 step #1 until 360:
draw #2 dir #5t -- #3 dir #6t
%% << change (r,g,b) spec to suit
withpen pencircle scaled #7 withcolor (0.2,0.5,0.5); %% (0,0,0) for black
endfor;
draw (288,0) .. (0,288) .. (-288,0) .. (0,-288) .. cycle;
endfig;
}%
\end{mplibcode}
}
\begin{document}
\makevenusL[.2]{260}{288}{8}{13}[0.125]
\makevenusL[.2]{260}{288}{8}{13}[0.125]*
\makevenusL[.2]{260}{288}[225]{8}{13}[0.125]**
\end{document}
%%% Local Variables:
%%% coding: utf-8
%%% mode: latex
%%% TeX-engine: luatex
%%% End:
答案2
这里有一个元帖子绘制轨道地心视图的“一行代码”。使用以下命令进行编译lualatex
:
\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
beginfig(1);
draw for t=0 upto 359: 108 dir 13t - 147 dir 8t .. endfor cycle;
endfig;
\end{mplibcode}
\end{document}
那么这里发生了什么?首先请注意,地球距离太阳 1.47 亿公里,金星距离太阳 1.08 亿公里。因此,我使用这些距离作为半径(按比例缩小,1 pt = 100 万公里)。然后,金星绕地球 8 圈,绕地球 13 圈。
现在请注意,在 MP 中,您可以将极坐标写为r * dir theta
。因此,对于给定的角度,当地球位于 时,t
金星将位于。(并且由于 MP 允许在已知常数和函数之间进行隐式乘法,因此我们实际上可以直接写出和。)108 * dir 13t
147 * dir 8t
108 dir 13t
147 dir 8t
为了获得地心视图,我们想知道金星相对于地球的位置,因此获取表示该点的最简单方法是从表示金星位置的点对中减去表示地球位置的点对。因此,在给定角度下t
,表示金星相对于地球的位置的一种方法是
108 dir 13t - 147 dir 8t
该行代码的剩余部分只是将其包装到内联 for 循环中。
for t=0 upto 359: 108 dir 13t - 147 dir 8t .. endfor cycle
使用..
将每个点连接到前一个点,并cycle
在最后关闭路径。这可以保存为path
变量。或者如我所示,您可以直接将其传递给draw
。路径在 处返回自身t=360
,
日心说
另一个则对应着日心说的观点(其中每条线连接地球和金星......)
\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibnumbersystem{double}
\begin{mplibcode}
beginfig(1);
for t=0 step 1/4 until 359: draw 108 dir 13t -- 147 dir 8t withpen pencircle scaled 1/8; endfor;
endfig;
\end{mplibcode}
\end{document}
注意这里需要增强数字系统...再次用 进行编译lualatex
。这个与第一个类似,只是我将语句移到了draw
循环内部,并且不是从金星点中减去地球点,而是在它们之间画一条线段,就像顶部的 OP 动画一样。
一些 HSV 颜色在这里会有所帮助。特别是五个心形线看起来更清晰,如下所示:
\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibnumbersystem{double}
\begin{mplibcode}
vardef hsv_color(expr h,s,v) =
% following wikipedia article on "HSL and HSV"
save chroma, hh, x, m;
chroma = v*s;
hh = h/60;
x = chroma * (1-abs(hh mod 2 - 1));
m = v - chroma;
if hh < 1: (chroma,x,0)+(m,m,m)
elseif hh < 2: (x,chroma,0)+(m,m,m)
elseif hh < 3: (0,chroma,x)+(m,m,m)
elseif hh < 4: (0,x,chroma)+(m,m,m)
elseif hh < 5: (x,0,chroma)+(m,m,m)
else: (chroma,0,x)+(m,m,m)
fi
enddef;
beginfig(1);
for t=0 step 1/4 until 360-1/4:
draw 108 dir 13t -- 147 dir 8t
withpen pencircle scaled 1/8 withcolor hsv_color(t, .4, .8); endfor;
endfig;
\end{mplibcode}
\end{document}
现在几乎足以成为一张钞票了......