在我正在撰写的论文中,我使用曼德布洛特生成器来测试我编写的应用程序。为了解释报告中讨论的某个问题,需要包含实际生成的图像。
由于到目前为止报告中的每个图形都是使用 TikZ 生成的,我想知道是否也可以使用 TikZ 生成曼德布洛特图像。但这可能吗?
答案1
库中有一个曼德布洛特集阴影shadings
:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shadings}
\begin{document}
\tikz\shade[shading=Mandelbrot set] (0,0) rectangle (4,4);
\end{document}
使用 Acrobat Reader 显示,因为 TeXworks PDF 预览器不显示高分辨率。
Mandelbrot 集由 PDF 渲染器计算和生成。该算法使用 PostScript 命令编写,PDF 支持 Postscript 运算符的子集,这就是为什么它应该比使用更高级的 pgf 或 TikZ 运算符计算要快得多。
答案2
这是一个使用 luatex 的相当粗糙的解决方案。请注意,计算没有经过任何优化,没有使用对称性或曼德布洛特集的任何其他属性。警告:即使在相当快的计算机上,代码也需要一段时间才能处理。
\documentclass{standalone}
\usepackage{tikz}
\usepackage{luacode}
\def\escapetime#1#2{\directlua{tex.print(escape_time(#1,#2))}}
\def\mandcolor#1#2{\directlua{mand_color(#1,#2)}}
\begin{document}
\begin{luacode}
local NUMITER=100
point_iter = function (a,b)
local n = 1
local x = a
local y = b
return function ()
if n > NUMITER then return nil end
n = n+1
x,y = x*x - y*y + a, 2*x*y + b
return n, x*x + y*y
end
end
escape_time = function (a,b)
local esc_time
for n, d in point_iter(a,b) do
esc_time = n
if d > 4 then break end
end
return esc_time
end
mand_color = function (a,b)
local etime = escape_time(a,b)
if etime == NUMITER+1 then tex.print("black") else tex.print("red!"..etime) end
end
\end{luacode}
\begin{tikzpicture}[scale=2]
\foreach \x in {-2,-1.99,...,.5}{
\foreach \y in {-1.3,-1.29,...,1.3}{
\draw[\mandcolor{\x}{\y},fill] (\x,\y) +(-.005,-.005) rectangle +(.005,.005);}}
\end{tikzpicture}
\end{document}
结果图像如下:
下一步将是直接从 lua 使用 mplib 来渲染图片。
答案3
对于那些对另一种方法(即使用 PSTricks)感兴趣的人:
\documentclass[border=12pt]{standalone}
\usepackage{pst-fractal}
\begin{document}
\psfractal[type=Mandel,baseColor=red,maxRadius=30,dIter=30,cx=-1.3,xWidth=4cm,yWidth=4cm](-3,-2)(2,2)
\end{document}
xelatex
使用或序列编译上面的代码片段latex-dvips-ps2pdf
。
答案4
我忍不住要推荐一个 MetaPost 版本。毕竟,MetaPost 嵌入在 LuaTeX 中,而且由于该软件包,luamplib
我们可以直接访问它,所以如果不利用这一事实,那将是一种遗憾 :-)) 不过,所有荣誉都应归功于 Stephan Kottwitz(以及之前的 Herbert),因为以下代码几乎完全是他的 Lua 代码对 MetaPost 的改编。如果没有它,我可能就不可能画出这个,因为我对分形知之甚少。
注意指令对 MetaPost 新实现的浮点数系统的调用\mplibnumbersystem{double}
。我认为这是必要的,因为计算量很大。
注意:编译以下代码可能需要几分钟!(对于我 5 年前的笔记本电脑来说需要 10 分钟。)
\documentclass[12pt]{article}
\usepackage{luamplib}
\mplibnumbersystem{double}
\mplibtextextlabel{enable}
\begin{document}
\begin{center}
\leavevmode
\begin{mplibcode}
u := 4cm;
vardef mandelbrot(expr xa, xb, ya, yb, steps, max_iter, maxs) =
save dx, dy, cx, cy, xtemp, ytemp, squaresum, iter; clearxy;
dx := (xb-xa)/steps;
dy := (yb-ya)/steps;
cx := xa;
forever:
exitunless cx <= xb;
cy := ya;
forever:
exitunless cy <= yb;
squaresum := 0;
x:= 0; y:= 0; iter := 0;
forever:
exitunless (squaresum <= maxs) and (iter < max_iter);
xtemp := x**2 - y**2 + cx;
ytemp := 2*x*y + cy;
x := xtemp;
y := ytemp;
iter := iter + 1;
squaresum := x**2 + y**2;
endfor;
if iter >= max_iter: draw u*(cx, cy); fi;
cy := cy + dy;
endfor;
cx := cx + dx;
endfor;
enddef;
beginfig(0);
% Coordinates and marks
xmin = -2; xmax = 0.75; ymin = -1.25; ymax = 1.25; len := 6bp;
draw u*(xmin, ymin) -- u*(xmax, ymin) -- u*(xmax, ymax) -- u*(xmin, ymax) -- cycle;
for i = -1.5 step .5 until .5:
label.bot("$" & decimal i & "$", u*(i, ymin));
draw u*(i, ymin) -- (i*u, ymin*u+len);
draw u*(i, ymax) -- (i*u, ymax*u-len);
endfor;
for j = -1 step 1 until 1:
label.lft("$"&decimal j&"$", u*(xmin, j));
draw u*(xmin, j) -- (xmin*u+len, j*u);
draw u*(xmax, j) -- (xmax*u-len, j*u);
endfor;
% Mandelbrot fractal
pickup pencircle scaled 1bp;
mandelbrot(-2, 1, -2, 2, 500, 1000, 4);
endfig;
\end{mplibcode}
\end{center}
\end{document}