feat/vtk-3d-view #7
|
|
@ -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})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
Loading…
Reference in New Issue