feat(data): Repository 接口 + LocalSampleRepository(QFile 读中文路径)
- 新增 repo/RepoTypes.hpp(POD 项目结构树)、IDatasetRepository.hpp(同步接口) - LocalSampleRepository 用 QFile + QString::fromUtf8 读真实中文路径样本(UTF-8), 合成单 GS/TM/DS 树(DsNode.id=grid1),映射 grid/colorscale/scatter/anomaly 文件 - geopro_data 链 Qt6::Core(AUTOMOC OFF、无 Q_OBJECT);core 仍无 Qt 依赖 - 测试 geopro_tests 因链 Qt 需运行时 DLL 在旁:POST_BUILD 拷贝 TARGET_RUNTIME_DLLS + gtest DISCOVERY_MODE PRE_TEST(推迟枚举到运行期) - 新增 tests/data/test_local_repo.cpp:实测中文路径读取 + scatter 2597/anomaly 3 全链路
This commit is contained in:
parent
fe5936a3a6
commit
f48b9ebb8f
|
|
@ -1,6 +1,9 @@
|
||||||
find_package(nlohmann_json CONFIG REQUIRED)
|
find_package(nlohmann_json CONFIG REQUIRED)
|
||||||
add_library(geopro_data STATIC parse/SampleParsers.cpp)
|
find_package(Qt6 COMPONENTS Core REQUIRED)
|
||||||
|
add_library(geopro_data STATIC
|
||||||
|
parse/SampleParsers.cpp
|
||||||
|
repo/LocalSampleRepository.cpp)
|
||||||
target_include_directories(geopro_data PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(geopro_data PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_link_libraries(geopro_data PUBLIC geopro_core PRIVATE nlohmann_json::nlohmann_json)
|
target_link_libraries(geopro_data PUBLIC geopro_core Qt6::Core PRIVATE nlohmann_json::nlohmann_json)
|
||||||
target_compile_features(geopro_data PUBLIC cxx_std_17)
|
target_compile_features(geopro_data PUBLIC cxx_std_17)
|
||||||
set_target_properties(geopro_data PROPERTIES AUTOMOC OFF AUTOUIC OFF AUTORCC OFF)
|
set_target_properties(geopro_data PROPERTIES AUTOMOC OFF AUTOUIC OFF AUTORCC OFF)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "repo/RepoTypes.hpp"
|
||||||
|
#include "model/Field.hpp"
|
||||||
|
#include "model/ColorScale.hpp"
|
||||||
|
#include "model/Anomaly.hpp"
|
||||||
|
namespace geopro::data {
|
||||||
|
|
||||||
|
// 数据集仓储抽象(同步接口;异步加载留 M1.5)。
|
||||||
|
class IDatasetRepository {
|
||||||
|
public:
|
||||||
|
virtual ~IDatasetRepository() = default;
|
||||||
|
virtual std::vector<GsNode> loadStructure() = 0;
|
||||||
|
virtual geopro::core::Grid loadGrid(const std::string& dsId) = 0;
|
||||||
|
virtual geopro::core::ScatterField loadScatter(const std::string& dsId) = 0;
|
||||||
|
virtual geopro::core::ColorScale loadColorScale(const std::string& dsId) = 0;
|
||||||
|
virtual std::vector<geopro::core::Anomaly> loadAnomalies(const std::string& dsId) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geopro::data
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include "repo/LocalSampleRepository.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "parse/SampleParsers.hpp"
|
||||||
|
|
||||||
|
namespace geopro::data {
|
||||||
|
|
||||||
|
using namespace geopro::core;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// grid1 数据集对应的样本文件名(UTF-8 中文路径)。
|
||||||
|
constexpr const char* kDsId = "grid1";
|
||||||
|
constexpr const char* kGridFile = u8"剖面网格数据1.txt";
|
||||||
|
constexpr const char* kColorScaleFile = u8"剖面网格数据的色阶数据1.txt";
|
||||||
|
constexpr const char* kScatterFile = u8"剖面原数据1.txt";
|
||||||
|
constexpr const char* kAnomalyFile = u8"剖面网格数据1——对应的异常圈定数据.txt";
|
||||||
|
|
||||||
|
// 校验 dsId,未知则抛错(输入边界验证)。
|
||||||
|
void requireKnownDs(const std::string& dsId) {
|
||||||
|
if (dsId != kDsId) {
|
||||||
|
throw std::runtime_error("LocalSampleRepository: unknown dataset id '" + dsId + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
LocalSampleRepository::LocalSampleRepository(std::string sampleDirUtf8)
|
||||||
|
: dirUtf8_(std::move(sampleDirUtf8)) {}
|
||||||
|
|
||||||
|
std::string LocalSampleRepository::readFile(const std::string& fileNameUtf8) const {
|
||||||
|
// QString::fromUtf8 保证中文路径正确还原为宽字符,QFile 在 Windows 走宽字符 API。
|
||||||
|
const QString path =
|
||||||
|
QString::fromUtf8(dirUtf8_.c_str()) + QString::fromUtf8(fileNameUtf8.c_str());
|
||||||
|
QFile file(path);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
throw std::runtime_error("LocalSampleRepository: cannot open file '" +
|
||||||
|
path.toStdString() + "'");
|
||||||
|
}
|
||||||
|
const QByteArray ba = file.readAll();
|
||||||
|
return std::string(ba.constData(), static_cast<size_t>(ba.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<GsNode> LocalSampleRepository::loadStructure() {
|
||||||
|
DsNode ds;
|
||||||
|
ds.id = kDsId;
|
||||||
|
ds.name = u8"剖面网格数据1";
|
||||||
|
ds.ddType = "grid";
|
||||||
|
|
||||||
|
TmNode tm;
|
||||||
|
tm.id = "tm-ert1";
|
||||||
|
tm.name = "ERT1";
|
||||||
|
tm.confCode = "ERT";
|
||||||
|
tm.dss.push_back(std::move(ds));
|
||||||
|
|
||||||
|
GsNode gs;
|
||||||
|
gs.id = "gs-1";
|
||||||
|
gs.name = u8"测区";
|
||||||
|
gs.tms.push_back(std::move(tm));
|
||||||
|
|
||||||
|
std::vector<GsNode> out;
|
||||||
|
out.push_back(std::move(gs));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid LocalSampleRepository::loadGrid(const std::string& dsId) {
|
||||||
|
requireKnownDs(dsId);
|
||||||
|
return parseGrid(readFile(kGridFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
ScatterField LocalSampleRepository::loadScatter(const std::string& dsId) {
|
||||||
|
requireKnownDs(dsId);
|
||||||
|
return parseScatter(readFile(kScatterFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorScale LocalSampleRepository::loadColorScale(const std::string& dsId) {
|
||||||
|
requireKnownDs(dsId);
|
||||||
|
return parseColorScale(readFile(kColorScaleFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Anomaly> LocalSampleRepository::loadAnomalies(const std::string& dsId) {
|
||||||
|
requireKnownDs(dsId);
|
||||||
|
return parseAnomalies(readFile(kAnomalyFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geopro::data
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "repo/IDatasetRepository.hpp"
|
||||||
|
namespace geopro::data {
|
||||||
|
|
||||||
|
// 本地样本仓储:用 QFile 读真实中文路径样本文件(UTF-8),调对应 parser。
|
||||||
|
// 合成最小项目结构树:单 GS「测区」→ 单 TM「ERT1」→ 单 DS「grid1」。
|
||||||
|
// 注意:实现使用 Qt(QFile 正确处理中文路径),但本接口不含 Q_OBJECT,AUTOMOC OFF。
|
||||||
|
class LocalSampleRepository : public IDatasetRepository {
|
||||||
|
public:
|
||||||
|
explicit LocalSampleRepository(std::string sampleDirUtf8);
|
||||||
|
|
||||||
|
std::vector<GsNode> loadStructure() override;
|
||||||
|
geopro::core::Grid loadGrid(const std::string& dsId) override;
|
||||||
|
geopro::core::ScatterField loadScatter(const std::string& dsId) override;
|
||||||
|
geopro::core::ColorScale loadColorScale(const std::string& dsId) override;
|
||||||
|
std::vector<geopro::core::Anomaly> loadAnomalies(const std::string& dsId) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// 用 QFile(路径 = fromUtf8(dir)+fromUtf8(name))读全文件并转 UTF-8 std::string。
|
||||||
|
// 读失败抛 std::runtime_error。
|
||||||
|
std::string readFile(const std::string& fileNameUtf8) const;
|
||||||
|
|
||||||
|
std::string dirUtf8_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geopro::data
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
namespace geopro::data {
|
||||||
|
struct DsNode { std::string id, name, ddType; };
|
||||||
|
struct TmNode { std::string id, name, confCode; std::vector<DsNode> dss; };
|
||||||
|
struct GsNode { std::string id, name; std::vector<TmNode> tms; };
|
||||||
|
struct Project { std::string id, name; std::vector<GsNode> gss; };
|
||||||
|
} // namespace geopro::data
|
||||||
|
|
@ -13,12 +13,16 @@ include(GoogleTest)
|
||||||
file(GLOB _proj_data_dirs
|
file(GLOB _proj_data_dirs
|
||||||
"${CMAKE_BINARY_DIR}/vcpkg_installed/*/share/proj"
|
"${CMAKE_BINARY_DIR}/vcpkg_installed/*/share/proj"
|
||||||
)
|
)
|
||||||
|
# DISCOVERY_MODE PRE_TEST:把用例枚举推迟到 ctest 运行时执行,而非构建后立即跑
|
||||||
|
# exe。因 geopro_data 链 Qt6::Core,构建期发现会因 Qt6Core.dll 尚未拷贝到 exe 旁而
|
||||||
|
# 失败(0xc0000135);推迟到运行期时 POST_BUILD 已把运行时 DLL 拷到位。
|
||||||
if(_proj_data_dirs)
|
if(_proj_data_dirs)
|
||||||
list(GET _proj_data_dirs 0 GEOPRO_PROJ_DATA)
|
list(GET _proj_data_dirs 0 GEOPRO_PROJ_DATA)
|
||||||
gtest_discover_tests(geopro_tests
|
gtest_discover_tests(geopro_tests
|
||||||
|
DISCOVERY_MODE PRE_TEST
|
||||||
PROPERTIES ENVIRONMENT "PROJ_DATA=${GEOPRO_PROJ_DATA}")
|
PROPERTIES ENVIRONMENT "PROJ_DATA=${GEOPRO_PROJ_DATA}")
|
||||||
else()
|
else()
|
||||||
gtest_discover_tests(geopro_tests)
|
gtest_discover_tests(geopro_tests DISCOVERY_MODE PRE_TEST)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_sources(geopro_tests PRIVATE core/test_local_frame.cpp)
|
target_sources(geopro_tests PRIVATE core/test_local_frame.cpp)
|
||||||
|
|
@ -30,6 +34,16 @@ target_sources(geopro_tests PRIVATE core/test_model_data.cpp)
|
||||||
target_link_libraries(geopro_tests PRIVATE geopro_core)
|
target_link_libraries(geopro_tests PRIVATE geopro_core)
|
||||||
|
|
||||||
target_sources(geopro_tests PRIVATE data/test_parsers.cpp)
|
target_sources(geopro_tests PRIVATE data/test_parsers.cpp)
|
||||||
|
target_sources(geopro_tests PRIVATE data/test_local_repo.cpp)
|
||||||
target_link_libraries(geopro_tests PRIVATE geopro_data)
|
target_link_libraries(geopro_tests PRIVATE geopro_data)
|
||||||
|
|
||||||
|
# geopro_data 链 Qt6::Core,测试 exe 运行(含 gtest 发现)需要 Qt6Core.dll 等运行时
|
||||||
|
# DLL 在旁。复用 app 同样的 TARGET_RUNTIME_DLLS POST_BUILD 拷贝。
|
||||||
|
if(WIN32)
|
||||||
|
add_custom_command(TARGET geopro_tests POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
$<TARGET_RUNTIME_DLLS:geopro_tests> $<TARGET_FILE_DIR:geopro_tests>
|
||||||
|
COMMAND_EXPAND_LISTS)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(spike) # spike S3: banded contour 渲染验证
|
add_subdirectory(spike) # spike S3: banded contour 渲染验证
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "repo/LocalSampleRepository.hpp"
|
||||||
|
using namespace geopro::data;
|
||||||
|
using namespace geopro::core;
|
||||||
|
|
||||||
|
static const std::string kDir = "D:/Git/lanbingtech/geopro/docs/剖面网格数据的色阶数据2等文件/";
|
||||||
|
|
||||||
|
TEST(LocalRepo, StructureNonEmpty) {
|
||||||
|
LocalSampleRepository repo(kDir);
|
||||||
|
auto gs = repo.loadStructure();
|
||||||
|
ASSERT_FALSE(gs.empty());
|
||||||
|
ASSERT_FALSE(gs[0].tms.empty());
|
||||||
|
ASSERT_FALSE(gs[0].tms[0].dss.empty());
|
||||||
|
EXPECT_EQ(gs[0].tms[0].dss[0].id, "grid1");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LocalRepo, LoadGridScatterAnomaly) {
|
||||||
|
LocalSampleRepository repo(kDir);
|
||||||
|
Grid g = repo.loadGrid("grid1");
|
||||||
|
EXPECT_EQ(g.nx(), 100); EXPECT_EQ(g.ny(), 22);
|
||||||
|
ScatterField s = repo.loadScatter("grid1");
|
||||||
|
EXPECT_EQ(s.v.size(), 2597u);
|
||||||
|
auto an = repo.loadAnomalies("grid1");
|
||||||
|
EXPECT_EQ(an.size(), 3u);
|
||||||
|
EXPECT_EQ(an[0].markType, AnomalyMarkType::Polyline);
|
||||||
|
ColorScale cs = repo.loadColorScale("grid1");
|
||||||
|
EXPECT_FALSE(cs.empty());
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue