feat/vtk-3d-view #7
|
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
||||
namespace geopro::core {
|
||||
|
||||
// int16 量化标量体(雷达体专用,内存/显存/磁盘 = double 体的 1/4)。
|
||||
// 与 double 的 ScalarVolume 并列,不污染主路径。布局:i 最快、k 最慢(匹配 vtkImageData)。
|
||||
|
||||
// 物理值 ↔ int16 量化映射。
|
||||
struct Quant {
|
||||
double scale = 1.0;
|
||||
double offset = 0.0;
|
||||
|
||||
// 物理值→int16:round((v-offset)/scale),钳到 [INT16_MIN+1, INT16_MAX]。
|
||||
// INT16_MIN 保留给 ScalarVolumeI16::kBlank(空值哨兵),不可被正常值占用。
|
||||
std::int16_t toQ(double v) const {
|
||||
long q = std::lround((v - offset) / scale);
|
||||
constexpr long kLo = static_cast<long>(std::numeric_limits<std::int16_t>::min()) + 1;
|
||||
constexpr long kHi = static_cast<long>(std::numeric_limits<std::int16_t>::max());
|
||||
if (q < kLo) q = kLo;
|
||||
if (q > kHi) q = kHi;
|
||||
return static_cast<std::int16_t>(q);
|
||||
}
|
||||
|
||||
// int16→物理值:q*scale + offset。
|
||||
double toPhys(std::int16_t q) const {
|
||||
return static_cast<double>(q) * scale + offset;
|
||||
}
|
||||
};
|
||||
|
||||
class ScalarVolumeI16 {
|
||||
public:
|
||||
// 空值哨兵 → 渲染透明。
|
||||
static constexpr std::int16_t kBlank = std::numeric_limits<std::int16_t>::min();
|
||||
|
||||
// data_ 填 0(非 kBlank);空值由调用方显式置 kBlank。
|
||||
ScalarVolumeI16(int nx, int ny, int nz)
|
||||
: nx_(nx), ny_(ny), nz_(nz),
|
||||
data_(static_cast<std::size_t>(nx) * ny * nz, 0) {}
|
||||
|
||||
int nx() const { return nx_; }
|
||||
int ny() const { return ny_; }
|
||||
int nz() const { return nz_; }
|
||||
|
||||
std::int16_t& at(int i, int j, int k) { return data_[idx(i, j, k)]; }
|
||||
std::int16_t at(int i, int j, int k) const { return data_[idx(i, j, k)]; }
|
||||
|
||||
std::vector<std::int16_t>& data() { return data_; }
|
||||
const std::vector<std::int16_t>& data() const { return data_; }
|
||||
|
||||
private:
|
||||
// i 最快、j 次之、k 最慢 ⇒ ((k*ny + j)*nx + i)。
|
||||
// 64 位域计算:整卷体素数 nx*ny*nz 可达约 96 亿(>2^31),先转 size_t 再乘以防溢出。
|
||||
std::size_t idx(int i, int j, int k) const {
|
||||
return (static_cast<std::size_t>(k) * ny_ + j) * nx_ + i;
|
||||
}
|
||||
|
||||
int nx_, ny_, nz_;
|
||||
std::vector<std::int16_t> data_;
|
||||
};
|
||||
|
||||
} // namespace geopro::core
|
||||
|
|
@ -32,6 +32,7 @@ target_sources(geopro_tests PRIVATE core/test_idw.cpp)
|
|||
target_sources(geopro_tests PRIVATE core/test_crs_transform.cpp)
|
||||
target_sources(geopro_tests PRIVATE core/test_model_data.cpp)
|
||||
target_sources(geopro_tests PRIVATE core/test_geo_frame.cpp)
|
||||
target_sources(geopro_tests PRIVATE core/test_scalar_volume_i16.cpp)
|
||||
target_link_libraries(geopro_tests PRIVATE geopro_core)
|
||||
|
||||
target_sources(geopro_tests PRIVATE data/test_parsers.cpp)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
#include "core/model/ScalarVolumeI16.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
using namespace geopro::core;
|
||||
|
||||
TEST(ScalarVolumeI16, QuantRoundTrip) {
|
||||
Quant q{0.5, -10.0};
|
||||
EXPECT_EQ(q.toQ(-10.0), 0);
|
||||
EXPECT_NEAR(q.toPhys(q.toQ(3.0)), 3.0, 0.25); // 半个量化步内
|
||||
}
|
||||
|
||||
TEST(ScalarVolumeI16, QuantClampReservesBlank) {
|
||||
Quant q{1.0, 0.0};
|
||||
EXPECT_GT(q.toQ(-1e9), ScalarVolumeI16::kBlank); // 下钳不撞 kBlank
|
||||
EXPECT_EQ(q.toQ(1e9), 32767); // 上钳到 INT16_MAX
|
||||
}
|
||||
|
||||
TEST(ScalarVolumeI16, IndexLayout) {
|
||||
ScalarVolumeI16 v(2, 2, 2);
|
||||
v.at(1, 0, 1) = 7;
|
||||
EXPECT_EQ(v.data()[(1 * 2 + 0) * 2 + 1], 7); // ((k*ny+j)*nx+i)=((1*2+0)*2+1)=5
|
||||
EXPECT_EQ(v.at(1, 0, 1), 7);
|
||||
}
|
||||
Loading…
Reference in New Issue