/* * mandel.cpp * * This file is covered by the LICENSE file in the root of this project. */ #include #include #include #include "colors.h" #include "mandel.h" static inline const MpzPoint calculate_offset( const MpzPoint center_f, const QSize size ) { return MpzPoint( center_f.get_x() - size.width() / 2, center_f.get_y() + size.height() / 2 ); } MandelParams::MandelParams() {} MandelParams::MandelParams( quint64 max_iter, QSize size, MpzPoint center_f, mpz_class one ) : max_iter(max_iter), size(size), center_f(center_f), offset(calculate_offset(center_f, size)), one(one) {} MandelParams::MandelParams(const MandelParams &other) : max_iter(other.max_iter), size(other.size), center_f(other.center_f), offset(calculate_offset(other.center_f, other.size)), one(other.one) {} void MandelParams::set_size(const QSize &size) { this->size = size; this->offset = calculate_offset(center_f, size); } MandelParams MandelParams::from_json(const QJsonObject &json) { return MandelParams( json["max_iter"].toString().toULongLong(), QSize(json["size_w"].toInt(), json["size_h"].toInt()), MpzPoint( mpz_class(json["center_f_x"].toString().toStdString()), mpz_class(json["center_f_y"].toString().toStdString()) ), mpz_class(json["one"].toString().toStdString()) ); } QJsonObject MandelParams::to_json() const { QJsonObject json; json["max_iter"] = QString::number(max_iter); json["size_w"] = size.width(); json["size_h"] = size.height(); json["center_f_x"] = QString::fromStdString(center_f.get_x().get_str()); json["center_f_y"] = QString::fromStdString(center_f.get_y().get_str()); json["one"] = QString::fromStdString(one.get_str()); return json; } static inline void incrpos(QPoint &pos, const int width) { pos.setX(pos.x() + 1); if (pos.x() == width) { pos.setX(0); pos.setY(pos.y() + 1); } } static inline void setup_cells( QVector &cells, const MandelParams *current ) { QSize size = current->get_size(); QVector::iterator i; QPoint pos; cells.resize(size.width() * size.height(), MandelCell(current)); for (i = cells.begin(); i != cells.end(); incrpos(pos, size.width()), i++) i->setup(pos); } static inline QImage *setup_image(QImage *img, const QSize &size) { if(!img || img->size() != size) { delete img; img = new QImage(size, QImage::Format_RGB888); } img->fill(Qt::GlobalColor::black); return img; } MandelSettings::MandelSettings(quint64 max_iter, const QSize size) : img(nullptr) { reset(max_iter, size); } void MandelSettings::clear() { img = setup_image(img, params.get_size()); img->fill(Qt::GlobalColor::black); setup_cells(cells, ¶ms); } void MandelSettings::zoom(const QSize size, int zoom_factor, const QPoint pos) { MpzPoint p = cells[img->width() * pos.y() + pos.x()].get_rpos0(); params = MandelParams( params.get_max_iter(), size, MpzPoint(p.get_x() * zoom_factor, p.get_y() * zoom_factor), params.get_one() * zoom_factor ); clear(); } void MandelSettings::finished_cell(int num, const MandelResultCell &result) { cells[num].set_result(result); if (!img) return; img->setPixelColor(cells[num].get_pos(), cells[num].get_color()); return; (void)colors; } void MandelSettings::save_img(QString file_name) { if (img) img->save(file_name); } void MandelSettings::reset(quint64 max_iter, const QSize size) { mpz_class one; MpzPoint center_f; int ione = std::min(size.width(), size.height()) / 3; ione--; ione |= ione >> 1; ione |= ione >> 2; ione |= ione >> 4; ione |= ione >> 8; ione |= ione >> 16; one = mpz_class(ione + 1); center_f = MpzPoint(one * -3 / 4, 0); params = MandelParams(max_iter, size, center_f, one); clear(); } void MandelSettings::from_json(const QJsonObject &json) { QJsonArray json_array; int i; params = MandelParams::from_json(json["params"].toObject()); json_array = json["cells"].toArray(); cells.resize(json_array.size(), MandelCell(¶ms)); img = setup_image(img, params.get_size()); for (i = 0; i < json_array.size(); i++) finished_cell(i, cells[i].from_json(json_array[i].toObject())); } QJsonObject MandelSettings::to_json() { QJsonArray c; QJsonObject json; QVector::iterator i; json["params"] = params.to_json(); for (i = cells.begin(); i != cells.end(); i++) c.append(i->to_json()); json["cells"] = c; return json; } MandelCell::MandelCell(const MandelParams *params) : params(params) {} MandelCell::MandelCell(const MandelCell &cell) : params(cell.params), pos(cell.pos), result(cell.result), rpos0(cell.rpos0) {} void MandelCell::setup(const QPoint pos) { const MpzPoint &offset = params->get_offset(); this->pos = pos; rpos0 = MpzPoint(offset.get_x() + pos.x(), offset.get_y() - pos.y()); result = MandelResultCell(); } MandelResultCell MandelCell::iterate() const { MpzPoint rpos = result.get_rpos(), sq; mpz_class one = params->get_one(), four = one * one * 4; mpz_class sqx, sqy; quint64 iter = result.get_iter(); for (; iter < params->get_max_iter(); iter++) { sqx = rpos.get_x() * rpos.get_x(); sqy = rpos.get_y() * rpos.get_y(); if (sqx + sqy > four) break; rpos = MpzPoint( (sqx - sqy) / one + rpos0.get_x(), rpos.get_x() * rpos.get_y() * 2 / one + rpos0.get_y() ); } return MandelResultCell(iter, rpos); } MandelResultCell MandelCell::from_json(const QJsonObject &json) { this->pos = QPoint(json["pos_x"].toInt(), json["pos_y"].toInt()); this->rpos0 = MpzPoint( mpz_class(json["rpos0_x"].toString().toStdString()), mpz_class(json["rpos0_y"].toString().toStdString()) ); return MandelResultCell( json["iter"].toString().toULongLong(), MpzPoint( mpz_class(json["rpos_x"].toString().toStdString()), mpz_class(json["rpos_y"].toString().toStdString()) ) ); } QJsonObject MandelCell::to_json() const { const MpzPoint rpos(result.get_rpos()); QJsonObject json; json["pos_x"] = pos.x(); json["pos_y"] = pos.y(); json["rpos0_x"] = QString::fromStdString(rpos0.get_x().get_str()); json["rpos0_y"] = QString::fromStdString(rpos0.get_y().get_str()); json["iter"] = QString::number(result.get_iter()); json["rpos_x"] = QString::fromStdString(rpos.get_x().get_str()); json["rpos_y"] = QString::fromStdString(rpos.get_y().get_str()); return json; }