| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 5117 人关注过本帖, 11 人收藏
标题:图形学的分支:分形
只看楼主 加入收藏
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
结帖率:96.15%
收藏(11)
已结贴  问题点数:50 回复次数:48 
图形学的分支:分形
分形,简单的来说就是自相似所产生的漂亮图形,能无穷放大并且保持性质不变
最简单的例子是旋涡:
图片附件: 游客没有浏览图片的权限,请 登录注册


不过说到分形,先要从Mandelbrot Set说起

曼德布洛特集合(Mandelbrot set)是在复平面上组成分形的点的集合。
Mandelbrot集合由复二次多项式f(z)=z^2+c来定义。
其中c是一个复常数。对于每一个c,从z=0开始对f(z)进行迭代
序列 (0, f(0), f(f(0)), f(f(f(0))), .......)的值或者延伸到无限大,或者只停留在有限半径的圆盘内。
曼德布洛特集合就是使以上序列不延伸至无限大的所有c点的集合。
从数学上来讲,曼德布洛特集合是一个复数的集合。一个给定的复数c或者属于曼德布洛特集合M,或者不是。
最后,根据常数c令多项式的敛散性不同,在平面上用不同的颜色标注,便可以以形象的方式把这个集合绘画出来


曼德布洛特集:
图片附件: 游客没有浏览图片的权限,请 登录注册


此图如果把它的局部放大,你会发现它是自相似的,以下是放大过程:
图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册


好了,现在我们也来用C来画出这个集合。
首先,我们要定义复数:
typedef struct COMPLEX
{
    double re; //实部
    double im; //虚部
} COMPLEX;

然后,我们只需要用到加法和乘法:

COMPLEX mul (const COMPLEX a, const 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 add (const COMPLEX a, const COMPLEX b)
{
    COMPLEX c;
    c.re = a.re + b.re;
    c.im = a.im + b.im;
    return c;
}

复数定义好了以后,我们要开始写计算部分了
我们假设输出窗口大小是640 * 480
那么就需要一个二重循环:
int x, y;
for(y=0; y<480; y++)
{
    for(x=0; x<640; x++)
    {
        // 这里为计算部分
    }
}

然后,你的(x,y)要映射到一个实数,比如你x的范围为-2.0到2.0
那么任意x实际对应的实数是 -2.0 + (2.0 - (-2.0)) / 640 * x
所以这个二重循环里面补上映射计算后的代码为:
int x, y;
for(y=0; y<480; y++)
{
    for(x=0; x<640; x++)
    {
        COMPLEX c;
        c.re = -2.0 + (2.0 - (-2.0)) / 640 * x;
        c.im = -1.5 + (1.5 - (-1.5)) / 480 * y;
        // 这里开始为计算部分
    }
}

这样,我们就算出了所需要的c,然后,根据公式,我们写一个函数来迭代,返回迭代结果:
int f(COMPLEX c)
{
    COMPLEX z = {0, 0}; //初始化为0
    int maxcalc = 100;  //最大迭代次数
    while (--maxcalc)
    {
        z = mul(z, z);
        z = add(z, c);
        if ( z.re*z.re + z.im*z.im > 4.0 ) break; //其模超过4,肯定发散,跳出
    }
    return maxcalc>0; //如果maxcalc>0说明没迭代完就越了界,否则就在集合内
}

最后,剩下的事情就简单了,只要补充上我们的主循环体:
int x, y;
for(y=0; y<480; y++)
{
    for(x=0; x<640; x++)
    {
        COMPLEX c;
        c.re = -2.0 + (2.0 - (-2.0)) / 640 * x;
        c.im = -1.5 + (1.5 - (-1.5)) / 480 * y;
        if (f(c)) putpixel(x, y, BLACK);
        else      putpixel(x, y, WHITE);
    }
}

好了,最简单的显示版本做好了,
以下为完整源代码(如果你要编译测试,请直接下载附件中整个工程的压缩包):
MandelbrotDemo.rar (212.97 KB)


#include "graphics.h"

//定义复数结构
typedef struct COMPLEX
{
    double re; //实部
    double im; //虚部
} COMPLEX;

//定义复数乘法
COMPLEX mul (const COMPLEX a, const 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 add (const COMPLEX a, const COMPLEX b)
{
    COMPLEX c;
    c.re = a.re + b.re;
    c.im = a.im + b.im;
    return c;
}

int f(COMPLEX c)
{
    COMPLEX z = {0, 0}; //初始化为0
    int maxcalc = 100;  //最大迭代次数
    while (--maxcalc)
    {
        z = mul(z, z);
        z = add(z, c);
        if ( z.re*z.re + z.im*z.im > 4.0 ) break; //其模超过4,肯定发散,跳出
    }
    return maxcalc>0; //如果maxcalc>0说明没迭代完就越了界,否则就在集合内
}

int main()
{
    initgraph(640, 480);
    {
        int x, y;
        for(y=0; y<480; y++)
        {
            for(x=0; x<640; x++)
            {
                COMPLEX c;
                c.re = -2.0 + (2.0 - (-2.0)) / 640 * x;
                c.im = -1.5 + (1.5 - (-1.5)) / 480 * y;
                if (f(c)) putpixel(x, y, BLACK);
                else      putpixel(x, y, WHITE);
            }
        }
    }
    getch();
    closegraph();
    return 0;
}

未完待续,匆回复。。。
搜索更多相关主题的帖子: 分形 分支 图形 
2010-12-18 14:38
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
收藏
得分:0 
从曼德布洛特集,衍生出Julia Set,它和曼德布洛特集很像,只是固定c,但以不同的z值迭代,同样可以得到漂亮的图形
以下为螺旋系的Julia Set:

简洁的螺旋
图片附件: 游客没有浏览图片的权限,请 登录注册



很多毛刺的
图片附件: 游客没有浏览图片的权限,请 登录注册



向日葵
图片附件: 游客没有浏览图片的权限,请 登录注册


另一种看着不太像螺旋的螺旋
图片附件: 游客没有浏览图片的权限,请 登录注册



更多旋臂
图片附件: 游客没有浏览图片的权限,请 登录注册



类似五星
图片附件: 游客没有浏览图片的权限,请 登录注册



不对称螺旋
图片附件: 游客没有浏览图片的权限,请 登录注册



另一种五星
图片附件: 游客没有浏览图片的权限,请 登录注册



雪花状
图片附件: 游客没有浏览图片的权限,请 登录注册



椭圆
图片附件: 游客没有浏览图片的权限,请 登录注册



[ 本帖最后由 御坂美琴 于 2010-12-18 14:57 编辑 ]

永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
http://bbs.bccn.net/space.php?action=threads&uid=483997
2010-12-18 14:50
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
收藏
得分:0 
六角系
图片附件: 游客没有浏览图片的权限,请 登录注册


四旋臂
图片附件: 游客没有浏览图片的权限,请 登录注册


除了单个中心的旋涡,还有双中心的:
图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册


永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
http://bbs.bccn.net/space.php?action=threads&uid=483997
2010-12-18 15:18
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
收藏
得分:0 
通过对原公式的变形(原式是z的平方),我们改为更高次,如3次,4次,等等,可以得到更漂亮的图形:

三中心
图片附件: 游客没有浏览图片的权限,请 登录注册



五星
图片附件: 游客没有浏览图片的权限,请 登录注册


五星第二种
图片附件: 游客没有浏览图片的权限,请 登录注册



前一个的放大
图片附件: 游客没有浏览图片的权限,请 登录注册



又一种五星
图片附件: 游客没有浏览图片的权限,请 登录注册


图片附件: 游客没有浏览图片的权限,请 登录注册


前一个的放大
图片附件: 游客没有浏览图片的权限,请 登录注册



雪花形
图片附件: 游客没有浏览图片的权限,请 登录注册


图片附件: 游客没有浏览图片的权限,请 登录注册

永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
http://bbs.bccn.net/space.php?action=threads&uid=483997
2010-12-18 15:26
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
收藏
得分:0 
除了这一种,还有一种是使用牛顿迭代法在复平面上的收敛根的不同而绘制的
它要解z^n + 1 = 0这个方程,很明显,这个方式有n个根,根据牛顿迭代法公式可得
f(z) = z - f(z) / f'(z)
f(z) = z - (z^n + 1) / (n * z^(n-1))
然后需要使用n种颜色分别标注,收敛到同一个根的用相同的颜色,同样会产生很漂亮的分形

目前这个的程序还没写好,敬请期待

永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
http://bbs.bccn.net/space.php?action=threads&uid=483997
2010-12-18 15:32
御坂美琴
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:魔術の禁書目錄
等 级:小飞侠
威 望:9
帖 子:952
专家分:2929
注 册:2010-8-18
收藏
得分:0 
前一个生成程序的改进

前一个程序(一楼的),只对敛散性做了判断,于是返回只有0/1两种,也就是说,只能画出黑白图案
为了能利用上更多的信息以绘画彩色的图片,我们不单纯地对敛散性做判断,还对敛散的速度加以填充颜色

其实这个并不难,我们对f函数做以下调整:
int f(COMPLEX c)
{
    COMPLEX z = {0, 0}; //初始化为0
    int maxcalc = 100;  //最大迭代次数
    while (--maxcalc)
    {
        z = mul(z, z);
        z = add(z, c);
        if ( z.re*z.re + z.im*z.im > 4.0 ) break; //其模超过4,肯定发散,跳出
    }
    return maxcalc;
}

没错,直接返回迭代次数,这样,我们可以运用迭代次数来加上彩色,只要修改主循环为:
    {
        int x, y;
        for(y=0; y<480; y++)
        {
            for(x=0; x<640; x++)
            {
                COMPLEX c;
                int n;
                c.re = -2.0 + (2.0 - (-2.0)) / 640 * x;
                c.im = -1.5 + (1.5 - (-1.5)) / 480 * y;
                n = f(c);
                if (n == 0) putpixel(x, y, BLACK);
                else        putpixel(x, y, HSVtoRGB((float)(n * 4 % 360), 1.0f, 1.0f));
            }
        }
    }

这样是不是比原来的好看多了?
当然,如果你想要生成更好看的颜色,就要对n做一个颜色映射的算法了,这样以便得到你希望的颜色

永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
http://bbs.bccn.net/space.php?action=threads&uid=483997
2010-12-18 16:04
zzgzzg00
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:2
帖 子:388
专家分:627
注 册:2010-8-2
收藏
得分:10 
呵呵  漂亮的说

粗心是大敌
2010-12-18 17:10
黑白世界
该用户已被删除
收藏
得分:10 
提示: 作者被禁止或删除 内容自动屏蔽
2010-12-18 17:39
a343637412
Rank: 7Rank: 7Rank: 7
来 自:そ ら
等 级:黑侠
帖 子:357
专家分:620
注 册:2010-9-26
收藏
得分:10 
瓦屋.....
           顶顶.......以便学习
2010-12-18 18:45
xiaomarn
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:5
帖 子:348
专家分:2026
注 册:2009-3-18
收藏
得分:10 
哇!好炫!
分形是不是讲那种几点几维的那个学科?
收藏,好好拜读

2010-12-18 19:33
快速回复:图形学的分支:分形
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.029456 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved