分形/复平面迭代/曼德勃罗集外部
曼德勃罗集外部的颜色可以是
- 非平滑 = 逃逸时间 = 驻留时间
- 布尔/二进制逃逸时间方法(bETM/M)
- 离散 = 水平集方法 = LSM/M = 整数 ETM = iETM/M
- 平滑
还可以绘制曲线
- 外射线
- 等势线(闭合曲线 - 准圆)
类似项目
- Claude Heiland-Allen 的曼德勃罗笔记本
- Arnaud Cheritat 的不同绘图技术和算法
- Linas Vepstas 的艺廊
这里,对于参数平面上给定的点 c,人们检查临界点 在动力学平面上的前向迭代下的行为。 如果你改变初始点,你将得到不同的结果[5]
要绘制给定的平面,需要检查/扫描(所有)它的点。 参见此处以获取更多详细信息(优化) 首先阅读定义。
- math.stackexchange 问题:is-there-an-equation-for-the-number-of-iterations-required-to-escape-the-mandelb
- math.stackexchange 问题:a-way-to-determine-the-ideal-number-of-maximum-iterations-for-an-arbitrary-zoom?
该算法回答了问题:“对于哪些 c 值,Julia 分形 J(c) 将是线状的,而对于哪些 c 值将是粉尘状的?”[6]
这里,复平面由 2 个集合组成:曼德勃罗集 及其补集
// http://mrl.nyu.edu/~perlin/
main(k){float i,j,r,x,y=-16;while(puts(""),y++<15)for(x
=0;x++<84;putchar(" .:-;!/>)|&IH%*#"[k&15]))for(i=k=r=0;
j=r*r-i*i-2+x/25,i=2*r*i+y/10,j*j+i*i<11&&k++<111;r=j);}
-- Haskell code by Ochronus
-- http://blog.mostof.it/mandelbrot-set-in-ruby-and-haskell/
import Data.Complex
mandelbrot a = iterate (\z -> z^2 + a) a !! 500
main = mapM_ putStrLn [[if magnitude (mandelbrot (x :+ y)) < 2 then '*' else ' '
| x <- [-2, -1.9685 .. 0.5]]
| y <- [1, 0.95 .. -1]]
; common lisp
(loop for y from -1.5 to 1.5 by 0.05 do
(loop for x from -2.5 to 0.5 by 0.025 do
(let* ((c (complex x y)) ; parameter
(z (complex 0 0))
(iMax 20) ; maximal number of iterations
(i 0)) ; iteration number
(loop while (< i iMax ) do
(setq z (+ (* z z) c)) ; iteration
(incf i)
(when (> (abs z) 2) (return i)))
; color of pixel
(if (= i iMax) (princ (code-char 42)) ; inside M
(princ (code-char 32))))) ; outside M
(format t "~%")) ; new line
以下是用于创建 pbm 文件的各种程序[9]
这是 C 单文件程序的完整代码。
- 它创建一个包含图像的 ppm 文件。 要查看文件(图像),请使用外部应用程序(图形查看器)。
- 程序由 3 个循环组成
- iY 和 iX,用于扫描参数平面的矩形区域
- 迭代。
对于屏幕上的每个点(iX,iY),其复数值将计算为 c=cx+cy*i。
对于每个点,c 都计算了临界点的迭代次数
它使用了一些速度改进。不是检查
sqrt(Zx2+Zy2)<ER
它检查
(Zx2+Zy2)<ER2 // ER2 = ER*ER
它给出了相同的结果,但速度更快。
/*
c program:
--------------------------------
1. draws Mandelbrot set for Fc(z)=z*z +c
using Mandelbrot algorithm ( boolean escape time )
-------------------------------
2. technique of creating ppm file is based on the code of Claudio Rocchini
http://en.wikipedia.org/wiki/Image:Color_complex_plot.jpg
create 24 bit color graphic file , portable pixmap file = PPM
see http://en.wikipedia.org/wiki/Portable_pixmap
to see the file use external application ( graphic viewer)
*/
#include <stdio.h>
#include <math.h>
int main()
{
/* screen ( integer) coordinate */
int iX,iY;
const int iXmax = 800;
const int iYmax = 800;
/* world ( double) coordinate = parameter plane*/
double Cx,Cy;
const double CxMin=-2.5;
const double CxMax=1.5;
const double CyMin=-2.0;
const double CyMax=2.0;
/* */
double PixelWidth=(CxMax-CxMin)/iXmax;
double PixelHeight=(CyMax-CyMin)/iYmax;
/* color component ( R or G or B) is coded from 0 to 255 */
/* it is 24 bit color RGB file */
const int MaxColorComponentValue=255;
FILE * fp;
char *filename="new1.ppm";
char *comment="# ";/* comment should start with # */
static unsigned char color[3];
/* Z=Zx+Zy*i ; Z0 = 0 */
double Zx, Zy;
double Zx2, Zy2; /* Zx2=Zx*Zx; Zy2=Zy*Zy */
/* */
int Iteration;
const int IterationMax=200;
/* bail-out value , radius of circle ; */
const double EscapeRadius=2;
double ER2=EscapeRadius*EscapeRadius;
/*create new file,give it a name and open it in binary mode */
fp= fopen(filename,"wb"); /* b - binary mode */
/*write ASCII header to the file*/
fprintf(fp,"P6\n %s\n %d\n %d\n %d\n",comment,iXmax,iYmax,MaxColorComponentValue);
/* compute and write image data bytes to the file*/
for(iY=0;iY<iYmax;iY++)
{
Cy=CyMin + iY*PixelHeight;
if (fabs(Cy)< PixelHeight/2) Cy=0.0; /* Main antenna */
for(iX=0;iX<iXmax;iX++)
{
Cx=CxMin + iX*PixelWidth;
/* initial value of orbit = critical point Z= 0 */
Zx=0.0;
Zy=0.0;
Zx2=Zx*Zx;
Zy2=Zy*Zy;
/* */
for (Iteration=0;Iteration<IterationMax && ((Zx2+Zy2)<ER2);Iteration++)
{
Zy=2*Zx*Zy + Cy;
Zx=Zx2-Zy2 +Cx;
Zx2=Zx*Zx;
Zy2=Zy*Zy;
};
/* compute pixel color (24 bit = 3 bytes) */
if (Iteration==IterationMax)
{ /* interior of Mandelbrot set = black */
color[0]=0;
color[1]=0;
color[2]=0;
}
else
{ /* exterior of Mandelbrot set = white */
color[0]=255; /* Red*/
color[1]=255; /* Green */
color[2]=255;/* Blue */
};
/*write color to the file*/
fwrite(color,1,3,fp);
}
}
fclose(fp);
return 0;
}
-
细节数量与最大迭代次数成正比
-
基于每个像素的固定迭代次数的曼德布罗特动画。在这里你可以看到为什么有时会使用偏移量(因为 - 颜色梯度会发生变化:对于高 MaxIteration 会消失。
这里颜色与最后一次迭代(final_n,最后一次迭代)成正比。[11]
这也被称为水平集方法 ( LSM )
曼德布罗特算法与 LSM/M 之间的区别仅在于部分指令,该指令计算曼德布罗特集外部的像素颜色。在 LSM/M 中是
if (Iteration==IterationMax)
{ /* interior of Mandelbrot set = black */
color[0]=0;
color[1]=0;
color[2]=0;
}
/* exterior of Mandelbrot set = LSM */
else if ((Iteration%2)==0)
{ /* even number = black */
color[0]=0; /* Red */
color[1]=0; /* Green */
color[2]=0; /* Blue */
}
else
{/* odd number = white */
color[0]=255; /* Red */
color[1]=255; /* Green */
color[2]=255; /* Blue */
};
这里有一个C函数,没有显式的复数,只有双精度浮点数
int GiveEscapeTime(double C_x, double C_y, int iMax, double _ER2)
{
int i;
double Zx, Zy;
double Zx2, Zy2; /* Zx2=Zx*Zx; Zy2=Zy*Zy */
Zx=0.0; /* initial value of orbit = critical point Z= 0 */
Zy=0.0;
Zx2=Zx*Zx;
Zy2=Zy*Zy;
for (i=0;i<iMax && ((Zx2+Zy2)<_ER2);i++)
{
Zy=2*Zx*Zy + C_y;
Zx=Zx2-Zy2 +C_x;
Zx2=Zx*Zx;
Zy2=Zy*Zy;
};
return i;
}
这里有一个使用复数的简短代码
// https://gitlab.com/adammajewski/mandelbrot_wiki_ACh/blob/master/betm.c
int iterate(double complex C , int iMax)
{
int i;
double complex Z= 0.0; // initial value for iteration Z0
for(i=0;i<iMax;i++)
{
Z=Z*Z+C; // https://stackoverflow.com/questions/6418807/how-to-work-with-complex-numbers-in-c
if(cabs(Z)>EscapeRadius) break;
}
return i;
}
这里有一个 C++ 函数,可用于绘制 LSM/M
int iterate_mandel(complex C , int imax, int bailout)
{
int i;
std::complex Z(0,0); // initial value for iteration Z0
for(i=0;i<=imax-1;i++)
{
Z=Z*Z+C; // overloading of operators
if(abs(Z)>bailout)break;
}
return i;
}
我认为它不能更简单地编写(它看起来比伪代码更好),但它可以用其他方法编写,这些方法可以更快地执行。
这里是一个更快的代码
// based on cpp code by Geek3
inline int fractal(double cx, double cy, int max_iters)
// gives last iteration
{
double zx = 0, zy = 0;
if (zx * zx + zy * zy > 4) return(0); // it=0
for (int it = 1; it < max_iters; it++)
{ double zx_old = zx;
zx = zx * zx - zy * zy;
zy = 2 * zx_old * zy;
zx += cx;
zy += cy;
if (zx * zx + zy * zy > 4.0) return(it);
}
return(max_iters);
}
稍微优化了一下
// optimised from cpp code by Geek3
inline int fractal(double cReal, double cImg, int max_iters)
// gives last iteration
{
double zReal = 0, zImg = 0, zReal2 = 0, zImg2 = 0;
//iteration zero is always 0^2+0^2, it will never escape
for (int it = 1; it < max_iters; it++)
{ //because we have zReal^2 and zImg^2 pre-calculated
//we can calculate zImg first
//then we don't need to calculate/store the "old" zReal
zImg = (2 * zReal * zImg ) + cImg;
zReal = zReal2 - zImg2 + cReal;
// calculate next iteration: zReal^2 and zImg^2
// they are used twice so calculate them once
zReal2 = zReal * zReal;
zImg2 = zImg * zImg;
if (zReal2 + zImg2 > 4.0) return(it);
}
return(max_iters);
}
See also :
//Java code by Josef Jelinek
// http://java.rubikscube.info/
int mandel(double cx, double cy) {
double zx = 0.0, zy = 0.0;
double zx2 = 0.0, zy2 = 0.0;
int iter = 0;
while (iter < iterMax && zx2 + zy2 < 4.0) {
zy = 2.0 * zx * zy + cy;
zx = zx2 - zy2 + cx;
zx2 = zx * zx;
zy2 = zy * zy;
iter++;
}
return iter;
}
这里有一个 JavaScript 函数,它不返回最后一次迭代,而是返回 LastIteration 模 maxCol。它使颜色循环(如果 maxCol < maxIt)。
function iterate(Cr,Ci) {
// JavaScript function by Evgeny Demidov
// http://www.ibiblio.org/e-notes/html5/fractals/mandelbrot.htm
var I=0, R=0, I2=0, R2=0, n=0;
if (R2+I2 > max) return 0;
do { I=(R+R)*I+Ci; R=R2-I2+Cr; R2=R*R; I2=I*I; n++;
} while ((R2+I2 < max) && (n < maxIt) );
if (n == maxIt) return maxCol; else return n % maxCol;
}
上面的函数没有使用复数的显式定义。
基于Frank Buss 的代码[12] [13]制作 ASCII 图形的完整 Lisp 程序
; common lisp
(loop for y from -1.5 to 1.5 by 0.1 do
(loop for x from -2.5 to 0.5 by 0.04 do
(let* ((i 0)
(z (complex x y))
(c z))
(loop while (< (abs
(setq z (+ (* z z) c)))
2)
while (< (incf i) 32))
(princ (code-char (+ i 32))))) ; ASCII chars <= 32 contains non-printing characters
(format t "~%"))
filter mandelbrot (gradient coloration) c=ri:(xy/xy:[X,X]*1.5-xy:[0.5,0]); z=ri:[0,0]; # initial value z0 = 0 # iteration of z iter=0; while abs(z)<2 && iter<31 do z=z*z+c; # z(n+1) = fc(zn) iter=iter+1 end; coloration(iter/32) # color of pixel end
Pov-Ray 有一个内置函数 mandel[14]
勒尼萨卡特是逃逸时间水平集 ( LSM/M ) 的边界。可以使用 绘制它们
分解是对逃逸时间算法的修改。
目标集被分成多个部分(2 个或更多)。使用非常大的逃逸半径,例如 ER = 12。
这里目标集合 在动态平面上被分为两部分(二进制分解 = 2 分解)
- 上半部分(白色)
- 下半部分(黑色)
目标集合的划分导致级别集 分解为 部分(单元格,子集)
- ,颜色为白色,
- ,颜色为黑色。
"The Level Sets and Field Lines are superimposed, creating a sort of grid, and the "squares" of the grid are filled with N-digit binary numbers giving the first N binary digits of the external angles of field lines passing through the square. (Alternately, only the Nth binary digit is used.) Each level set is divided into 2n squares. It is easy to "read" the external arguments of points in the boundary of the Mandelbrot Set using a binary decomposition." Robert P. Munafo
对于二进制分解,使用 exp(pi) 作为逃逸半径,以便方框看起来是方形的(来自 mrob 的提示)。
角度为(以圈数测量)
可以被视为子集的边界。
二进制分解算法与 Mandel 或 LSM/M 之间的区别仅在于计算 Mandelbrot 集合外部像素颜色的指令部分。在二进制分解中,
if (Iteration==IterationMax)
{ /* interior of Mandelbrot set = black */
color[0]=0;
color[1]=0;
color[2]=0;
}
/* exterior of Mandelbrot set = LSM */
else if (Zy>0)
{
color[0]=0; /* Red */
color[1]=0; /* Green */
color[2]=0; /* Blue */
}
else
{
color[0]=255; /* Red */
color[1]=255; /* Green */
color[2]=255; /* Blue */
};
还有来自 Fragmentarium 的 GLSL 代码。
#include "2D.frag"
#group Simple Mandelbrot
// maximal number of iterations
uniform int iMax; slider[1,100,1000] // increase iMax
// er2= er^2 wher er= escape radius = bailout
uniform float er2; slider[4.0,1000,10000] // increase er2
// compute color of pixel
vec3 color(vec2 c) {
vec2 z = vec2(0.0); // initial value
// iteration
for (int i = 0; i < iMax; i++) {
z = vec2(z.x*z.x-z.y*z.y,2*z.x*z.y) + c; // z= z^2+c
if (dot(z,z)> er2) // escape test
// exterior
if (z.x>0){ return vec3( 1.0);} // upper part of the target set
else return vec3(0.0); //lower part of the target set
}
return vec3(0.0); //interior
}
// zoomasm -- zoom video assembler
// (c) 2019,2020,2021,2022 Claude Heiland-Allen
// SPDX-License-Identifier: AGPL-3.0-only
// recommended KF bailout settings: linear smoothing, custom radius 25
vec3 colour(void)
{
if (getInterior())
{
return vec3(1.0, 0.0, 0.0);
}
bool decomp = getT() < 0.5;
return vec3(decomp ? 0.0 : 1.0);
}
如果最后一次迭代的 虚部 (Zy) 为正或负,则点 c 绘制为白色或黑色。[17]
此方法是二进制分解的扩展。
目标集 T = { z : |zn| > R } 具有非常大的逃逸半径(例如 R = 12),被划分为多于 2 部分(例如 8)。[18]
此方法/算法的其他名称是:
- 完全重整化的分数迭代计数(由 Linas Vepstas 于 1997 年提出)[19]
- 广义 Mandelbrot 集合的平滑迭代计数(由 Inigo Quilez 于 2016 年提出)[20]
- Mandelbrot 集合的连续迭代计数
- 归一化迭代计数算法
- 连续着色
- 平滑颜色渐变
- 分数迭代
- 分数逃逸时间
这里 Mandelbrot 集合外部的颜色不是与最后一次迭代(它是整数)成正比,而是与实数成正比
其他方法和加速方法
Ultrafractal 中的着色公式:[21]
smooth iter = iter + 1 + ( log(log(bailout)-log(log(cabs(z))) )/log(2)
其中:
- log(log(bailout) 可以预先计算
克劳德的描述
首次描述
如果 R 很大,第一个逃逸的 z 满足(近似):[22]
所以取对数
所以再取一次对数
所以根据代数
当 在逃逸时更大,平滑迭代次数应该更小,所以这个值需要从整数迭代次数中减去
或者,这个分数可以用于插值,或者与 arg(z) 一起用于外部平铺/二进制分解。
第二次描述[23]
选择一个半径 R > 2,然后 |Z| > R 意味着 |Z^2 + C| > |Z|,更一般地,|Z| -> 无限大,这给 R 起了逃逸半径的名字。证明在 math.stackexchange.com 上 somewhere。
现在假设 R 很大,n 是第一次 |Z_n| > R 的迭代。
考虑当您将点 C 从曼德勃罗集边界稍微移开时,|Z_n| 会怎样增加。
最终 |Z_n| > R^2,但随后 |Z_{n-1}| > R,所以迭代次数应该是 n - 1。
为了平滑,我们想要一个值加到 n 上,当 |Z_n| = R 时为 0,当 |Z_n| = R^2 时为 -1。
取对数,得到 log |Z| 在 log(R) 和 2 log(R) 之间
再次取对数,得到 log log |Z| 在 log log R 和 log log R + log 2 之间
除以 log 2,得到 log_2 log |Z| 在 log_2 log R 和 log_2 log R + 1 之间
减去 log_2 log R 给出 (log_2 log |Z| - log_2 log R) 在 0 和 1 之间
否定它给出介于 0 和 -1 之间的值,如预期
所以平滑迭代次数是
(如果你做 Z^P + C,将 2 替换为 P)
另请参阅 http://linas.org/art-gallery/escape/escape.html,它会生成一个与 R 无关的值,但这对于某些着色算法来说不是很有用(例如,逃逸计数的平滑部分不与最终迭代的角度对齐)
要在程序开头添加 log2 函数,请添加:
#include <math.h>
在程序开头。
if (Iteration==IterationMax)
{ /* interior of Mandelbrot set = black */
color[0]=0;
color[1]=0;
color[2]=0;
}
/* exterior of Mandelbrot set */
else GiveRainbowColor((double)(Iteration- log2(log2(sqrt(Zx2+Zy2))))/IterationMax,color);
其中:
- Zx2 = Zx*Zx
- Zy2 = Zy*Zy
以下是 Tony Finch 的另一个版本[24]
while (n++ < max &&
x2+y2 < inf) {
y = 2*x*y + b;
x = x2-y2 + a;
y2 = y*y;
x2 = x*x;
}
nu = n - log(log(x2+y2)/2)/ log(2);
基于公式[25]
// based on cpp code by Geek3 from https://wikibooks.cn/wiki/File:Mandelbrot_set_rainbow_colors.png
sqrxy = x * x + y * y;
double m = LastIteration + 1.5 - log2(log2(sqrxy));
/**
Smooth coloring algorithm
https://gitlab.com/shreyas.siravara/mandelbrot-with-smooth-coloring/blob/master/Mandelbrot.java
Mandelbrot with Smooth Coloring by Shreyas Siravara
*/
double nsmooth = (iterations + 1 - Math.log(Math.log(Zn.getMagnitude())) / Math.log(ESCAPE_RADIUS));
double smoothcolor = nsmooth / MAX_ITERATIONS;
if (iterations < MAX_ITERATIONS) {
int rgb = Color.HSBtoRGB((float) (0.99f + 1.9 * smoothcolor), 0.9f, 0.9f);
g2d.setColor(new Color(rgb));
} else {
g2d.setColor(Color.black.darker());
}
以下是 Paul Nylander 的代码。它使用不同的公式
使用 mpmath 库的 Python 代码[26]
def mandelbrot(z):
c = z
for i in xrange(ITERATIONS):
zprev = z
z = z*z + c
if abs(z) > ESCAPE_RADIUS:
return ctx.exp(1j*(i + 1 - ctx.log(ctx.log(abs(z)))/ctx.log(2)))
return 0
-
外部 DEM/M
-
使用 DEM/M 的简单边界
-
使用 DEM/M 和 Sobel 滤波器的边界
变体
- 外部 DEM/M
- 内部 DEM/M
- https://web.archive.org/web/20071008112609/http://rgba.scenesp.org/iq/trastero/fieldlines/
- http://fraktal.republika.pl/mset_bottcher.html
- ↑ 发散分形的数学 by
- ↑ jussi harkonen : 着色技术
- ↑ 维基百科 : 轨道陷阱
- ↑ 曼德勃罗轨道陷阱渲染!编程教程视频 by DKM101
- ↑ Dieter Röß 编写的 Java 程序,展示了改变曼德勃罗迭代初始点的结果
- ↑ PostScript 中的 Julia 分形 by Kees van der Laan, EUROTEX 2012 & 6CM PROCEEDINGS 47
- ↑ 分形基准测试 by Erik Wrenholt
- ↑ 12 分钟曼德勃罗:50 年前的 IBM 1401 大型机上的分形
- ↑ 计算机语言基准测试游戏
- ↑ 演示代码示例 - 以多种方式查看 Julia 集 by ed Burke
- ↑ 计算曼德勃罗集 by Andrew Williams
- ↑ LIsp 程序 by Frank Buss
- ↑ Bill Clementson 博客中的曼德勃罗集 ASCII 艺术
- ↑ 来自 2.5.11.14 分形模式的曼德勃罗函数 at Pov-Ray 文档
- ↑ 通过逃逸线方法绘制曼德勃罗集。M. Romera 等人。
- ↑ http://www.metabit.org/~rfigura/figura-fractal/math.html 边界跟踪 by Robert Figura
- ↑ http://web.archive.org/20010415125044/www.geocities.com/CapeCanaveral/Launchpad/5113/fr27.htm%7C 乔伊斯·哈斯拉姆在FRACTAL REPORT 27中致密奇博士的公开信
- ↑ 曼德博集合 n 次分解
- ↑ linas.org : 曼德博逃逸的重整化
- ↑ I Quilez : mset_smooth
- ↑ fractalforums : 曼德博/朱利亚集合的分数逃逸计数的范围/精度是多少?
- ↑ fractalforums : 使用两种颜色的渐变调色板
- ↑ fractalforums.org : 有人可以帮我理解平滑着色吗
- ↑ 托尼·芬奇制作曼德博集电影
- ↑ Linas Vepstas. 重整化曼德博逃逸.
- ↑ mpmath Python 库