feat: v0.5.0 P1 + 差异化功能 — Voronoi, Marching Cubes, 曲率, 序列化, Python绑定
CI / Build & Test (push) Failing after 1m31s
CI / Release Build (push) Failing after 16m55s

新增功能:
- 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:
ViewDesignEngine
2026-07-23 06:27:43 +00:00
parent 9f2536498b
commit cf13496ff6
12 changed files with 774 additions and 0 deletions
+109
View File
@@ -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