#include "io/gpr/GprSurveyAssembler.hpp" #include #include #include #include #include #include #include "io/gpr/GprGeometry.hpp" #include "io/gpr/IprHeader.hpp" #include "io/gpr/IprbReader.hpp" #include "io/gpr/LocalPath.hpp" namespace geopro::io::gpr { namespace { // 把 .iprb 路径的扩展名替换为 .iprh(取最后一个 '.' 之后)。 std::string toHeaderPath(const std::string& iprbPath) { const std::size_t dot = iprbPath.find_last_of('.'); const std::size_t slash = iprbPath.find_last_of("/\\"); // 仅当 '.' 在最后一个路径分隔符之后才视为扩展名。 if (dot != std::string::npos && (slash == std::string::npos || dot > slash)) { return iprbPath.substr(0, dot) + ".iprh"; } return iprbPath + ".iprh"; } std::string readFileText(const std::string& path) { std::ifstream f(localPath(path), std::ios::binary); if (!f) { throw std::runtime_error("无法打开文件: " + path); } std::ostringstream ss; ss << f.rdbuf(); return ss.str(); } // 由各通道 .ord 横偏、header、已读 BScan 段装配 GprSurvey。 // scans 已是待装配的道段(全线或 slab);ntraces 取各通道段道数最小值(对齐); // x0 由调用方给出(全线=0,slab=t0*dx)。samples 校验、Y 升序置换、值转置同源。 geopro::core::GprSurvey assembleFromScans(const std::vector& channelY0, const std::vector& headers, const std::vector& scans, double x0) { const std::size_t nchan = scans.size(); const int samples = scans.front().samples; std::int64_t minTraces = scans.front().traces; for (std::size_t c = 0; c < nchan; ++c) { if (scans[c].samples != samples) { throw std::runtime_error("通道 samples 不一致"); } minTraces = std::min(minTraces, scans[c].traces); } geopro::core::GprSurvey survey; survey.samples = samples; survey.ntraces = static_cast(minTraces); survey.x0 = x0; survey.dx = headers.front().distanceInterval; survey.z0 = 0.0; survey.dz = (samples > 1) ? depthOfSample(1, headers.front()) : 0.0; // 按 Y 升序求置换:order[c] = 升序第 c 位对应的原通道索引。 std::vector order(nchan); std::iota(order.begin(), order.end(), std::size_t{0}); std::stable_sort(order.begin(), order.end(), [&](std::size_t a, std::size_t b) { return channelY0[a] < channelY0[b]; }); survey.channelY.resize(nchan); const std::size_t ntraces = static_cast(survey.ntraces); const std::size_t ns = static_cast(samples); survey.values.assign(nchan * ntraces * ns, 0.0); for (std::size_t c = 0; c < nchan; ++c) { const std::size_t src = order[c]; survey.channelY[c] = channelY0[src]; const BScan& bscan = scans[src]; for (std::size_t t = 0; t < ntraces; ++t) { for (std::size_t s = 0; s < ns; ++s) { survey.values[(c * ntraces + t) * ns + s] = static_cast(bscan.data[t * ns + s]); } } } return survey; } } // namespace geopro::core::GprSurvey assembleGprSurvey( const std::vector& channelIprbPaths, const std::string& ordPath) { // 1. .ord -> 各通道横偏(文件序)。 const std::vector channelY0 = parseChannelXOffsets(readFileText(ordPath)); if (channelY0.size() != channelIprbPaths.size()) { throw std::runtime_error( "通道数不一致: .ord 有效通道数与 .iprb 路径数量不符"); } const std::size_t nchan = channelIprbPaths.size(); if (nchan == 0) { throw std::runtime_error("无通道可装配"); } // 2. 各通道读 header + 全线 BScan。 std::vector headers; std::vector scans; headers.reserve(nchan); scans.reserve(nchan); for (const std::string& iprbPath : channelIprbPaths) { const IprHeader h = parseIprHeader(readFileText(toHeaderPath(iprbPath))); headers.push_back(h); scans.push_back(readIprb(iprbPath, h)); } // 3. 全线 x0=0;其余校验/标尺/排序/置换由公共 helper 完成。 return assembleFromScans(channelY0, headers, scans, 0.0); } geopro::core::GprSurvey assembleGprSurveySlab( const std::vector& channelIprbPaths, const std::string& ordPath, std::int64_t t0, std::int64_t t1) { // 1. .ord -> 各通道横偏(文件序)。 const std::vector channelY0 = parseChannelXOffsets(readFileText(ordPath)); if (channelY0.size() != channelIprbPaths.size()) { throw std::runtime_error( "通道数不一致: .ord 有效通道数与 .iprb 路径数量不符"); } const std::size_t nchan = channelIprbPaths.size(); if (nchan == 0) { throw std::runtime_error("无通道可装配"); } // 2. 各通道读 header + 仅 [t0,t1) 道段(readIprbRange 内做越界校验)。 std::vector headers; std::vector scans; headers.reserve(nchan); scans.reserve(nchan); for (const std::string& iprbPath : channelIprbPaths) { const IprHeader h = parseIprHeader(readFileText(toHeaderPath(iprbPath))); headers.push_back(h); scans.push_back(readIprbRange(iprbPath, h, t0, t1)); } // 3. x0 = t0*dx,使该段世界 X 与全线对齐;其余同全线装配。 const double dx = headers.front().distanceInterval; return assembleFromScans(channelY0, headers, scans, static_cast(t0) * dx); } } // namespace geopro::io::gpr