#include <QtCore/QCoreApplication>
#include <QtGui/QPainter>
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
class FractalViewer : public QWidget
{
Q_OBJECT
public:
explicit FractalViewer(QWidget *parent = nullptr)
: QWidget(parent), mCurrentFractal(0)
{
setWindowTitle("Fractal Viewer");
mFractals.append([this](QPainter &painter){ drawSierpinski(painter); });
mFractals.append([this](QPainter &painter){ drawDragon(painter); });
mFractals.append([this](QPainter &painter){ drawCantorSet(painter); });
setFixedSize(800, 800);
}
protected:
void paintEvent(QPaintEvent *) override
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
mFractals[mCurrentFractal](painter);
}
void mousePressEvent(QMouseEvent *) override
{
mCurrentFractal = (mCurrentFractal + 1) % mFractals.size();
update();
}
private:
using FractalFunc = std::function<void(QPainter &)>;
void drawSierpinski(QPainter &painter)
{
painter.setPen(QPen(Qt::black, 2));
painter.translate(400, 400);
drawSierpinskiRec(painter, 200, 0);
}
void drawSierpinskiRec(QPainter &painter, int size, int depth)
{
if (depth == 6) return;
painter.drawLine(-size, -size, size, -size);
painter.drawLine(-size, -size, -size, size);
painter.drawLine(size, -size, size, size);
drawSierpinskiRec(painter, size/2, depth+1);
painter.translate(-size/2, -size/2);
drawSierpinskiRec(painter, size/2, depth+1);
painter.rotate(90);
painter.translate(size/2, -size/2);
drawSierpinskiRec(painter, size/2, depth+1);
painter.translate(-size/2, size/2);
drawSierpinskiRec(painter, size/2, depth+1);
painter.translate(size/2, size/2);
painter.rotate(-90);
painter.translate(size/2, -size/2);
}
void drawDragon(QPainter &painter)
{
painter.setPen(QPen(Qt::black, 2));
painter.translate(400, 400);
int size = 7;
QPoint p(0, 0);
painter.drawPoint(p);
for (int i = 0; i < 100000; i++) {
QPoint q = p;
if (i % 2 == 0) {
p.setX(p.x() + size);
} else {
p.setY(p.y() + size);
}
painter.drawLine(p, q);
}
}
void drawCantorSet(QPainter &painter)
{
painter.setPen(QPen(Qt::black, 2));
painter.translate(400, 400);
drawCantorSetRec(painter, 200, 0);
}
void drawCantorSetRec(QPainter &painter, int size, int depth)
{
if (depth == 6) return;
int lineHeight = 30;
painter.drawRect(-size/2, -lineHeight/2, size, lineHeight);
painter.save();
painter.translate(-size*3/8, lineHeight);
drawCantorSetRec(painter, size/4, depth+1);
painter.restore();
painter.save();
painter.translate(size/4, lineHeight);
drawCantorSetRec(painter, size/4, depth+1);
painter.restore();
}
QVector<FractalFunc> mFractals;
int mCurrentFractal;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FractalViewer viewer;
viewer.show();
return a.exec();
}
#include "main.moc"
这是一个非常简单的 Demo,主要有以下几个功能:
在窗口上展示 Sierpinski 三角形、Dragon 曲线和 Cantor Set;
点击窗口可以切换展示的分形图;
点击窗口以外的区域可以关闭程序。
其中,Sierpinski 三角形的绘制借助了递归的方法,Dragon 曲线的绘制基于线段的拐弯,
而 Cantor Set 的绘制主要是基于矩形的绘制。这个 Demo 只是一个小小的开端,通过在
其中添加更多的功能,可以实现更加复杂和有趣的分形图的绘制。