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
6 changed files with 120 additions and 0 deletions
Showing only changes of commit 07cf75d967 - Show all commits

View File

@ -107,6 +107,7 @@ add_executable(geopro_desktop WIN32
VolumePropertiesDialog.cpp
Logging.cpp
DatasetDimension.cpp
DatasetCategory.cpp
TileBasemap.cpp)
target_include_directories(geopro_desktop PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -0,0 +1,22 @@
#include "DatasetCategory.hpp"
namespace geopro::app {
CategoryBuckets splitByCategory(const std::vector<geopro::data::DsRow>& rows) {
const auto& cfg = categoryConfigs();
CategoryBuckets b;
b.segments.resize(cfg.size());
for (const auto& r : rows) {
int hit = -1;
// 先按 ddCode三维体/切片)——它们无 dsTypeCode来自 Api3dRepository mock 行)。
for (std::size_t i = 0; i < cfg.size() && hit < 0; ++i)
if (!cfg[i].ddCode.empty() && r.ddCode == cfg[i].ddCode) hit = static_cast<int>(i);
// 再按 dsTypeCode。
for (std::size_t i = 0; i < cfg.size() && hit < 0; ++i)
if (!cfg[i].dsTypeCode.empty() && r.dsTypeCode == cfg[i].dsTypeCode) hit = static_cast<int>(i);
if (hit >= 0) b.segments[static_cast<std::size_t>(hit)].push_back(r);
}
return b;
}
} // namespace geopro::app

View File

@ -0,0 +1,16 @@
#pragma once
#include <vector>
#include "repo/CategoryConfig.hpp"
#include "repo/RepoTypes.hpp"
namespace geopro::app {
struct CategoryBuckets {
std::vector<std::vector<geopro::data::DsRow>> segments; // 与 categoryConfigs() 同序同长
};
// 按 CategoryConfig 把 ds 分入大类段:先判 ddCode 白名单(三维体/切片),否则按 dsTypeCode 匹配;
// 不在表内的丢弃(接地电阻/原始数据/白化/坐标等)。保留原顺序。
CategoryBuckets splitByCategory(const std::vector<geopro::data::DsRow>& rows);
} // namespace geopro::app

View File

@ -0,0 +1,29 @@
#pragma once
#include <string>
#include <vector>
namespace geopro::app {
// 一个数据类型大类段的配置spec §5。识别键二选一dsTypeCode 优先ddCode 用于三维体/切片。
struct CategorySpec {
std::string id; // 段稳定 id
std::string title; // 段标题UI 显示)
std::string dsTypeCode; // 主识别键(空=不按 dsTypeCode
std::string ddCode; // 次识别键dd_voxel/dd_slice空=不按 ddCode
bool canGenerateVolume; // 段内是否提供「生成三维体」入口(仅反演类)
bool hasArrayTypeFilter; // 段头是否显示装置类型筛选(仅 ERT 类)
};
// 5 段固定有序spec §5 表)。
inline const std::vector<CategorySpec>& categoryConfigs() {
static const std::vector<CategorySpec> kCfg = {
{"resistivity", "电阻率数据", "ERT platform inversion data", "", true, true},
{"apparent", "视电阻率数据", "visual resistivity data", "", true, true},
{"transient", "瞬变电磁数据", "DD TRANSIENT ELECTROMAGNETIC INVERSION", "", true, false},
{"voxel", "三维体", "", "dd_voxel", false, false},
{"slice", "切片", "", "dd_slice", false, false},
};
return kCfg;
}
} // namespace geopro::app

View File

@ -168,6 +168,11 @@ target_sources(geopro_tests PRIVATE
app/test_dataset_dimension.cpp
${CMAKE_SOURCE_DIR}/src/app/DatasetDimension.cpp
)
# splitByCategory: dsTypeCode/ddCode -> 5 Qt/VTK
target_sources(geopro_tests PRIVATE
app/test_dataset_category.cpp
${CMAKE_SOURCE_DIR}/src/app/DatasetCategory.cpp
)
# measurement / id / / Qt6::Core JSON + core model
target_sources(geopro_tests PRIVATE
app/test_scatter_data_ops.cpp

View File

@ -0,0 +1,47 @@
#include <gtest/gtest.h>
#include "DatasetCategory.hpp"
using geopro::data::DsRow;
using namespace geopro::app;
namespace {
DsRow row(const std::string& id, const std::string& ddCode, const std::string& dsTypeCode) {
DsRow r;
r.id = id;
r.ddCode = ddCode;
r.dsTypeCode = dsTypeCode;
return r;
}
} // namespace
TEST(SplitByCategory, RoutesByDsTypeCodeAndDdCode) {
std::vector<DsRow> rows = {
row("a", "dd_inversion_data", "ERT platform inversion data"), // 电阻率
row("b", "dd_inversion_data", "visual resistivity data"), // 视电阻率
row("c", "dd_inversion_data", "DD TRANSIENT ELECTROMAGNETIC INVERSION"), // 瞬变
row("v", "dd_voxel", ""), // 三维体(按 ddCode)
row("s", "dd_slice", ""), // 切片(按 ddCode)
row("x", "dd_ert_measurement_gr_data", "earth resistance"), // 接地电阻 → 丢弃
};
const CategoryBuckets b = splitByCategory(rows);
ASSERT_EQ(b.segments.size(), categoryConfigs().size());
EXPECT_EQ(b.segments[0].size(), 1u); EXPECT_EQ(b.segments[0][0].id, "a");
EXPECT_EQ(b.segments[1].size(), 1u); EXPECT_EQ(b.segments[1][0].id, "b");
EXPECT_EQ(b.segments[2].size(), 1u); EXPECT_EQ(b.segments[2][0].id, "c");
EXPECT_EQ(b.segments[3].size(), 1u); EXPECT_EQ(b.segments[3][0].id, "v");
EXPECT_EQ(b.segments[4].size(), 1u); EXPECT_EQ(b.segments[4][0].id, "s");
// 接地电阻不进任何段。
std::size_t total = 0;
for (auto& s : b.segments) total += s.size();
EXPECT_EQ(total, 5u);
}
TEST(SplitByCategory, PreservesOrderWithinSegment) {
std::vector<DsRow> rows = {
row("a1", "dd_inversion_data", "ERT platform inversion data"),
row("a2", "dd_inversion_data", "ERT platform inversion data"),
};
const CategoryBuckets b = splitByCategory(rows);
ASSERT_EQ(b.segments[0].size(), 2u);
EXPECT_EQ(b.segments[0][0].id, "a1");
EXPECT_EQ(b.segments[0][1].id, "a2");
}