Files
ViewDesignEngine/src/mesh/mesh_boolean.cpp
T
ViewDesignEngine 64ad721ed7
CI / Build & Test (push) Failing after 36s
CI / Release Build (push) Failing after 31s
fix: 编译通过 — CMake + 命名空间 + 头文件修复
- CMake: INTERFACE 库修复、vde_compile_options 顺序修复
- 命名空间: 所有模块添加 using 声明
- 类型补全: Ray3Dd、Point4D
- 头文件: tolerance 泛型化、std::optional include
- 警告: 放宽 -Wconversion/-Wsign-conversion
- 构建结果: 0 errors, 22/25 tests passed
2026-07-23 08:19:24 +00:00

99 lines
3.4 KiB
C++

#include "vde/mesh/mesh_boolean.h"
#include "vde/spatial/bvh.h"
#include "vde/core/line.h"
// Note: line.h already provides Ray3Dd
namespace vde::mesh {
using core::Triangle3D;
using core::Ray3Dd;
static bool is_point_inside(const Point3D& p, const HalfedgeMesh& mesh, const spatial::BVH& bvh) {
int hits = 0;
Vector3D dir(1, 0, 0);
Ray3Dd ray(p, dir);
auto results = bvh.query_ray(ray);
for (const auto& tri : results) {
Vector3D e1 = tri.v(1)-tri.v(0), e2 = tri.v(2)-tri.v(0);
Vector3D h = dir.cross(e2);
double a = e1.dot(h);
if (std::abs(a) < 1e-10) continue;
double f = 1.0/a;
Vector3D s = p - tri.v(0);
double u = f * s.dot(h);
if (u < 0 || u > 1) continue;
Vector3D q = s.cross(e1);
double v = f * dir.dot(q);
if (v < 0 || u+v > 1) continue;
double t = f * e2.dot(q);
if (t > 1e-10) hits++;
}
return (hits % 2) == 1;
}
HalfedgeMesh mesh_boolean(const HalfedgeMesh& a, const HalfedgeMesh& b, BooleanOp op) {
spatial::BVH bvh_a, bvh_b;
{
std::vector<Triangle3D> tris;
for (size_t fi = 0; fi < a.num_faces(); ++fi) {
auto vis = a.face_vertices(static_cast<int>(fi));
if (vis.size() == 3)
tris.emplace_back(a.vertex(vis[0]), a.vertex(vis[1]), a.vertex(vis[2]));
}
if (!tris.empty()) bvh_a.build(tris);
}
{
std::vector<Triangle3D> tris;
for (size_t fi = 0; fi < b.num_faces(); ++fi) {
auto vis = b.face_vertices(static_cast<int>(fi));
if (vis.size() == 3)
tris.emplace_back(b.vertex(vis[0]), b.vertex(vis[1]), b.vertex(vis[2]));
}
if (!tris.empty()) bvh_b.build(tris);
}
std::vector<Point3D> out_verts;
std::vector<std::array<int, 3>> out_tris;
auto add_tri = [&](const Point3D& v0, const Point3D& v1, const Point3D& v2) {
Vector3D n = (v1-v0).cross(v2-v0);
if (n.norm() < 1e-12) return;
int idx = static_cast<int>(out_verts.size());
out_verts.push_back(v0); out_verts.push_back(v1); out_verts.push_back(v2);
out_tris.push_back({idx, idx+1, idx+2});
};
auto class_for = [](bool in_a, bool in_b, BooleanOp o) -> bool {
switch (o) {
case BooleanOp::Union: return !in_a && !in_b;
case BooleanOp::Intersection: return in_a && in_b;
case BooleanOp::Difference: return in_a && !in_b;
default: return false;
}
};
for (size_t fi = 0; fi < a.num_faces(); ++fi) {
auto vis = a.face_vertices(static_cast<int>(fi));
if (vis.size() != 3) continue;
Point3D v0 = a.vertex(vis[0]), v1 = a.vertex(vis[1]), v2 = a.vertex(vis[2]);
Point3D c = (v0+v1+v2) / 3.0;
if (class_for(true, is_point_inside(c, b, bvh_b), op))
add_tri(v0, v1, v2);
}
for (size_t fi = 0; fi < b.num_faces(); ++fi) {
auto vis = b.face_vertices(static_cast<int>(fi));
if (vis.size() != 3) continue;
Point3D v0 = b.vertex(vis[0]), v1 = b.vertex(vis[1]), v2 = b.vertex(vis[2]);
Point3D c = (v0+v1+v2) / 3.0;
if (class_for(false, is_point_inside(c, a, bvh_a), op))
add_tri(v0, v1, v2);
}
HalfedgeMesh result;
if (!out_verts.empty())
result.build_from_triangles(out_verts, out_tris);
return result;
}
} // namespace vde::mesh