
Детали фрактала
Изначально есть лишь буква Н, затем к каждому из концов этой буквы пририсовывается точно такая же буква Н, но в два раза меньше, и так далее.
Известно, что Н-фрактал заполняет свой квадрат и его фрактальная размерность равна двум.
Принцип построения данного фрактала используется в проектировании микросхем.
Если рисовать толстые буквы Н, то получается дерево Мандельброта.
Принцип построения Н-фрактала очень похож на пострение Т-фрактала.
Детали реализации
Чтобы запоминать точки в которых надо рисовать буквы H будем использовать очередь, так как данная структура данных лучше всего подходит для наших целей. На каждой итерации построения букв H мы будем использовать рандомные цвета.
Все остальные детали будут описаны в комментариях в коде.
Конкретно данный пример кода был написан на Qt/C++, из-за удобств работы с ui интерфейсом.
// widget.h #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QPair> #include <QPainter> #include <queue> #include <time.h> #include <stdlib.h> using namespace std; namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); void drawH(int size, QPair<int,int> coord, QPainter *paint); // функция для отрисовки Н в какой-то точке coord с длиной линий size int getSize(int depth); // в зависимости от глубины узнаем длину линии, она равна начальной длине, деленной на два в степени глубина минус один (в 1-индексации) void drawHDepth(int depth); // отрисовка всех Н до глубины depth QColor getRandColor(); // функция, возвращающая рандомный цвет private slots: void on_drawButton_clicked(); // метод клика по кнопке private: Ui::Widget *ui; // форма int oX,oY; // начальные координаты центра int sizeMin; // начальная длина queue<QPair<int,int> > coords; // очередь, используемая для запоминания точек в которых надо рисовать Н }; #endif // WIDGET_H
#include "widget.h" #include "ui_widget.h" // в конструкторе проинициализируем начальные значения координат и длины Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); oX = 290; oY = 255; sizeMin = 200; } Widget::~Widget() { delete ui; } void Widget::drawH(int size, QPair<int,int> coord, QPainter *paint) { // в данном методы мы просто рисуем три линии, которые и являются буквой Н // *paint нужен для отрисовки paint->drawLine(coord.first-(size/2),coord.second,coord.first+(size/2),coord.second); paint->drawLine(coord.first-(size/2),coord.second-(size/2),coord.first-(size/2),coord.second+(size/2)); paint->drawLine(coord.first+(size/2),coord.second-(size/2),coord.first+(size/2),coord.second+(size/2)); return; } int Widget::getSize(int depth) { // функция, возвращающая длину линий на каждом шаге return sizeMin/(1<<(depth-1)); } // так как на i-том шаге у нас будет ровно четыре в степени i-1 точек из которых надо рисовать Н, напишем рекурсивную функцию бинарного возведения в степень, которая за логарифмическую асимптотику позволяет вычислять степень числа int binPow(int a, int b) { if(!b) return 1; if(b%2) return binPow(a,b-1)*a; int tmp = binPow(a,b/2); return tmp*tmp; } // в данном методе мы лишь задаем рандомные значения RGB для класса QColor QColor Widget::getRandColor() { int r = rand()%255; int g = rand()%255; int b = rand()%255; return QColor(r,g,b); } void Widget::drawHDepth(int depth) { srand(time(NULL)); // для начала инициализируем рандомные значения QPixmap H(580,510); // далее создадим область рисования QPainter paint; paint.begin(&H); paint.eraseRect(0,0,580,510); // и закрасим её белым цветом while(!coords.empty()) // чтобы при каждой новой отрисовке не было конфузов, очистим очередь вершин coords.pop(); QPair<int,int> a(oX,oY),tmp; int size; coords.push(a); // изначально в очередь поместим только центральную точку for(int i=1;i<=depth;++i) { // и последовательно пройдемся по всем глубинам size = getSize(i); // узнаем размер линии на каждом шаге глубины paint.setPen(QPen(getRandColor(),1)); // задаем кисть рандомного цвета толщиной 1 for(int j=1;j<=binPow(4,i-1);j++) { // т.к. вершин на данном шаге будет 4 в степени i-1, проходимся только по 4 в степени i-1 первым значениям в очереди a = coords.front(); // узнаем координату очередной вершины coords.pop(); // удаляем её из очереди drawH(size,a,&paint); // и рисуем // далее просто добавляем 4 новые вершины в стек tmp.first = a.first-(size/2); tmp.second = a.second-(size/2); coords.push(tmp); tmp.first = a.first-(size/2); tmp.second = a.second+(size/2); coords.push(tmp); tmp.first = a.first+(size/2); tmp.second = a.second-(size/2); coords.push(tmp); tmp.first = a.first+(size/2); tmp.second = a.second+(size/2); coords.push(tmp); } } paint.end(); // заканчиваем рисование ui->output->setPixmap(H); // и выводим картинку на экран } void Widget::on_drawButton_clicked() { QString tmp = ui->depthEdit->text(); // получаем глубину, которую пользователь вводит в форме int depth; if(tmp=="") // если строка пуста depth = 1; // то считаем, что глубина равна 1 else // иначе depth = tmp.toInt(); // преобразовываем строку в число drawHDepth(depth); // и запускаем отрисовку фрактала до глубины depth }
Прикрепленный файл | Размер |
---|---|
Kish_Hfrac.zip | 2.47 кб |