#ifndef GEOPRO_DATA_STORE_CHUNKEDVOLUMESTORE_HPP #define GEOPRO_DATA_STORE_CHUNKEDVOLUMESTORE_HPP #include #include #include #include #include #include "model/ScalarVolumeI16.hpp" // geopro::core::Quant namespace geopro::core { struct BuiltI16; // src/core/algo/GprVolumeBuilder.hpp } namespace geopro::data { // 分块存储的 sidecar 元数据(meta.json 反序列化结果,不含逐块索引)。 struct StoreMeta { int nx = 0, ny = 0, nz = 0; int brick = 64; std::array origin{{0, 0, 0}}; std::array spacing{{0, 0, 0}}; geopro::core::Quant quant; // scale/offset double vminPhys = 0, vmaxPhys = 0; }; // GPR 三维体的分块压缩落盘(B/C 共用基座)。 // 格式:dir/meta.json(几何 + 量化 + 逐块索引)+ dir/data.bin(逐块 qCompress 流)。 // 块布局与体一致(块内 i 最快、k 最慢);边缘块尺寸 < brick。 // 偏移/长度全程 64 位(块偏移可能 > 2GB)。 class ChunkedVolumeStore { public: // 落盘:dir/meta.json + dir/data.bin。逐块 int16 → qCompress 压缩流, // 块索引/偏移/压缩长度记入 meta.json。dir 不存在则创建。 static void write(const std::string& dir, const geopro::core::BuiltI16& b, int brick = 64); // 只读 meta.json(不打开 data.bin)。 static StoreMeta readMeta(const std::string& dir); // 读 meta + 打开 data.bin。 explicit ChunkedVolumeStore(const std::string& dir); const StoreMeta& meta() const { return meta_; } // --- level 0 兼容接口(语义不变,= 全分辨率级)--- int bricksX() const { return bricksX_; } int bricksY() const { return bricksY_; } int bricksZ() const { return bricksZ_; } // 读单块 → 还原 int16 vector。返回长度 = bw*bh*bd(内部块 = brick³,边缘块更小)。 // == readBrick(0, bx, by, bz)。 std::vector readBrick(int bx, int by, int bz) const; // --- 金字塔(多分辨率 LOD)--- // 在已 write 的 store 目录上构建金字塔:level 0=全分辨率(已存), // level 1..levels 逐级 2× 降采样(维度 ceil(n/2)),故总级数 = levels+1。 // 同时为所有 level(含 0)计算并存每块 (min,max)(跳过 kBlank)。结果写回 // meta.json + 各级数据文件(level 0 复用现有 data.bin,level L 写 // data_L.bin)。levels<=0 视为无金字塔(仅 level 0)。 void buildPyramid(int levels); // 总层数(含 level 0);未建金字塔时 = 1。 int levels() const { return levelCount_; } // 各级块数;bricksX() == bricksX(0) 保持兼容。 int bricksX(int level) const; int bricksY(int level) const; int bricksZ(int level) const; // 各级体素维度。 void dims(int level, int& nx, int& ny, int& nz) const; // 读某级单块 → 还原 int16 vector。level 0 与兼容重载等价。 std::vector readBrick(int level, int bx, int by, int bz) const; // 每块 (min,max),跳过 kBlank;全 blank 块返回 (kBlank,kBlank)。 // 对未建金字塔的 level 0,惰性读块计算。 std::pair brickRange(int level, int bx, int by, int bz) const; private: // 单块在所属级数据文件中的位置、未压缩尺寸与值域。 struct BrickEntry { std::int64_t offset = 0; std::int64_t compressedLen = 0; int bw = 0, bh = 0, bd = 0; std::int16_t vmin = 0, vmax = 0; // 块内 (min,max),跳过 kBlank;全 blank=(kBlank,kBlank) // 显式「值域已算」标志:替代 (0,0) 哨兵。(0,0) 是合法值域,不能当未计算用。 // false → brickRange 惰性读块计算(并缓存);true → 直接返回 (vmin,vmax)。 bool hasRange = false; }; // 一个分辨率级:维度 + 块数 + 逐块索引 + 数据文件名。 struct Level { int nx = 0, ny = 0, nz = 0; int bx = 0, by = 0, bz = 0; // 块数 std::string dataFile; std::vector bricks; }; int brickIndexAt(const Level& lv, int bx, int by, int bz) const { return (bz * lv.by + by) * lv.bx + bx; } const Level& levelAt(int level) const; std::vector readBrickFrom(const Level& lv, int bx, int by, int bz) const; std::string dir_; StoreMeta meta_; int bricksX_ = 0, bricksY_ = 0, bricksZ_ = 0; // = level 0 块数(兼容字段) std::vector bricks_; // = level 0 索引(兼容字段,readBrick(bx,by,bz) 用) int levelCount_ = 1; // mutable:brickRange 为 const,但惰性算出值域后需就地缓存(置 hasRange=true)。 mutable std::vector levels_; // levels_[0] 即 level 0(与 bricks_ 同源) friend class StreamingVolumeWriter; }; // 逐块增量写 level0 store(不持整卷)。块写入顺序任意,但每块只写一次。 // 产出与 ChunkedVolumeStore::write(整卷) 逐 brick + meta 完全一致:data.bin 为 // 逐块 qCompress 流(按 bz 最慢、bx 最快的固定顺序排布),meta.json 结构同 write, // 故 ChunkedVolumeStore(dir)/readBrick 能照常读。偏移/长度全程 64 位。 class StreamingVolumeWriter { public: // 用 StoreMeta 定 dims/brick/origin/spacing/quant/vminmax(与 write 一致的元信息)。 StreamingVolumeWriter(const std::string& dir, const StoreMeta& meta); // 写一块:voxels 为该块体素(大小=bw*bh*bd,块内 i 最快,与 write 同布局)。 // bx/by/bz 为块索引;体素数不符或同块重复写 → 抛 std::runtime_error。 void writeBrick(int bx, int by, int bz, const std::vector& voxels); // 收尾:写 meta.json(含所有已写块的索引)。有缺块 → 抛 std::runtime_error。 void finalize(); private: // 单块在 data.bin 中的索引(与 ChunkedVolumeStore::BrickEntry 子集对应)。 struct Entry { std::int64_t offset = 0; std::int64_t compressedLen = 0; int bw = 0, bh = 0, bd = 0; bool written = false; }; std::string dir_; StoreMeta meta_; int bricksX_ = 0, bricksY_ = 0, bricksZ_ = 0; std::vector entries_; // 固定顺序索引(bz 最慢、bx 最快) std::int64_t offset_ = 0; // data.bin 当前追加偏移(64 位) std::int64_t written_ = 0; // 已写块计数 bool finalized_ = false; }; } // namespace geopro::data #endif // GEOPRO_DATA_STORE_CHUNKEDVOLUMESTORE_HPP