📄 fractalview.cpp
字号:
// FractalView.cpp : implementation of the CFractalView class
//
#include "stdafx.h"
#include "Fractal.h"
#include "FractalDoc.h"
#include "FractalView.h"
#include "Math.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//山峦初始三角形
static POINT Triangle[3]={{500,300},{350,150},{50,200}};
//焰火粒子属性
static int Particle[72];
//树叶图形初始数据
static POINT leaf[10]={{-4,54},{-16,46},{-21,33},{-10,7},{0,0},{9,-7},{17,33},{4,49},{-2,32},{1,14}};
//树枝图形初始数据
static POINT twig[4]={{-12,42},{-17,0},{17,0},{12,42}};
//树拓扑结构初始字符串
static char tree[5]={'A','B','(','B',')'};
/////////////////////////////////////////////////////////////////////////////
// CFractalView
IMPLEMENT_DYNCREATE(CFractalView, CView)
BEGIN_MESSAGE_MAP(CFractalView, CView)
//{{AFX_MSG_MAP(CFractalView)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_TIMER()
ON_COMMAND(ID_btnGrass, OnbtnGrass)
ON_COMMAND(ID_btnHill, OnbtnHill)
ON_COMMAND(ID_btnSkyrocket, OnbtnSkyrocket)
ON_COMMAND(ID_btnTree, OnbtnTree)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFractalView construction/destruction
CFractalView::CFractalView()
{
m_pDC=NULL;
Hill[0]=NULL;
Vertices[0]=NULL;
Tree[0]=NULL;
Stack[0]=NULL;
opStatus=0;
}
CFractalView::~CFractalView()
{
}
BOOL CFractalView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CFractalView drawing
void CFractalView::OnDraw(CDC* pDC)
{
CFractalDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
Draw();
}
/////////////////////////////////////////////////////////////////////////////
// CFractalView diagnostics
#ifdef _DEBUG
void CFractalView::AssertValid() const
{
CView::AssertValid();
}
void CFractalView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CFractalDoc* CFractalView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFractalDoc)));
return (CFractalDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CFractalView message handlers
////////////////////////////////////////////////////////////
//初始化函数:将生成山峦的初始三角形的顶点保存到顶点链表,创
//建山峦树型结构的根节点,初始化焰火粒子属性,初始化树与草的
//拓扑结构链表。
//
void CFractalView::Init()
{
VERTEX v;
TRINODE *pCurr;
m_pDC=new CClientDC(this);
level=5;
//创建山峦树型结构的根节点
//
pCurr= new _TRINODE;
if(pCurr==NULL)
{
MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
exit(0);
}
pCurr->Fractal =NULL;
pCurr->tr0.v0=0;
pCurr->tr0.v1=1;
pCurr->tr0.v2=2;
Hill[0]=pCurr;
//将生成山峦的初始三角形的顶点进行编号并保存到顶点链表
//
v.pt.x=Triangle[0].x;
v.pt.y=Triangle[0].y;
v.Num =0;
v.Next =NULL;
InsertVertex(v,Vertices);
v.pt.x=Triangle[1].x;
v.pt.y=Triangle[1].y;
v.Num =1;
v.Next =NULL;
InsertVertex(v,Vertices);
v.pt.x=Triangle[2].x;
v.pt.y=Triangle[2].y;
v.Num =2;
v.Next =NULL;
InsertVertex(v,Vertices);
//初始化焰火粒子属性
//
InitSize(50);
//初始化树与草的拓扑结构链表
//
InitTree();
}
/////////////////////////////////////////////////////////////////
//插值点生成函数:根据给定两点按随机插值模型算法生成一个扰动点。
//
void CFractalView::CreateVertex(int v1, int v2,POINT *Out)
{
int rY;
int p;
VERTEX *pV1,*pV2,*pCurr;
//根据给定两点的逻辑编号从顶点链标中找出这两点所在的节点
//
pV1=NULL;
pV2=NULL;
pCurr=Vertices[0];
while(pCurr)
{
if(pCurr->Num ==v1)
{
pV1=pCurr;
}
if(pCurr->Num ==v2)
{
pV2=pCurr;
}
if(pV1&&pV2)
break;
pCurr=pCurr->Next ;
};
if(!pV1|!pV2)
exit(0);
//在Y方向进行随机扰动并插值,然后输出
//
srand((unsigned)time(NULL));
rY=rand();
p=(rY%50)+abs(pV2->pt.x-pV1->pt.x)%10;
Out->x=(pV1->pt.x+pV2->pt.x)>>1;
Out->y=((pV1->pt.y+pV2->pt.y)>>1)-p;
Out->y=Out->y<0?1:Out->y;
}
/////////////////////////////////////////////////////////
//顶点插入函数:将插值生成的顶点插入顶点链表的末尾
//
void CFractalView::InsertVertex(VERTEX v, VERTEX **pLink)
{
VERTEX *pCurr,*pLast;
//得到指向尾部节点的指针变量
//
pCurr=pLink[0];
pLast=pCurr;
while(pCurr)
{
pLast=pCurr;
pCurr=pCurr->Next ;
};
//链入节点
//
pCurr= new _VERTEX;
if(pCurr==NULL)
{
MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
exit(0);
}
pCurr->pt.x=v.pt.x;
pCurr->pt.y=v.pt.y;
pCurr->Num =v.Num ;
pCurr->Next =NULL;
//边界效应处理
//
if(pLast)
{
pLast->Next =pCurr;
}
else
{
pLink[0]=pCurr;
}
}
///////////////////////////////////////////////////////
//山峦删除函数:从山峦树型结构的叶子向根部方向删除由参
//数top指定的层数数据,top的取值限制在0-9范围内
void CFractalView::DeleteTip(int top)
{
int High,index,iDelete;
FRACTAL *Ten[10];
FRACTAL *pCurr,*pTemp;
High=top>9?9:top;
High=top<0?0:top;
//从根部顺次得到指向每层第一个节点的指针
//
pCurr=Hill[0]->Fractal;
index=0;
while(pCurr)
{
Ten[index++]=pCurr;
pCurr=pCurr->Child_A1B ;
};
//根据得到的指针从叶子向根部逐层删除
//
index--;
for(iDelete=index;iDelete>=High;iDelete--)
{
pCurr=Ten[iDelete];
do
{
pTemp=pCurr->Sibling ;
delete pCurr;
pCurr=pTemp;
}while(pCurr!=Ten[iDelete]);
}
}
//////////////////////////////////////////////////////////
//山峦生成函数:按随机插值模型算法回归生成并保存Level个细分
//步的山峦
//
void CFractalView::CreateHill(int Level)
{
int iWill,iLayer,iCreated,iLittle;
FRACTAL *Ten[10];
FRACTAL *pCurr,*pTemp;
FRACTAL *pNew,*pNewA1B,*pNewABC,*pNewCB2,*pNew0AC;
FRACTAL *pFirst,*pLast;
int ExistedNum;
int vs[3];
iWill=Level>9?9:Level;
iWill=Level<0?0:Level;
ExistedNum=2;
iLayer=0;
pCurr=Hill[0]->Fractal;
//检查树结构已有的层数
//
while(pCurr)
{
Ten[iLayer]=pCurr;
pCurr=pCurr->Child_A1B ;
ExistedNum=ExistedNum+Pow(4,iLayer-1)*3;
iLayer++;
};
//如果已有的层数比指定的层数少,则生成剩下的层数
//
if(iLayer<iWill)
{
for(iCreated=iLayer;iCreated<iWill;iCreated++)
{
//开始时,要单独创建树的根节点
//
if(iCreated<1)
{
pNew=new _FRACTAL;
if(pNew==NULL)
{
MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
exit(0);
}
for(iLittle=0;iLittle<3;iLittle++)
{
vs[iLittle]=iLittle;
}
ConstructNode(pNew,&ExistedNum,vs);
Hill[0]->Fractal =pNew;
Ten[iCreated]=pNew;
}
else
{
//循环生成某层的所有细分节点并进行链接
//
pCurr=Ten[iCreated-1];
pTemp=pCurr;
pFirst=NULL;
pLast=NULL;
do
{
//一个细分步的生成逻辑
//
pNewA1B=new _FRACTAL;
pNewABC=new _FRACTAL;
pNewCB2=new _FRACTAL;
pNew0AC=new _FRACTAL;
if(!pNewA1B||!pNewABC||!pNewCB2||!pNew0AC)
{
MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
exit(0);
}
vs[0]=pCurr->tr_A1B.v0 ;
vs[1]=pCurr->tr_A1B.v1 ;
vs[2]=pCurr->tr_A1B.v2 ;
ConstructNode(pNewA1B,&ExistedNum,vs);
vs[0]=pCurr->tr_ABC.v0 ;
vs[1]=pCurr->tr_ABC.v1 ;
vs[2]=pCurr->tr_ABC.v2 ;
ConstructNode(pNewABC,&ExistedNum,vs);
vs[0]=pCurr->tr_CB2.v0 ;
vs[1]=pCurr->tr_CB2.v1 ;
vs[2]=pCurr->tr_CB2.v2 ;
ConstructNode(pNewCB2,&ExistedNum,vs);
vs[0]=pCurr->tr_0AC.v0 ;
vs[1]=pCurr->tr_0AC.v1 ;
vs[2]=pCurr->tr_0AC.v2 ;
ConstructNode(pNew0AC,&ExistedNum,vs);
pNewA1B->Sibling =pNewABC;
pNewABC->Sibling =pNewCB2;
pNewCB2->Sibling =pNew0AC;
pCurr->Child_A1B =pNewA1B;
pCurr->Child_ABC =pNewABC;
pCurr->Child_CB2 =pNewCB2;
pCurr->Child_0AC =pNew0AC;
if(!pFirst)
pFirst=pNewA1B;
if(pLast)
pLast->Sibling =pNewA1B;
pLast=pNew0AC;
pCurr=pCurr->Sibling ;
}while(pCurr!=pTemp);
pLast->Sibling =pFirst;
Ten[iCreated]=pFirst;
}
}
}
}
/////////////////////////////////////////////
//幂函数:求a的n次幂
//
int CFractalView::Pow(int a, int n)
{
int i;
int pow;
for(pow=1,i=0;i<n;i++)
pow=pow*a;
return pow;
}
/////////////////////////////////////////////////////////////////////////
//细分节点构造函数:根据当前最大顶点编号,对细分节点中各个三角形的顶点进行
//逻辑编号(编号规则参见原理说明),并将顶点插入到顶点链表
//
void CFractalView::ConstructNode(FRACTAL *p, int *ExistedNo,int *vs)
{
VERTEX v0,v1,v2;
POINT pt;
CreateVertex(vs[0],vs[1],&pt);
v0.pt.x=pt.x;
v0.pt.y=pt.y;
v0.Num=++(*ExistedNo);
InsertVertex(v0,Vertices);
CreateVertex(vs[1],vs[2],&pt);
v1.pt.x=pt.x;
v1.pt.y=pt.y;
v1.Num=++(*ExistedNo);
InsertVertex(v1,Vertices);
CreateVertex(vs[2],vs[0],&pt);
v2.pt.x=pt.x;
v2.pt.y=pt.y;
v2.Num=++(*ExistedNo);
InsertVertex(v2,Vertices);
p->Sibling =p;
p->tr_01A .v0=vs[0];
p->tr_01A .v1=vs[1];
p->tr_01A .v2=*ExistedNo-2;
p->tr_12B .v0=vs[1];
p->tr_12B .v1=vs[2];
p->tr_12B .v2=*ExistedNo-1;
p->tr_20C .v0=vs[2];
p->tr_20C .v1=vs[0];
p->tr_20C .v2=*ExistedNo;
p->tr_0AC.v0 =vs[0];
p->tr_0AC.v1 =*ExistedNo-2;
p->tr_0AC.v2 =*ExistedNo;
p->tr_A1B .v0=*ExistedNo-2;
p->tr_A1B .v1=vs[1];
p->tr_A1B .v2=*ExistedNo-1;
p->tr_ABC .v0=*ExistedNo-2;
p->tr_ABC .v1=*ExistedNo-1;
p->tr_ABC .v2=*ExistedNo;
p->tr_CB2 .v0=*ExistedNo;
p->tr_CB2 .v1=*ExistedNo-1;
p->tr_CB2 .v2=vs[2];
p->Child_0AC =NULL;
p->Child_A1B =NULL;
p->Child_ABC =NULL;
p->Child_CB2 =NULL;
}
////////////////////////////////////////////////////////////////
//山峦绘制函数:从树型结构根部顺次遍历各细分顶点,并逐个绘制三角
//形
//
void CFractalView::DrawHill(TRINODE **root)
{
FRACTAL *pCurr,*pTemp;
FRACTAL *Ten[10];
int iLayer,iDraw;
int v0,v1,v2;
CBrush hBrush,*OldBrush;
POINT TriTemp[3];
//检查绘制层数
//
iLayer=0;
pCurr=root[0]->Fractal ;
while(pCurr)
{
Ten[iLayer]=pCurr;
pCurr=pCurr->Child_A1B;
iLayer++;
};
//创建绘制三角形的画笔和填充画刷
//
hBrush.CreateSolidBrush (RGB(128,128,128));
OldBrush=m_pDC->SelectObject (&hBrush);
//绘制根部三角形
//
v0=root[0]->tr0.v0 ;
v1=root[0]->tr0.v1 ;
v2=root[0]->tr0.v2 ;
VertexFromNum(TriTemp,v0 ,v1,v2);
m_pDC->Polygon (TriTemp,3);
//绘制根部以外的各层的三角形
if(iLayer>0)
{
for(iDraw=0;iDraw<iLayer;iDraw++)
{
pCurr=Ten[iDraw];
pTemp=pCurr;
do
{
//绘制一个细分节点的全部三角形
//
v0=pCurr->tr_01A.v0 ;
v1=pCurr->tr_01A.v1 ;
v2=pCurr->tr_01A.v2 ;
VertexFromNum(TriTemp,v0 ,v1,v2);
m_pDC->Polygon (TriTemp,3);
v0=pCurr->tr_12B.v0 ;
v1=pCurr->tr_12B.v1 ;
v2=pCurr->tr_12B.v2 ;
VertexFromNum(TriTemp,v0 ,v1,v2);
m_pDC->Polygon (TriTemp,3);
v0=pCurr->tr_20C.v0 ;
v1=pCurr->tr_20C.v1 ;
v2=pCurr->tr_20C.v2 ;
VertexFromNum(TriTemp,v0 ,v1,v2);
m_pDC->Polygon (TriTemp,3);
v0=pCurr->tr_A1B.v0 ;
v1=pCurr->tr_A1B.v1 ;
v2=pCurr->tr_A1B.v2 ;
VertexFromNum(TriTemp,v0 ,v1,v2);
m_pDC->Polygon (TriTemp,3);
v0=pCurr->tr_ABC.v0 ;
v1=pCurr->tr_ABC.v1 ;
v2=pCurr->tr_ABC.v2 ;
VertexFromNum(TriTemp,v0 ,v1,v2);
m_pDC->Polygon (TriTemp,3);
v0=pCurr->tr_CB2.v0 ;
v1=pCurr->tr_CB2.v1 ;
v2=pCurr->tr_CB2.v2 ;
VertexFromNum(TriTemp,v0 ,v1,v2);
m_pDC->Polygon (TriTemp,3);
v0=pCurr->tr_0AC.v0 ;
v1=pCurr->tr_0AC.v1 ;
v2=pCurr->tr_0AC.v2 ;
VertexFromNum(TriTemp,v0 ,v1,v2);
m_pDC->Polygon (TriTemp,3);
pCurr=pCurr->Sibling ;
}while(pCurr!=pTemp);
}
}
m_pDC->SelectObject (OldBrush);
hBrush.DeleteObject ();
}
/////////////////////////////////////////////////////////////////////////
//求取三角形顶点坐标的函数:根据给定的三个顶点的编号从顶点链表中查出顶点
//的坐标值
//
void CFractalView::VertexFromNum(POINT *triangle, int v0, int v1, int v2)
{
VERTEX *pV0,*pV1,*pV2,*pCurr;
pV0=NULL;
pV1=NULL;
pV2=NULL;
pCurr=Vertices[0];
while(pCurr)
{
if(pCurr->Num ==v0)
{
pV0=pCurr;
}
if(pCurr->Num ==v1)
{
pV1=pCurr;
}
if(pCurr->Num ==v2)
{
pV2=pCurr;
}
if(pV0&&pV1&&pV2)
break;
pCurr=pCurr->Next ;
};
triangle[0].x=pV0->pt.x;
triangle[0].y=pV0->pt.y;
triangle[1].x=pV1->pt.x;
triangle[1].y=pV1->pt.y;
triangle[2].x=pV2->pt.x;
triangle[2].y=pV2->pt.y;
}
int CFractalView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
//初试化
//
Init();
return 0;
}
//////////////////////////////////////////////////////////
//删除函数:在程序退出时释放资源
//
void CFractalView::OnDestroy()
{
CView::OnDestroy();
//删除山峦树型结构及全部三角形顶点
//
DeleteTip(0);
if(Hill[0])
delete Hill[0];
DeleteVertices(Vertices);
//删除树或者草的拓扑结构
//
while(Pop());
DeleteTree(Tree);
//取消焰火动画定时
//
KillTimer(1);
if(m_pDC)
delete m_pDC;
}
////////////////////////////////////////////////////////////////////////////
//焰火生成函数:按照粒子系统模型根据定时与计数的情况,生成不同阶
//段焰火画面
//
void CFractalView::DrawParticle(int x0,int y0,int Size,int Level,bool Erase)
{
int Num;
CPen purplePen,whitePen,*OldPen;
CBrush blkBrush,*OldBrush;
int PenSize,Dis;
int x,y,xNew,yNew;
RECT rect;
int sx,sy,sd;
//生成焰火燃放间隔的漆黑夜空的画面
//
srand((unsigned)time(NULL));
if(Level==0||Level==6)
{
blkBrush.CreateSolidBrush (RGB(0,0,0));
rect.left =x0-50;
rect.bottom =y0+50;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -