feat/vtk-3d-view #7

Merged
gaozheng merged 301 commits from feat/vtk-3d-view into main 2026-06-27 18:43:52 +08:00
5 changed files with 35 additions and 4 deletions
Showing only changes of commit 484992a434 - Show all commits

View File

@ -43,7 +43,10 @@ const char* kTk = "aca91d8c9f59a4f779f39061b8a07737";
constexpr int kRootZoom = 9; // 四叉树根层级(单块~78km±1 覆盖~234km 到天边) constexpr int kRootZoom = 9; // 四叉树根层级(单块~78km±1 覆盖~234km 到天边)
constexpr double kTargetPx = 384.0; // 瓦片屏幕像素阈值:超过则细分(越小越清晰但块更多) constexpr double kTargetPx = 384.0; // 瓦片屏幕像素阈值:超过则细分(越小越清晰但块更多)
constexpr int kMaxLeaves = 200; // 一次覆盖的叶瓦片上限(安全兜底,防细分爆炸) 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 kMaxConcurrent = 8; // 瓦片请求最大并发(防暴发饱和单域名连接)
constexpr int kMinZoom = 3; constexpr int kMinZoom = 3;
constexpr int kMaxZoom = 18; constexpr int kMaxZoom = 18;
@ -217,9 +220,9 @@ void TileBasemap::refineTile(int z, int x, int y, std::set<long long>& out, int&
const double cx = (sw.x + ne.x) * 0.5, cy = (sw.y + ne.y) * 0.5; // 瓦片中心(局部米) 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)); // 瓦片地面尺寸(米) const double g = std::max(std::abs(ne.x - sw.x), std::abs(ne.y - sw.y)); // 瓦片地面尺寸(米)
// 距离上限:数据中心在局部原点(0,0);瓦片离它太远则不加载——远裁剪面有界(剖面不被近裁剪面切) // 距离上限(按剖面范围动态):数据中心在局部原点(0,0);瓦片离它太远则不加载——远裁剪面有界
// 也避免拉远无限铺。叶块本身可大于此距离(其近端仍在范围内即保留)。 // (剖面不被近裁剪面切)也避免拉远无限铺。叶块本身可大于此距离(其近端仍在范围内即保留)。
if (std::sqrt(cx * cx + cy * cy) - g * 0.5 > kMaxTileDist) return; if (std::sqrt(cx * cx + cy * cy) - g * 0.5 > maxTileDist_) return;
// 该瓦片投影到屏幕的近似像素尺寸 > 阈值且未到最大层级 → 细分为 4 子块(近处更细)。 // 该瓦片投影到屏幕的近似像素尺寸 > 阈值且未到最大层级 → 细分为 4 子块(近处更细)。
double screenPx; double screenPx;
@ -268,6 +271,13 @@ void TileBasemap::refresh() {
for (int k = 0; k < 4; ++k) pl[k] = -pl[k]; 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(); desired_.clear();
int count = 0; int count = 0;

View File

@ -9,6 +9,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <set> #include <set>
#include <utility>
#include <vector> #include <vector>
#include <vtkSmartPointer.h> #include <vtkSmartPointer.h>
@ -39,6 +40,8 @@ public:
void hide(); // 移除全部瓦片 void hide(); // 移除全部瓦片
void refresh(); // 按当前相机重算层级+覆盖,增量更新瓦片(交互结束回调) void refresh(); // 按当前相机重算层级+覆盖,增量更新瓦片(交互结束回调)
void setVerticalExaggeration(double ve); // 地形垂向夸张(须与剖面 VE 一致才对齐) void setVerticalExaggeration(double ve); // 地形垂向夸张(须与剖面 VE 一致才对齐)
// 数据半径提供者:刷新时查询当前所有勾选剖面的合并范围(半径,米),据此动态定底图最大范围。
void setDataRadiusProvider(std::function<double()> fn) { dataRadiusProvider_ = std::move(fn); }
private: private:
static long long tileKey(int z, int x, int y); static long long tileKey(int z, int x, int y);
@ -73,6 +76,8 @@ private:
std::map<long long, QImage> demCache_; // DEM 块缓存(key=DEMz/x/y),跨隐藏/重选复用 std::map<long long, QImage> demCache_; // DEM 块缓存(key=DEMz/x/y),跨隐藏/重选复用
std::map<long long, vtkSmartPointer<vtkTexture>> texCache_; // 影像纹理缓存,重选/缩放回看免重拉 std::map<long long, vtkSmartPointer<vtkTexture>> texCache_; // 影像纹理缓存,重选/缩放回看免重拉
double ve_ = 1.0; // 地形垂向夸张(与剖面 verticalExaggeration 一致才对齐) double ve_ = 1.0; // 地形垂向夸张(与剖面 verticalExaggeration 一致才对齐)
double maxTileDist_ = 2000.0; // 底图最大距离(米),每次刷新按剖面范围动态算
std::function<double()> dataRadiusProvider_; // 返回当前勾选剖面合并范围的半径
// 四叉树当前帧相机参数(refresh 写, refineTile 读):相机位置 + 投影系数 + 视锥 6 面。 // 四叉树当前帧相机参数(refresh 写, refineTile 读):相机位置 + 投影系数 + 视锥 6 面。
double camX_ = 0, camY_ = 0, camZ_ = 0; double camX_ = 0, camY_ = 0, camZ_ = 0;
double projK_ = 1.0; double projK_ = 1.0;

View File

@ -1,6 +1,7 @@
#include "VtkSceneView.hpp" #include "VtkSceneView.hpp"
#include <algorithm> #include <algorithm>
#include <cmath>
#include <memory> #include <memory>
#include <utility> #include <utility>
@ -88,6 +89,13 @@ bool VtkSceneView::computeDataBounds(double out[6]) const {
return true; 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() { void VtkSceneView::clear() {
// 只移除数据 prop按 ds 跟踪)+ 杂项(地形/测线)+ 坐标轴;不动底图(TileBasemap 自管)→ 重建不丢图。 // 只移除数据 prop按 ds 跟踪)+ 杂项(地形/测线)+ 坐标轴;不动底图(TileBasemap 自管)→ 重建不丢图。
for (auto& kv : dsProps_) removeProps(kv.second); for (auto& kv : dsProps_) removeProps(kv.second);

View File

@ -72,6 +72,12 @@ private:
// 仅数据图元(剖面/体素/地形/测线)的包围盒,不含底图 → 坐标轴/取景不被~公里级底图撑大。 // 仅数据图元(剖面/体素/地形/测线)的包围盒,不含底图 → 坐标轴/取景不被~公里级底图撑大。
bool computeDataBounds(double out[6]) const; bool computeDataBounds(double out[6]) const;
public:
// 当前所有数据图元(剖面等)合并范围的水平半径(米);无数据返回 0。供底图动态定最大范围。
double dataHorizontalRadius() const;
private:
geopro::render::Scene& scene_; geopro::render::Scene& scene_;
vtkRenderWindow* renderWindow_; vtkRenderWindow* renderWindow_;
std::shared_ptr<geopro::core::GeoLocalFrame> frame_; std::shared_ptr<geopro::core::GeoLocalFrame> frame_;

View File

@ -414,6 +414,8 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
}; };
// 相机程序化变化(取景/预设/缩放)后,底图按新视锥重算覆盖(治首帧部分瓦片需手动微动才出)。 // 相机程序化变化(取景/预设/缩放)后,底图按新视锥重算覆盖(治首帧部分瓦片需手动微动才出)。
sceneView->onCameraChanged = [basemap]() { basemap->refresh(); }; sceneView->onCameraChanged = [basemap]() { basemap->refresh(); };
// 底图最大范围按当前勾选剖面合并范围动态定(随增删自动伸缩);刷新时实时查询。
basemap->setDataRadiusProvider([sceneView]() { return sceneView->dataHorizontalRadius(); });
// 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。 // 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。
QObject::connect(drawer->col3D(), &geopro::app::Column3DDataset::verticalExaggerationChanged, QObject::connect(drawer->col3D(), &geopro::app::Column3DDataset::verticalExaggerationChanged,
basemap, [basemap](double ve) { basemap->setVerticalExaggeration(ve); }); basemap, [basemap](double ve) { basemap->setVerticalExaggeration(ve); });