📄 fractalview.cpp
字号:
rect.right =x0+50;
rect.top=y0-50;
OldBrush=m_pDC->SelectObject (&blkBrush);
m_pDC->Rectangle (&rect);
m_pDC->SelectObject (OldBrush);
blkBrush.DeleteObject ();
}
//生成焰火升空阶段的画面
//
if(Level<=5)
for(Num=0;Num<72;Num++)
{
xNew=1.0*Level/10*Particle[Num]*cos(5.0*Num*PI/180);
yNew=1.0*Level/10*Particle[Num]*sin(5.0*Num*PI/180);
x=x0+xNew;
y=y0-yNew;
PenSize=1+rand()%3;
purplePen.CreatePen (PS_SOLID,PenSize,RGB(255,255,0));
OldPen=m_pDC->SelectObject (&purplePen);
m_pDC->MoveTo (x0,y0);
m_pDC->LineTo (x,y);
m_pDC->SelectObject (OldPen);
purplePen.DeleteObject ();
}
//生成焰火在空中炸开阶段的画面
//
if(Level>=10&&Level<13)
for(Num=0;Num<500;Num++)
{
sx=rand()%2;
sy=rand()%2;
sd=rand()%10;
xNew=rand()%50;
yNew=rand()%50;
if(sx)
x=x0+xNew;
else
x=x0-xNew;
if(sy)
y=y0+yNew;
else
y=y0-yNew;
Dis=(x-x0)*(x-x0)+(y-y0)*(y-y0);
if(Dis>625&&Dis<2500||sd<=4)
m_pDC->SetPixel (x,y,RGB(255,255,0));
}
//生成空中焰火逐渐熄灭阶段的画面
//
if(Level>11)
for(Num=0;Num<1200;Num++)
{
sx=rand()%2;
sy=rand()%2;
xNew=rand()%50;
yNew=rand()%50;
if(sx)
x=x0+xNew;
else
x=x0-xNew;
if(sy)
y=y0+yNew;
else
y=y0-yNew;
m_pDC->SetPixel (x,y,RGB(0,0,0));
}
}
////////////////////////////////////////////////////
//焰火粒子属性指定函数:随机每个角度方向的粒子的大小
//
void CFractalView::InitSize(int size)
{
int i;
particle=0;
srand((unsigned)time(NULL));
for(i=0;i<72;i++)
{
Particle[i]=size+rand()%10;
}
}
void CFractalView::OnTimer(UINT nIDEvent)
{
//对焰火的燃放阶段进行定时与计数
DrawParticle(200,200,10,particle,TRUE);
particle++;
particle=particle>20?0:particle;
CView::OnTimer(nIDEvent);
}
///////////////////////////////////////////////////////////////////////////////////
//树叶绘制函数:根据几何解释和树叶的模型(叶轮廓多边形)数据,绘制一片树叶
//
void CFractalView::DrawLeaf(double angle, float xratio, float yratio, int x0, int y0)
{
POINT Temp[10];
int x,y;
int iIndex;
double Dis,radian;
CBrush GreenBrush,*OldBrush;
CPen GreenPen,*OldPen;
//按比例缩放叶面大小
//
for(iIndex=0;iIndex<10;iIndex++)
{
Temp[iIndex].x=xratio*leaf[iIndex].x;
Temp[iIndex].y=yratio*leaf[iIndex].y;
}
//计算旋转以后的叶面模型顶点坐标
//
for(iIndex=0;iIndex<10;iIndex++)
{
Dis=sqrt(Temp[iIndex].x*Temp[iIndex].x+Temp[iIndex].y*Temp[iIndex].y);
radian=angle*PI/180+atan2(Temp[iIndex].y,Temp[iIndex].x);
Temp[iIndex].x=x0+Dis*cos(radian);
Temp[iIndex].y=y0-Dis*sin(radian);
}
//创建画笔与画刷
//
GreenPen.CreatePen (PS_SOLID,1,RGB(25,200,25));
GreenBrush.CreateSolidBrush (RGB(0,255,0));
OldPen=m_pDC->SelectObject (&GreenPen);
OldBrush=m_pDC->SelectObject (&GreenBrush);
//按填充多边形的方式画叶面
//
m_pDC->Polygon (Temp,8);
//通过画线画叶茎
//
m_pDC->MoveTo (Temp[1]);
m_pDC->LineTo (Temp[8]);
m_pDC->LineTo (Temp[7]);
m_pDC->MoveTo (Temp[2]);
m_pDC->LineTo (Temp[9]);
m_pDC->LineTo (Temp[6]);
m_pDC->MoveTo (Temp[0]);
m_pDC->LineTo (Temp[4]);
//释放创建的画笔与画刷对象
//
m_pDC->SelectObject (OldPen);
m_pDC->SelectObject (OldBrush);
GreenPen.DeleteObject ();
GreenBrush.DeleteObject ();
}
///////////////////////////////////////////////////////////////////////////////////
//树枝绘制函数:根据几何解释和树枝的模型(枝轮廓多边形)数据,绘制一段树枝
//
void CFractalView::DrawTwig(double angle, float xratio, float yratio, int x0, int y0,POINT *InOut,bool delta)
{
POINT Temp[4];
int x,y;
int iIndex;
double Dis,radian;
CBrush GreenBrush,*OldBrush;
CPen GreenPen,*OldPen;
//按比例缩放枝干大小
//
for(iIndex=0;iIndex<4;iIndex++)
{
Temp[iIndex].x=xratio*twig[iIndex].x;
Temp[iIndex].y=yratio*twig[iIndex].y;
}
//计算旋转以后的树枝模型顶点坐标
//
for(iIndex=0;iIndex<4;iIndex++)
{
Dis=sqrt(Temp[iIndex].x*Temp[iIndex].x+Temp[iIndex].y*Temp[iIndex].y);
radian=angle*PI/180+atan2(Temp[iIndex].y,Temp[iIndex].x);
Temp[iIndex].x=x0+Dis*cos(radian);
Temp[iIndex].y=y0-Dis*sin(radian);
}
//将树枝末端直线段输出以便为后续绘制进行定位
//
if(delta)
{
Temp[1].x =InOut[0].x;
Temp[1].y =InOut[0].y;
Temp[2].x =InOut[1].x;
Temp[2].y =InOut[1].y;
}
//创建画笔与画刷
//
GreenPen.CreatePen (PS_SOLID,1,RGB(128,0,64));
GreenBrush.CreateSolidBrush (RGB(255,210,233));
OldPen=m_pDC->SelectObject (&GreenPen);
OldBrush=m_pDC->SelectObject (&GreenBrush);
//按填充多边形的方式画树枝
//
m_pDC->Polygon (Temp,4);
//释放创建的画笔与画刷对象
//
m_pDC->SelectObject (OldPen);
m_pDC->SelectObject (OldBrush);
GreenPen.DeleteObject ();
GreenBrush.DeleteObject ();
//输出树枝末端直线段
InOut[0].x=Temp[0].x;
InOut[0].y=Temp[0].y;
InOut[1].x=Temp[3].x;
InOut[1].y=Temp[3].y;
}
////////////////////////////////////////////////////////////////////
//树造型函数:按指定的细分步数(参数level指定)利用正规文法模型生成
//树或者草(参数grass决定)
//
void CFractalView::CreateTree(TREENODE **Tree, int level,bool grass)
{
int iWill;
TREENODE *pCurr,*pNext,*pNew;
TREENODE *pA;
TREENODE *pB2,*pB3,*pB4,*pB5,*pB6,*pB7,*pB8,*pB9;
//删除已有结构
//
if(Tree[0])
{
DeleteTree(Tree);
TreeLevel=0;
}
InitTree();
level=level<0?0:level;
level=level>10?10:level;
if(level>TreeLevel)
{
for(iWill=0;iWill<=level-TreeLevel;iWill++)
{
//一个细分步
//
pCurr=Tree[0];
while(pCurr)
{
//生成过程体现正规文法的产生式规则
//
pNext=pCurr->Next ;
//A->AA:对于字符A,重新生成一个A节点并插入
//前一个A节点后面,而得到AA
//
if(pCurr->Value=='A')
{
pA= new _TREENODE;
if(pA==NULL)
{
MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
exit(0);
}
pA->Value ='A';
pA->Next =pNext;
}
//对于字符B,分别按树或草结构生成A[B]AA(B)或
//A[B]BB(B)系列字符节点并取代B节点
//
if(pCurr->Value=='B')
{
pCurr->Value ='A';
pB2= new _TREENODE;
pB3= new _TREENODE;
pB4= new _TREENODE;
pB5= new _TREENODE;
pB6= new _TREENODE;
pB7= new _TREENODE;
pB8= new _TREENODE;
pB9= new _TREENODE;
if(!pB2||!pB3||!pB4||!pB5||!pB6||!pB7||!pB8||!pB9)
{
MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
exit(0);
}
pCurr->Next =pB2;
pB2->Value ='[';
pB2->Next=pB3;
pB3->Value ='B';
pB3->Next=pB4;
pB4->Value =']';
pB4->Next=pB5;
if(grass)
pB5->Value ='B'; //草
else
pB5->Value ='A'; //树
pB5->Next=pB6;
if(grass)
pB6->Value ='B'; //草
else
pB6->Value ='A'; //树
pB6->Next=pB7;
pB7->Value ='(';
pB7->Next=pB8;
pB8->Value ='B';
pB8->Next=pB9;
pB9->Value =')';
pB9->Next=pNext;
}
pCurr=pNext;
}
}
}
TreeLevel=level;
}
///////////////////////////////////////////////////////////
//树初始化函数:根据初始数据创建一个树的基本拓扑结构
//
void CFractalView::InitTree()
{
int iIndex;
TREENODE *pCurr,*pTemp;
for(iIndex=0;iIndex<5;iIndex++)
{
pCurr= new _TREENODE;
if(pCurr==NULL)
{
MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
exit(0);
}
pCurr->Value =tree[iIndex];
pCurr->Next =NULL;
if(!iIndex)
Tree[0]=pCurr;
else
pTemp->Next =pCurr;
pTemp=pCurr;
}
TreeLevel=0;
}
////////////////////////////////////////////////////////
//压栈函数:将节点存入栈顶
//
void CFractalView::Push(STACKNODE **pStack,STACKNODE sn)
{
STACKNODE *pCurr;
pCurr= new _STACKNODE;
if(pCurr==NULL)
{
MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
exit(0);
}
pCurr->angle =sn.angle ;
pCurr->p1 =sn.p1 ;
pCurr->p2 =sn.p2;
pCurr->Next =pStack[0];
pStack[0]=pCurr;
}
////////////////////////////////////////////////////////
//出栈函数:删除并栈顶节点
//
STACKNODE * CFractalView::Pop()
{
STACKNODE *pCurr;
pCurr=Stack[0];
if(pCurr)
Stack[0]=pCurr->Next ;
return pCurr;
}
/////////////////////////////////////////////////////////
//树显示函数:遍历树的拓扑结构链表,进行几何解释并显示解
//释内容
//
void CFractalView::DrawTree(TREENODE **Tree,int x0,int y0)
{
TREENODE *pCurr;
STACKNODE *pStack,*pLastA,sn,LastA;
POINT Connection[2];
bool delta;
float xratio,yratio;
float deltaAngle;
bool Kept;
int xNew0,yNew0;
int Direction;
delta=FALSE;
Kept=TRUE;
pLastA=NULL;
Direction=0;
pCurr=Tree[0];
while(pCurr)
{
switch(pCurr->Value)
{
//将A解释成树枝
//
case 'A':
//单独处理首段树枝的情况
//
if(!pLastA)
{
xratio=0.4;
yratio=0.5;
xNew0=x0;
yNew0=y0;
deltaAngle=0;
delta=FALSE;
pLastA=&LastA;
}
else
{
//计算树枝的大小和角度并将树枝接在前一段树枝上
//
xNew0=(pLastA->p1.x+pLastA->p2.x)>>1;
yNew0=(pLastA->p1.y+pLastA->p2.y)>>1;
xratio=0.5*abs(pLastA->p2.x-pLastA->p1.x)/twig[2].x;
yratio=0.5;
Connection[0].x=pLastA->p1.x;
Connection[0].y=pLastA->p1.y;
Connection[1].x=pLastA->p2.x;
Connection[1].y=pLastA->p2.y;
delta=TRUE;
switch(Direction)
{
case 0://主干
deltaAngle=0;
break;
case -1://左枝
if(!Kept)
deltaAngle=pLastA->angle +15;
else
deltaAngle=pLastA->angle;
break;
case 1://由枝
if(!Kept)
deltaAngle=pLastA->angle -15;
else
deltaAngle=pLastA->angle;
break;
}
}
DrawTwig(deltaAngle,xratio,yratio,xNew0,yNew0,Connection,delta);
//为简化后续使用保存当前信息
//
pLastA->angle=deltaAngle ;
pLastA->Direction =Direction;
pLastA->p1.x =Connection[0].x;
pLastA->p1.y =Connection[0].y;
pLastA->p2.x =Connection[1].x;
pLastA->p2.y =Connection[1].y;
pLastA->zoom =xratio;
Kept=TRUE;
break;
//将B解释成叶片
//
case 'B':
xratio=0.3;
yratio=xratio;
if(Direction==-1)//左叶片
{
xNew0=pLastA->p1.x;
yNew0=pLastA->p1 .y;
if(!Kept)
deltaAngle=pLastA->angle +15;
else
deltaAngle=pLastA->angle;
}
else //右叶片
{
xNew0=pLastA->p2.x;
yNew0=pLastA->p2 .y;
if(!Kept)
deltaAngle=pLastA->angle -15;
else
deltaAngle=pLastA->angle;
}
DrawLeaf(deltaAngle,xratio,yratio,xNew0,yNew0);
Kept=TRUE;
break;
//[解释为后续树枝或叶在当前角度上向左偏
//
case '[':
//保存当前树枝的位置与角度等信息
//
sn.angle =pLastA->angle ;
sn.p1 =pLastA->p1 ;
sn.p2=pLastA->p2 ;
sn.Direction =pLastA->Direction ;
Push(Stack,sn);
Direction=-1;
Kept=FALSE;
break;
//]解释为左偏结束要回到分叉位置
//
case ']':
//恢复到分叉位置
//
pLastA=Pop();
Direction=pLastA->Direction ;
break;
//(解释为后续树枝或叶在当前角度上向右偏
//
case '(':
sn.angle =pLastA->angle ;
sn.p1 =pLastA->p1 ;
sn.p2=pLastA->p2 ;
sn.Direction =pLastA->Direction ;
Push(Stack,sn);
Direction=1;
Kept=FALSE;
break;
//)解释为右偏结束要回到分叉位置
//
case ')':
pLastA=Pop();
Direction=pLastA->Direction ;
}
pCurr=pCurr->Next ;
}
}
/////////////////////////////////////////////
//树结构删除函数:删除树结构链表的所有节点
//
void CFractalView::DeleteTree(TREENODE **Tree)
{
TREENODE *pCurr,*pTemp;
pCurr=Tree[0];
pTemp=pCurr->Next ;
while(pCurr)
{
delete pCurr;
pCurr=pTemp;
if(pTemp)
pTemp=pTemp->Next ;
}
Tree[0]=NULL;
}
/////////////////////////////////////////
//生成草命令函数:启动生成并显示草的过程
//
void CFractalView::OnbtnGrass()
{
opStatus=4;
ClrScr();
}
////////////////////////////////////////////
//生成山峦命令函数:启动生成并显示山峦的过程
//
void CFractalView::OnbtnHill()
{
opStatus=1;
ClrScr();
}
////////////////////////////////////////////
//生成焰火命令函数:启动生成并显示焰火的过程
//
void CFractalView::OnbtnSkyrocket()
{
opStatus=2;
ClrScr();
}
/////////////////////////////////////////
//生成树命令函数:启动生成并显示树的过程
//
void CFractalView::OnbtnTree()
{
opStatus=3;
ClrScr();
}
//////////////////////////////////////////////////
//顶点删除函数:删除顶点(三角形)链表中的全部节点
//
void CFractalView::DeleteVertices(VERTEX **pLink)
{
VERTEX *pCurr,*pTemp;
pCurr=pLink[0];
pTemp=pCurr->Next;
while(pCurr)
{
delete pCurr;
pCurr=pTemp;
if(pTemp)
pTemp=pTemp->Next;
};
pLink[0]=NULL;
}
/////////////////////////////////
//清屏函数:清除显示导致重画屏幕
//
void CFractalView::ClrScr()
{
RECT rect;
int i,j;
GetClientRect(&rect);
InvalidateRect(&rect,TRUE);
}
//////////////////////////////////////////////////////////
//景物创建与显示执行函数:根据景物的类型调用相关函数创建并
//显示相应景物
//
void CFractalView::Draw()
{
switch(opStatus)
{
case 1:KillTimer(1); //山峦
CreateHill(5);
DrawHill(Hill);
break;
case 2:SetTimer(1,250,NULL); //焰火
break;
case 3: //树
KillTimer(1);
CreateTree(Tree,5,FALSE);
DrawTree(Tree,350,400);
break;
case 4: //草
KillTimer(1);
CreateTree(Tree,4,TRUE);
DrawTree(Tree,350,350);
break;
default:; //初始情况
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -