上学期选修了一门课《现代数学方法选讲》,包含两部分内容:模糊数学和分形几何。觉得分形几何中的论点新颖有趣,其中比较基础的就是朱里叶集和曼得布罗特集了。这两种集合的图形体现了无限可分的概念,往往带给人们意想不到的震撼和不同凡响的美感。恰好那时侯正在自学MFC,感觉该做些什么练练手,所以做了这个画这两种集合的程序。使用了内存缓冲绘图法,以提高绘图效率。可任意放大缩小,能够观察到分形图形无限可分的特性。
奇妙的分形几何图形
主要代码如下:
朱里叶集的绘制:
void CJuliaView::OnDraw(CDC* pDC/*pDC*/)
{
CJuliaDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: 在此处为本机数据添加绘制代码
int i,j,k;
CDC dcMem;
CBitmap* pOldBitmap = NULL;
if(b_Change==TRUE)
{
double lx,ly,x,y,m,n,r,a,b;
const int kmax=256,M=4,iColor[19]={0x800000,0x8000,0x808000,0x80,0x800080,0x8080,0xc0c0c0,0xc0dcc0,0xa6caf0,0xfffbf0,0xa0a0a4,0x808080,0xff0000,0xff00,0xffff00,0xff,0xff00ff,0xffff,0xffffff};
CRect rect;
GetClientRect(rect);
cxClient=rect.right-rect.left;
cyClient=rect.bottom-rect.top;
lx=(m_Xmax-m_Xmin)/cxClient;
ly=(m_Ymax-m_Ymin)/cyClient;
a=pDoc->m_ParamA;
b=pDoc->m_ParamB;
dcMem.CreateCompatibleDC(pDC);
pDoc->m_bmpBuffer.DeleteObject();
pDoc->m_bmpBuffer.CreateCompatibleBitmap(pDC,cxClient,cyClient);
pOldBitmap = dcMem.SelectObject(&pDoc->m_bmpBuffer);
::SetCursor(::LoadCursor(NULL,IDC_WAIT));
for(i=0;i<cxClient;i++)
{
for(j=0;j<cyClient;j++)
{
x=m_Xmin+i*lx;
y=m_Ymax-j*ly;
k=0;
while(TRUE)
{
m=x*x-y*y+a;
n=2*x*y+b;
k++;
r=m*m+n*n;
if(r>M)
{
dcMem.SetPixel(i,j,iColor[(k-1)%19]);
break;
}
if(k==kmax)
{
dcMem.SetPixel(i,j,0);
break;
}
x=m;
y=n;
}
}
}
b_Change=FALSE;
pDC->BitBlt(0,0,cxClient,cyClient,&dcMem,0,0,SRCCOPY);
}
else
{
dcMem.CreateCompatibleDC(NULL);//这里我们就在内存中虚拟建造了DC
pOldBitmap = dcMem.SelectObject(&pDoc->m_bmpBuffer);//我们调入了我们bitmap目标
pDC->BitBlt(0,0,cxClient,cyClient,&dcMem,0,0,SRCCOPY);
}
dcMem.SelectObject(pOldBitmap);
dcMem.DeleteDC();
}
曼得布罗特集的绘制:
void CMandelbrotView::OnDraw(CDC* pDC/*pDC*/)
{
CMandelbrotDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: 在此处为本机数据添加绘制代码
int i,j,k;
CDC dcMem;
CBitmap* pOldBitmap = NULL;
if(b_Change==TRUE)
{
double lx,ly,x,y,m,n,r,a,b;
const int kmax=256,M=4,iColor[19]={0x800000,0x8000,0x808000,0x80,0x800080,0x8080,0xc0c0c0,0xc0dcc0,0xa6caf0,0xfffbf0,0xa0a0a4,0x808080,0xff0000,0xff00,0xffff00,0xff,0xff00ff,0xffff,0xffffff};
CRect rect;
GetClientRect(rect);
cxClient=rect.right-rect.left;
cyClient=rect.bottom-rect.top;
lx=(m_Xmax-m_Xmin)/cxClient;
ly=(m_Ymax-m_Ymin)/cyClient;
dcMem.CreateCompatibleDC(pDC);
pDoc->m_bmpBuffer.DeleteObject();
pDoc->m_bmpBuffer.CreateCompatibleBitmap(pDC,cxClient,cyClient);
pOldBitmap = dcMem.SelectObject(&pDoc->m_bmpBuffer);
::SetCursor(::LoadCursor(NULL,IDC_WAIT));
for(i=0;i<cxClient;i++)
{
for(j=0;j<cyClient;j++)
{
a=m_Xmin+i*lx;
b=m_Ymax-j*ly;
k=0;
x=0;
y=0;
while(TRUE)
{
m=x*x-y*y+a;
n=2*x*y+b;
k++;
r=m*m+n*n;
if(r>M)
{
dcMem.SetPixel(i,j,iColor[(k-1)%19]);
break;
}
if(k==kmax)
{
dcMem.SetPixel(i,j,0);
break;
}
x=m;
y=n;
}
}
}
b_Change=FALSE;
pDC->BitBlt(0,0,cxClient,cyClient,&dcMem,0,0,SRCCOPY);
}
else
{
dcMem.CreateCompatibleDC(NULL);//这里我们就在内存中虚拟建造了DC
pOldBitmap = dcMem.SelectObject(&pDoc->m_bmpBuffer);//我们调入了我们bitmap目标
pDC->BitBlt(0,0,cxClient,cyClient,&dcMem,0,0,SRCCOPY);
}
dcMem.SelectObject(pOldBitmap);
dcMem.DeleteDC();
}
两者大同小异,仅在算法部分略有不同。