diff --git a/src/io/gpr/CMakeLists.txt b/src/io/gpr/CMakeLists.txt index eee22e7..15cf3fb 100644 --- a/src/io/gpr/CMakeLists.txt +++ b/src/io/gpr/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(geopro_io_gpr STATIC IprHeader.cpp IprbReader.cpp) +add_library(geopro_io_gpr STATIC IprHeader.cpp IprbReader.cpp GprGeometry.cpp) target_include_directories(geopro_io_gpr PUBLIC ${CMAKE_SOURCE_DIR}/src) target_compile_features(geopro_io_gpr PUBLIC cxx_std_17) diff --git a/src/io/gpr/GprGeometry.cpp b/src/io/gpr/GprGeometry.cpp new file mode 100644 index 0000000..b45b023 --- /dev/null +++ b/src/io/gpr/GprGeometry.cpp @@ -0,0 +1,33 @@ +#include "io/gpr/GprGeometry.hpp" + +#include +#include +#include + +namespace geopro::io::gpr { + +std::vector parseChannelXOffsets(const std::string& ordText) { + std::vector offsets; + std::istringstream lines(ordText); + std::string line; + while (std::getline(lines, line)) { + std::istringstream tok(line); + std::vector cols; + std::string col; + while (tok >> col) cols.push_back(col); + if (cols.size() < 4) continue; // 空行/列数不足,跳过 + if (cols.back() != "1") continue; // 末列==1 才是有效通道 + offsets.push_back(std::stod(cols[1])); + } + return offsets; +} + +double depthOfSample(int s, const IprHeader& h) { + if (h.samples <= 1) return 0.0; // 防除零 + const double timeNs = static_cast(s) * h.timeWindowNs / + static_cast(h.samples - 1); + const double timeSec = timeNs * 1e-9; + return h.soilVelocity * timeSec / 2.0; +} + +} // namespace geopro::io::gpr diff --git a/src/io/gpr/GprGeometry.hpp b/src/io/gpr/GprGeometry.hpp new file mode 100644 index 0000000..cabcecc --- /dev/null +++ b/src/io/gpr/GprGeometry.hpp @@ -0,0 +1,20 @@ +#ifndef GEOPRO_IO_GPR_GPRGEOMETRY_HPP +#define GEOPRO_IO_GPR_GPRGEOMETRY_HPP + +#include +#include + +#include "io/gpr/IprHeader.hpp" + +namespace geopro::io::gpr { + +// 解析 .ord 文本,返回末列==1 的有效通道的横向偏移(第 2 列),按文件顺序。 +std::vector parseChannelXOffsets(const std::string& ordText); + +// 采样序号 s → 深度(米)。depth = soilVelocity[m/s] * (s * timeWindowNs/(samples-1) * 1e-9) / 2。 +// samples<=1 时返回 0 防除零。 +double depthOfSample(int s, const IprHeader& h); + +} // namespace geopro::io::gpr + +#endif // GEOPRO_IO_GPR_GPRGEOMETRY_HPP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bd84fb5..8b381f8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -171,6 +171,7 @@ target_link_libraries(geopro_tests PRIVATE geopro_controller Qt6::Test) # io/gpr 层:.iprh 头解析 + .iprb B-scan 读取(纯 C++17,零 Qt/VTK)。 target_sources(geopro_tests PRIVATE io/gpr/test_ipr_header.cpp) target_sources(geopro_tests PRIVATE io/gpr/test_iprb_reader.cpp) +target_sources(geopro_tests PRIVATE io/gpr/test_gpr_geometry.cpp) target_link_libraries(geopro_tests PRIVATE geopro_io_gpr) add_subdirectory(spike) # spike S3: banded contour 渲染验证 diff --git a/tests/io/gpr/test_gpr_geometry.cpp b/tests/io/gpr/test_gpr_geometry.cpp new file mode 100644 index 0000000..51f9287 --- /dev/null +++ b/tests/io/gpr/test_gpr_geometry.cpp @@ -0,0 +1,21 @@ +#include "io/gpr/GprGeometry.hpp" +#include "io/gpr/IprHeader.hpp" +#include +using namespace geopro::io::gpr; + +TEST(GprGeometry, ParsesActiveChannelOffsets) { + const std::string ord = "0 -0.686000 -1.5 1\n1 -0.581000 -1.5 1\n14 0 -1.5 0\n"; + auto xs = parseChannelXOffsets(ord); + ASSERT_EQ(xs.size(), 2u); // 仅 2 个有效(末列=1) + EXPECT_NEAR(xs[0], -0.686, 1e-6); + EXPECT_NEAR(xs[1], -0.581, 1e-6); +} + +TEST(GprGeometry, DepthOfLastSampleMatchesPhysics) { + IprHeader h{}; + h.samples = 821; + h.timeWindowNs = 160.352; + h.soilVelocity = 1e8; // m/s + EXPECT_NEAR(depthOfSample(820, h), 8.0, 0.05); // ~8m + EXPECT_NEAR(depthOfSample(0, h), 0.0, 1e-9); +}