From: mar77i Date: Sun, 31 Mar 2024 14:41:36 +0000 (+0200) Subject: initial commit X-Git-Url: https://git.mar77i.info/?a=commitdiff_plain;h=e548c5e6c0dfdffbf75db61fb198dcf81c1b90b5;p=bigintmandel initial commit --- e548c5e6c0dfdffbf75db61fb198dcf81c1b90b5 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