Skip to main content
标签ad报错:该广告ID(9)不存在。
  主页 > Qt入门

一个qt/c++ demo,用于切换显示Sierpinski 三角形,Dragon 曲线和Cantor Set Cantor Set分形图

2023-04-24 浏览:
标签ad报错:该广告ID(7)不存在。
#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 只是一个小小的开端,通过在
其中添加更多的功能,可以实现更加复杂和有趣的分形图的绘制。