feat/vtk-3d-view #7

Merged
gaozheng merged 301 commits from feat/vtk-3d-view into main 2026-06-27 18:43:52 +08:00
5 changed files with 135 additions and 14 deletions
Showing only changes of commit 98114a36e0 - Show all commits

View File

@ -82,6 +82,7 @@ add_executable(geopro_desktop WIN32
panels/columns/Column3DDataset.cpp panels/columns/Column3DDataset.cpp
panels/columns/Column3DAnalysis.cpp panels/columns/Column3DAnalysis.cpp
panels/columns/CategorySection.cpp panels/columns/CategorySection.cpp
panels/columns/CategoryAnalysisTab.cpp
panels/columns/ColumnDrawer.cpp panels/columns/ColumnDrawer.cpp
panels/AnomalyTablePanel.cpp panels/AnomalyTablePanel.cpp
panels/LoadingOverlay.cpp panels/LoadingOverlay.cpp

View File

@ -0,0 +1,67 @@
#include "panels/columns/CategoryAnalysisTab.hpp"
#include <QScrollArea>
#include <QVBoxLayout>
#include "Theme.hpp"
#include "panels/columns/CategorySection.hpp"
namespace geopro::app {
CategoryAnalysisTab::CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* dict, QWidget* parent)
: QWidget(parent) {
auto* outer = new QVBoxLayout(this);
outer->setContentsMargins(0, 0, 0, 0);
outer->setSpacing(0);
auto* scroll = new QScrollArea(this);
scroll->setWidgetResizable(true);
scroll->setFrameShape(QFrame::NoFrame);
outer->addWidget(scroll, 1);
auto* content = new QWidget(scroll);
auto* col = new QVBoxLayout(content);
col->setContentsMargins(0, 0, 0, 0);
col->setSpacing(space::kSm);
for (const CategorySpec& spec : categoryConfigs()) {
auto* sec = new CategorySection(spec, dict, content);
sections_[spec.id] = sec;
const std::string segId = spec.id;
connect(sec, &CategorySection::checkedDatasetsChanged, this,
[this, segId](const QStringList& ids) {
checkedBySeg_[segId] = ids;
recomputeCheckedUnion();
});
connect(sec, &CategorySection::generateVolumeRequested, this,
&CategoryAnalysisTab::generateVolumeRequested);
connect(sec, &CategorySection::detailRequested, this, &CategoryAnalysisTab::detailRequested);
col->addWidget(sec);
}
col->addStretch(1);
scroll->setWidget(content);
}
void CategoryAnalysisTab::setBuckets(const CategoryBuckets& b) {
const auto& cfg = categoryConfigs();
for (std::size_t i = 0; i < cfg.size() && i < b.segments.size(); ++i) {
if (auto* sec = section(cfg[i].id)) sec->setDatasets(b.segments[i]);
}
}
void CategoryAnalysisTab::setStructure(const std::vector<geopro::data::StructNode>& nodes) {
for (auto& [id, sec] : sections_) sec->setStructure(nodes);
}
CategorySection* CategoryAnalysisTab::section(const std::string& id) const {
const auto it = sections_.find(id);
return it != sections_.end() ? it->second : nullptr;
}
void CategoryAnalysisTab::recomputeCheckedUnion() {
QStringList all; // ds 归属唯一段,跨段不重复,直接拼接
for (const auto& [id, ids] : checkedBySeg_) all += ids;
emit checkedDatasetsChanged(all);
}
} // namespace geopro::app

View File

@ -0,0 +1,41 @@
#pragma once
#include <QStringList>
#include <QWidget>
#include <map>
#include <string>
#include <vector>
#include "DatasetCategory.hpp" // CategoryBuckets
#include "repo/RepoTypes.hpp"
namespace geopro::data {
class DatasetFieldDictionary;
}
namespace geopro::app {
class CategorySection;
// 「三维分析」tabQScrollArea 竖向堆叠 5 个数据类型大类段spec §4
// 各段勾选合并为并集上抛;生成/详情请求透传。
class CategoryAnalysisTab : public QWidget {
Q_OBJECT
public:
explicit CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* dict, QWidget* parent = nullptr);
void setBuckets(const CategoryBuckets& b); // 分发到 5 段(与 categoryConfigs 同序)
void setStructure(const std::vector<geopro::data::StructNode>& nodes); // 转发各段
CategorySection* section(const std::string& id) const; // 按 CategorySpec.id 取段
signals:
void checkedDatasetsChanged(const QStringList& dsIds); // 5 段勾选并集
void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds);
void detailRequested(const QString& dsId, const QString& ddCode, const QString& name);
private:
void recomputeCheckedUnion();
std::map<std::string, CategorySection*> sections_;
std::map<std::string, QStringList> checkedBySeg_; // 各段当前勾选(合并成并集)
};
} // namespace geopro::app

View File

@ -2,6 +2,7 @@
#include "panels/columns/Column3DDataset.hpp" #include "panels/columns/Column3DDataset.hpp"
#include "panels/columns/Column2DDataset.hpp" #include "panels/columns/Column2DDataset.hpp"
#include "panels/columns/Column3DAnalysis.hpp" #include "panels/columns/Column3DAnalysis.hpp"
#include "panels/columns/CategoryAnalysisTab.hpp"
#include "Glyphs.hpp" #include "Glyphs.hpp"
#include "Theme.hpp" #include "Theme.hpp"
#include <QHBoxLayout> #include <QHBoxLayout>
@ -10,20 +11,22 @@
namespace geopro::app { namespace geopro::app {
ColumnDrawer::ColumnDrawer(QWidget* parent) ColumnDrawer::ColumnDrawer(QWidget* parent, geopro::data::DatasetFieldDictionary* dict)
: QWidget(parent) : QWidget(parent)
{ {
// 创建三个栏
col3D_ = new Column3DDataset(this);
col2D_ = new Column2DDataset(this); col2D_ = new Column2DDataset(this);
analysisTab_ = new CategoryAnalysisTab(dict, this);
// 过渡:旧三维数据集/三维分析栏仍实例化以兼容 main 现有接线,但隐藏、不入 tabTask 12 退役)。
col3D_ = new Column3DDataset(this);
colAnalysis_ = new Column3DAnalysis(this); colAnalysis_ = new Column3DAnalysis(this);
col3D_->hide();
colAnalysis_->hide();
// Tab 容器body_ // Tab 容器body_:两 tab三维分析[分段] / 二维分析)。
auto* tabs = new QTabWidget(this); auto* tabs = new QTabWidget(this);
body_ = tabs; body_ = tabs;
tabs->addTab(col3D_, QStringLiteral("三维数据集")); tabs->addTab(analysisTab_, QStringLiteral("三维分析"));
tabs->addTab(col2D_, QStringLiteral("二维数据集")); tabs->addTab(col2D_, QStringLiteral("二维分析"));
tabs->addTab(colAnalysis_, QStringLiteral("三维分析"));
// 折叠按钮:固定宽 18px垂直拉伸。 // 折叠按钮:固定宽 18px垂直拉伸。
// 用 SVG 图标(makeGlyph)而非 ◀/▶ 文字——三角符(U+25C0/25B6)不在 YaHei作按钮文字会触发 // 用 SVG 图标(makeGlyph)而非 ◀/▶ 文字——三角符(U+25C0/25B6)不在 YaHei作按钮文字会触发

View File

@ -3,30 +3,39 @@
class QPushButton; class QPushButton;
namespace geopro::data {
class DatasetFieldDictionary;
}
namespace geopro::app { namespace geopro::app {
class Column3DDataset; class Column3DDataset;
class Column2DDataset; class Column2DDataset;
class Column3DAnalysis; class Column3DAnalysis;
class CategoryAnalysisTab;
// VTK视图左侧内嵌抽屉三 tab(三维数据集/二维数据集/三维分析) + 折叠开关。 // VTK视图左侧内嵌抽屉两 tab(三维分析[按数据类型分段]/二维分析) + 折叠开关。
// 旧 col3D_/colAnalysis_ 仍实例化但隐藏(不入 tab保留访问器供 main 现有接线过渡Task 12 退役。
class ColumnDrawer : public QWidget { class ColumnDrawer : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit ColumnDrawer(QWidget* parent = nullptr); explicit ColumnDrawer(QWidget* parent = nullptr,
geopro::data::DatasetFieldDictionary* dict = nullptr);
Column3DDataset* col3D() const { return col3D_; } Column3DDataset* col3D() const { return col3D_; } // 【过渡Task 12 删】
Column2DDataset* col2D() const { return col2D_; } Column2DDataset* col2D() const { return col2D_; }
Column3DAnalysis* colAnalysis() const { return colAnalysis_; } Column3DAnalysis* colAnalysis() const { return colAnalysis_; } // 【过渡Task 12 删】
CategoryAnalysisTab* analysisTab() const { return analysisTab_; }
public slots: public slots:
void toggleCollapsed(); void toggleCollapsed();
void expand(); // 强制展开(进入全屏时确保三栏可见) void expand(); // 强制展开(进入全屏时确保三栏可见)
private: private:
Column3DDataset* col3D_ = nullptr; Column3DDataset* col3D_ = nullptr; // 【过渡,隐藏不入 tabTask 12 删】
Column2DDataset* col2D_ = nullptr; Column2DDataset* col2D_ = nullptr;
Column3DAnalysis* colAnalysis_ = nullptr; Column3DAnalysis* colAnalysis_ = nullptr; // 【过渡,隐藏不入 tabTask 12 删】
CategoryAnalysisTab* analysisTab_ = nullptr;
QWidget* body_ = nullptr; // QTabWidget折叠时隐藏 QWidget* body_ = nullptr; // QTabWidget折叠时隐藏
QPushButton* toggleBtn_ = nullptr; QPushButton* toggleBtn_ = nullptr;
bool collapsed_ = false; bool collapsed_ = false;