#include #include #include #include #include #include #include #include "CameraPreset.hpp" using namespace geopro::render; namespace { // 造一个带包围盒的 renderer(一个 cone actor),使 ResetCamera 有内容可重定位。 vtkSmartPointer rendererWithContent() { auto cone = vtkSmartPointer::New(); cone->SetCenter(0, 0, 0); cone->SetHeight(2.0); cone->SetRadius(1.0); auto mapper = vtkSmartPointer::New(); mapper->SetInputConnection(cone->GetOutputPort()); auto actor = vtkSmartPointer::New(); actor->SetMapper(mapper); auto r = vtkSmartPointer::New(); r->AddActor(actor); return r; } // 相机的视线方向单位向量 = focalPoint - position(归一化)。 void viewDir(vtkRenderer* r, double out[3]) { auto* c = r->GetActiveCamera(); double p[3], f[3]; c->GetPosition(p); c->GetFocalPoint(f); double d[3] = {f[0] - p[0], f[1] - p[1], f[2] - p[2]}; double n = std::sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); out[0] = d[0] / n; out[1] = d[1] / n; out[2] = d[2] / n; } } // namespace // Top:相机在焦点上方(pos.z>focal.z),视线朝 -Z,viewUp=+Y。 TEST(CameraPreset, TopLooksDown) { auto r = rendererWithContent(); applyView(r, ViewDir::Top); auto* c = r->GetActiveCamera(); double p[3], f[3], up[3]; c->GetPosition(p); c->GetFocalPoint(f); c->GetViewUp(up); EXPECT_GT(p[2], f[2]); // 相机在上方 double d[3]; viewDir(r, d); EXPECT_NEAR(d[2], -1.0, 1e-6); // 视线向下 EXPECT_NEAR(up[1], 1.0, 1e-6); // 北朝上 } // Bottom:相机在焦点下方,视线朝 +Z。 TEST(CameraPreset, BottomLooksUp) { auto r = rendererWithContent(); applyView(r, ViewDir::Bottom); auto* c = r->GetActiveCamera(); double p[3], f[3]; c->GetPosition(p); c->GetFocalPoint(f); EXPECT_LT(p[2], f[2]); double d[3]; viewDir(r, d); EXPECT_NEAR(d[2], 1.0, 1e-6); } // Front:相机在 -Y,视线朝 +Y,viewUp=+Z。 TEST(CameraPreset, FrontLooksNorth) { auto r = rendererWithContent(); applyView(r, ViewDir::Front); auto* c = r->GetActiveCamera(); double p[3], f[3], up[3]; c->GetPosition(p); c->GetFocalPoint(f); c->GetViewUp(up); EXPECT_LT(p[1], f[1]); double d[3]; viewDir(r, d); EXPECT_NEAR(d[1], 1.0, 1e-6); EXPECT_NEAR(up[2], 1.0, 1e-6); } // Back:相机在 +Y,视线朝 -Y。 TEST(CameraPreset, BackLooksSouth) { auto r = rendererWithContent(); applyView(r, ViewDir::Back); double d[3]; viewDir(r, d); EXPECT_NEAR(d[1], -1.0, 1e-6); } // Left:相机在 -X,视线朝 +X。 TEST(CameraPreset, LeftLooksEast) { auto r = rendererWithContent(); applyView(r, ViewDir::Left); auto* c = r->GetActiveCamera(); double p[3], f[3]; c->GetPosition(p); c->GetFocalPoint(f); EXPECT_LT(p[0], f[0]); double d[3]; viewDir(r, d); EXPECT_NEAR(d[0], 1.0, 1e-6); } // Right:相机在 +X,视线朝 -X。 TEST(CameraPreset, RightLooksWest) { auto r = rendererWithContent(); applyView(r, ViewDir::Right); double d[3]; viewDir(r, d); EXPECT_NEAR(d[0], -1.0, 1e-6); } // zoomBy(>1) 放大:透视下 vtkCamera::Zoom 收窄视角(ViewAngle 变小→画面放大)。 TEST(CameraPreset, ZoomInNarrowsViewAngle) { auto r = rendererWithContent(); applyFree3D(r); auto* c = r->GetActiveCamera(); const double before = c->GetViewAngle(); zoomBy(r, 1.2); EXPECT_LT(c->GetViewAngle(), before); } // zoomBy(<1) 缩小:透视下视角变宽(画面缩小)。 TEST(CameraPreset, ZoomOutWidensViewAngle) { auto r = rendererWithContent(); applyFree3D(r); auto* c = r->GetActiveCamera(); const double before = c->GetViewAngle(); zoomBy(r, 1.0 / 1.2); EXPECT_GT(c->GetViewAngle(), before); } // 正交投影下 zoomBy 改 parallelScale(放大缩小可视范围)。 TEST(CameraPreset, ZoomInOrthoReducesParallelScale) { auto r = rendererWithContent(); applyView(r, ViewDir::Top); // Top 不改投影模式;显式打开正交 auto* c = r->GetActiveCamera(); c->ParallelProjectionOn(); r->ResetCamera(); const double before = c->GetParallelScale(); zoomBy(r, 2.0); EXPECT_LT(c->GetParallelScale(), before); } // 空指针/非法 factor 安全。 TEST(CameraPreset, NullAndInvalidAreSafe) { applyView(nullptr, ViewDir::Top); zoomBy(nullptr, 1.2); fitView(nullptr); auto r = rendererWithContent(); const double before = r->GetActiveCamera()->GetDistance(); zoomBy(r, 0.0); // 非法 factor 忽略 zoomBy(r, -1.0); EXPECT_DOUBLE_EQ(r->GetActiveCamera()->GetDistance(), before); }