Files
ViewDesignEngine/tests/sdf/test_sdf_to_mesh.cpp
T
茂之钳 b7419a7881
CI / Build & Test (push) Failing after 29s
CI / Release Build (push) Failing after 35s
feat(sdf): S11 — SDF 隐式建模完整模块
S11-A: SDF 图元库
- 14 种基础形状(inline header)
- sphere/box/round_box/torus/capsule/cylinder/cone/plane/ellipsoid
- triangular_prism/hex_prism/link/wedge
- 2D 挤出(extrusion/extrusion_bounded/revolution)

S11-B: SDF 操作 + 域变形
- 锐利布尔: union/intersection/difference
- 平滑布尔: smooth_union/smooth_intersection/smooth_difference
- 修饰器: round/onion
- 域变形: repeat/mirror/rotate/translate/scale/twist/bend/elongate/displace/cheap_bend
- 24 项测试

S11-C: CSG 表达式树 + 网格转换 + Python 绑定
- SdfNode 树结构 — 工厂构造函数,递归求值
- sdf_to_mesh — 基于 marching_cubes 的 SDF→网格
- bind_sdf — pybind11 Python 绑定

文件: 14 文件,2,545 行(测试 1,296 行)
2026-07-24 07:04:55 +00:00

87 lines
2.6 KiB
C++

#include "vde/sdf/sdf_to_mesh.h"
#include <gtest/gtest.h>
using namespace vde::sdf;
using core::Point3D;
TEST(SdfToMesh, SphereProducesValidMesh) {
auto sphere = SdfNode::sphere(2.0);
auto mesh = sdf_to_mesh(sphere, 32, 0.0);
EXPECT_GT(mesh.vertices.size(), 0u);
EXPECT_GT(mesh.triangles.size(), 0u);
// All vertices should be near the sphere surface (r ≈ 2)
for (const auto& v : mesh.vertices) {
double r = v.norm();
EXPECT_NEAR(r, 2.0, 1.0); // coarse resolution → loose tolerance
}
// Each triangle should have 3 indices
for (const auto& tri : mesh.triangles) {
for (int i = 0; i < 3; ++i) {
EXPECT_GE(tri[i], 0);
EXPECT_LT(tri[i], static_cast<int>(mesh.vertices.size()));
}
}
}
TEST(SdfToMesh, UnionOfTwoSpheres) {
auto s1 = SdfNode::translate(SdfNode::sphere(1.0), Point3D(-1.5, 0, 0));
auto s2 = SdfNode::translate(SdfNode::sphere(1.0), Point3D(1.5, 0, 0));
auto tree = SdfNode::op_union(std::move(s1), std::move(s2));
auto mesh = sdf_to_mesh(tree, 32, 0.0);
EXPECT_GT(mesh.vertices.size(), 0u);
EXPECT_GT(mesh.triangles.size(), 0u);
}
TEST(SdfToMesh, BoxProducesValidMesh) {
auto box = SdfNode::box(Point3D(1, 1, 1));
auto mesh = sdf_to_mesh(box, 32, 0.0);
EXPECT_GT(mesh.vertices.size(), 0u);
EXPECT_GT(mesh.triangles.size(), 0u);
}
TEST(SdfToMesh, HigherResolutionProducesMoreTriangles) {
auto sphere = SdfNode::sphere(1.0);
auto low = sdf_to_mesh(sphere, 16, 0.0);
auto high = sdf_to_mesh(sphere, 32, 0.0);
EXPECT_GT(high.vertices.size(), low.vertices.size());
}
TEST(SdfToMesh, LambdaSphere) {
auto mesh = sdf_to_mesh_lambda(
[](double x, double y, double z) {
return std::sqrt(x*x + y*y + z*z) - 2.0;
},
Point3D(-3, -3, -3), Point3D(3, 3, 3),
32, 0.0
);
EXPECT_GT(mesh.vertices.size(), 0u);
EXPECT_GT(mesh.triangles.size(), 0u);
}
TEST(SdfToMesh, LambdaBox) {
auto mesh = sdf_to_mesh_lambda(
[](double x, double y, double z) {
double dx = std::abs(x) - 1.0;
double dy = std::abs(y) - 1.0;
double dz = std::abs(z) - 1.0;
return std::sqrt(std::max(dx, 0.0) * std::max(dx, 0.0) +
std::max(dy, 0.0) * std::max(dy, 0.0) +
std::max(dz, 0.0) * std::max(dz, 0.0)) +
std::min(std::max({dx, dy, dz}), 0.0);
},
Point3D(-2, -2, -2), Point3D(2, 2, 2),
32, 0.0
);
EXPECT_GT(mesh.vertices.size(), 0u);
EXPECT_GT(mesh.triangles.size(), 0u);
}