前言
看分形图形时偶然看到了希尔伯特曲线,因此决定写个程序画着玩。
希尔伯特曲线
希尔伯特曲线是一种能填充满一个平面正方形的分形曲线(空间填充曲线)。
绘制希尔伯特曲线
求曲线上点的各个语言版本请参照开源的Github项目Hilbert_curve,本文主要使用GDI+进行希尔伯特曲线的绘制。
控制台版
控制台版本是上述开源项目自带的,效果图如下:
Hilbert curve, order=1
|__|
Hilbert curve, order=2
__ __
__| |__
| __ |
|__| |__|
Hilbert curve, order=3
__ __ __ __
|__| __| |__ |__|
__ |__ __| __
| |__ __| |__ __| |
|__ __ __ __ __|
__| |__ __| |__
| __ | | __ |
|__| |__| |__| |__|
Hilbert curve, order=4
__ __ __ __ __ __ __ __ __ __
__| |__ |__| __| |__ |__| __| |__
| __ | __ |__ __| __ | __ |
|__| |__| | |__ __| |__ __| | |__| |__|
__ __ | __ __ __ __ | __ __
| |__| | |__| __| |__ |__| | |__| |
|__ __| __ |__ __| __ |__ __|
__| |__ __| |__ __| |__ __| |__ __| |__
| __ __ __ __ __ __ __ __ __ |
|__| __| |__ |__| |__| __| |__ |__|
__ |__ __| __ __ |__ __| __
| |__ __| |__ __| | | |__ __| |__ __| |
|__ __ __ __ __| |__ __ __ __ __|
__| |__ __| |__ __| |__ __| |__
| __ | | __ | | __ | | __ |
|__| |__| |__| |__| |__| |__| |__| |__|
图片版
基于控制台版本的代码,我使用GDI+将其绘制到图片并保存。
画数字
即将希尔伯特曲线图中的每个方块按顺序标上数字。
主要代码:
void DrawNumber(const std::vector<Point> &points, int order, int pixel = 20)
{
int n = 1 << order;
int width = n * pixel;
int height = width;
BitmapPtr bitmap = std::make_shared<Gdiplus::Bitmap>(width, height);
std::shared_ptr<Gdiplus::Graphics> graphics = std::make_shared<Gdiplus::Graphics>(bitmap.get());
if (!bitmap) return;
int cnt = 0;
int font_size = 8;
for (auto &p : points) {
int i = cnt % n;
int j = cnt / n;
++cnt;
double r = i / double(n);
double g = j / double(n);
double b = 0.25;
int ir = static_cast<int>(255.999 * r);
int ig = static_cast<int>(255.999 * g);
int ib = static_cast<int>(255.999 * b);
int argb = 0xff000000 | (ir << 16) | (ig << 8) | (ib);
Gdiplus::Rect rect(p.x * pixel, p.y * pixel, pixel, pixel);
Gdiplus::SolidBrush brush(argb);
graphics->FillRectangle(&brush, rect);
Gdiplus::FontFamily ff(L"Microsoft YaHei");
Gdiplus::Font font(&ff, font_size, Gdiplus::FontStyleRegular, Gdiplus::Unit::UnitPixel);
Gdiplus::Color text_color(0xffffffff);
Gdiplus::SolidBrush text_brush(text_color);
std::wstring num_str = std::to_wstring(cnt);
graphics->DrawString(num_str.c_str(), num_str.length(), &font, Gdiplus::PointF(p.x*pixel, p.y*pixel), &text_brush);
}
BitmapUtil::SaveBitmapAsPng(bitmap, std::string("Hilbert_") + std::to_string(order) + ".png");
}
效果图:
画线
即绘制希尔伯特曲线。
主要代码:
void DrawLine(const std::vector<Point> &points, int order, int pixel = 20)
{
int n = 1 << order;
int width = n * pixel;
int height = width;
BitmapPtr bitmap = std::make_shared<Gdiplus::Bitmap>(width, height);
std::shared_ptr<Gdiplus::Graphics> graphics = std::make_shared<Gdiplus::Graphics>(bitmap.get());
if (!bitmap) return;
int cnt = 0;
int font_size = 6;
double t = (pixel / 2.0);
Gdiplus::PointF last_point(t, t);
for (auto &p : points) {
int i = cnt % n;
int j = cnt / n;
++cnt;
double r = i / double(n);
double g = j / double(n);
double b = 0.25;
int ir = static_cast<int>(255.999 * r);
int ig = static_cast<int>(255.999 * g);
int ib = static_cast<int>(255.999 * b);
int argb = 0xff000000 | (ir << 16) | (ig << 8) | (ib);
Gdiplus::Rect rect(p.x * pixel, p.y * pixel, pixel, pixel);
Gdiplus::SolidBrush brush(argb);
Gdiplus::SolidBrush line_brush(0xffffffff);
Gdiplus::Pen pen(&line_brush, 2);
Gdiplus::PointF ps(last_point.X, last_point.Y);
Gdiplus::PointF pe(p.x*pixel + t, p.y * pixel + t);
last_point = pe;
graphics->FillRectangle(&brush, rect);
graphics->DrawLine(&pen, ps, pe);
}
BitmapUtil::SaveBitmapAsPng(bitmap, std::string("Hilbert_curve_") + std::to_string(order) + ".png");
}
效果图: