geopro/tests/io/gpr/test_normalized_radar_bridg...

99 lines
4.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <gtest/gtest.h>
#include <clocale>
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <string>
#include "core/algo/GprVolumeBuilder.hpp"
#include "io/gpr/NormalizedRadarVolumeBridge.hpp"
#ifdef _WIN32
#include <windows.h>
#endif
namespace fs = std::filesystem;
namespace {
// 在指定目录写出一组最小可解析的规范化 .head/.dataK=4 道 M=2 通道 N=3 采样)。
void writeMinimalLine(const fs::path& head, const fs::path& data) {
{ std::ofstream f(head);
f << "SAMPLES:3\nNUMBER_OF_CH:2\nLAST_TRACE:8\nBITS:16\nENDIAN_TYPE:1\n"
"DISTANCE_INTERVAL:0.1\nTIMEWINDOW:30\nDIELECTRIC:9\n"; }
{ std::ofstream f(data, std::ios::binary);
for (int t = 0; t < 4; ++t) for (int c = 0; c < 2; ++c) for (int s = 0; s < 3; ++s) {
std::int16_t v = static_cast<std::int16_t>(t * 10 + c * 100 + s);
f.write(reinterpret_cast<const char*>(&v), 2); } }
}
} // namespace
TEST(NormalizedRadarBridge, BuildsVolumeWithExpectedAxes) {
// K=4 道, M=2 通道, N=3 采样, 无通道偏移(不插值), coarse=1。
fs::path dir = fs::temp_directory_path() / "radar_bridge_test";
fs::create_directories(dir);
{ std::ofstream f(dir / "L.head");
f << "SAMPLES:3\nNUMBER_OF_CH:2\nLAST_TRACE:8\nBITS:16\nENDIAN_TYPE:1\n"
"DISTANCE_INTERVAL:0.1\nTIMEWINDOW:30\nDIELECTRIC:9\n"; }
{ std::ofstream f(dir / "L.data", std::ios::binary);
for (int t = 0; t < 4; ++t) for (int c = 0; c < 2; ++c) for (int s = 0; s < 3; ++s) {
std::int16_t v = static_cast<std::int16_t>(t * 10 + c * 100 + s);
f.write(reinterpret_cast<const char*>(&v), 2); } }
const auto b = geopro::io::gpr::buildLineVolumeFromNormalized(
(dir).string(), "L", /*coarse=*/1, /*targetDy=*/0.0); // targetDy=0 不插值
EXPECT_EQ(b.vol.nx(), 4); // 道
EXPECT_EQ(b.vol.ny(), 2); // 通道
EXPECT_EQ(b.vol.nz(), 3); // 采样
EXPECT_DOUBLE_EQ(b.spacing[0], 0.1); // dx=DISTANCE_INTERVAL
EXPECT_GT(b.spacing[2], 0.0); // dz 由 timewindow/dielectric 求得 >0
EXPECT_NEAR(b.quant.toPhys(b.vol.at(3, 1, 2)), 132.0, b.quant.scale); // t3c1s2=30+100+2
}
// 回归中文目录路径必须能打开渲染。app 传入的是 QString::toLocal8Bit(),即当前
// ANSI 代码页(简中=GBK)窄字节。关键复现条件——GUI app 链接 QWebEngine(Chromium)/VTK
// 它们在启动时 setlocale(LC_ALL,"") 把 LC_CTYPE 提升为系统 UTF-8 locale此后窄字符
// ifstream 会把 GBK 路径字节当 UTF-8 解析 → open 失败(即"打开 .head 失败")。
// 故本测试显式置 UTF-8 locale 复现该失败面,走宽字符打开(见 io/gpr/LocalPath)守护回归。
// (纯 "C" locale 下 UCRT 用 CP_ACP=GBK 解窄路径,反而不失败,无法复现——须置 UTF-8。)
TEST(NormalizedRadarBridge, OpensCjkDirectoryPathUnderUtf8Locale) {
#ifdef _WIN32
const std::wstring wname = L"radar_cjk_南同大道";
const fs::path dir = fs::temp_directory_path() / wname;
fs::remove_all(dir);
fs::create_directories(dir);
writeMinimalLine(dir / L"南同大道_000.head", dir / L"南同大道_000.data");
// 模拟 app宽字符 → 当前 ANSI 代码页(GBK)窄字节,等价 QString::toLocal8Bit()。
auto toAcp = [](const std::wstring& w) {
const int n = ::WideCharToMultiByte(CP_ACP, 0, w.data(),
static_cast<int>(w.size()), nullptr, 0,
nullptr, nullptr);
std::string s(static_cast<std::size_t>(n), '\0');
::WideCharToMultiByte(CP_ACP, 0, w.data(), static_cast<int>(w.size()),
s.data(), n, nullptr, nullptr);
return s;
};
const std::string dirAcp = toAcp(dir.wstring());
const std::string prefixAcp = toAcp(L"南同大道_000");
// 复现 app 运行期的 UTF-8 C locale(QWebEngine/VTK 所置)——不修复则 narrow open 失败。
const char* prevC = std::setlocale(LC_ALL, nullptr);
const std::string savedC = prevC ? prevC : "C";
std::setlocale(LC_ALL, ".UTF-8");
geopro::core::BuiltI16 b;
try {
b = geopro::io::gpr::buildLineVolumeFromNormalized(
dirAcp, prefixAcp, /*coarse=*/1, /*targetDy=*/0.0);
} catch (...) {
std::setlocale(LC_ALL, savedC.c_str());
fs::remove_all(dir);
throw; // 未修复时会在此抛"打开 .head 失败"→ 测试红,正是回归守护
}
std::setlocale(LC_ALL, savedC.c_str());
EXPECT_EQ(b.vol.nx(), 4);
EXPECT_EQ(b.vol.ny(), 2);
EXPECT_EQ(b.vol.nz(), 3);
fs::remove_all(dir);
#else
GTEST_SKIP() << "中文窄路径打开问题仅 Windows 相关";
#endif
}