CodeBus

分享代码,一起进步~

[分形学] 基于 L 系统绘制 Hilbert (希尔伯特) 曲线

德国数学家 David Hilbert 发现了这样一种可以填满整个单位正方形的分形曲线,称它为 Hilbert 曲线。具体的我就不多做介绍了,相关内容请自己搜索。这里只说程序。 程序执行后,按数字键 1~8 可以显示相应阶数的 Hilbert (希尔伯特) 曲线,按 ESC 退出。 五阶 Hilbert (希尔伯特) 曲线的执行效果如下: 完整的程序源码如下: // 程序名称:Hilbert (希尔伯特)曲线 (基于 L 系统绘制) // 编译环境:Visual C++ 6.0,EasyX 2011惊蛰版 // 最后修改:2011-3-7 // #include <graphics.h> #include <conio.h> int g_len; // Hilbert 曲线的单位长度 // 递归绘制 Hilbert 曲线 void hilbert(LPCTSTR cmd, int level) { static BYTE d = 0; // 方向 static POINT c[4] = {1, 0, 0, -1, -1, 0, 0, 1}; // 方向对应的轴系数 if (level < 0) return; // 处理命令字符串 int i = 0; while(cmd[i]) { switch(cmd[i++]) { case '+': d = (d + 1) & 3; break; case '-': d = (d - 1) & 3; break; case 'X': hilbert("+YF-XFX-FY+", level - 1); break; case 'Y': hilbert("-XF+YFY+FX-", level - 1); break; case 'F': linerel(c[d].x * g_len, c[d].y * g_len); break; } } } // 主函数 void main() { // 设置绘图环境 initgraph(800, 600); // 设置窗口大小 outtextxy(20, 550, "按 1~8 显示不同级别的 Hilbert 曲线,按 ESC 退出。"); rectangle(143, 23, 657, 537); // 绘制表示范围的矩形框 setorigin(144, 24); // 设置原点坐标 setcolor(RED); // 设置颜色 setfillstyle(BLACK); int level = '5'; // 设置初始级别 do { if (level >= '1' && level <= '8') // 仅处理 1~8 { level -= '0'; // 转换为对应的数字值 bar(0, 0, 511, 511); // 清空绘图区 g_len = 512 >> level; // 计算单位长度 moveto(g_len / 2, 512 - g_len / 2); // 设定起点 hilbert("X", level); // 递归绘制 Hilbert 曲线 } } while( (level = getch()) != 27 ); // 按 ESC 退出 closegraph(); }

[分形学] 谢宾斯基 (Sierpinski) 三角形,也叫垫片

先说一个程序的实现过程: 随机生成 3 个点 P[0]、P[1]、P[2]; 随机生成 1 个点 P; 绘制点 P; 随机生成 [0, 2] 内的整数 n; 令 P = P 与 P[n] 的中点; 重复执行步骤 (3)~(5) 三万次。 这个程序很简单,虽然随机性很大,但是结果几乎是完全相似的,会是一个很有趣的图案,也就是传说中的谢宾斯基三角形。以上步骤就是生成谢宾斯基三角形的随机迭代法。 程序代码如下: (注:为了效果,将步骤(1)的三个点手动指定了。喜欢的话,可以将其修改为随机产生) // 程序名称:谢宾斯基(Sierpinski)三角形,也叫垫片 // 编译环境:Visual C++ 6.0,EasyX 2011惊蛰版 // 最后更新:2010-11-16 // #include <graphics.h> #include <conio.h> #include <time.h> void main() { srand((unsigned)time(NULL)); // 设置随机种子 POINT P[3] = {{320, 50}, {120, 400}, {520, 400}}; // 设定三角形的三个顶点 POINT p = {rand() % 640, rand() % 480}; // 随机产生当前点 // 初始化图形模式 initgraph(640, 480); // 绘制三万个点 int n; for(int i = 0; i <= 30000; i++) { n = rand() % 3; p.x = (p.x + P[n].x) / 2; p.y = (p.y + P[n].y) / 2; putpixel(p.x, p.y, GREEN); } // 按任意键退出 getch(); closegraph(); } 执行效果要贴图就没意思了,呵呵。先猜想一下会是什么图案?

[分形学] 可以无穷放大的 Mandelbrot Set (曼德布洛特集) VC 源代码

基于上篇文章 Mandelbrot Set (曼德布洛特集) 的源代码:http://www.codebus.cn/yw80/post/mandelbrot-set 我修改了几个地方: 1. 修改了颜色,使用黑->蓝->白->棕->黑这样的渐变颜色方案(当然,大家可以修改 InitColor() 函数改变配色方案) 2. 增加了放大鼠标选中区域的功能。按鼠标中键可以恢复原尺寸。 3. 将迭代次数提了出来,定义了常量。如果需要绘制更精细的图,请加大常量 ITERATIONS。不过越大绘制的越慢。精细程度开始看不出来,放大次数多了就明显了。 4. 理论上是可以无穷放大,但实际受 double 类型精度的影响,放大到一定程度就会是马赛克了。 先看看逐步放大的效果吧: 另一个位置的逐步放大效果: 完整的 VC 源代码如下: // 程序名称:分形学 - 可以无穷放大的 Mandelbrot Set (曼德布洛特集) // 编译环境:Visual C++ 6.0,EasyX 2011惊蛰版 // 最后更新:2010-9-9 // #include <graphics.h> #include <conio.h> // 定义常量 #define ITERATIONS 1000 // 迭代次数,越高,图像越精细 #define MAXCOLOR 64 // 颜色数 ///////////////////////////////////////////////// // 定义复数及乘、加运算 ///////////////////////////////////////////////// // 定义复数 struct COMPLEX { double re; double im; }; // 定义复数“乘”运算 COMPLEX operator * (COMPLEX a, COMPLEX b) { COMPLEX c; c.re = a.re * b.re - a.im * b.im; c.im = a.im * b.re + a.re * b.im; return c; } // 定义复数“加”运算 COMPLEX operator + (COMPLEX a, COMPLEX b) { COMPLEX c; c.re = a.re + b.re; c.im = a.im + b.im; return c; } ///////////////////////////////////////////////// // 定义颜色及初始化颜色 ///////////////////////////////////////////////// // 定义颜色 int Color[MAXCOLOR]; // 初始化颜色 void InitColor() { // 使用 HSL 颜色模式产生角度 h1 到 h2 的渐变色 int h1 = 240, h2 = 30; for(int i=0; i<MAXCOLOR/2; i++) { Color[i] = HSLtoRGB((float)h1, 1.0f, i * 2.0f / MAXCOLOR); Color[MAXCOLOR-1-i] = HSLtoRGB((float)h2, 1.0f, i * 2.0f / MAXCOLOR); } } ///////////////////////////////////////////////// // 绘制 Mandelbrot Set (曼德布洛特集) ///////////////////////////////////////////////// void Draw(double fromx, double fromy, double tox, double toy) { COMPLEX z, c; int x, y, k; // 定义循环变量 for(x = 0; x < 640; x++) { c.re = fromx + (tox - fromx) * (x / 640.0); for(y = 0; y < 480; y++) { c.im = fromy + (toy - fromy) * (y / 480.0); z.re = z.im = 0; for(k = 0; k < ITERATIONS; k++) { if ( z.re * z.re + z.im * z.im > 4.0 ) break; z = z * z + c; } putpixel(x, y, (k >= ITERATIONS) ? 0 : Color[k % MAXCOLOR]); } } } ///////////////////////////////////////////////// // 主函数 ///////////////////////////////////////////////// void main() { // 初始化绘图窗口及颜色 initgraph(640, 480); InitColor(); // 初始化 Mandelbrot Set(曼德布洛特集)坐标系 double fromx, fromy, tox, toy; fromx = -2.1; tox = 1.1; fromy = -1.2; toy = 1.2; Draw(fromx, fromy, tox, toy); // 捕获鼠标操作,实现放大鼠标选中区域 MOUSEMSG m; bool isLDown = false; int selfx, selfy, seltx, selty; // 定义选区 while(!kbhit()) { m = GetMouseMsg(); // 获取一条鼠标消息 switch(m.uMsg) { // 按鼠标中键恢复原图形坐标系 case WM_MBUTTONUP: fromx = -2.1; tox = 1.1; fromy = -1.2; toy = 1.2; Draw(fromx, fromy, tox, toy); break; // 按鼠标左键并拖动,选择区域 case WM_MOUSEMOVE: if (isLDown) { rectangle(selfx, selfy, seltx, selty); seltx = m.x; selty = m.y; rectangle(selfx, selfy, seltx, selty); } break; // 按鼠标左键并拖动,选择区域 case WM_LBUTTONDOWN: setcolor(WHITE); setwritemode(R2_XORPEN); isLDown = true; selfx = seltx = m.x; selfy = selty = m.y; rectangle(selfx, selfy, seltx, selty); break; // 按鼠标左键并拖动,选择区域 case WM_LBUTTONUP: rectangle(selfx, selfy, seltx, selty); setwritemode(R2_COPYPEN); isLDown = false; seltx = m.x; selty = m.y; if (selfx == seltx || selfy == selty) break; // 修正选区为 4:3 int tmp; if (selfx > seltx) {tmp = selfx; selfx = seltx; seltx = tmp;} if (selfy > selty) {tmp = selfy; selfy = selty; selty = tmp;} if ( (seltx - selfx) * 0.75 < (selty - selfy) ) { selty += (3 - (selty - selfy) % 3); selfx -= (selty - selfy) / 3 * 4 / 2 - (seltx - selfx) / 2; seltx = selfx + (selty - selfy) / 3 * 4; } else { seltx += (4 - (seltx - selfx) % 4); selfy -= (seltx - selfx) * 3 / 4 / 2 - (selty - selfy ) / 2; selty = selfy + (seltx - selfx ) * 3 / 4; } // 更新坐标系 double f, t; f = fromx + (tox - fromx) * selfx / 640; t = fromx + (tox - fromx) * seltx / 640; fromx = f; tox = t; f = fromy + (toy - fromy) * selfy / 480; t = fromy + (toy - fromy) * selty / 480; fromy = f; toy = t; // 画图形 Draw(fromx, fromy, tox, toy); break; } } getch(); closegraph(); }