fix(vtk): 坐标轴设置交互修复(批1/#5)-增量渲染+VE滑块+隐藏轴全隐+关闭按钮

- 5.1 关闭按钮空白:全局 QPushButton padding(6px14px) 挤掉 ×,显式 setStyleSheet padding:0
- 5.2 取消某轴「显示」时禁用其 min/max 编辑框(show toggled→lo/hi setEnabled,回灌同步)
- 5.3 隐藏轴后刻度数字仍在:SetXAxisVisibility 只关线,补 SetXAxisLabelVisibility/TickVisibility
- 5.4 应用即全量重绘→改增量:setAxesConfig 不再 rebuildInternal(clear场景),改
       view_.setAxes+setAxesRanges+renderIncremental(仅重建坐标轴 prop,不动数据/相机)
- 5.5 放大系数下拉→滑块(1~10×,恢复重构前交互):拖动实时改标签,sliderReleased 才发
       verticalExaggerationChanged 触发一次重建(VE 改几何须重建但不在拖动中连续重建)
       main.cpp 接 applied(去scale) + verticalExaggerationChanged(→控制器+底图)

构建:app 链接通过
This commit is contained in:
gaozheng 2026-06-25 16:39:48 +08:00
parent 70f77c1736
commit a2770ba49d
5 changed files with 81 additions and 23 deletions

View File

@ -1,11 +1,14 @@
#include "AxesSettingsPanel.hpp"
#include <algorithm>
#include <QCheckBox>
#include <QComboBox>
#include <QDoubleSpinBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QSlider>
#include <QVBoxLayout>
#include "Theme.hpp"
@ -28,8 +31,12 @@ AxesSettingsPanel::AxesSettingsPanel(QWidget* parent) : QFrame(parent) {
auto* title = new QLabel(QStringLiteral("坐标轴设置"), this);
title->setStyleSheet(QStringLiteral("font-weight:600;font-size:15px;border:none;"));
auto* close = new QPushButton(QStringLiteral(""), this);
close->setFlat(true);
close->setFixedSize(24, 24);
close->setCursor(Qt::PointingHandCursor);
// 显式覆盖全局 QPushButton 的 padding(6px 14px)/border——否则 24×24 容不下 padding× 被挤出不可见。
close->setStyleSheet(QStringLiteral(
"QPushButton{border:none;background:transparent;padding:0;margin:0;font-size:16px;color:#888;}"
"QPushButton:hover{color:#2f6fed;}"));
connect(close, &QPushButton::clicked, this, &AxesSettingsPanel::closed);
titleRow->addWidget(title);
titleRow->addStretch(1);
@ -49,15 +56,25 @@ AxesSettingsPanel::AxesSettingsPanel(QWidget* parent) : QFrame(parent) {
y_ = addAxisRow(v, QStringLiteral("Y轴"), {true, -500, 500});
z_ = addAxisRow(v, QStringLiteral("Z轴"), {true, 0, 200});
// 放大系数(=垂直夸张)。
// 放大系数(=垂直夸张):滑块 1~10×恢复重构前的拖动交互。拖动实时改标签
// 松手sliderReleased才发信号触发一次重建——VE 改的是几何,必须重建,但不在拖动中连续重建。
auto* scaleRow = new QHBoxLayout();
auto* scaleLbl = new QLabel(QStringLiteral("放大系数"), this);
scaleLbl->setStyleSheet(QStringLiteral("border:none;"));
v->addWidget(scaleLbl);
scale_ = new QComboBox(this);
scale_->addItems({QStringLiteral("0.1"), QStringLiteral("0.5"), QStringLiteral("1"),
QStringLiteral("2"), QStringLiteral("5")});
scale_->setCurrentText(QStringLiteral("1"));
v->addWidget(scale_);
scaleRow->addWidget(scaleLbl);
scaleSlider_ = new QSlider(Qt::Horizontal, this);
scaleSlider_->setMinimum(1);
scaleSlider_->setMaximum(10);
scaleSlider_->setValue(1);
scaleLabel_ = new QLabel(QStringLiteral("1.0×"), this);
scaleLabel_->setStyleSheet(QStringLiteral("border:none;color:#888;min-width:36px;"));
connect(scaleSlider_, &QSlider::valueChanged, this,
[this](int v) { scaleLabel_->setText(QStringLiteral("%1.0×").arg(v)); });
connect(scaleSlider_, &QSlider::sliderReleased, this,
[this] { emit verticalExaggerationChanged(static_cast<double>(scaleSlider_->value())); });
scaleRow->addWidget(scaleSlider_, 1);
scaleRow->addWidget(scaleLabel_);
v->addLayout(scaleRow);
// 取消 / 应用。
auto* btns = new QHBoxLayout();
@ -71,7 +88,7 @@ AxesSettingsPanel::AxesSettingsPanel(QWidget* parent) : QFrame(parent) {
auto rd = [](const Row& r) {
return AxisRange{r.show->isChecked(), r.lo->value(), r.hi->value()};
};
emit applied(rd(x_), rd(y_), rd(z_), unit_->currentIndex(), scale_->currentText().toDouble());
emit applied(rd(x_), rd(y_), rd(z_), unit_->currentIndex());
});
btns->addStretch(1);
btns->addWidget(cancel);
@ -115,6 +132,16 @@ AxesSettingsPanel::Row AxesSettingsPanel::addAxisRow(QVBoxLayout* col, const QSt
hiCol->addWidget(r.hi);
range->addLayout(hiCol);
col->addLayout(range);
// 取消「显示」时禁用该轴的最小/最大值编辑(隐藏的轴改范围无意义)。
auto* lo = r.lo;
auto* hi = r.hi;
connect(r.show, &QCheckBox::toggled, this, [lo, hi](bool on) {
lo->setEnabled(on);
hi->setEnabled(on);
});
r.lo->setEnabled(def.show);
r.hi->setEnabled(def.show);
return r;
}
@ -123,12 +150,17 @@ void AxesSettingsPanel::setValues(AxisRange x, AxisRange y, AxisRange z, int uni
r.show->setChecked(a.show);
r.lo->setValue(a.min);
r.hi->setValue(a.max);
r.lo->setEnabled(a.show); // 回灌时同步禁用态(隐藏轴 → 禁编辑)
r.hi->setEnabled(a.show);
};
wr(x_, x);
wr(y_, y);
wr(z_, z);
unit_->setCurrentIndex(unitIdx);
scale_->setCurrentText(QString::number(scale)); // 命中预设项则选中,否则保持
const int v = std::max(1, std::min(10, static_cast<int>(scale + 0.5)));
QSignalBlocker block(scaleSlider_); // 回灌不触发 sliderReleased
scaleSlider_->setValue(v);
scaleLabel_->setText(QStringLiteral("%1.0×").arg(v));
}
} // namespace geopro::app

View File

@ -7,6 +7,8 @@ class QCheckBox;
class QComboBox;
class QDoubleSpinBox;
class QVBoxLayout;
class QSlider;
class QLabel;
namespace geopro::app {
@ -21,7 +23,10 @@ public:
void setValues(AxisRange x, AxisRange y, AxisRange z, int unitIdx, double scale);
signals:
void applied(AxisRange x, AxisRange y, AxisRange z, int unitIdx, double scale);
// 「应用」:仅坐标轴(显示方式/单位/per-axis 可见性·范围);走增量重建,不重绘数据。
void applied(AxisRange x, AxisRange y, AxisRange z, int unitIdx);
// 放大系数(=垂直夸张)滑块:拖动实时改数值标签,松手才发此信号触发一次重建。
void verticalExaggerationChanged(double ve);
void closed(); // × 或 取消
private:
@ -32,8 +37,9 @@ private:
};
Row addAxisRow(QVBoxLayout* col, const QString& title, const AxisRange& def);
QComboBox* unit_ = nullptr; // 坐标轴单位:米 / 英尺
QComboBox* scale_ = nullptr; // 放大系数0.1 / 0.5 / 1 / 2 / 5
QComboBox* unit_ = nullptr; // 坐标轴单位:米 / 英尺
QSlider* scaleSlider_ = nullptr; // 放大系数(=垂直夸张)滑块 1~10×
QLabel* scaleLabel_ = nullptr; // 滑块当前值标签如「3.0×」)
Row x_, y_, z_;
};

View File

@ -943,11 +943,11 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
// 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。单一来源 kVerticalExaggeration 下发
// 控制器(上方)/底图;运行时 VE 改由坐标轴设置抽屉「应用」下发(旧三维数据集栏滑块已退役)。
basemap->setVerticalExaggeration(kVerticalExaggeration);
// 坐标轴设置抽屉「应用」:轴显示开关 + 放大系数(=垂直夸张,下发控制器+底图);范围/单位待控制器 API。
// 坐标轴设置抽屉「应用」:仅轴显示开关 + 单位 + per-axis 范围 → 走 setAxesConfig已改增量重建
// 不再清场景重绘数据)。放大系数=垂直夸张改由滑块独立信号下发(见下)。
QObject::connect(axesPanel, &geopro::app::AxesSettingsPanel::applied, &window,
[axesPanel, sceneCtrl, basemap](geopro::app::AxisRange x, geopro::app::AxisRange y,
geopro::app::AxisRange z, int unitIdx,
double scale) {
[axesPanel, sceneCtrl](geopro::app::AxisRange x, geopro::app::AxisRange y,
geopro::app::AxisRange z, int unitIdx) {
const bool anyShow = x.show || y.show || z.show;
// 每轴:可见性=显示开关;自定义范围=面板 min/max按当前单位真正改刻度。
auto cfg = [](const geopro::app::AxisRange& a) {
@ -958,12 +958,15 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
unitIdx == 1 ? geopro::controller::AxesUnit::Feet
: geopro::controller::AxesUnit::Meter,
cfg(x), cfg(y), cfg(z));
if (scale > 0) { // 放大系数=垂直夸张:控制器 + 底图同步
sceneCtrl->setVerticalExaggeration(scale);
basemap->setVerticalExaggeration(scale);
}
axesPanel->hide();
});
// 放大系数滑块(=垂直夸张):松手即下发控制器 + 底图VE 改几何须一次重建,但不在拖动中连续重建)。
QObject::connect(axesPanel, &geopro::app::AxesSettingsPanel::verticalExaggerationChanged, &window,
[sceneCtrl, basemap](double ve) {
if (ve <= 0) return;
sceneCtrl->setVerticalExaggeration(ve);
basemap->setVerticalExaggeration(ve);
});
// ── 中央“空状态”引导浮层:未接入真实 sections 时,引导首次使用者从左侧入手。──
// 透明背景 + 鼠标穿透(不挡 QVTK 交互CenterOverlay 随视口尺寸保持居中;

View File

@ -256,7 +256,11 @@ void VtkSceneController::setAxesConfig(AxesMode mode, AxesUnit unit, const AxisR
axisX_ = x;
axisY_ = y;
axisZ_ = z;
rebuildInternal(); // 一次重建应用全部坐标轴设置
// 增量:坐标轴只是 overlay prop改单位/范围/可见性无需清场景重载数据。仅把配置下发 view 后
// renderIncrementalrebuildAxes 重建坐标轴 prop + Render不动数据图元、不重置相机。
view_.setAxes(axesMode_, axesUnit_, kAxesFontSize);
view_.setAxesRanges(axisX_, axisY_, axisZ_);
view_.renderIncremental();
}
// 快捷视图 / 缩放:仅改相机,不重建场景(无须取数/重装图元)。

View File

@ -94,10 +94,23 @@ vtkSmartPointer<vtkCubeAxesActor> buildAxes(const double bounds[6], const AxesOp
ax->SetZUnits(u);
}
// per-axis 显示开关(整轴:线 + 刻度 + 标签 + 标题)。
// per-axis 显示开关。SetXAxisVisibility 只关轴线,刻度数字/标签/刻度线需单独关,
// 否则隐藏某轴后该轴的数字仍悬浮在场景里(用户实测 bug
ax->SetXAxisVisibility(opts.x.visible);
ax->SetYAxisVisibility(opts.y.visible);
ax->SetZAxisVisibility(opts.z.visible);
if (!opts.x.visible) {
ax->SetXAxisLabelVisibility(false);
ax->SetXAxisTickVisibility(false);
}
if (!opts.y.visible) {
ax->SetYAxisLabelVisibility(false);
ax->SetYAxisTickVisibility(false);
}
if (!opts.z.visible) {
ax->SetZAxisLabelVisibility(false);
ax->SetZAxisTickVisibility(false);
}
applyFont(ax, opts.fontSize);
return ax;