feat/vtk-3d-view #7
|
|
@ -50,6 +50,7 @@ add_executable(geopro_desktop WIN32
|
||||||
panels/chart/ContourPlotItem.cpp
|
panels/chart/ContourPlotItem.cpp
|
||||||
panels/chart/LivePanner.cpp
|
panels/chart/LivePanner.cpp
|
||||||
panels/chart/ScatterHoverTip.cpp
|
panels/chart/ScatterHoverTip.cpp
|
||||||
|
panels/columns/Column3DDataset.cpp
|
||||||
panels/AnomalyTablePanel.cpp
|
panels/AnomalyTablePanel.cpp
|
||||||
panels/LoadingOverlay.cpp
|
panels/LoadingOverlay.cpp
|
||||||
panels/DatasetDetailPage.cpp
|
panels/DatasetDetailPage.cpp
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include "panels/columns/Column3DDataset.hpp"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QTreeWidget>
|
||||||
|
#include <QTreeWidgetItemIterator>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "Theme.hpp"
|
||||||
|
#include "panels/DatasetListPanel.hpp"
|
||||||
|
|
||||||
|
using geopro::controller::AxesMode;
|
||||||
|
using geopro::controller::AxesUnit;
|
||||||
|
using geopro::controller::ViewDir;
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
Column3DDataset::Column3DDataset(QWidget* parent) : QWidget(parent) {
|
||||||
|
auto* root = new QVBoxLayout(this);
|
||||||
|
root->setContentsMargins(space::kMd, space::kMd, space::kMd, space::kMd);
|
||||||
|
root->setSpacing(space::kMd);
|
||||||
|
|
||||||
|
// 坐标轴设置
|
||||||
|
{
|
||||||
|
auto* form = new QFormLayout();
|
||||||
|
auto* mode = new QComboBox();
|
||||||
|
mode->addItem(QStringLiteral("标准"), static_cast<int>(AxesMode::Standard));
|
||||||
|
mode->addItem(QStringLiteral("三维立体"), static_cast<int>(AxesMode::Stereo));
|
||||||
|
mode->addItem(QStringLiteral("不显示"), static_cast<int>(AxesMode::None));
|
||||||
|
connect(mode, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
|
[this, mode](int) { emit axesModeChanged(static_cast<AxesMode>(mode->currentData().toInt())); });
|
||||||
|
auto* oPoint = new QPushButton(QStringLiteral("设置…"));
|
||||||
|
connect(oPoint, &QPushButton::clicked, this, &Column3DDataset::oPointClicked);
|
||||||
|
auto* unit = new QComboBox();
|
||||||
|
unit->addItem(QStringLiteral("无刻度"), static_cast<int>(AxesUnit::None));
|
||||||
|
unit->addItem(QStringLiteral("米"), static_cast<int>(AxesUnit::Meter));
|
||||||
|
unit->addItem(QStringLiteral("英尺"), static_cast<int>(AxesUnit::Feet));
|
||||||
|
unit->addItem(QStringLiteral("经纬度"), static_cast<int>(AxesUnit::LatLon));
|
||||||
|
unit->setCurrentIndex(1);
|
||||||
|
connect(unit, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
|
[this, unit](int) { emit axesUnitChanged(static_cast<AxesUnit>(unit->currentData().toInt())); });
|
||||||
|
auto* font = new QPushButton(QStringLiteral("设置…"));
|
||||||
|
connect(font, &QPushButton::clicked, this, &Column3DDataset::fontClicked);
|
||||||
|
form->addRow(QStringLiteral("显示方式"), mode);
|
||||||
|
form->addRow(QStringLiteral("O点位置"), oPoint);
|
||||||
|
form->addRow(QStringLiteral("刻度"), unit);
|
||||||
|
form->addRow(QStringLiteral("字体"), font);
|
||||||
|
root->addWidget(new QLabel(QStringLiteral("坐标轴设置")));
|
||||||
|
root->addLayout(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 水平/垂直比例(单滑块 + 数值)
|
||||||
|
{
|
||||||
|
auto* row = new QHBoxLayout();
|
||||||
|
auto* slider = new QSlider(Qt::Horizontal);
|
||||||
|
slider->setMinimum(1);
|
||||||
|
slider->setMaximum(10);
|
||||||
|
slider->setValue(2);
|
||||||
|
auto* val = new QLabel(QStringLiteral("2.0\xc3\x97")); // ×
|
||||||
|
connect(slider, &QSlider::valueChanged, this, [this, val](int v) {
|
||||||
|
val->setText(QStringLiteral("%1.0\xc3\x97").arg(v));
|
||||||
|
emit verticalExaggerationChanged(static_cast<double>(v));
|
||||||
|
});
|
||||||
|
row->addWidget(slider, 1);
|
||||||
|
row->addWidget(val);
|
||||||
|
root->addWidget(new QLabel(QStringLiteral("水平/垂直比例")));
|
||||||
|
root->addLayout(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 快捷视图
|
||||||
|
{
|
||||||
|
auto* row = new QHBoxLayout();
|
||||||
|
struct V {
|
||||||
|
const char* t;
|
||||||
|
ViewDir d;
|
||||||
|
};
|
||||||
|
const V views[] = {
|
||||||
|
{"\xe5\x89\x8d", ViewDir::Front}, // 前
|
||||||
|
{"\xe5\x90\x8e", ViewDir::Back}, // 后
|
||||||
|
{"\xe5\xb7\xa6", ViewDir::Left}, // 左
|
||||||
|
{"\xe5\x8f\xb3", ViewDir::Right}, // 右
|
||||||
|
{"\xe4\xb8\x8a", ViewDir::Top}, // 上
|
||||||
|
{"\xe4\xb8\x8b", ViewDir::Bottom}, // 下
|
||||||
|
};
|
||||||
|
for (const V& v : views) {
|
||||||
|
auto* b = new QPushButton(QString::fromUtf8(v.t));
|
||||||
|
ViewDir d = v.d;
|
||||||
|
connect(b, &QPushButton::clicked, this, [this, d] { emit viewRequested(d); });
|
||||||
|
row->addWidget(b);
|
||||||
|
}
|
||||||
|
root->addWidget(new QLabel(QStringLiteral("快捷视图")));
|
||||||
|
root->addLayout(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缩放
|
||||||
|
{
|
||||||
|
auto* row = new QHBoxLayout();
|
||||||
|
auto* in = new QPushButton(QStringLiteral("放大"));
|
||||||
|
auto* out = new QPushButton(QStringLiteral("缩小"));
|
||||||
|
auto* fit = new QPushButton(QStringLiteral("适配"));
|
||||||
|
connect(in, &QPushButton::clicked, this, &Column3DDataset::zoomInRequested);
|
||||||
|
connect(out, &QPushButton::clicked, this, &Column3DDataset::zoomOutRequested);
|
||||||
|
connect(fit, &QPushButton::clicked, this, &Column3DDataset::fitRequested);
|
||||||
|
row->addWidget(in);
|
||||||
|
row->addWidget(out);
|
||||||
|
row->addWidget(fit);
|
||||||
|
root->addWidget(new QLabel(QStringLiteral("缩放")));
|
||||||
|
root->addLayout(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据集列表(可勾选)
|
||||||
|
list_ = new QTreeWidget();
|
||||||
|
list_->setHeaderHidden(true);
|
||||||
|
list_->setRootIsDecorated(true);
|
||||||
|
applyDatasetCardDelegate(list_);
|
||||||
|
connect(list_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem*, int) {
|
||||||
|
QStringList ids;
|
||||||
|
for (QTreeWidgetItemIterator it(list_); *it; ++it) {
|
||||||
|
if ((*it)->checkState(0) == Qt::Checked)
|
||||||
|
ids << (*it)->data(0, kDsIdRole).toString();
|
||||||
|
}
|
||||||
|
emit checkedDatasetsChanged(ids);
|
||||||
|
});
|
||||||
|
root->addWidget(list_, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Column3DDataset::setDatasets(const std::vector<geopro::data::DsRow>& rows) {
|
||||||
|
populateDatasetList(list_, rows, /*append=*/false);
|
||||||
|
for (QTreeWidgetItemIterator it(list_); *it; ++it) {
|
||||||
|
(*it)->setFlags((*it)->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
if ((*it)->checkState(0) != Qt::Checked)
|
||||||
|
(*it)->setCheckState(0, Qt::Unchecked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <vector>
|
||||||
|
#include "I3dSceneView.hpp" // AxesMode/AxesUnit/ViewDir
|
||||||
|
#include "repo/RepoTypes.hpp"
|
||||||
|
|
||||||
|
class QTreeWidget;
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
// 三维数据集栏:坐标轴设置 + 水平/垂直比例 + 快捷视图 + 缩放 + 3D 数据集列表。
|
||||||
|
class Column3DDataset : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Column3DDataset(QWidget* parent = nullptr);
|
||||||
|
void setDatasets(const std::vector<geopro::data::DsRow>& rows);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void axesModeChanged(geopro::controller::AxesMode mode);
|
||||||
|
void axesUnitChanged(geopro::controller::AxesUnit unit);
|
||||||
|
void verticalExaggerationChanged(double ve);
|
||||||
|
void viewRequested(geopro::controller::ViewDir dir);
|
||||||
|
void zoomInRequested();
|
||||||
|
void zoomOutRequested();
|
||||||
|
void fitRequested();
|
||||||
|
void oPointClicked();
|
||||||
|
void fontClicked();
|
||||||
|
void checkedDatasetsChanged(const QStringList& dsIds);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTreeWidget* list_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
Loading…
Reference in New Issue