feat/vtk-3d-view #7
|
|
@ -41,4 +41,52 @@ BScan readIprb(const std::string& path, const IprHeader& h) {
|
|||
return b;
|
||||
}
|
||||
|
||||
BScan readIprbRange(const std::string& path, const IprHeader& h,
|
||||
std::int64_t t0, std::int64_t t1) {
|
||||
std::ifstream f(path, std::ios::binary | std::ios::ate);
|
||||
if (!f) {
|
||||
throw std::runtime_error("readIprbRange: 无法打开文件: " + path);
|
||||
}
|
||||
|
||||
const std::int64_t fileBytes = static_cast<std::int64_t>(f.tellg());
|
||||
const std::int64_t samples = static_cast<std::int64_t>(h.samples);
|
||||
if (samples <= 0) {
|
||||
throw std::runtime_error("readIprbRange: samples 非法(<=0): " + path);
|
||||
}
|
||||
const std::int64_t bytesPerTrace = samples * 2; // int16
|
||||
if (fileBytes % bytesPerTrace != 0) {
|
||||
throw std::runtime_error(
|
||||
"readIprbRange: 文件大小不是 samples*2 的整数倍: " + path);
|
||||
}
|
||||
const std::int64_t totalTraces = fileBytes / bytesPerTrace;
|
||||
|
||||
// 区间校验:0<=t0<=t1<=总道数。
|
||||
if (t0 < 0 || t0 > t1 || t1 > totalTraces) {
|
||||
throw std::runtime_error("readIprbRange: 道区间越界 [t0,t1)");
|
||||
}
|
||||
|
||||
const std::int64_t rangeTraces = t1 - t0;
|
||||
const std::int64_t offsetBytes = t0 * bytesPerTrace; // 64 位防溢出
|
||||
const std::int64_t readBytes = rangeTraces * bytesPerTrace; // 64 位防溢出
|
||||
|
||||
BScan b;
|
||||
b.samples = h.samples;
|
||||
b.traces = rangeTraces;
|
||||
b.data.resize(static_cast<std::size_t>(samples * rangeTraces));
|
||||
|
||||
f.seekg(static_cast<std::streamoff>(offsetBytes), std::ios::beg);
|
||||
if (!f) {
|
||||
throw std::runtime_error("readIprbRange: seek 失败: " + path);
|
||||
}
|
||||
if (readBytes > 0) {
|
||||
f.read(reinterpret_cast<char*>(b.data.data()),
|
||||
static_cast<std::streamsize>(readBytes));
|
||||
if (!f) {
|
||||
throw std::runtime_error("readIprbRange: 读取数据失败: " + path);
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
} // namespace geopro::io::gpr
|
||||
|
|
|
|||
|
|
@ -21,6 +21,14 @@ struct BScan {
|
|||
// 注意:h.lastTrace 仅作 header 提示,不决定道数(真实数据规律为道数==lastTrace,非 +1)。
|
||||
BScan readIprb(const std::string& path, const IprHeader& h);
|
||||
|
||||
// 只读 [t0, t1) 道(0<=t0<=t1<=总道数)。seek 到 t0*samples*2,读 (t1-t0)*samples*2 字节,
|
||||
// 不载全文件,供流式 slab 装配做到内存有界。
|
||||
// 返回 BScan.samples=h.samples, traces=(t1-t0), data 大小=(t1-t0)*samples,布局同 readIprb。
|
||||
// 总道数 = fileBytes/(samples*2);越界(t1>总道数 或 t0>t1 或 t0<0)抛 std::runtime_error;
|
||||
// 文件打不开抛 std::runtime_error。偏移用 64 位防大文件溢出。
|
||||
BScan readIprbRange(const std::string& path, const IprHeader& h,
|
||||
std::int64_t t0, std::int64_t t1);
|
||||
|
||||
} // namespace geopro::io::gpr
|
||||
|
||||
#endif // GEOPRO_IO_GPR_IPRBREADER_HPP
|
||||
|
|
|
|||
|
|
@ -47,3 +47,23 @@ TEST(IprbReader, ThrowsOnMissingFile) {
|
|||
IprHeader h{}; h.samples = 3; h.lastTrace = 3;
|
||||
EXPECT_THROW(readIprb("____no_such_file____.iprb", h), std::runtime_error);
|
||||
}
|
||||
TEST(IprbReader, RangeReadMatchesFullSlice) {
|
||||
// 造 samples=3, traces=5 的文件(15 个 int16,值=trace*10+s)
|
||||
std::vector<int16_t> raw; for(int t=0;t<5;t++)for(int s=0;s<3;s++) raw.push_back((int16_t)(t*10+s));
|
||||
auto path = writeTmp(raw);
|
||||
IprHeader h{}; h.samples=3; h.lastTrace=4; // 总道数=5(由文件大小推)
|
||||
auto full = readIprb(path, h);
|
||||
auto seg = readIprbRange(path, h, 1, 4); // 读道 [1,4)=3 道
|
||||
EXPECT_EQ(seg.traces, 3); EXPECT_EQ(seg.samples, 3);
|
||||
ASSERT_EQ(seg.data.size(), 9u);
|
||||
for (int t=0;t<3;t++) for(int s=0;s<3;s++)
|
||||
EXPECT_EQ(seg.data[t*3+s], full.data[(t+1)*3+s]); // 段==全读对应段
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
TEST(IprbReader, RangeOutOfBoundsThrows) {
|
||||
std::vector<int16_t> raw(15,0); auto path=writeTmp(raw);
|
||||
IprHeader h{}; h.samples=3; h.lastTrace=4;
|
||||
EXPECT_THROW(readIprbRange(path,h,3,99), std::runtime_error); // t1>5
|
||||
EXPECT_THROW(readIprbRange(path,h,4,2), std::runtime_error); // t0>t1
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue