From e548c5e6c0dfdffbf75db61fb198dcf81c1b90b5 Mon Sep 17 00:00:00 2001 From: mar77i Date: Sun, 31 Mar 2024 16:41:36 +0200 Subject: [PATCH] initial commit --- .gitignore | 77 ++++++++++++++ CMakeLists.txt | 76 +++++++++++++ bigintwidget.cpp | 69 ++++++++++++ bigintwidget.h | 30 ++++++ colors.h | 269 +++++++++++++++++++++++++++++++++++++++++++++++ main.cpp | 14 +++ mandel.cpp | 109 +++++++++++++++++++ mandel.h | 69 ++++++++++++ 8 files changed, 713 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 bigintwidget.cpp create mode 100644 bigintwidget.h create mode 100644 colors.h create mode 100644 main.cpp create mode 100644 mandel.cpp create mode 100644 mandel.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c9e5c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,77 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* +CMakeLists.txt.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + +# Build directories +# ----------------- +build-*/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..243407b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 3.5) + +project(bigintmandel VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Concurrent) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Concurrent) + +set(PROJECT_SOURCES + main.cpp + bigintwidget.cpp + bigintwidget.h + mandel.cpp + mandel.h +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(bigintmandel + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET bigintmandel APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation +else() + if(ANDROID) + add_library(bigintmandel SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(bigintmandel + ${PROJECT_SOURCES} + ) + endif() +endif() + +target_link_libraries( + bigintmandel + PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Concurrent +) + +# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. +# If you are developing for iOS or macOS you should consider setting an +# explicit, fixed bundle identifier manually though. +if(${QT_VERSION} VERSION_LESS 6.1.0) + set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.bigintmandel) +endif() +set_target_properties(bigintmandel PROPERTIES + ${BUNDLE_ID_OPTION} + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +include(GNUInstallDirs) +install(TARGETS bigintmandel + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(bigintmandel) +endif() diff --git a/bigintwidget.cpp b/bigintwidget.cpp new file mode 100644 index 0000000..c965e0f --- /dev/null +++ b/bigintwidget.cpp @@ -0,0 +1,69 @@ + +// bigintwidget.cpp + +#include +#include +#include + +#include "bigintwidget.h" + +BigintWidget::BigintWidget(QWidget *parent) +: QWidget(parent), + fw(new QFutureWatcher(this)), + meta(1024, QSize(1800, 1000)), + img_label(new QLabel(this)), + img_dirty(true) +{ + connect( + fw, + &QFutureWatcher::resultReadyAt, + this, + &BigintWidget::finished_cell + ); + connect( + fw, + &QFutureWatcher::finished, + this, + &BigintWidget::finished + ); + fw->setFuture(QtConcurrent::mapped(meta.get_cells(), MandelMeta::iterate)); + setLayout(new QVBoxLayout()); + layout()->addWidget(img_label); + img_label->setMinimumSize(meta.get_size()); +} + +BigintWidget::~BigintWidget() { + fw->cancel(); + fw->waitForFinished(); +} + +void BigintWidget::finished_cell(int num) { + meta.finished_cell(num, fw->resultAt(num)); + img_dirty = true; + update(); +} + +void BigintWidget::finished() { + img_dirty = true; + update(); +} + +void BigintWidget::paintEvent(QPaintEvent *event) { + if (img_dirty) { + img_label->setPixmap(meta.get_pixmap()); + img_dirty = false; + } +} + +void BigintWidget::mousePressEvent(QMouseEvent *event) { + if (!fw->isFinished() || event->button() != Qt::MouseButton::LeftButton) + return; + QPoint pos = img_label->mapFromParent(event->pos()); + if (pos.x() < 0 || pos.x() >= meta.get_width() + || pos.y() < 0 || pos.y() >= meta.get_height()) + return; + meta.zoom2x(pos); + fw->setFuture(QtConcurrent::mapped(meta.get_cells(), MandelMeta::iterate)); + img_dirty = true; + update(); +} diff --git a/bigintwidget.h b/bigintwidget.h new file mode 100644 index 0000000..5d1964b --- /dev/null +++ b/bigintwidget.h @@ -0,0 +1,30 @@ + +// bigintwidget.h + +#ifndef BIGINTWIDGET_H +#define BIGINTWIDGET_H + +#include +#include +#include + +#include "mandel.h" + +class BigintWidget : public QWidget { + Q_OBJECT + + QFutureWatcher *fw; + MandelMeta meta; + QLabel *img_label; + bool img_dirty; + +public: + BigintWidget(QWidget *parent = nullptr); + ~BigintWidget(); + void finished_cell(int num); + void finished(); + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); +}; + +#endif // BIGINTWIDGET_H diff --git a/colors.h b/colors.h new file mode 100644 index 0000000..b6f8724 --- /dev/null +++ b/colors.h @@ -0,0 +1,269 @@ + +// colors.h + +#ifndef COLORS_H +#define COLORS_H + +#include +#include + +static QVector colors = { + "#3868b8", + "#3468b4", + "#3468b4", + "#3468b0", + "#3468b0", + "#3068ac", + "#3068ac", + "#3064a8", + "#3064a8", + "#2c64a4", + "#2c64a4", + "#2c64a4", + "#2c64a0", + "#2c64a0", + "#28649c", + "#28649c", + "#286098", + "#286098", + "#246094", + "#246094", + "#246090", + "#246090", + "#20608c", + "#20608c", + "#206088", + "#205c88", + "#1c5c84", + "#1c5c84", + "#1c5c80", + "#1c5c80", + "#185c7c", + "#185c7c", + "#185c78", + "#185c78", + "#185c78", + "#3c6c70", + "#607868", + "#808464", + "#a4945c", + "#c8a054", + "#e8ac50", + "#e4a854", + "#e4a458", + "#e0a058", + "#e09c5c", + "#e0985c", + "#dc9460", + "#dc9060", + "#dc9064", + "#d88c64", + "#d88868", + "#d88468", + "#d4806c", + "#d47c70", + "#d07870", + "#d07874", + "#d07474", + "#cc7078", + "#cc6c78", + "#cc687c", + "#c8647c", + "#c86080", + "#c86080", + "#c4647c", + "#c0687c", + "#bc6c7c", + "#b8707c", + "#4cc470", + "#48c870", + "#40cc6c", + "#3cd06c", + "#38d06c", + "#3ccc70", + "#40cc70", + "#40cc74", + "#44c874", + "#44c878", + "#48c878", + "#4cc87c", + "#4cc47c", + "#50c480", + "#50c480", + "#54c484", + "#58c084", + "#58c084", + "#5cc088", + "#5cc088", + "#60bc8c", + "#64bc8c", + "#64bc90", + "#68bc90", + "#68b894", + "#6cb894", + "#70b898", + "#70b498", + "#74b49c", + "#74b49c", + "#78b49c", + "#78b0a0", + "#7cb0a0", + "#80b0a4", + "#80b0a4", + "#84aca8", + "#84aca8", + "#88acac", + "#8cacac", + "#8ca8b0", + "#90a8b0", + "#90a8b4", + "#94a8b4", + "#98a4b4", + "#98a4b8", + "#9ca4b8", + "#9ca0bc", + "#a0a0bc", + "#a4a0c0", + "#a4a0c0", + "#a89cc4", + "#a89cc4", + "#ac9cc8", + "#b09cc8", + "#b098cc", + "#b498cc", + "#b498cc", + "#b898d0", + "#b894d0", + "#bc94d4", + "#c094d4", + "#c094d8", + "#c490d8", + "#c490dc", + "#c890dc", + "#cc8ce0", + "#cc8ce0", + "#d08ce4", + "#d08ce4", + "#d488e4", + "#d888e8", + "#d888e8", + "#dc88ec", + "#dc84ec", + "#e084f0", + "#e484f0", + "#e484f4", + "#e880f4", + "#e880f8", + "#ec80f8", + "#ec80f8", + "#e87cf0", + "#e47cec", + "#e07ce8", + "#dc78e0", + "#d878dc", + "#d478d8", + "#d474d4", + "#d074cc", + "#cc74c8", + "#c870c4", + "#c470c0", + "#c070b8", + "#bc6cb4", + "#bc6cb0", + "#b86ca8", + "#b468a4", + "#b068a0", + "#ac689c", + "#a86494", + "#a46490", + "#a4648c", + "#a06488", + "#9c6080", + "#98607c", + "#946078", + "#905c74", + "#8c5c6c", + "#8c5c68", + "#885864", + "#84585c", + "#805858", + "#7c5454", + "#785450", + "#745448", + "#745044", + "#705040", + "#6c503c", + "#684c34", + "#644c30", + "#604c2c", + "#604c28", + "#5c502c", + "#5c5030", + "#5c5034", + "#5c5038", + "#5c5038", + "#5c503c", + "#5c5440", + "#585444", + "#585444", + "#585448", + "#58544c", + "#585450", + "#585850", + "#585854", + "#585858", + "#54585c", + "#54585c", + "#545860", + "#545c64", + "#545c68", + "#545c6c", + "#545c6c", + "#545c70", + "#505c74", + "#506078", + "#506078", + "#50607c", + "#506080", + "#506084", + "#506084", + "#506488", + "#4c648c", + "#4c6490", + "#4c6490", + "#4c6494", + "#4c6498", + "#4c689c", + "#4c68a0", + "#4c68a0", + "#4868a4", + "#4868a8", + "#4868ac", + "#486cac", + "#486cb0", + "#486cb4", + "#486cb8", + "#486cb8", + "#446cbc", + "#4470c0", + "#4470c4", + "#4470c4", + "#4470c8", + "#4470cc", + "#4470d0", + "#4470d0", + "#406ccc", + "#406ccc", + "#406cc8", + "#406cc8", + "#3c6cc4", + "#3c6cc4", + "#3c6cc0", + "#3c6cc0", + "#386cbc", + "#3868bc", + "#3868b8", + "#3868b8", +}; + +#endif // COLORS_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..07cdecd --- /dev/null +++ b/main.cpp @@ -0,0 +1,14 @@ + +// main.cpp + +#include + +#include "bigintwidget.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + BigintWidget w; + w.show(); + return a.exec(); +} diff --git a/mandel.cpp b/mandel.cpp new file mode 100644 index 0000000..e633fb0 --- /dev/null +++ b/mandel.cpp @@ -0,0 +1,109 @@ + +// mandel.cpp + +#include "colors.h" +#include "mandel.h" + +MandelResultCell::MandelResultCell() {} + +MandelResultCell::MandelResultCell(size_t iter, QPointF rpos) +: iter(iter), rpos(rpos) {} + +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); + } +} + +MandelMeta::MandelMeta(size_t max_iter, const QSize size) +: max_iter(max_iter), + img(size, QImage::Format_RGB888), + cells(size.width() * size.height(), MandelCell(this)), + center_f(qreal(-3) / 4, 0), + one(1), + four(4), + scale(std::max(qreal(3) / size.width(), qreal(3) / size.height())) +{ + QVector::iterator i; + QPointF c(size.width() / 2., size.height() / 2.); + QPoint pos; + + for (i = cells.begin(); i != cells.end(); incrpos(pos, size.width()), i++) { + i->set_meta(this); + i->set_pos(pos); + } +} + +void MandelMeta::zoom2x(QPoint pos) { + QVector::iterator i; + center_f = cells[img.width() * pos.y() + pos.x()].get_rpos0(); + scale /= 2; + img.fill(Qt::GlobalColor::black); + for (i = cells.begin(); i != cells.end(); i++) + i->reset_iter_and_rpos(); +} + +void MandelMeta::finished_cell(int num, const MandelResultCell &cell) { + img.setPixelColor( + cells[num].update_result(cell.iter, cell.rpos), + cell.iter < max_iter + ? colors[cell.iter % colors.size()] + : Qt::GlobalColor::black + ); +} + +MandelResultCell MandelMeta::iterate(const MandelCell &cell) { + return cell.iterate(); +} + +void MandelCell::reset_rpos0() { + QPointF center_f = meta->get_center_f(); + rpos0 = QPointF( + center_f.x() + (pos.x() - meta->get_width() / 2.) * meta->get_scale(), + center_f.y() + (pos.y() - meta->get_height() / 2.) * meta->get_scale() + ); +} + +MandelCell::MandelCell(MandelMeta *meta) : meta(meta), iter(0) {} + +MandelCell::MandelCell(const MandelCell &cell) +: meta(cell.meta), pos(cell.pos), iter(cell.iter), + rpos(cell.rpos), rpos0(cell.rpos0) {} + +QPoint MandelCell::update_result(size_t iter, const QPointF &rpos) { + this->iter = iter; + this->rpos = rpos; + return pos; +} + +void MandelCell::reset_iter_and_rpos() { + iter = 0; + rpos = QPointF(); + reset_rpos0(); +} + +void MandelCell::set_meta(MandelMeta *meta) { + this->meta = meta; +} + +void MandelCell::set_pos(QPoint pos) { + this->pos = pos; + reset_rpos0(); +} + +MandelResultCell MandelCell::iterate() const { + size_t iter = this->iter; + QPointF rpos = this->rpos, sq; + for (; iter < this->meta->get_max_iter(); iter++) { + sq = QPointF(rpos.x() * rpos.x(), rpos.y() * rpos.y()); + if (sq.x() + sq.y() > meta->get_four()) + break; + rpos = QPointF( + sq.x() - sq.y() + rpos0.x(), + 2 * rpos.x() * rpos.y() + rpos0.y() + ); + } + return MandelResultCell(iter, rpos); +} diff --git a/mandel.h b/mandel.h new file mode 100644 index 0000000..487dd0b --- /dev/null +++ b/mandel.h @@ -0,0 +1,69 @@ + +// mandel.h + +#ifndef MANDEL_H +#define MANDEL_H + +#include +#include +#include + +class MandelCell; + +class MandelResultCell { + friend class MandelMeta; + + size_t iter; + QPointF rpos; +public: + MandelResultCell(); + MandelResultCell(size_t iter, QPointF rpos); +}; + +class MandelMeta { + size_t max_iter; + QImage img; + QVector cells; + QPointF center_f; + qreal one, four, scale; + +public: + MandelMeta(size_t max_iter, QSize size); + const size_t get_max_iter() const { return max_iter; } + const QPixmap get_pixmap() const { return QPixmap::fromImage(img); } + const int get_width() const { return img.width(); } + const int get_height() const { return img.height(); } + const QSize get_size() const { return img.size(); } + const QVector get_cells() const { return cells; } + const QPointF get_center_f() const { return center_f; } + const qreal get_four() const { return four; } + const qreal get_scale() const { return scale; } + + void zoom2x(QPoint pos); + void finished_cell(int num, const MandelResultCell &cell); + static MandelResultCell iterate(const MandelCell &cell); +}; + +class MandelCell { + MandelMeta *meta; + QPoint pos; + size_t iter; + QPointF rpos, rpos0; + +protected: + void reset_rpos0(); + +public: + MandelCell(MandelMeta *meta); + MandelCell(const MandelCell &cell); + inline const size_t get_iter() const { return iter; } + inline const QPointF get_rpos0() const { return rpos0; } + + QPoint update_result(size_t iter, const QPointF &rpos); + void reset_iter_and_rpos(); + void set_meta(MandelMeta *meta); + void set_pos(const QPoint pos); + MandelResultCell iterate() const; +}; + +#endif // MANDEL_H -- 2.47.0