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
7 changed files with 51 additions and 12 deletions
Showing only changes of commit b9a655126f - Show all commits

View File

@ -140,6 +140,7 @@
#include "panels/columns/CategorySection.hpp" #include "panels/columns/CategorySection.hpp"
#include "VtkViewToolbar.hpp" #include "VtkViewToolbar.hpp"
#include "AxesSettingsDialog.hpp" #include "AxesSettingsDialog.hpp"
#include "repo/DatasetFieldDictionary.hpp"
#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"
@ -363,8 +364,21 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
{{geopro::app::Glyph::Fullscreen, QStringLiteral("全屏")}}); {{geopro::app::Glyph::Fullscreen, QStringLiteral("全屏")}});
// 左侧内嵌三栏抽屉(自带折叠按钮)+ 右侧 GL 画布,水平并列(非 GL 覆盖层,避免 z-order/圆角伪影)。 // 左侧内嵌三栏抽屉(自带折叠按钮)+ 右侧 GL 画布,水平并列(非 GL 覆盖层,避免 z-order/圆角伪影)。
auto* drawer = new geopro::app::ColumnDrawer(centerWidget); auto* fieldDict = new geopro::data::DatasetFieldDictionary(); // 进程级ColumnDrawer/段持非拥有指针
auto* drawer = new geopro::app::ColumnDrawer(centerWidget, fieldDict);
auto* viewToolbar = new geopro::app::VtkViewToolbar(centerWidget); // VTK 画布全局视图控制竖排工具条 auto* viewToolbar = new geopro::app::VtkViewToolbar(centerWidget); // VTK 画布全局视图控制竖排工具条
// 拉装置类型枚举(全局,登录后一次)→ 填字典;电阻率/视电阻率段装置下拉据此显示 + 过滤spec §6/§10
cmdRepo.listArrayTypes([fieldDict](bool ok, QJsonArray list, QString) {
if (!ok) return;
std::map<std::string, std::string> e;
for (const auto& v : list) {
const QJsonObject o = v.toObject();
const std::string iv =
o.value(QStringLiteral("itemValue")).toVariant().toString().toStdString();
if (!iv.empty()) e[iv] = o.value(QStringLiteral("name")).toString().toStdString();
}
fieldDict->setArrayTypeEnum(std::move(e));
});
auto* viewRow = new QHBoxLayout(); auto* viewRow = new QHBoxLayout();
viewRow->setContentsMargins(0, 0, 0, 0); viewRow->setContentsMargins(0, 0, 0, 0);
viewRow->setSpacing(0); viewRow->setSpacing(0);

View File

@ -108,14 +108,19 @@ void CategorySection::refreshArrayCombo() {
const QSignalBlocker block(arrayCombo_); const QSignalBlocker block(arrayCombo_);
arrayCombo_->clear(); arrayCombo_->clear();
arrayCombo_->addItem(QStringLiteral("全部装置"), QString()); arrayCombo_->addItem(QStringLiteral("全部装置"), QString());
const DsTypeFields* f = dict_ ? dict_->fields(spec_.dsTypeCode) : nullptr; if (dict_) {
if (f) { const auto& en = dict_->arrayTypeEnum(); // 全局装置枚举 itemValue→中文
QSet<QString> seen; QSet<QString> seen;
// 列出当前数据里出现过、且命中枚举的装置值 → 中文名。
for (const auto& r : rows_) { for (const auto& r : rows_) {
const QString val = QString::fromStdString(arrayValueOf(r, *f)); for (const auto& kv : r.properties) {
if (val.isEmpty() || seen.contains(val)) continue; const auto it = en.find(kv.value);
if (it == en.end()) continue; // 非装置类型值
const QString val = QString::fromStdString(kv.value);
if (seen.contains(val)) continue;
seen.insert(val); seen.insert(val);
arrayCombo_->addItem(QString::fromStdString(arrayLabel(*f, val.toStdString())), val); arrayCombo_->addItem(QString::fromStdString(it->second), val);
}
} }
} }
const int idx = arrayCombo_->findData(prev); // 尽量保留上次选择 const int idx = arrayCombo_->findData(prev); // 尽量保留上次选择
@ -123,17 +128,19 @@ void CategorySection::refreshArrayCombo() {
} }
bool CategorySection::passesFilters(const DsRow& row) const { bool CategorySection::passesFilters(const DsRow& row) const {
const DsTypeFields* f = dict_ ? dict_->fields(spec_.dsTypeCode) : nullptr; // 装置类型筛选(全局枚举;"全部"=空不筛ds.properties 任一 value 命中选中 itemValue。
// 装置类型筛选(仅 ERT 类;"全部"=空 value 不筛)。
if (spec_.hasArrayTypeFilter && arrayCombo_) { if (spec_.hasArrayTypeFilter && arrayCombo_) {
const QString sel = arrayCombo_->currentData().toString(); const QString sel = arrayCombo_->currentData().toString();
if (!sel.isEmpty()) { if (!sel.isEmpty()) {
const QString val = f ? QString::fromStdString(arrayValueOf(row, *f)) : QString(); bool hit = false;
if (val != sel) return false; for (const auto& kv : row.properties)
if (QString::fromStdString(kv.value) == sel) { hit = true; break; }
if (!hit) return false;
} }
} }
// 采集时间下限collectTime 回退 createTime最小日期=不限)。 // 采集时间下限collectTime 经 dict 取;缺则回退 createTime最小日期=不限)。
if (fromDate_ && fromDate_->date() > fromDate_->minimumDate()) { if (fromDate_ && fromDate_->date() > fromDate_->minimumDate()) {
const DsTypeFields* f = dict_ ? dict_->fields(spec_.dsTypeCode) : nullptr;
std::string ts = f ? collectTimeOf(row, *f) : std::string(); std::string ts = f ? collectTimeOf(row, *f) : std::string();
if (ts.empty()) ts = row.createTime; if (ts.empty()) ts = row.createTime;
const QDate d = QDate::fromString(QString::fromStdString(ts).left(10), QStringLiteral("yyyy-MM-dd")); const QDate d = QDate::fromString(QString::fromStdString(ts).left(10), QStringLiteral("yyyy-MM-dd"));

View File

@ -387,6 +387,11 @@ void ApiDatasetCommandRepository::listExceptionTypes(
std::move(cb)); std::move(cb));
} }
void ApiDatasetCommandRepository::listArrayTypes(
std::function<void(bool, QJsonArray, QString)> cb) {
wireArray(api_.getAsync(QStringLiteral("/business/script/arrayTypeList")), std::move(cb));
}
void ApiDatasetCommandRepository::getExceptionName( void ApiDatasetCommandRepository::getExceptionName(
const QString& exceptionTypeId, const QString& remarkSourceId, const QString& exceptionTypeId, const QString& remarkSourceId,
std::function<void(bool, QString, QString)> cb) { std::function<void(bool, QString, QString)> cb) {

View File

@ -81,6 +81,7 @@ public:
void listExceptionTypes( void listExceptionTypes(
const QString& projectId, const QString& remarkSourceType, const QString& projectId, const QString& remarkSourceType,
std::function<void(bool ok, QJsonArray list, QString msg)> cb) override; std::function<void(bool ok, QJsonArray list, QString msg)> cb) override;
void listArrayTypes(std::function<void(bool ok, QJsonArray list, QString msg)> cb) override;
void getExceptionName( void getExceptionName(
const QString& exceptionTypeId, const QString& remarkSourceId, const QString& exceptionTypeId, const QString& remarkSourceId,
std::function<void(bool ok, QString name, QString msg)> cb) override; std::function<void(bool ok, QString name, QString msg)> cb) override;

View File

@ -57,4 +57,8 @@ const DsTypeFields* DatasetFieldDictionary::fields(const std::string& dsTypeCode
return it != byType_.end() ? &it->second : nullptr; return it != byType_.end() ? &it->second : nullptr;
} }
void DatasetFieldDictionary::setArrayTypeEnum(std::map<std::string, std::string> e) {
arrayTypeEnum_ = std::move(e);
}
} // namespace geopro::data } // namespace geopro::data

View File

@ -33,8 +33,13 @@ public:
bool has(const std::string& dsTypeCode) const; // 是否已缓存该 dsType 映射 bool has(const std::string& dsTypeCode) const; // 是否已缓存该 dsType 映射
const DsTypeFields* fields(const std::string& dsTypeCode) const; // 未缓存=nullptr const DsTypeFields* fields(const std::string& dsTypeCode) const; // 未缓存=nullptr
// 全局装置类型枚举GET script/arrayTypeList → itemValue→中文名所有 ERT 类共用spec §6 装置筛选)。
void setArrayTypeEnum(std::map<std::string, std::string> e);
const std::map<std::string, std::string>& arrayTypeEnum() const { return arrayTypeEnum_; }
private: private:
std::map<std::string, DsTypeFields> byType_; std::map<std::string, DsTypeFields> byType_;
std::map<std::string, std::string> arrayTypeEnum_; // itemValue → 中文名
}; };
} // namespace geopro::data } // namespace geopro::data

View File

@ -167,6 +167,9 @@ public:
const QString& projectId, const QString& remarkSourceType, const QString& projectId, const QString& remarkSourceType,
std::function<void(bool ok, QJsonArray list, QString msg)> cb) = 0; std::function<void(bool ok, QJsonArray list, QString msg)> cb) = 0;
// 装置类型枚举GET /business/script/arrayTypeList → [{itemValue,name}](电阻率/视电阻率段装置筛选用)。
virtual void listArrayTypes(std::function<void(bool ok, QJsonArray list, QString msg)> cb) = 0;
// 获取异常名称POST /business/exception/getExceptionName // 获取异常名称POST /business/exception/getExceptionName
// body {exceptionTypeId, remarkSourceId}(对应原版 queryExceptionNameInProfileInversion // body {exceptionTypeId, remarkSourceId}(对应原版 queryExceptionNameInProfileInversion
// 原版 res.data 是「纯字符串」(建议名称本身),故回调直接回传 name 字符串。 // 原版 res.data 是「纯字符串」(建议名称本身),故回调直接回传 name 字符串。