Temporary repository used to save branch code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

111 lines
5.1 KiB

// sdf_visualizer.cpp
// ──────────────────────────────────────────────────────────────────────────────
// 依赖:
// prim_gen.hpp → baked_blobtree_t、aabb_t、primitive_t …
// base/subface.hpp → internal::get_eval_sdf_ptr、surface_type
//
// 文件格式(output_path):
// 行 0 : grid_res y_slice
// 行 1 : x0 x1 z0 z1 (世界坐标范围)
// 行 2 : num_subfaces
// 然后对每个 subface 重复:
// 行 : surface_type_int
// N 行 : N 个空格分隔的 float(iz 行,ix 列,N = grid_res+1)
// ──────────────────────────────────────────────────────────────────────────────
#include "sdf_visualizer.hpp"
#include <base/subface.hpp> // internal::get_eval_sdf_ptr, surface_type
#include <Eigen/Dense>
#include <fstream>
#include <functional>
#include <iostream>
#include <limits>
#include <vector>
void dump_sdf_slice(const baked_blobtree_t& tree,
const std::string& output_path,
double y_slice,
int grid_res,
double extra_margin)
{
// ── 0. 基本校验 ────────────────────────────────────────────────────────
if (tree.subfaces.empty()) {
std::cerr << "[SDF_VIZ] No subfaces — nothing to dump.\n";
return;
}
// ── 1. 计算场景 AABB(含边距)──────────────────────────────────────────
aabb_t scene_aabb{};
for (const auto& prim : tree.primitives) { scene_aabb.extend(prim->fetch_aabb()); }
if (scene_aabb.isEmpty()) {
std::cerr << "[SDF_VIZ] Scene AABB is invalid.\n";
return;
}
const double base_margin = scene_aabb.sizes().maxCoeff() * extra_margin + 0.05;
scene_aabb.min().array() -= base_margin;
scene_aabb.max().array() += base_margin;
const double x0 = scene_aabb.min().x(), x1 = scene_aabb.max().x();
const double z0 = scene_aabb.min().z(), z1 = scene_aabb.max().z();
const int N = grid_res + 1; // 每轴采样点数
const uint32_t ns = static_cast<uint32_t>(tree.subfaces.size());
std::cout << "[SDF_VIZ] Grid " << N << "×" << N << " | " << ns << " subface(s)"
<< " | Y=" << y_slice << " | X[" << x0 << ", " << x1 << "]"
<< " | Z[" << z0 << ", " << z1 << "]\n";
// ── 2. 对每个 subface 在网格上采样 SDF ────────────────────────────────
// grids[s][iz * N + ix] = SDF 值(float 节省内存)
std::vector<std::vector<float>> grids(ns, std::vector<float>(N * N, 0.0f));
for (uint32_t s = 0; s < ns; ++s) {
// 不再调用 .raw() 获取原始指针,而是直接使用包装器对象
const auto& subface_wrapper = tree.subfaces[s]; // 使用引用,避免拷贝
surface_type subface_type = tree.subface_types[s];
auto sdf_fn = internal::get_eval_sdf_ptr(subface_type);
if (!sdf_fn) {
std::cout << "[SDF_VIZ] subface[" << s << "] type=" << static_cast<int>(subface_type)
<< " → null eval_sdf, skipped.\n";
continue;
}
for (int iz = 0; iz < N; ++iz) {
const double z = z0 + (z1 - z0) * static_cast<double>(iz) / grid_res;
for (int ix = 0; ix < N; ++ix) {
const double x = x0 + (x1 - x0) * static_cast<double>(ix) / grid_res;
const Eigen::Vector3d pos(x, y_slice, z);
// 传递包装器对象,而不是原始指针
grids[s][iz * N + ix] = static_cast<float>(sdf_fn(subface_wrapper, pos));
}
}
std::cout << "[SDF_VIZ] subface[" << s << "] type=" << static_cast<int>(subface_type) << "\n";
}
// ── 3. 写文件 ──────────────────────────────────────────────────────────
std::ofstream ofs(output_path);
if (!ofs) {
std::cerr << "[SDF_VIZ] Cannot open: " << output_path << "\n";
return;
}
// 文件头
ofs << grid_res << ' ' << y_slice << '\n';
ofs << x0 << ' ' << x1 << ' ' << z0 << ' ' << z1 << '\n';
ofs << ns << '\n';
// 每个 subface 的数据块
for (uint32_t s = 0; s < ns; ++s) {
ofs << static_cast<int>(tree.subface_types[s]) << '\n';
for (int iz = 0; iz < N; ++iz) {
for (int ix = 0; ix < N; ++ix) {
if (ix) ofs << ' ';
ofs << grids[s][iz * N + ix];
}
ofs << '\n';
}
}
std::cout << "[SDF_VIZ] Written → " << output_path << '\n';
}