Day4 教学示例:Mandelbrot 分形渲染器(QPainter 绘图 + 多线程 + 事件处理综合演示)
三段式对比直击 Day4 slides「主线程耗时=冻结」痛点:主线程渲染冻结 / 后台单线程不卡但慢 / 后台多线程不卡且快。 - QThreadPool + QRunnable 分水平条带并行,排队信号槽回传,epoch 版本号防过期覆盖 - wheelEvent 缩放(鼠标为锚)+ mouseEvent 拖拽平移 + paintEvent 画 QImage - 子目录自带独立 CMakeLists.txt,可单独构建/共享(双模式约定同 lineedit_eye_toggle) - 配套 README(概念/走读/双构建/5 踩坑点/练习)+ 设计规格 - 已验证:独立工程 offscreen 运行 exit=0;主工程构建 exit=0(w64devkit g++16 + mingw73 Qt5.14.2) 注:主工程 examples/CMakeLists.txt 的接入(mandelbrot + lineedit_eye_toggle + qdialog + themes 原子接入)与顶层 CMakeLists 本地调试改动未一并提交,待整体确认后单独提交。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
// ============================================================================
|
||||
// mandelbrot_strip_task.cpp —— 调色板构造 + renderStrip 纯计算实现
|
||||
// MandelbrotStripTask 的成员全部内联在头文件,本 .cpp 只需让 AUTOMOC 扫到
|
||||
// strip_task.h 的 Q_OBJECT(#include 它即可),并实现非内联的 MandelPalette
|
||||
// 与 renderStrip。
|
||||
// ============================================================================
|
||||
#include "mandelbrot_strip_task.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QtGlobal>
|
||||
|
||||
// 迭代次数 → HSV 色相循环(彩虹环),集合内部点统一黑色。
|
||||
MandelPalette::MandelPalette(int maxIter) {
|
||||
const int n = qMax(1, maxIter);
|
||||
table_.resize(n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (i == n - 1) { table_[i] = qRgb(0, 0, 0); continue; } // 集合内 → 黑
|
||||
const int hue = static_cast<int>((360.0 * 4.0 * i / n));
|
||||
table_[i] = QColor::fromHsv(hue % 360, 255, 255).rgb();
|
||||
}
|
||||
}
|
||||
|
||||
// 标准 Mandelbrot 迭代 z = z² + c,逃逸半径 2。逐像素写入 RGB32。
|
||||
QImage renderStrip(const MandelViewport& vp, const MandelPalette& pal, int y0, int y1) {
|
||||
const int w = vp.width;
|
||||
const int top = qBound(0, y0, vp.height);
|
||||
const int bot = qBound(0, y1, vp.height);
|
||||
if (w <= 0 || bot <= top) return {};
|
||||
|
||||
QImage img(w, bot - top, QImage::Format_RGB32);
|
||||
const double x0 = vp.centerX - vp.scale * vp.width / 2.0;
|
||||
const double y0c = vp.centerY - vp.scale * vp.height / 2.0;
|
||||
const int maxIter = vp.maxIter;
|
||||
|
||||
for (int py = top; py < bot; ++py) {
|
||||
const double cy = y0c + vp.scale * py;
|
||||
auto* line = reinterpret_cast<QRgb*>(img.scanLine(py - top)); // RGB32 = 每像素 1 个 QRgb
|
||||
for (int px = 0; px < w; ++px) {
|
||||
const double cx = x0 + vp.scale * px;
|
||||
double zx = 0.0, zy = 0.0;
|
||||
int iter = 0;
|
||||
while (iter < maxIter) {
|
||||
const double zx2 = zx * zx;
|
||||
const double zy2 = zy * zy;
|
||||
if (zx2 + zy2 > 4.0) break; // 逃逸
|
||||
zy = 2.0 * zx * zy + cy;
|
||||
zx = zx2 - zy2 + cx;
|
||||
++iter;
|
||||
}
|
||||
line[px] = pal.color(iter >= maxIter ? maxIter - 1 : iter);
|
||||
}
|
||||
}
|
||||
return img;
|
||||
}
|
||||
Reference in New Issue
Block a user