diff --git a/src/app/TileBasemap.cpp b/src/app/TileBasemap.cpp index 2bbf928..4cde51d 100644 --- a/src/app/TileBasemap.cpp +++ b/src/app/TileBasemap.cpp @@ -43,7 +43,10 @@ const char* kTk = "aca91d8c9f59a4f779f39061b8a07737"; constexpr int kRootZoom = 9; // 四叉树根层级(单块~78km,±1 覆盖~234km 到天边) constexpr double kTargetPx = 384.0; // 瓦片屏幕像素阈值:超过则细分(越小越清晰但块更多) constexpr int kMaxLeaves = 200; // 一次覆盖的叶瓦片上限(安全兜底,防细分爆炸) -constexpr double kMaxTileDist = 10000.0; // 底图离数据中心最大距离(米):远裁剪面有界,且免无限拉远 +// 底图最大距离按剖面范围动态定:半径×倍数,夹在[下限,上限]。随勾选增删自动伸缩;无数据时用下限。 +constexpr double kRangeFactor = 10.0; +constexpr double kRangeFloor = 2000.0; // 至少 2km(小剖面也有足够地理背景) +constexpr double kRangeCeil = 30000.0; // 最多 30km(防远裁剪面失控) constexpr int kMaxConcurrent = 8; // 瓦片请求最大并发(防暴发饱和单域名连接) constexpr int kMinZoom = 3; constexpr int kMaxZoom = 18; @@ -217,9 +220,9 @@ void TileBasemap::refineTile(int z, int x, int y, std::set& out, int& const double cx = (sw.x + ne.x) * 0.5, cy = (sw.y + ne.y) * 0.5; // 瓦片中心(局部米) const double g = std::max(std::abs(ne.x - sw.x), std::abs(ne.y - sw.y)); // 瓦片地面尺寸(米) - // 距离上限:数据中心在局部原点(0,0);瓦片离它太远则不加载——远裁剪面有界(剖面不被近裁剪面切), - // 也避免拉远时无限铺。叶块本身可大于此距离(其近端仍在范围内即保留)。 - if (std::sqrt(cx * cx + cy * cy) - g * 0.5 > kMaxTileDist) return; + // 距离上限(按剖面范围动态):数据中心在局部原点(0,0);瓦片离它太远则不加载——远裁剪面有界 + // (剖面不被近裁剪面切),也避免拉远无限铺。叶块本身可大于此距离(其近端仍在范围内即保留)。 + if (std::sqrt(cx * cx + cy * cy) - g * 0.5 > maxTileDist_) return; // 该瓦片投影到屏幕的近似像素尺寸 > 阈值且未到最大层级 → 细分为 4 子块(近处更细)。 double screenPx; @@ -268,6 +271,13 @@ void TileBasemap::refresh() { for (int k = 0; k < 4; ++k) pl[k] = -pl[k]; } + // 底图最大距离按当前剖面合并范围动态定(随勾选增删自动伸缩);无数据用下限。 + maxTileDist_ = kRangeFloor; + if (dataRadiusProvider_) { + const double r = dataRadiusProvider_(); + if (r > 0.0) maxTileDist_ = std::clamp(r * kRangeFactor, kRangeFloor, kRangeCeil); + } + // 四叉树:从数据中心一圈粗根块出发,按屏幕误差细分 → 近细远粗、铺满视野,无单层级盲区。 desired_.clear(); int count = 0; diff --git a/src/app/TileBasemap.hpp b/src/app/TileBasemap.hpp index 4fd8925..128de87 100644 --- a/src/app/TileBasemap.hpp +++ b/src/app/TileBasemap.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,8 @@ public: void hide(); // 移除全部瓦片 void refresh(); // 按当前相机重算层级+覆盖,增量更新瓦片(交互结束回调) void setVerticalExaggeration(double ve); // 地形垂向夸张(须与剖面 VE 一致才对齐) + // 数据半径提供者:刷新时查询当前所有勾选剖面的合并范围(半径,米),据此动态定底图最大范围。 + void setDataRadiusProvider(std::function fn) { dataRadiusProvider_ = std::move(fn); } private: static long long tileKey(int z, int x, int y); @@ -73,6 +76,8 @@ private: std::map demCache_; // DEM 块缓存(key=DEMz/x/y),跨隐藏/重选复用 std::map> texCache_; // 影像纹理缓存,重选/缩放回看免重拉 double ve_ = 1.0; // 地形垂向夸张(与剖面 verticalExaggeration 一致才对齐) + double maxTileDist_ = 2000.0; // 底图最大距离(米),每次刷新按剖面范围动态算 + std::function dataRadiusProvider_; // 返回当前勾选剖面合并范围的半径 // 四叉树当前帧相机参数(refresh 写, refineTile 读):相机位置 + 投影系数 + 视锥 6 面。 double camX_ = 0, camY_ = 0, camZ_ = 0; double projK_ = 1.0; diff --git a/src/app/VtkSceneView.cpp b/src/app/VtkSceneView.cpp index f14bbeb..d5bb518 100644 --- a/src/app/VtkSceneView.cpp +++ b/src/app/VtkSceneView.cpp @@ -1,6 +1,7 @@ #include "VtkSceneView.hpp" #include +#include #include #include @@ -88,6 +89,13 @@ bool VtkSceneView::computeDataBounds(double out[6]) const { return true; } +double VtkSceneView::dataHorizontalRadius() const { + double b[6]; + if (!computeDataBounds(b)) return 0.0; + const double dx = b[1] - b[0], dy = b[3] - b[2]; + return 0.5 * std::sqrt(dx * dx + dy * dy); // 水平对角线半径 +} + void VtkSceneView::clear() { // 只移除数据 prop(按 ds 跟踪)+ 杂项(地形/测线)+ 坐标轴;不动底图(TileBasemap 自管)→ 重建不丢图。 for (auto& kv : dsProps_) removeProps(kv.second); diff --git a/src/app/VtkSceneView.hpp b/src/app/VtkSceneView.hpp index 70dbeab..7bffe6c 100644 --- a/src/app/VtkSceneView.hpp +++ b/src/app/VtkSceneView.hpp @@ -72,6 +72,12 @@ private: // 仅数据图元(剖面/体素/地形/测线)的包围盒,不含底图 → 坐标轴/取景不被~公里级底图撑大。 bool computeDataBounds(double out[6]) const; +public: + // 当前所有数据图元(剖面等)合并范围的水平半径(米);无数据返回 0。供底图动态定最大范围。 + double dataHorizontalRadius() const; + +private: + geopro::render::Scene& scene_; vtkRenderWindow* renderWindow_; std::shared_ptr frame_; diff --git a/src/app/main.cpp b/src/app/main.cpp index a9048ba..67ff4e5 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -414,6 +414,8 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re }; // 相机程序化变化(取景/预设/缩放)后,底图按新视锥重算覆盖(治首帧部分瓦片需手动微动才出)。 sceneView->onCameraChanged = [basemap]() { basemap->refresh(); }; + // 底图最大范围按当前勾选剖面合并范围动态定(随增删自动伸缩);刷新时实时查询。 + basemap->setDataRadiusProvider([sceneView]() { return sceneView->dataHorizontalRadius(); }); // 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。 QObject::connect(drawer->col3D(), &geopro::app::Column3DDataset::verticalExaggerationChanged, basemap, [basemap](double ve) { basemap->setVerticalExaggeration(ve); });