跳转至

3D柱状图 - Qwt3DBar

Qwt3DBar 是在 3D 空间中绘制柱状图的 3D 绘图 item。每个样本变成一个轴对齐的长方体("柱"),其高度编码标量值。支持 1D 序列柱与 2D 网格(3D 直方图 / "bar3"),可按柱做 colormap 着色、带光照的扁平着色、以及线框/边线叠加。

3D 模块总览见 3D绘图简介。Qwt3DBar 是 Qwt3DPlotItem,遵循与 Qwt3DSurface 相同的 attach/draw/hull 契约。

主要功能特性

  • 两种数据形态:1D 序列(柱自由放置在 xy 平面)与 2D 网格(在 x/y 域上的 3D 直方图)

  • 带光照的实体几何:逐柱立方体、逐面扁平法向,响应 Qwt3DPlot::enableLighting()(Blinn-Phong)

  • 三种样式:Filled、FilledMesh(填充+边线)、Wireframe

  • 逐柱颜色:由 Qwt3DColor functor 驱动(通常按高度 z),通过 Qwt3DColorMapColor 使用全部 colormap 预设

  • 几何可配:baseline 与自动底面(柱宽/深默认取间距的 80%)

  • 主题集成:由 Qwt3DTheme::applyToItem() 自动接管

基本概念

数据形态

形态 setSamples 重载 用途
1D 序列 setSamples(QVector<QwtPoint3D>) 或 (x, heights) 沿轴排列 / 散布柱
2D 网格 setSamples(double** z, cols, rows, minX, maxX, minY, maxY) 或 (Qwt3DFunctionData) 3D 直方图(bar3)

1D 序列中,(x, y) 为柱底中心,z 为高度;2D 网格中,z[i][j] 为网格节点 (xi, yj) 处的高度。

渲染样式

样式 说明
Qwt3DBar::Filled 仅填充,无边线
Qwt3DBar::FilledMesh 填充 + 单独颜色的边线(默认)
Qwt3DBar::Wireframe 仅边线

架构


classDiagram

    class Qwt3DPlotItem {

        <<abstract>>

        +attach(plot)

        +draw()*

        +hull()*

        +itemChanged()

    }

    class Qwt3DBar {

        +setSamples()

        +setBarStyle()

        +setDataColor()

        +setBarWidth()/setBarDepth()

        +setBaseline()

        +invalidateColors()

    }

    Qwt3DPlotItem <|-- Qwt3DBar

Qwt3DBar 复用带光照的 surface 着色器(:/shaders/surface.vert/frag);每根柱发射为 6 个扁平法向面(24 顶点、36 三角索引)。它自持 VBO/VAO/EBO 与 Qwt3DColor functor,与 Qwt3DSurface 完全一致。

使用方法

3D 柱状图示例位于:examples/3D/bar3D。

1. 2D 网格柱状图(3D 直方图)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <qwt3d_plot.h>

#include <qwt3d_bar.h>

#include <qwt3d_colormap_color.h>



Qwt3DPlot* plot = new Qwt3DPlot();

plot->setTitle("Gaussian peak as 3D bars");



Qwt3DBar* bars = new Qwt3DBar();

bars->attach(plot);



// 9x9 网格,域 [-2,2] x [-2,2]

const int cols = 9, rows = 9;

const double minX = -2, maxX = 2, minY = -2, maxY = 2;

QVector<QVector<double>> z(cols, QVector<double>(rows));

for (int i = 0; i < cols; ++i)

    for (int j = 0; j < rows; ++j) {

        const double x = minX + (maxX - minX) * i / (cols - 1);

        const double y = minY + (maxY - minY) * j / (rows - 1);

        z[i][j] = std::exp(-(x * x + y * y) / 1.5);

    }

std::vector<double*> ptrs(cols);

for (int i = 0; i < cols; ++i)

    ptrs[i] = z[i].data();

bars->setSamples(ptrs.data(), cols, rows, minX, maxX, minY, maxY);



bars->setBarStyle(Qwt3DBar::FilledMesh);

bars->setDataColor(new Qwt3DColorMapColor("viridis"));

bars->setBaseline(0.0);



plot->enableLighting(true);

plot->setRotation(35, 0, 25);

plot->show();

2. 1D 序列柱

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 柱沿 x 轴排列,y = 0,高度 = h[i]

QVector<double> x = {0, 1, 2, 3, 4};

QVector<double> h = {1.2, 2.3, 0.8, 3.1, 1.7};

bars->setSamples(x, h);



// 或在 xy 平面自由放置(x,y 为柱底中心,z 为高度)

QVector<QwtPoint3D> pts;

pts << QwtPoint3D(0, 0, 1.2) << QwtPoint3D(1, 1, 2.3) << QwtPoint3D(2, 0, 0.8);

bars->setSamples(pts);

3. 柱几何:底面与基线

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 显式底面(世界单位)。<= 0 表示自动 = 间距的 80%

bars->setBarWidth(0.7);

bars->setBarDepth(0.7);



// 基线:柱起始 z(默认 0)。负高度使柱从基线向下延伸。

bars->setBaseline(0.0);

4. 着色

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 按高度的逐柱 colormap(默认行为)。可复用 22 种预设。

bars->setDataColor(new Qwt3DColorMapColor("plasma"));



// 就地修改已挂载 functor(如 alpha)需触发重建:

auto* cm = new Qwt3DColorMapColor("viridis");

bars->setDataColor(cm);

cm->setAlpha(0.8);          // 静默 mutator

bars->invalidateColors();   // 触发 VBO 颜色重建

5. 切换样式

1
2
3
4
5
6
7
8
9
bars->setBarStyle(Qwt3DBar::Filled);      // 仅实体

bars->setBarStyle(Qwt3DBar::FilledMesh);  // 实体 + 边线(默认)

bars->setBarStyle(Qwt3DBar::Wireframe);   // 仅边线

bars->setMeshColor(RGBA(0.1, 0.1, 0.1, 0.4));

bars->setMeshLineWidth(1.0);

6. 主题与坐标系

1
2
3
4
5
6
7
8
9
// 应用主题 —— Qwt3DBar 由 Qwt3DTheme::applyToItem() 处理。

plot->applyTheme(Qwt3DTheme::Scientific);



// 调节轴刻度长度(逐轴、各向异性免疫):

plot->coordinates()->setTicLengthScale(0.02);

核心方法总结

方法 说明
setSamples(...) 加载柱数据(1D 或 2D 网格,见数据形态)
setBarWidth(w) / setBarDepth(d) 柱底面(<= 0 = 自动,间距 80%)
setBaseline(z) 柱底 z(默认 0)
setBarStyle(BarStyle) Filled / FilledMesh / Wireframe
setDataColor(Qwt3DColor*) 逐柱颜色 functor(获取所有权)
dataColor() 获取颜色 functor
setMeshColor(RGBA) / setMeshLineWidth(double) 边线外观
invalidateColors() 就地修改 functor 后重建 VBO 颜色
hull() 包围盒(供 plot 构建坐标系)
draw() / populateLegendColors() Qwt3DPlotItem 接口

提示

  • 网格不宜过大(数千柱以内),每柱 24 顶点。

  • 用 FilledMesh 配半透明 mesh 色可获得清晰边线,又不至于杂乱。

  • enableLighting(true) 显著改善扁平着色柱的 3D 观感。

  • 各向异性数据时调用 plot->coordinates()->setTicLengthScale(...) 让刻度保持比例。

示例 — 相关示例

  • 3D 柱状图:examples/3D/bar3D

  • 不用柱状而用实时堆叠轨迹(频谱):3D瀑布图,示例 examples/3D/waterfall3D