From 89b507123e82284a3f830131cdd6caf41473a95d Mon Sep 17 00:00:00 2001 From: mar77i Date: Mon, 22 Apr 2024 01:16:30 +0200 Subject: [PATCH] save and load calculations as json --- bigintwidget.cpp | 74 ++++++++++++++++++++-------- bigintwidget.h | 6 +++ mandel.cpp | 118 +++++++++++++++++++++++++++++++++++++-------- mandel.h | 37 +++++++++----- settingswidget.cpp | 1 - 5 files changed, 182 insertions(+), 54 deletions(-) diff --git a/bigintwidget.cpp b/bigintwidget.cpp index d4289a1..30c7ff2 100644 --- a/bigintwidget.cpp +++ b/bigintwidget.cpp @@ -20,6 +20,18 @@ static inline QMenuBar *setup_menu_bar(BigintWidget *parent) { parent, &BigintWidget::reset ); + QObject::connect( + menu->addAction("&Load"), + &QAction::triggered, + parent, + &BigintWidget::load_json + ); + QObject::connect( + menu->addAction("&Save"), + &QAction::triggered, + parent, + &BigintWidget::save_json + ); menu->addSeparator(); QObject::connect( menu->addAction("&Export"), @@ -45,6 +57,17 @@ static inline QMenuBar *setup_menu_bar(BigintWidget *parent) { return menu_bar; } +static inline void start_calculation( + QFutureWatcher *fw, QVector cells +) { + fw->setFuture( + QtConcurrent::mapped( + cells, + [](const MandelCell &cell){ return cell.iterate(); } + ) + ); +} + BigintWidget::BigintWidget(QWidget *parent) : QWidget(parent), fw(new QFutureWatcher(this)), @@ -74,15 +97,13 @@ BigintWidget::BigintWidget(QWidget *parent) this, &BigintWidget::finished ); - fw->setFuture( - QtConcurrent::mapped(settings.get_cells(), MandelSettings::iterate) - ); + start_calculation(fw, settings.get_cells()); setLayout(new QVBoxLayout()); layout()->addWidget(setup_menu_bar(this)); layout()->addWidget(scroll_area); status_bar->setSizeGripEnabled(false); layout()->addWidget(status_bar); - img_label->setMinimumSize(settings.get_current().get_size()); + img_label->resize(settings.get_params().get_size()); } BigintWidget::~BigintWidget() { @@ -132,7 +153,7 @@ void BigintWidget::paintEvent(QPaintEvent *event) { } void BigintWidget::mousePressEvent(QMouseEvent *event) { - QSize size(settings.get_current().get_size()); + QSize size(settings.get_params().get_size()); QPoint pos(event->pos()); QWidget *w; for (w = img_label; w != this; w = w->parentWidget()) @@ -144,10 +165,8 @@ void BigintWidget::mousePressEvent(QMouseEvent *event) { || pos.y() < 0 || pos.y() >= size.height()) return; - settings.zoom(scroll_area->viewport()->size(), pos); - fw->setFuture( - QtConcurrent::mapped(settings.get_cells(), MandelSettings::iterate) - ); + settings.zoom(get_ideal_size(), pos); + start_calculation(fw, settings.get_cells()); update_img(); } @@ -157,33 +176,46 @@ void BigintWidget::update_img() { } void BigintWidget::export_img() { - QString filename = QFileDialog::getSaveFileName( + QString file_name = QFileDialog::getSaveFileName( this, "Save image", "", "Images (*.png *.xpm *.jpg)" ); - if (!filename.isEmpty()) - settings.save_img(filename); + if (!file_name.isEmpty()) + settings.save_img(file_name); } void BigintWidget::exec_settings_widget() { - settings_widget->update_fields(settings.get_current(), fw->isFinished()); + settings_widget->update_fields(settings.get_params(), fw->isFinished()); settings_widget->exec(); } void BigintWidget::reset() { - QSize size(scroll_area->viewport()->size()); fw->cancel(); fw->waitForFinished(); - settings.reset(128, size); - fw->setFuture( - QtConcurrent::mapped(settings.get_cells(), MandelSettings::iterate) - ); + settings.reset(128, get_ideal_size()); + start_calculation(fw, settings.get_cells()); update_img(); } void BigintWidget::settings_widget_accepted() { settings.set_max_iter(settings_widget->get_max_iter().toULongLong()); - fw->setFuture( - QtConcurrent::mapped(settings.get_cells(), MandelSettings::iterate) - ); + start_calculation(fw, settings.get_cells()); update_img(); } + +void BigintWidget::load_json() { + QString file_name = QFileDialog::getOpenFileName( + this, "Load JSON", "", "JSON Documents (*.json)" + ); + if (!file_name.isEmpty()) { + settings.load_json(file_name); + update_img(); + } +} + +void BigintWidget::save_json() { + QString file_name = QFileDialog::getSaveFileName( + this, "Save JSON", "", "JSON Documents (*.json)" + ); + if (!file_name.isEmpty()) + settings.save_json(file_name); +} diff --git a/bigintwidget.h b/bigintwidget.h index 6db7f5c..705be18 100644 --- a/bigintwidget.h +++ b/bigintwidget.h @@ -25,6 +25,10 @@ class BigintWidget : public QWidget { QStatusBar *status_bar; SettingsWidget *settings_widget; + inline const QSize get_ideal_size() const { + return scroll_area->size().shrunkBy(scroll_area->contentsMargins()); + } + public: BigintWidget(QWidget *parent = nullptr); ~BigintWidget(); @@ -39,6 +43,8 @@ public Q_SLOT: void settings_widget_accepted(); void finished_cell(int num); void finished(); + void load_json(); + void save_json(); }; #endif // BIGINTWIDGET_H diff --git a/mandel.cpp b/mandel.cpp index 70910d3..f68b5ff 100644 --- a/mandel.cpp +++ b/mandel.cpp @@ -1,6 +1,10 @@ // mandel.cpp +#include +#include +#include + #include "colors.h" #include "mandel.h" @@ -32,6 +36,28 @@ MandelParams::MandelParams(const MandelParams &other) center_f(other.center_f), one(other.one) {} +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); @@ -70,21 +96,15 @@ MandelSettings::MandelSettings(size_t max_iter, const QSize size) void MandelSettings::zoom(const QSize size, const QPoint pos) { MpzPoint p = cells[img->width() * pos.y() + pos.x()].get_rpos0(); - bool resize_img = size != current.get_size(); - current = MandelParams( - current.get_max_iter(), + params = MandelParams( + params.get_max_iter(), size, MpzPoint(p.get_x() * 2, p.get_y() * 2), - current.get_one() * 2 + params.get_one() * 2 ); - if (resize_img) - img = setup_image(img, size); + img = setup_image(img, size); img->fill(Qt::GlobalColor::black); - setup_cells(cells, ¤t); -} - -void MandelSettings::set_max_iter(size_t max_iter) { - current.set_max_iter(max_iter); + setup_cells(cells, ¶ms); } void MandelSettings::finished_cell(int num, const MandelResultCell &result) { @@ -95,10 +115,6 @@ void MandelSettings::finished_cell(int num, const MandelResultCell &result) { img->setPixelColor(cells[num].get_pos(), cells[num].get_color()); } -MandelResultCell MandelSettings::iterate(const MandelCell &cell) { - return cell.iterate(); -} - void MandelSettings::save_img(QString file_name) { if (img) img->save(file_name); @@ -116,9 +132,45 @@ void MandelSettings::reset(size_t max_iter, const QSize size) { ione |= ione >> 16; one = mpz_class(ione + 1); center_f = MpzPoint(one * -3 / 4, 0); - current = MandelParams(max_iter, size, center_f, one); + params = MandelParams(max_iter, size, center_f, one); img = setup_image(img, size); - setup_cells(cells, ¤t); + setup_cells(cells, ¶ms); +} + +void MandelSettings::load_json(QString file_name) { + QFile file(file_name); + QJsonObject json; + QJsonArray json_array; + int i; + if (!file.open(QIODevice::ReadOnly)) { + qWarning("Couldn't open save file."); + return; + } + json = QJsonDocument::fromJson(file.readAll()).object(); + 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())); + file.close(); +} + +void MandelSettings::save_json(QString file_name) { + QVector::iterator i; + QFile file(file_name); + QJsonObject json; + QJsonArray c; + json["params"] = params.to_json(); + for (i = cells.begin(); i != cells.end(); i++) + c.append(i->to_json()); + json["cells"] = c; + if (!file.open(QIODevice::WriteOnly)) { + qWarning("Couldn't open save file."); + return; + } + file.write(QJsonDocument(json).toJson()); + file.close(); } MandelCell::MandelCell(const MandelParams *params) : params(params) {} @@ -139,10 +191,10 @@ void MandelCell::setup(const QPoint pos) { } MandelResultCell MandelCell::iterate() const { - MpzPoint rpos = result.rpos, sq; + MpzPoint rpos = result.get_rpos(), sq; mpz_class one = params->get_one(), four = one * one * 4; mpz_class sqx, sqy; - size_t iter = result.iter; + size_t 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(); @@ -155,3 +207,31 @@ MandelResultCell MandelCell::iterate() const { } 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; +} diff --git a/mandel.h b/mandel.h index ffb9ff1..dba45e3 100644 --- a/mandel.h +++ b/mandel.h @@ -4,6 +4,7 @@ #ifndef MANDEL_H #define MANDEL_H +#include #include #include #include @@ -22,14 +23,13 @@ public: }; class MandelResultCell { - friend class MandelCell; - size_t iter; MpzPoint rpos; public: MandelResultCell(); MandelResultCell(size_t iter, MpzPoint rpos); const size_t get_iter() const { return iter; } + const MpzPoint get_rpos() const { return rpos; } }; class MandelParams { @@ -48,31 +48,34 @@ public: mpz_class one ); MandelParams(const MandelParams &other); - const size_t get_max_iter() const { return max_iter; } void set_max_iter(const size_t max_iter) { this->max_iter = max_iter; } const QSize get_size() const { return size; } const MpzPoint get_center_f() const { return center_f; } const mpz_class get_one() const { return one; } + + static MandelParams from_json(const QJsonObject &json); + QJsonObject to_json() const; }; class MandelSettings { - MandelParams current; + MandelParams params; QImage *img; QVector cells; public: MandelSettings(size_t max_iter, QSize size); - const QPixmap get_pixmap() const { return QPixmap::fromImage(*img); } - const QVector get_cells() const { return cells; } - const MandelParams get_current() const { return current; } + inline const QPixmap get_pixmap() const { return QPixmap::fromImage(*img); } + inline const QVector get_cells() const { return cells; } + inline const MandelParams &get_params() const { return params; } + inline void set_max_iter(size_t max_iter) { params.set_max_iter(max_iter); } void zoom(const QSize size, const QPoint pos); - void set_max_iter(size_t max_iter); void finished_cell(int num, const MandelResultCell &cell); - static MandelResultCell iterate(const MandelCell &cell); void save_img(QString file_name); void reset(size_t max_iter, QSize size); + void load_json(QString file_name); + void save_json(QString file_name); }; extern QVector colors; @@ -85,14 +88,20 @@ class MandelCell { public: MandelCell(const MandelParams *params); + MandelCell( + const MandelParams *params, + const QPoint pos, + const MpzPoint rpos0, + const MandelResultCell result + ); MandelCell(const MandelCell &cell); inline const QPoint get_pos() const { return pos; } - inline const size_t get_iter() const { return result.iter; } inline const MpzPoint get_rpos0() const { return rpos0; } inline const QColor get_color() const { - return result.iter < params->get_max_iter() - ? colors[result.iter % colors.size()] - : Qt::GlobalColor::black; + size_t iter = result.get_iter(); + return iter < params->get_max_iter() + ? colors[iter % colors.size()] + : Qt::GlobalColor::black; } void setup(const QPoint pos); @@ -100,6 +109,8 @@ public: this->result = result; } MandelResultCell iterate() const; + MandelResultCell from_json(const QJsonObject &json); + QJsonObject to_json() const; }; #endif // MANDEL_H diff --git a/settingswidget.cpp b/settingswidget.cpp index a6d3c6e..f87086f 100644 --- a/settingswidget.cpp +++ b/settingswidget.cpp @@ -8,7 +8,6 @@ #include "settingswidget.h" - SettingsWidget::SettingsWidget(QWidget *parent) : QDialog(parent), max_iter(new QLineEdit("", this)), -- 2.47.0