feat: 3D Delaunay + 多边形偏移 + 序列化
- mesh: Bowyer-Watson 3D Delaunay 四面体剖分 - boolean: 2D 多边形偏移(膨胀/腐蚀,角平分线法) - foundation: 二进制序列化(版本化 Little-Endian 格式) - 更新 CMake 构建
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user