feat(v3.8): 2D projection views + section + DXF + dimensions + G2 curvature
This commit is contained in:
@@ -12,3 +12,4 @@ add_vde_test(test_measure)
|
||||
add_vde_test(test_assembly_constraints)
|
||||
add_vde_test(test_trimmed_surface)
|
||||
add_vde_test(test_brep_heal)
|
||||
add_vde_test(test_brep_drawing)
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "vde/brep/brep_drawing.h"
|
||||
#include "vde/brep/modeling.h"
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
using namespace vde::brep;
|
||||
using namespace vde::core;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// generate_views — 基本测试
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
TEST(BrepDrawingTest, GenerateViews_Box_ReturnsFourViews) {
|
||||
auto box = make_box(2, 3, 4);
|
||||
auto views = generate_views(box);
|
||||
|
||||
EXPECT_EQ(views.size(), 4u);
|
||||
EXPECT_EQ(views[0].name, "front");
|
||||
EXPECT_EQ(views[1].name, "top");
|
||||
EXPECT_EQ(views[2].name, "right");
|
||||
EXPECT_EQ(views[3].name, "iso");
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, GenerateViews_Box_EachViewHasSegments) {
|
||||
auto box = make_box(2, 3, 4);
|
||||
auto views = generate_views(box);
|
||||
|
||||
for (const auto& v : views) {
|
||||
EXPECT_GT(v.total_segments(), 0u)
|
||||
<< "View " << v.name << " should have segments";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, GenerateViews_Box_FrontViewHasExpectedContent) {
|
||||
auto box = make_box(2, 2, 2);
|
||||
auto views = generate_views(box);
|
||||
|
||||
const auto& front = views[0];
|
||||
EXPECT_EQ(front.name, "front");
|
||||
// Front view: XY plane projection, should show X=[-1,1], Y=[-1,1]
|
||||
EXPECT_GT(front.total_segments(), 0u);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, GenerateViews_Box_ViewDirections) {
|
||||
auto box = make_box(1, 1, 1);
|
||||
auto views = generate_views(box);
|
||||
|
||||
// Front: looking down -Z
|
||||
EXPECT_NEAR(views[0].view_direction.z(), -1.0, 1e-6);
|
||||
|
||||
// Top: looking down -Y
|
||||
EXPECT_NEAR(views[1].view_direction.y(), -1.0, 1e-6);
|
||||
|
||||
// Right: looking down -X
|
||||
EXPECT_NEAR(views[2].view_direction.x(), -1.0, 1e-6);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, GenerateViews_EmptyBody_ReturnsEmpty) {
|
||||
BrepModel empty;
|
||||
auto views = generate_views(empty);
|
||||
EXPECT_TRUE(views.empty());
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, GenerateViews_Cylinder_ReturnsFourViews) {
|
||||
auto cyl = make_cylinder(1.0, 3.0, 16);
|
||||
auto views = generate_views(cyl);
|
||||
|
||||
EXPECT_EQ(views.size(), 4u);
|
||||
for (const auto& v : views) {
|
||||
EXPECT_GT(v.total_segments(), 0u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, GenerateViews_Sphere_ReturnsFourViews) {
|
||||
auto sphere = make_sphere(2.0, 16, 8);
|
||||
auto views = generate_views(sphere);
|
||||
|
||||
EXPECT_EQ(views.size(), 4u);
|
||||
// 球所有视图的主要轮廓应类似
|
||||
for (const auto& v : views) {
|
||||
ASSERT_GT(v.total_segments(), 0u);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// section_view — 测试
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
TEST(BrepDrawingTest, SectionView_Box_AtCenter) {
|
||||
auto box = make_box(4, 4, 4);
|
||||
// 截平面 z = 0(XY 平面,法向量沿 Z)
|
||||
auto view = section_view(box, Point3D(0, 0, 0), Vector3D(0, 0, 1));
|
||||
|
||||
EXPECT_EQ(view.name, "section");
|
||||
// 截面应为矩形轮廓,至少有 4 个交点形成轮廓线段
|
||||
// + hatch 线,总数应 > 4
|
||||
ASSERT_GT(view.total_segments(), 4u);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, SectionView_Box_HorizontalPlane) {
|
||||
auto box = make_box(4, 4, 4);
|
||||
// z = 1 的水平截面(穿过盒子)
|
||||
auto view = section_view(box, Point3D(0, 0, 1), Vector3D(0, 0, 1));
|
||||
|
||||
ASSERT_GT(view.total_segments(), 4u);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, SectionView_Box_PlaneOutside) {
|
||||
auto box = make_box(2, 2, 2);
|
||||
// 截平面在盒子之外(z = 5)
|
||||
auto view = section_view(box, Point3D(0, 0, 5), Vector3D(0, 0, 1));
|
||||
|
||||
// 交点不足 3 个 → 无法形成截面
|
||||
EXPECT_LT(view.total_segments(), 3u);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, SectionView_EmptyBody_ReturnsEmpty) {
|
||||
BrepModel empty;
|
||||
auto view = section_view(empty, Point3D(0, 0, 0), Vector3D(0, 0, 1));
|
||||
|
||||
EXPECT_EQ(view.name, "section");
|
||||
EXPECT_EQ(view.total_segments(), 0u);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, SectionView_Cylinder_Midplane) {
|
||||
auto cyl = make_cylinder(2.0, 6.0, 32);
|
||||
// 垂直圆柱的 z=0 截面 → 圆形截面
|
||||
auto view = section_view(cyl, Point3D(0, 0, 0), Vector3D(0, 0, 1));
|
||||
|
||||
ASSERT_GT(view.segments.size(), 3u);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// DXF 导出 — 测试
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
TEST(BrepDrawingTest, ExportDxf_CreatesFile) {
|
||||
auto box = make_box(2, 2, 2);
|
||||
auto views = generate_views(box);
|
||||
|
||||
const char* filepath = "test_output.dxf";
|
||||
std::remove(filepath); // 清理旧文件
|
||||
|
||||
bool ok = export_dxf(filepath, views);
|
||||
EXPECT_TRUE(ok);
|
||||
|
||||
// 验证文件存在
|
||||
std::ifstream in(filepath);
|
||||
EXPECT_TRUE(in.is_open());
|
||||
std::string content((std::istreambuf_iterator<char>(in)),
|
||||
std::istreambuf_iterator<char>());
|
||||
in.close();
|
||||
|
||||
// 验证关键结构
|
||||
EXPECT_NE(content.find("SECTION"), std::string::npos);
|
||||
EXPECT_NE(content.find("ENTITIES"), std::string::npos);
|
||||
EXPECT_NE(content.find("LINE"), std::string::npos);
|
||||
EXPECT_NE(content.find("ENDSEC"), std::string::npos);
|
||||
EXPECT_NE(content.find("EOF"), std::string::npos);
|
||||
|
||||
// 验证有至少一条 LINE 实体
|
||||
EXPECT_NE(content.find("LINE"), std::string::npos);
|
||||
|
||||
std::remove(filepath);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, ExportDxf_HasLayers) {
|
||||
auto box = make_box(2, 2, 2);
|
||||
auto views = generate_views(box);
|
||||
|
||||
const char* filepath = "test_layers.dxf";
|
||||
std::remove(filepath);
|
||||
export_dxf(filepath, views);
|
||||
|
||||
std::ifstream in(filepath);
|
||||
std::string content((std::istreambuf_iterator<char>(in)),
|
||||
std::istreambuf_iterator<char>());
|
||||
in.close();
|
||||
|
||||
EXPECT_NE(content.find("visible"), std::string::npos);
|
||||
EXPECT_NE(content.find("DASHED"), std::string::npos);
|
||||
|
||||
std::remove(filepath);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, ExportDxf_EmptyViews_StillWritesSkeleton) {
|
||||
std::vector<ProjectionView> empty_views;
|
||||
|
||||
const char* filepath = "test_empty.dxf";
|
||||
std::remove(filepath);
|
||||
bool ok = export_dxf(filepath, empty_views);
|
||||
EXPECT_TRUE(ok);
|
||||
|
||||
std::ifstream in(filepath);
|
||||
std::string content((std::istreambuf_iterator<char>(in)),
|
||||
std::istreambuf_iterator<char>());
|
||||
in.close();
|
||||
|
||||
EXPECT_NE(content.find("SECTION"), std::string::npos);
|
||||
EXPECT_NE(content.find("EOF"), std::string::npos);
|
||||
|
||||
std::remove(filepath);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, ExportDxf_InvalidPath_ReturnsFalse) {
|
||||
auto box = make_box(1, 1, 1);
|
||||
auto views = generate_views(box);
|
||||
bool ok = export_dxf("/nonexistent_dir_xyz/test.dxf", views);
|
||||
EXPECT_FALSE(ok);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 隐藏线 — 测试
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
TEST(BrepDrawingTest, HiddenLines_Box_HasHiddenEdges) {
|
||||
auto box = make_box(2, 2, 2);
|
||||
auto views = generate_views(box);
|
||||
|
||||
// 每个标准视图均应有隐藏边
|
||||
for (size_t i = 0; i < std::min(views.size(), 3u); ++i) {
|
||||
// 前/俯/右视图都应该有隐藏线
|
||||
EXPECT_GE(views[i].hidden_lines.size() + views[i].segments.size(), 1u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, DrawSegment_DefaultNotHidden) {
|
||||
DrawSegment seg{0, 0, 1, 1};
|
||||
EXPECT_FALSE(seg.hidden);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, DrawSegment_Hidden) {
|
||||
DrawSegment seg{0, 0, 1, 1, true};
|
||||
EXPECT_TRUE(seg.hidden);
|
||||
}
|
||||
|
||||
TEST(BrepDrawingTest, ProjectionView_TotalSegments) {
|
||||
ProjectionView v;
|
||||
v.segments = {{0,0,1,0}, {1,0,1,1}};
|
||||
v.hidden_lines = {{0,1,0,0, true}};
|
||||
EXPECT_EQ(v.total_segments(), 3u);
|
||||
}
|
||||
Reference in New Issue
Block a user