#include #include #include #include "interact/SlicePlaneMath.hpp" using namespace geopro::render::interact; namespace { void expectVec(const Vec3& a, double x, double y, double z, double eps = 1e-9) { EXPECT_NEAR(a[0], x, eps); EXPECT_NEAR(a[1], y, eps); EXPECT_NEAR(a[2], z, eps); } } // namespace // ── axisNormal:轴向法向(spec F22–F24)+ 任意 45°(F25)── TEST(SlicePlaneMath, AxisNormalUpDownIsZ) { expectVec(axisNormal(SliceAxis::UpDown), 0, 0, 1); } TEST(SlicePlaneMath, AxisNormalFrontBackIsY) { expectVec(axisNormal(SliceAxis::FrontBack), 0, 1, 0); } TEST(SlicePlaneMath, AxisNormalLeftRightIsX) { expectVec(axisNormal(SliceAxis::LeftRight), 1, 0, 0); } TEST(SlicePlaneMath, AxisNormalObliqueIs45) { const auto n = axisNormal(SliceAxis::Oblique); const double s = std::sqrt(0.5); expectVec(n, s, 0, s); EXPECT_NEAR(norm(n), 1.0, 1e-9); // 单位向量 } // ── boundsCenter ── TEST(SlicePlaneMath, BoundsCenter) { expectVec(boundsCenter({0, 10, -4, 4, 0, 6}), 5, 0, 3); } // ── advanceOrigin:沿法向平移(滚轮推进,D46)── TEST(SlicePlaneMath, AdvanceAlongZ) { expectVec(advanceOrigin({1, 2, 3}, {0, 0, 1}, 5.0), 1, 2, 8); } TEST(SlicePlaneMath, AdvanceBackward) { expectVec(advanceOrigin({1, 2, 3}, {0, 0, 1}, -2.0), 1, 2, 1); } TEST(SlicePlaneMath, AdvanceNormalizesDirection) { // 非单位法向:先归一化再推进,步长为世界距离。 expectVec(advanceOrigin({0, 0, 0}, {0, 0, 5}, 3.0), 0, 0, 3); } TEST(SlicePlaneMath, AdvanceObliqueMovesAlong45) { const auto o = advanceOrigin({0, 0, 0}, {1, 0, 1}, std::sqrt(2.0)); expectVec(o, 1, 0, 1); // 沿 45° 推进 √2 → (1,0,1) } // ── clampToBounds:推进出体外被夹回(滚轮限位)── TEST(SlicePlaneMath, ClampInsideUnchanged) { expectVec(clampToBounds({5, 0, 3}, {0, 10, -4, 4, 0, 6}), 5, 0, 3); } TEST(SlicePlaneMath, ClampOutsideHigh) { expectVec(clampToBounds({5, 0, 99}, {0, 10, -4, 4, 0, 6}), 5, 0, 6); } TEST(SlicePlaneMath, ClampOutsideLow) { expectVec(clampToBounds({-5, 0, -1}, {0, 10, -4, 4, 0, 6}), 0, 0, 0); } // ── faceOnCamera:双击正视(E54)── // 法向 +Y:相机退到 focal+Y*dist,视线 = -Y,viewUp = +Z(切面内向上)。 TEST(SlicePlaneMath, FaceOnFrontBackNormal) { const auto cam = faceOnCamera({0, 0, 0}, {0, 1, 0}, 10.0); expectVec(cam.position, 0, 10, 0); // viewUp 与法向正交且偏 +Z。 EXPECT_NEAR(dot(cam.viewUp, Vec3{0, 1, 0}), 0.0, 1e-9); EXPECT_GT(cam.viewUp[2], 0.5); } // 法向 +X:position=focal+X*dist,viewUp 偏 +Z。 TEST(SlicePlaneMath, FaceOnLeftRightNormal) { const auto cam = faceOnCamera({1, 2, 3}, {1, 0, 0}, 5.0); expectVec(cam.position, 6, 2, 3); EXPECT_NEAR(dot(cam.viewUp, Vec3{1, 0, 0}), 0.0, 1e-9); EXPECT_GT(cam.viewUp[2], 0.5); } // 法向竖直 +Z(上下切片):viewUp 不能再取 +Z(与法向共线),兜底取 +Y。 TEST(SlicePlaneMath, FaceOnVerticalNormalFallsBackToY) { const auto cam = faceOnCamera({0, 0, 0}, {0, 0, 1}, 8.0); expectVec(cam.position, 0, 0, 8); // viewUp 与法向(+Z)正交(z≈0),且非零。 EXPECT_NEAR(cam.viewUp[2], 0.0, 1e-9); EXPECT_NEAR(norm(cam.viewUp), 1.0, 1e-9); } // 法向竖直 -Z 同样兜底。 TEST(SlicePlaneMath, FaceOnVerticalDownNormalFallsBack) { const auto cam = faceOnCamera({0, 0, 0}, {0, 0, -1}, 4.0); expectVec(cam.position, 0, 0, -4); EXPECT_NEAR(cam.viewUp[2], 0.0, 1e-9); EXPECT_NEAR(norm(cam.viewUp), 1.0, 1e-9); } // 非单位法向:position 用归一化法向 → 距焦点恰为 dist。 TEST(SlicePlaneMath, FaceOnNormalizesNormal) { const auto cam = faceOnCamera({0, 0, 0}, {0, 3, 0}, 6.0); expectVec(cam.position, 0, 6, 0); } // ── wheelStep:滚轮推进步长(按对角线比例 × 方向)── TEST(SlicePlaneMath, WheelStepForwardPositive) { EXPECT_GT(wheelStep({0, 10, 0, 0, 0, 0}, +1), 0.0); } TEST(SlicePlaneMath, WheelStepBackwardNegative) { EXPECT_LT(wheelStep({0, 10, 0, 0, 0, 0}, -1), 0.0); } TEST(SlicePlaneMath, WheelStepScalesWithBounds) { const double small = wheelStep({0, 10, 0, 0, 0, 0}, 1); const double big = wheelStep({0, 100, 0, 0, 0, 0}, 1); EXPECT_GT(big, small); // 体越大步长越大 } // ── nearestPlane:找点所在切片(按到平面距离最小)── TEST(SlicePlaneMath, NearestPlaneEmptyIsMinusOne) { EXPECT_EQ(nearestPlane({}, {}, {0, 0, 0}), -1); } TEST(SlicePlaneMath, NearestPlanePicksClosest) { // 两张水平切片 z=0 与 z=10(法向 +Z);点 z=8 → 更近 z=10(索引 1)。 std::vector centers{{0, 0, 0}, {0, 0, 10}}; std::vector normals{{0, 0, 1}, {0, 0, 1}}; EXPECT_EQ(nearestPlane(centers, normals, {5, 5, 8}), 1); EXPECT_EQ(nearestPlane(centers, normals, {5, 5, 2}), 0); } TEST(SlicePlaneMath, NearestPlaneIgnoresInPlaneOffset) { // 单张 z=0 水平面:点无论 x/y 多远,只要 z=0 距离为 0 → 命中。 std::vector centers{{0, 0, 0}}; std::vector normals{{0, 0, 1}}; EXPECT_EQ(nearestPlane(centers, normals, {999, -999, 0}), 0); } // ── 向量工具 ── TEST(SlicePlaneMath, NormalizeZeroFallsBack) { expectVec(normalize({0, 0, 0}), 0, 0, 1); } TEST(SlicePlaneMath, CrossBasic) { expectVec(cross({1, 0, 0}, {0, 1, 0}), 0, 0, 1); }