Files
scuc-qt-course/docs/teaching/examples/mandelbrot_renderer/mandelbrot_strip_task.cpp
T
张宗平 6773f9b29e 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>
2026-07-09 09:01:29 +08:00

55 lines
2.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================================
// 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;
}