l Snowflake
分形简介
分形理论建立于20世纪70年代末,30年来震惊了世界科学界,被科学界列入20世纪的20项重大科学发现之一。
众所周知,基于传统欧几里得几何学的各门自然科学总是把研究对象想象成一个个规则的形体,而人类"熟悉"却无法描述的自然界许许多多真实的图形竟如此不规则和支离破碎,与欧几里得几何图形相比,拥有完全不同层次的复杂性。现代科学研究面对起伏蜿蜒的山脉、坑坑洼洼的地面、曲曲折折的海岸线、层层分叉的树枝、支流纵横的水系、翻腾变幻的浮云、地壳上的褶皱、密布人体周身的血管、满天闪烁的繁星、撕裂夜空的闪电、魔鬼般跳跃的火焰、船尾湍急的涡流、拍岸的惊涛与浪花、金属和非金属材料的断面、生物的大分子结构、分子光谱分布以及电磁波噪声分布等等,急切要求等到精确和深入的解。在这个传统欧几里得几何学无能为力的领域,分形理论脱颖而出,它的研究和应用成果大放异彩。
目前,分形理论是非线性科学研究中十分活跃的一枝,它的研究对象是自然界和非线性系统中出现的不光滑和不规则的几何形体,分形理论的数学基础是分形几何。什么是分形?分形是对没有特征长度(特征长度是指所考虑的集合对象所含有的各种长度的代表者,例如一个球,可用它的半径作为它的特征长度。)但具有一定意义下的自相似图形和结构的总称。“分形”一词译于英文Fractal,系分形理论的创始人曼德尔布罗特(B.B.Mandelbrot)于 1975年由拉丁语Frangere,一词创造而成,词本身具有“破碎”和“不规则”两个含义。
Kotch curve分形
本文采用Kotch curve分形技术生成类似雪花的形状. 程序运行时, 屏幕上会出现一些颜色,位置,大小随机的雪花形状. 其算法非常简单:
1. 首先画一条直线
2. 三等分
3. 升起中间线段形成一个等边三角形
4. 对3中每条线段重复1-3的过程…..
如果开始用三角形代替上面的直线, 就会得到类似下面的图形:
代码
Segment类代表一条线段.
//
// Construction/Destruction
//
Segment::Segment()
{}
Segment::~Segment()
{}
Segment::Segment( POINT p1, POINT p2 )
{
m_p1 = p1;
m_p2 = p2;
}
Segment::Segment( int x1, int y1, int x2, int y2 )
{
m_p1.x = x1;
m_p1.y = y1;
m_p2.x = x2;
m_p2.y = y2;
}
POINT Segment::GetP1()
{
return m_p1;
}
POINT Segment::GetP2()
{
return m_p2;
}
void Segment::SetP1( POINT p )
{
m_p1 = p;
}
void Segment::SetP2( POINT p )
{
m_p2 = p;
}
long Segment::Height()
{
return m_p2.y - m_p1.y;
}
long Segment::Width()
{
return m_p2.x - m_p1.x;
}
double Segment::Length()
{
return sqrt( Height() * Height() + Width() * Width() );
}
double Segment::Angle()
{
return atan2( Height(), Width() );
}
void Segment::Draw( CDC* pDC )
{
pDC->MoveTo( m_p1 );
pDC->LineTo( m_p2 );
}
Snow类是Segment类的集合.
Snow::Snow()
{
}
Snow::Snow()
{
}
Snow::~Snow()
{
m_Segments.RemoveAll();
}
/*
Snow::Snow( CArray< Segment, Segment > segments )
{
}
*/
void Snow::Draw( CDC* pDC )
{
// draw each of the segment
for( int i = 0; i < this->m_Segments.GetSize(); i++ )
{
Segment seg = this->m_Segments.GetAt( i );
pDC->MoveTo( seg.GetP1() );
pDC->LineTo( seg.GetP2() );
}
}
生成分形
CArray< Segment, Segment > newSegments;
for( int i = 0; i < m_Segments.GetSize(); i++ )
{
Segment seg = m_Segments.GetAt( i );
double length = seg.Length() / 3;
double angle = seg.Angle();
angle += RANGLE;
POINT p31, p32, pmid;
p31.x = seg.GetP1().x + seg.Width() / 3;
p31.y = seg.GetP1().y + seg.Height() / 3;
p32.x = seg.GetP1().x + seg.Width() * 2 / 3;
p32.y = seg.GetP1().y + seg.Height() * 2 / 3;
pmid.x = p31.x + length * cos( angle );
pmid.y = p31.y + length * sin( angle );
// Add to new segments list
newSegments.Add( Segment( seg.GetP1(), p31 ) );
newSegments.Add( Segment( p31, pmid ) );
newSegments.Add( Segment( pmid, p32 ) );
newSegments.Add( Segment( p32, seg.GetP2() ) );
}
// 线段长度小于1, 将此保存至Snow
if( m_Segments.GetSize() > 0 && m_Segments.GetAt( 0 ).Length() <= 1 )
{
delete m_pSnow;
m_pSnow = NULL;
m_pSnow = new Snow();
m_pen.DeleteObject();
m_pen2.DeleteObject();
// 创建不同颜色的画笔
m_pen.CreatePen( PS_SOLID, 2, MakeRandColor() );
m_pen2.CreatePen( PS_SOLID, 2, MakeRandColor() );
m_pSnow->m_Segments.Copy( m_Segments );
m_Segments.RemoveAll();
// create new random temp segments
//srand( (unsigned)time(NULL) );
int nWidth = rand()%400;
int nPosX = rand()%(m_nPixelsX/2) + 120;
int nPosY = rand()%(m_nPixelsY/2) + 80;
m_Segments.Add( Segment( nPosX + 0 , nPosY + nWidth, nPosX + nWidth/2, nPosY + 0 ) );
m_Segments.Add( Segment( nPosX + nWidth/2, nPosY + 0 , nPosX + nWidth , nPosY + nWidth ) );
m_Segments.Add( Segment( nPosX + nWidth , nPosY + nWidth, nPosX + 0 , nPosY + nWidth ) );
}
else
m_Segments.Copy( newSegments );
// cleanup
newSegments.RemoveAll();
绘制图形, 响应ON_PAINT消息:
void CSnowflakeDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
CPen* pOldPen = dc.SelectObject( &m_pen2 );
// draw
for( int i = 0; i < m_Segments.GetSize(); i++ )
{
Segment seg = m_Segments.GetAt( i );
seg.Draw( &dc );
}
dc.SelectObject( pOldPen );
// draw the saved snow
if( m_pSnow != NULL )
{
pOldPen = dc.SelectObject( &m_pen );
m_pSnow->Draw( &dc );
dc.SelectObject( pOldPen );
}
CDialog::OnPaint();
}
总结
Kotch curve非常的实用. 使用它能创造出许多有趣的图形, 如具有真实感的地形, 海岸线.
下面的链接是一些非常漂亮的分形作品