⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fractalview.cpp

📁 可以生成山、火焰、树与草等自然景物的实例
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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 + -