feat: 3D Delaunay + 多边形偏移 + 序列化
CI / Build & Test (push) Failing after 34s
CI / Release Build (push) Failing after 25s

- mesh: Bowyer-Watson 3D Delaunay 四面体剖分
- boolean: 2D 多边形偏移(膨胀/腐蚀,角平分线法)
- foundation: 二进制序列化(版本化 Little-Endian 格式)
- 更新 CMake 构建
This commit is contained in:
ViewDesignEngine
2026-07-23 06:28:34 +00:00
parent cf13496ff6
commit 6f7835c458
5 changed files with 220 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
#include "vde/boolean/polygon_offset.h"
#include <algorithm>
#include <cmath>
namespace vde::boolean {
std::vector<Polygon2D> polygon_offset(const Polygon2D& poly, double distance) {
const auto& verts = poly.vertices();
if (verts.size() < 3 || std::abs(distance) < 1e-12) return {poly};
int n = static_cast<int>(verts.size());
std::vector<Point2D> result_verts;
// Offset each edge inward/outward by moving vertices along angle bisectors
for (int i = 0; i < n; ++i) {
const Point2D& prev = verts[(i - 1 + n) % n];
const Point2D& curr = verts[i];
const Point2D& next = verts[(i + 1) % n];
// Edge directions
Vector2D e1 = (curr - prev);
Vector2D e2 = (next - curr);
double len1 = e1.norm(), len2 = e2.norm();
if (len1 < 1e-12 || len2 < 1e-12) {
result_verts.push_back(curr);
continue;
}
e1 /= len1; e2 /= len2;
// Inward normals (rotate CW by 90°)
Vector2D n1(-e1.y(), e1.x());
Vector2D n2(-e2.y(), e2.x());
// Bisector direction
Vector2D bisector = n1 + n2;
double bisector_len = bisector.norm();
if (bisector_len < 1e-12) {
// Colinear edges — just offset along normal
result_verts.push_back(Point2D(curr.x() + distance * n1.x(),
curr.y() + distance * n1.y()));
} else {
bisector /= bisector_len;
// Scale: offset = distance / sin(angle/2)
double cos_angle = e1.dot(e2);
double sin_half_angle = std::sqrt(std::max(0.0, (1.0 - cos_angle) * 0.5));
if (sin_half_angle > 1e-12) {
double scale = distance / sin_half_angle;
result_verts.push_back(Point2D(curr.x() + scale * bisector.x(),
curr.y() + scale * bisector.y()));
} else {
result_verts.push_back(curr);
}
}
}
return {Polygon2D(result_verts)};
}
} // namespace vde::boolean