feat: 测试覆盖扩展 + 文档更新

This commit is contained in:
茂之钳
2026-07-23 12:36:39 +00:00
parent 41a8992332
commit f2203c7255
42 changed files with 3448 additions and 106 deletions
+1
View File
@@ -2,3 +2,4 @@ add_vde_test(test_point)
add_vde_test(test_convex_hull)
add_vde_test(test_transform)
add_vde_test(test_distance)
add_vde_test(test_polygon)
+111
View File
@@ -1,13 +1,124 @@
#include <gtest/gtest.h>
#include "vde/core/distance.h"
#include "vde/core/line.h"
#include "vde/core/plane.h"
#include "vde/core/triangle.h"
using namespace vde::core;
// ── Point to Point ──
TEST(DistanceTest, PointToPoint) {
EXPECT_DOUBLE_EQ(distance(Point3D(0,0,0), Point3D(1,0,0)), 1.0);
EXPECT_DOUBLE_EQ(distance(Point3D(0,0,0), Point3D(3,4,0)), 5.0);
EXPECT_DOUBLE_EQ(distance(Point3D(1,2,3), Point3D(1,2,3)), 0.0);
}
// ── Point to Plane ──
TEST(DistanceTest, PointToPlane) {
Plane3D plane(Point3D(0,0,0), Vector3D(0,0,1));
EXPECT_DOUBLE_EQ(distance(Point3D(0,0,5), plane), 5.0);
EXPECT_DOUBLE_EQ(distance(Point3D(0,0,-5), plane), 5.0);
EXPECT_DOUBLE_EQ(distance(Point3D(0,0,0), plane), 0.0);
}
TEST(DistanceTest, PointToPlane_OffsetOrigin) {
Plane3D plane(Point3D(0,0,10), Vector3D(0,0,1));
EXPECT_DOUBLE_EQ(distance(Point3D(0,0,0), plane), 10.0);
EXPECT_DOUBLE_EQ(distance(Point3D(0,0,10), plane), 0.0);
}
// ── Point to Line ──
TEST(DistanceTest, PointToLine_OnLine) {
Line3Dd line(Point3D(0,0,0), Vector3D(1,0,0));
EXPECT_DOUBLE_EQ(distance(Point3D(5,0,0), line), 0.0);
}
TEST(DistanceTest, PointToLine_Perpendicular) {
Line3Dd line(Point3D(0,0,0), Vector3D(1,0,0));
// Point at (0, 3, 0), line along X-axis → distance = 3
EXPECT_DOUBLE_EQ(distance(Point3D(0,3,0), line), 3.0);
}
TEST(DistanceTest, PointToLine_OffsetOrigin) {
Line3Dd line(Point3D(1,2,0), Vector3D(0,1,0));
// Line through (1,2,0) along Y-axis
// Point (1,0,0) → perpendicular distance = 2
EXPECT_DOUBLE_EQ(distance(Point3D(1,0,0), line), 2.0);
}
// ── Point to Segment ──
TEST(DistanceTest, PointToSegment_PointOnSegment) {
Segment3Dd seg(Point3D(0,0,0), Point3D(2,0,0));
EXPECT_DOUBLE_EQ(distance(Point3D(1,0,0), seg), 0.0);
}
TEST(DistanceTest, PointToSegment_EndpointClosest) {
Segment3Dd seg(Point3D(0,0,0), Point3D(2,0,0));
// Point beyond P1 → closest is P1
EXPECT_DOUBLE_EQ(distance(Point3D(3,0,0), seg), 1.0);
// Point before P0 → closest is P0
EXPECT_DOUBLE_EQ(distance(Point3D(-1,0,0), seg), 1.0);
}
TEST(DistanceTest, PointToSegment_PerpendicularProjection) {
Segment3Dd seg(Point3D(0,0,0), Point3D(4,0,0));
// Point directly above middle → perpendicular projection
EXPECT_DOUBLE_EQ(distance(Point3D(2,3,0), seg), 3.0);
}
TEST(DistanceTest, PointToSegment_ZeroLength) {
Segment3Dd seg(Point3D(1,1,1), Point3D(1,1,1));
EXPECT_DOUBLE_EQ(distance(Point3D(1,1,0), seg), 1.0);
}
// ── Point to Triangle ──
TEST(DistanceTest, PointToTriangle_InteriorProjection) {
Triangle3D tri(Point3D(0,0,0), Point3D(2,0,0), Point3D(0,2,0));
// Point directly above centroid → interior projection
EXPECT_DOUBLE_EQ(distance(Point3D(0.5, 0.5, 3), tri), 3.0);
}
TEST(DistanceTest, PointToTriangle_OnPlaneInside) {
Triangle3D tri(Point3D(0,0,0), Point3D(2,0,0), Point3D(0,2,0));
// Point on the triangle plane, inside the triangle
EXPECT_DOUBLE_EQ(distance(Point3D(0.5, 0.5, 0), tri), 0.0);
}
TEST(DistanceTest, PointToTriangle_OnPlaneOutside) {
Triangle3D tri(Point3D(0,0,0), Point3D(2,0,0), Point3D(0,2,0));
// Point on the triangle plane but outside → closest to edge or vertex
double d = distance(Point3D(3, 3, 0), tri);
EXPECT_GT(d, 0.0);
}
// ── closest_point ──
TEST(DistanceTest, ClosestPoint_Triangle) {
Triangle3D tri(Point3D(0,0,0), Point3D(2,0,0), Point3D(0,2,0));
Point3D c = closest_point(Point3D(1, 1, 5), tri);
// Closest point should be on triangle plane, within bounds
EXPECT_NEAR(c.z(), 0.0, 1e-9);
EXPECT_GE(c.x(), 0.0);
EXPECT_GE(c.y(), 0.0);
}
TEST(DistanceTest, ClosestPoint_Segment) {
Segment3Dd seg(Point3D(0,0,0), Point3D(4,0,0));
Point3D c = closest_point(Point3D(2, 5, 0), seg);
EXPECT_NEAR(c.x(), 2.0, 1e-9);
EXPECT_NEAR(c.y(), 0.0, 1e-9);
EXPECT_NEAR(c.z(), 0.0, 1e-9);
}
TEST(DistanceTest, ClosestPoint_SegmentAtEndpoint) {
Segment3Dd seg(Point3D(0,0,0), Point3D(4,0,0));
Point3D c = closest_point(Point3D(5, 0, 3), seg);
// Should clamp to P1
EXPECT_NEAR(c.x(), 4.0, 1e-9);
EXPECT_NEAR(c.y(), 0.0, 1e-9);
}
+146
View File
@@ -0,0 +1,146 @@
#include <gtest/gtest.h>
#include "vde/core/polygon.h"
using namespace vde::core;
// ── signed_area tests ──
TEST(PolygonTest, SignedArea_CCWSquare_Positive) {
// Counter-clockwise unit square
Polygon2D poly({{0, 0}, {1, 0}, {1, 1}, {0, 1}});
EXPECT_GT(poly.signed_area(), 0.0);
EXPECT_NEAR(poly.signed_area(), 1.0, 1e-9);
}
TEST(PolygonTest, SignedArea_CWSquare_Negative) {
// Clockwise unit square
Polygon2D poly({{0, 0}, {0, 1}, {1, 1}, {1, 0}});
EXPECT_LT(poly.signed_area(), 0.0);
EXPECT_NEAR(poly.signed_area(), -1.0, 1e-9);
}
TEST(PolygonTest, SignedArea_Triangle) {
Polygon2D poly({{0, 0}, {3, 0}, {0, 4}});
EXPECT_NEAR(std::abs(poly.signed_area()), 6.0, 1e-9);
}
TEST(PolygonTest, SignedArea_Collinear_Degenerate) {
// All points on a line → zero area
Polygon2D poly({{0, 0}, {1, 1}, {2, 2}});
EXPECT_NEAR(poly.signed_area(), 0.0, 1e-9);
}
TEST(PolygonTest, SignedArea_Empty) {
Polygon2D poly;
EXPECT_DOUBLE_EQ(poly.signed_area(), 0.0);
}
TEST(PolygonTest, Area_AbsoluteValue) {
// area() should be absolute value of signed_area()
Polygon2D ccw({{0, 0}, {2, 0}, {2, 2}, {0, 2}});
Polygon2D cw({{0, 0}, {0, 2}, {2, 2}, {2, 0}});
EXPECT_NEAR(ccw.area(), 4.0, 1e-9);
EXPECT_NEAR(cw.area(), 4.0, 1e-9);
}
// ── contains (point-in-polygon via ray casting) ──
TEST(PolygonTest, Contains_InteriorPoint) {
Polygon2D square({{0, 0}, {2, 0}, {2, 2}, {0, 2}});
// Center of the square
EXPECT_TRUE(square.contains(Point2D(1.0, 1.0)));
}
TEST(PolygonTest, Contains_ExteriorPoint) {
Polygon2D square({{0, 0}, {2, 0}, {2, 2}, {0, 2}});
// Far outside
EXPECT_FALSE(square.contains(Point2D(10.0, 10.0)));
// Outside but near
EXPECT_FALSE(square.contains(Point2D(-0.1, 1.0)));
}
TEST(PolygonTest, Contains_BoundaryPoint) {
Polygon2D square({{0, 0}, {2, 0}, {2, 2}, {0, 2}});
// On edge — behavior may vary; ray casting treats as intersection
// Not strictly "interior" in most implementations
Point2D on_edge(1.0, 0.0);
// Just verify it doesn't crash; boundary is valid input
bool result = square.contains(on_edge);
(void)result; // implementation-defined for boundary
SUCCEED();
}
TEST(PolygonTest, Contains_PointOnVertex) {
Polygon2D tri({{0, 0}, {2, 0}, {0, 2}});
// Exact vertex — should not crash
bool result = tri.contains(Point2D(0.0, 0.0));
(void)result;
SUCCEED();
}
TEST(PolygonTest, Contains_ConcavePolygon) {
// L-shaped polygon (concave)
Polygon2D L({{0, 0}, {3, 0}, {3, 1}, {2, 1}, {2, 3}, {0, 3}});
// Point in the "notch" area (1.5, 2) should be inside
EXPECT_TRUE(L.contains(Point2D(1.0, 2.0)));
// Point in the concave void
EXPECT_FALSE(L.contains(Point2D(2.5, 2.0)));
}
// ── is_ccw ──
TEST(PolygonTest, IsCCW) {
Polygon2D ccw({{0, 0}, {1, 0}, {1, 1}, {0, 1}});
Polygon2D cw({{0, 0}, {0, 1}, {1, 1}, {1, 0}});
EXPECT_TRUE(ccw.is_ccw());
EXPECT_FALSE(cw.is_ccw());
}
// ── Basic accessors ──
TEST(PolygonTest, SizeAndEmpty) {
Polygon2D empty;
EXPECT_TRUE(empty.empty());
EXPECT_EQ(empty.size(), 0u);
Polygon2D tri({{0, 0}, {1, 0}, {0, 1}});
EXPECT_FALSE(tri.empty());
EXPECT_EQ(tri.size(), 3u);
}
TEST(PolygonTest, VerticesAccessor) {
std::vector<Point2D> v = {{0, 0}, {1, 0}, {0, 1}};
Polygon2D poly(v);
EXPECT_EQ(poly.vertices().size(), 3u);
EXPECT_DOUBLE_EQ(poly.vertices()[0].x(), 0.0);
EXPECT_DOUBLE_EQ(poly.vertices()[1].y(), 0.0);
}
TEST(PolygonTest, DefaultConstructor_Empty) {
Polygon2D poly;
EXPECT_TRUE(poly.vertices().empty());
EXPECT_TRUE(poly.empty());
}
// ── Larger polygon area (regular hexagon) ──
TEST(PolygonTest, SignedArea_RegularHexagon) {
// Regular hexagon centered at origin, radius 1
// Vertices CCW: (1,0), (0.5,0.866), (-0.5,0.866), (-1,0), (-0.5,-0.866), (0.5,-0.866)
Polygon2D hex({
{1.0, 0.0}, {0.5, std::sqrt(3.0) / 2.0},
{-0.5, std::sqrt(3.0) / 2.0}, {-1.0, 0.0},
{-0.5, -std::sqrt(3.0) / 2.0}, {0.5, -std::sqrt(3.0) / 2.0}
});
// Area of regular hexagon = (3√3 / 2) * r² ≈ 2.598
EXPECT_NEAR(hex.signed_area(), 3.0 * std::sqrt(3.0) / 2.0, 1e-9);
}
TEST(PolygonTest, Contains_StarShapedHexagon) {
Polygon2D hex({
{1.0, 0.0}, {0.5, 0.866}, {-0.5, 0.866},
{-1.0, 0.0}, {-0.5, -0.866}, {0.5, -0.866}
});
EXPECT_TRUE(hex.contains(Point2D(0.0, 0.0)));
EXPECT_FALSE(hex.contains(Point2D(2.0, 0.0)));
}