科赫雪花是一种分形图案,它的绘制规则是:从一个等边三角形开始,将每个边中间三分之一段去掉,然后在此部分向外绘制一个小等边三角形,以此类推。
下面的代码是在 Win32 API 中绘制科赫雪花的方法
// 返回 p1 p2 两点之间的点 p , pp1 : pp2 = r
POINT ratio(double r, POINT p1, POINT p2)
{
POINT p;
p.x = p1.x + (p2.x - p1.x) * r;
p.y = p1.y + (p2.y - p1.y) * r;
return p;
}
// 递归绘制线段
void drawLine(HDC hdc, POINT p1, POINT p2, int count)
{
// 当为 0 ,就直接连接
if (count == 0)
{
POINT p[2] = {p1, p2};
Polyline(hdc, p, 2);
return;
}
// 如果不是最后一次迭代,就空出中间 1/3 段
POINT interp[2] = {ratio(1.0 / 3, p1, p2), ratio(2.0 / 3, p1, p2)};
// 绘制这两段
drawLine(hdc, p1, interp[0], count - 1);
drawLine(hdc, interp[1], p2, count - 1);
// 计算中点
POINT c = {(p1.x + p2.x) / 2, (p1.y + p2.y) / 2};
// 计算斜率,注意由于纵坐标向下,斜率与标准坐标下相反
double k = 1.0 * (p2.y - p1.y) / (p1.x - p2.x);
double d = sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
double distance = sqrt(3) * d / 6;
double dx = distance * k / sqrt(1 + k * k);
double dy = distance / sqrt(1 + k * k);
// 计算新增点的位置
int sign = (p1.x > c.x ? -1 : 1);
c.x += sign * dx;
c.y += sign * dy;
// 绘制凸出部分
drawLine(hdc, interp[0], c, count - 1);
drawLine(hdc, c, interp[1], count - 1);
}
// 绘制三个边
void drawTriangle(HDC hdc, POINT points[], int count)
{
drawLine(hdc, points[0], points[1], count);
drawLine(hdc, points[1], points[2], count);
drawLine(hdc, points[2], points[0], count);
}
// 绘图函数
void draw(HDC hdc, POINT c, int d, int count)
{
POINT points[3] = {{c.x, c.y - d}, {c.x - d / 2 * sqrt(3), c.y + d / 2}, {c.x + d / 2 * sqrt(3), c.y + d / 2}};
drawTriangle(hdc, points, count);
}
接着在 WM_PAINT
中添加如下代码:
// 绘制图形
int d = 100;
POINT c = {150, 150};
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
draw(hdc, c, d, i * 2 + j);
c.x += 250;
}
c.x = 150;
c.y += 250;
}
此段代码绘制前 4 个科赫雪花。
最终的绘制结果: