feat/vtk-3d-view #7
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 随视口尺寸保持居中;
|
||||
|
|
|
|||
|
|
@ -256,7 +256,11 @@ void VtkSceneController::setAxesConfig(AxesMode mode, AxesUnit unit, const AxisR
|
|||
axisX_ = x;
|
||||
axisY_ = y;
|
||||
axisZ_ = z;
|
||||
rebuildInternal(); // 一次重建应用全部坐标轴设置
|
||||
// 增量:坐标轴只是 overlay prop,改单位/范围/可见性无需清场景重载数据。仅把配置下发 view 后
|
||||
// renderIncremental(rebuildAxes 重建坐标轴 prop + Render),不动数据图元、不重置相机。
|
||||
view_.setAxes(axesMode_, axesUnit_, kAxesFontSize);
|
||||
view_.setAxesRanges(axisX_, axisY_, axisZ_);
|
||||
view_.renderIncremental();
|
||||
}
|
||||
|
||||
// 快捷视图 / 缩放:仅改相机,不重建场景(无须取数/重装图元)。
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue