// ============================================================================ // mandelbrot_strip_task —— Day4 Mandelbrot 渲染器的「分块计算 + 调色板」单元 // 职责: // * MandelViewport : 视口参数(复平面中心 / 像素跨度 / 尺寸 / 最大迭代) // * MandelPalette : 迭代次数→RGB 的预计算调色板(提升趣味,与知识点无关) // * renderStrip() : 纯计算函数,渲染视口内 [y0,y1) 行像素。多线程 task 与 // 「主线程卡死」演示路径共用它——保证两路径算的是同一份分形, // 差异只在「是否阻塞事件循环 / 是否并行」。 // * MandelbrotStripTask : 一条水平带的 QRunnable 任务。多继承 QObject+QRunnable // 以获得信号能力(QRunnable 本身无信号——这是初学者高频困惑, // 见 README 踩坑点 2)。 // 设计要点:task 持 palette/viewport 的【值副本】,自包含、不引用主线程对象, // 避免主对象先析构导致的悬垂访问(见 README 踩坑点 4)。 // ============================================================================ #ifndef MANDELBROT_STRIP_TASK_H #define MANDELBROT_STRIP_TASK_H #include #include #include #include #include // 视口参数:复平面映射。scale = 每像素对应的复平面跨度。 struct MandelViewport { double centerX = -0.5; // 经典 Mandelbrot 主分形居中 double centerY = 0.0; double scale = 3.0 / 600.0; int width = 0; // show 后由 widget 尺寸填入 int height = 0; int maxIter = 256; }; // 调色板:迭代次数 → RGB。集合内部(迭代未逃逸)映射为黑。 class MandelPalette { public: explicit MandelPalette(int maxIter = 256); QRgb color(int i) const { return table_.at(i); } private: QVector table_; }; // 纯计算:渲染视口内 [y0, y1) 行像素,返回 (width × (y1-y0)) 的 RGB32 QImage。 QImage renderStrip(const MandelViewport& vp, const MandelPalette& pal, int y0, int y1); // 一条水平带的多线程任务。多继承 QObject + QRunnable 以拥有信号。 // setAutoDelete(true)(默认):run() 结束后由线程池回收;不设 QObject parent, // 避免与 QThreadPool 的自动删除发生双重所有权——见 README 踩坑点 2。 class MandelbrotStripTask : public QObject, public QRunnable { Q_OBJECT public: MandelbrotStripTask(quint64 epoch, int stripIndex, const MandelViewport& vp, const MandelPalette& pal, int y0, int y1) : QObject(nullptr), epoch_(epoch), stripIndex_(stripIndex), vp_(vp), pal_(pal), y0_(y0), y1_(y1) { setAutoDelete(true); } void run() override { // 算完一条带 → 通过信号把结果「排队」送回主线程(Qt 自动跨线程调度)。 emit stripReady(epoch_, stripIndex_, renderStrip(vp_, pal_, y0_, y1_)); } signals: void stripReady(quint64 epoch, int stripIndex, QImage strip); private: quint64 epoch_; int stripIndex_; MandelViewport vp_; MandelPalette pal_; // 值副本:任务自包含 int y0_; int y1_; }; #endif // MANDELBROT_STRIP_TASK_H