标题分形图制作两例
栏目软件世界
作者周鸣扬
发布2001年43期
在B1版中我们谈到了分形在计算机图形中的重要地位,现在就以制作B1版所提到的那两个简单的分形图为例,着手于具体编程应用。在VC中新建一个单文档项目Fractal,在FractalView.cpp中加入下面的代码:
#include “math.h”
//将树枝的切分点定义为黄金分割点
#define CUT_RATE 0.618
//左侧树枝相对于主枝的张开度
#define LEFT_BRANCH_ANGLE 80
//右侧树枝相对于主枝的张开度
#define RIGHT_BRANCH_ANGLE 20
//树的主枝长度
#define BRANCH_LENGTH 300
//最小分支的长度,改变这个值可以控制树叶的浓度
#define LAST_BRANCH_LENGTH 0.1
//树枝上的节点数,改变这个值可以控制树枝的浓度
#define BRANCH_NUM 40
/*DrawBranch函数的功能:从点(x,y)到点(Lengh*cos(StartAngle*3.14/180),y-Lengh*sin(StartAngle*3.14/180))之间画一条直线
Lengh:直线的长度
StartAngle:直线的倾斜度
pDC:绘直线时使用的设备环境句柄
*/
void DrawBranch(int x,int y,float Lengh,int StartAngle,CD C*pDC)
{
float x1,y1,nx,ny,count;
float nLengh;
//从树枝的起点计算树枝的终点
x1=x+Lengh*cos(StartAngle*3.14/180);
y1=y-Lengh*sin(StartAngle*3.14/180);
//绘制树枝,实际就是画一条线
pDC->MoveTo(x,y);
pDC->LineTo(x1,y1);
//pDC->SetPixel(x1,y1,RGB(255,0,0));
//如果树枝的长度小于预定的树枝长度最小值,则返回
//这一步很重要,否则递归就会陷入死循环
if(Lengh<LAST_BRANCH_LENGTH)
return;
nLengh=Lengh;
nx=x;
ny=y;
for(count=0;count<BRANCH_NUM;count++)
{
//改变树枝的起点
nx+=nLengh*(1-CUT_RATE)*cos(StartAngle*3.14/180);
ny-=nLengh*(1-CUT_RATE)*sin(StartAngle*3.14/180);
//递归调用DrawBranch,画树枝的左边部份
DrawBranch(nx,ny,nLengh*1-CUT_RATE),StartAngle+LEFT_BRANCH_ANGLE,pDC);
//画树枝的右边部份
DrawBranch(nx,ny,nLengh*1-CUT_RATE),StartAngle-RIGHT_BRANCH_ANGLE,pDC);
nLengh*=CUT_RATE;
}
}
void CFractalView::OnDraw(CDC*pDC)
{
CRect rect;
this->GetClientRect(&rect);
BeginWaitCursor();
DrawBranch(rect.left+rect.Width()/2,rect.bottom,BRANCH_LENGTH,90,this->GetDC());
EndWaitCursor();
CFractalDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
}
好了,编译上面的程序,在运行时,你会发现一棵树从小到大的生长过程,很有趣。由于程序采用的是递归调用的方式,程序运行的速度有些慢。如果想绘制鸡冠花图片,只需要将预定义部分的代码替换成下面所示的代码。
#include “math.h”
#define CUT_RATE 0.3
#define LEFT_BRANCH_ANGLE 9
#define RIGHT_BRANCH_ANGLE 9
#define BRANCH_LENGTH 100
#define LAST_BRANCH_LENGTH 0.8
#define BRANCH_NUM 3
同时将上面代码中的“pDC->LineTo(x1,y1);”换成“pDC->SetPixel(x1,y1,RGB(255,0,0));”即可。如果你还想得到更丰富的分形图片,你只须不断地更改上面的预定义部分代码。会得到什么样的精彩结果?我不知道,因为:没有两幅分形图片是一样的!
相信大家现在对分形图有了更深刻的认识了吧?还不快快动手制作出自己认为最美丽的图案!