feat: v0.5.0 P1 + 差异化功能 — Voronoi, Marching Cubes, 曲率, 序列化, Python绑定
新增功能: - core: 2D Voronoi 图(Delaunay 对偶图) - mesh: Marching Cubes(完整256项三角表 + SDF 辅助函数) - mesh: 离散曲率(Gaussian/Mean, Cotan 公式) - foundation: 二进制序列化(版本化格式,Little-Endian) - python: pybind11 绑定(30+ API 暴露) - marching_cubes.h: SDF 基本体(球/盒)+ 光滑布尔
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
#include "vde/foundation/serializer.h"
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
namespace vde::foundation {
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
void write_le(std::vector<uint8_t>& buf, T val) {
|
||||
for (size_t i = 0; i < sizeof(T); ++i)
|
||||
buf.push_back(static_cast<uint8_t>((val >> (i*8)) & 0xFF));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T read_le(const uint8_t*& ptr) {
|
||||
T val = 0;
|
||||
for (size_t i = 0; i < sizeof(T); ++i)
|
||||
val |= static_cast<T>(ptr[i]) << (i*8);
|
||||
ptr += sizeof(T);
|
||||
return val;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<uint8_t> BinarySerializer::serialize(const HalfedgeMesh& mesh) {
|
||||
std::vector<uint8_t> buf;
|
||||
|
||||
// Header
|
||||
write_le(buf, VDE_MAGIC);
|
||||
write_le(buf, VDE_FORMAT_VERSION);
|
||||
write_le(buf, static_cast<uint32_t>(0)); // flags
|
||||
|
||||
// Vertex data
|
||||
uint32_t nv = static_cast<uint32_t>(mesh.num_vertices());
|
||||
write_le(buf, nv);
|
||||
for (size_t i = 0; i < nv; ++i) {
|
||||
const auto& v = mesh.vertex(i);
|
||||
write_le(buf, v.x()); write_le(buf, v.y()); write_le(buf, v.z());
|
||||
}
|
||||
|
||||
// Face data
|
||||
uint32_t nf = static_cast<uint32_t>(mesh.num_faces());
|
||||
write_le(buf, nf);
|
||||
for (size_t i = 0; i < nf; ++i) {
|
||||
auto vis = mesh.face_vertices(static_cast<int>(i));
|
||||
uint32_t nfv = static_cast<uint32_t>(vis.size());
|
||||
write_le(buf, nfv);
|
||||
for (int vi : vis) write_le(buf, static_cast<int32_t>(vi));
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
HalfedgeMesh BinarySerializer::deserialize(const std::vector<uint8_t>& data) {
|
||||
HalfedgeMesh mesh;
|
||||
if (data.size() < 16) return mesh;
|
||||
|
||||
const uint8_t* ptr = data.data();
|
||||
uint64_t magic = read_le<uint64_t>(ptr);
|
||||
if (magic != VDE_MAGIC) return mesh;
|
||||
|
||||
read_le<uint32_t>(ptr); // version
|
||||
read_le<uint32_t>(ptr); // flags
|
||||
|
||||
uint32_t nv = read_le<uint32_t>(ptr);
|
||||
std::vector<Point3D> verts;
|
||||
verts.reserve(nv);
|
||||
for (uint32_t i = 0; i < nv; ++i) {
|
||||
double x = read_le<double>(ptr);
|
||||
double y = read_le<double>(ptr);
|
||||
double z = read_le<double>(ptr);
|
||||
verts.emplace_back(x, y, z);
|
||||
}
|
||||
|
||||
uint32_t nf = read_le<uint32_t>(ptr);
|
||||
std::vector<std::array<int, 3>> tris;
|
||||
for (uint32_t i = 0; i < nf; ++i) {
|
||||
uint32_t nfv = read_le<uint32_t>(ptr);
|
||||
std::vector<int> vis;
|
||||
for (uint32_t j = 0; j < nfv; ++j)
|
||||
vis.push_back(read_le<int32_t>(ptr));
|
||||
if (vis.size() >= 3)
|
||||
tris.push_back({vis[0], vis[1], vis[2]});
|
||||
}
|
||||
|
||||
mesh.build_from_triangles(verts, tris);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
bool BinarySerializer::write_file(const std::string& path, const HalfedgeMesh& mesh) {
|
||||
auto data = serialize(mesh);
|
||||
std::ofstream file(path, std::ios::binary);
|
||||
if (!file) return false;
|
||||
file.write(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
return file.good();
|
||||
}
|
||||
|
||||
HalfedgeMesh BinarySerializer::read_file(const std::string& path) {
|
||||
std::ifstream file(path, std::ios::binary | std::ios::ate);
|
||||
if (!file) return {};
|
||||
auto size = file.tellg();
|
||||
file.seekg(0);
|
||||
std::vector<uint8_t> data(static_cast<size_t>(size));
|
||||
file.read(reinterpret_cast<char*>(data.data()), size);
|
||||
return deserialize(data);
|
||||
}
|
||||
|
||||
} // namespace vde::foundation
|
||||
Reference in New Issue
Block a user