Files
ViewDesignEngine/tests/brep/test_brep_drawing.cpp
T
茂之钳 93852075dd
CI / Build & Test (push) Failing after 32s
CI / Release Build (push) Failing after 16m59s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled
feat(v4.3): offset_section_view — stepped section with multiple parallel planes
- offset_section_view(body, normal, offsets): combines section profiles at each offset
- Step lines connect boundaries between adjacent planes
- 4 new tests
2026-07-25 07:18:49 +00:00

274 lines
9.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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(), size_t(3)); ++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);
}
// ═══════════════════════════════════════════════════════════
// Offset (stepped) section views
// ═══════════════════════════════════════════════════════════
TEST(OffsetSectionTest, SingleOffset) {
auto box = make_box(4, 4, 4);
auto view = offset_section_view(box, Vector3D(0, 0, 1), {0.0});
EXPECT_FALSE(view.segments.empty());
EXPECT_EQ(view.name, "offset_section");
}
TEST(OffsetSectionTest, MultipleOffsets) {
auto box = make_box(4, 4, 4);
auto view = offset_section_view(box, Vector3D(0, 0, 1), {-1.0, 0.0, 1.0});
EXPECT_GE(view.segments.size(), 3u); // section + step lines
}
TEST(OffsetSectionTest, EmptyOffsets) {
auto box = make_box(4, 4, 4);
auto view = offset_section_view(box, Vector3D(0, 0, 1), {});
EXPECT_TRUE(view.segments.empty());
}
TEST(OffsetSectionTest, CylinderSection) {
auto cyl = make_cylinder(2, 6, 32);
auto view = offset_section_view(cyl, Vector3D(0, 0, 1), {-2.0, 0.0, 2.0});
EXPECT_GE(view.total_segments(), 3u);
}