#include #include #include #include "algo/VolumeBuilder.hpp" using namespace geopro::core; namespace { // 构造一个直角三角形足迹的散点:顶点 (0,0)/(100,0)/(0,100),沿三条边各撒点(值=10)。 // 凸包 = 该三角形;外接盒 = [0,100]×[0,100],右上角 (100,100) 落在凸包外。 PointSet trianglePoints() { PointSet pts; auto add = [&](double x, double y) { pts.x.push_back(x); pts.y.push_back(y); pts.z.push_back(0.0); pts.v.push_back(10.0); }; for (int t = 0; t <= 100; t += 10) { add(static_cast(t), 0.0); // 底边 y=0 add(0.0, static_cast(t)); // 左边 x=0 add(static_cast(t), 100.0 - t); // 斜边 x+y=100 } return pts; } } // namespace // maxDist=0(自动有界半径)+ 默认凸包裁剪:凸包内填满;凸包外即便在半径内也被裁成 NaN。 TEST(VolumeBuilder, FootprintClipBlanksOutsideHull) { const PointSet pts = trianglePoints(); const BuiltVolume bv = buildVolume(pts, /*cellXY*/10.0, /*cellZ*/10.0, /*power*/2.0, /*maxDist*/0.0, /*clipToFootprint*/true); // 网格:ox=oy=0, dx=dy=10, nx=ny=11;nz 退化(z 跨度 0)补到 2(防 GPU 体绘制拒绝 1 层厚体)。 ASSERT_EQ(bv.spec.nx, 11); ASSERT_EQ(bv.spec.ny, 11); ASSERT_EQ(bv.spec.nz, 2); // (40,40) 在三角形内(40+40<100)→ 有限值。 EXPECT_TRUE(std::isfinite(bv.vol.at(4, 4, 0))); // (60,60) 在凸包外(60+60>100)但离斜边仅 ~14m(在自动半径 ~28m 内)→ 足迹裁剪置空 → NaN。 EXPECT_TRUE(std::isnan(bv.vol.at(6, 6, 0))); } // 关闭裁剪:凸包外但在半径内的 (60,60) 被 IDW 填满(证明上例的 NaN 确由足迹裁剪所致,而非取不到点)。 TEST(VolumeBuilder, NoClipKeepsInRadiusOutsideHull) { const PointSet pts = trianglePoints(); const BuiltVolume bv = buildVolume(pts, 10.0, 10.0, 2.0, /*maxDist*/0.0, /*clipToFootprint*/false); EXPECT_TRUE(std::isfinite(bv.vol.at(6, 6, 0))); } // 退化(单条近共线剖面:XY 全在一条线上)→ 凸包退化 → 跳过裁剪,不致全盘置空。 TEST(VolumeBuilder, DegenerateCollinearSkipsClip) { PointSet pts; for (int t = 0; t <= 100; t += 10) { pts.x.push_back(static_cast(t)); pts.y.push_back(0.0); pts.z.push_back(0.0); pts.v.push_back(5.0); } const BuiltVolume bv = buildVolume(pts, 10.0, 10.0, 2.0, /*maxDist*/0.0, /*clipToFootprint*/true); // y 跨度 0(退化维补到 ny=2);节点应被 IDW 正常填充(裁剪跳过,不应全 NaN)。 EXPECT_TRUE(std::isfinite(bv.vol.at(5, 0, 0))); }