feat/vtk-3d-view #7
|
|
@ -180,6 +180,17 @@ void TileBasemap::refineTile(int z, int x, int y, std::set<long long>& out, int&
|
||||||
const geopro::render::LonLatBox b = geopro::render::tileBounds(z, x, y);
|
const geopro::render::LonLatBox b = geopro::render::tileBounds(z, x, y);
|
||||||
const auto sw = frame_->toLocal(b.south, b.west);
|
const auto sw = frame_->toLocal(b.south, b.west);
|
||||||
const auto ne = frame_->toLocal(b.north, b.east);
|
const auto ne = frame_->toLocal(b.north, b.east);
|
||||||
|
|
||||||
|
// 视锥剔除:瓦片 AABB 全在某视锥面外侧 → 不在视野内,直接丢弃(否则会在屏幕外乱细分耗尽预算)。
|
||||||
|
const double zmin = -1000.0, zmax = 1000.0; // 地形起伏远小于瓦片尺度,给宽松 z 带
|
||||||
|
for (int p = 0; p < 6; ++p) {
|
||||||
|
const double* pl = &frustum_[p * 4]; // 内法向:内侧 a·x+b·y+c·z+d ≥ 0
|
||||||
|
const double vx = pl[0] >= 0 ? ne.x : sw.x; // 取最朝法向的角点(p-vertex)
|
||||||
|
const double vy = pl[1] >= 0 ? ne.y : sw.y;
|
||||||
|
const double vz = pl[2] >= 0 ? zmax : zmin;
|
||||||
|
if (pl[0] * vx + pl[1] * vy + pl[2] * vz + pl[3] < 0.0) return; // 全在外 → 剔除
|
||||||
|
}
|
||||||
|
|
||||||
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)); // 瓦片地面尺寸(米)
|
||||||
|
|
||||||
|
|
@ -219,6 +230,16 @@ void TileBasemap::refresh() {
|
||||||
projParallel_ = cam->GetParallelProjection();
|
projParallel_ = cam->GetParallelProjection();
|
||||||
projK_ = projParallel_ ? H / (2.0 * std::max(1.0, cam->GetParallelScale()))
|
projK_ = projParallel_ ? H / (2.0 * std::max(1.0, cam->GetParallelScale()))
|
||||||
: H / (2.0 * std::tan(cam->GetViewAngle() * 0.5 * kPi / 180.0));
|
: H / (2.0 * std::tan(cam->GetViewAngle() * 0.5 * kPi / 180.0));
|
||||||
|
const double aspect = (sz && sz[1] > 0) ? double(sz[0]) / double(sz[1]) : 1.0;
|
||||||
|
cam->GetFrustumPlanes(aspect, frustum_); // 6 视锥面(供 refineTile 剔除屏幕外瓦片)
|
||||||
|
// 用焦点(必在视锥内)统一各面方向为"内侧≥0",规避 VTK 法向内/外约定差异(否则可能全剔成黑屏)。
|
||||||
|
double fp[3];
|
||||||
|
cam->GetFocalPoint(fp);
|
||||||
|
for (int p = 0; p < 6; ++p) {
|
||||||
|
double* pl = &frustum_[p * 4];
|
||||||
|
if (pl[0] * fp[0] + pl[1] * fp[1] + pl[2] * fp[2] + pl[3] < 0.0)
|
||||||
|
for (int k = 0; k < 4; ++k) pl[k] = -pl[k];
|
||||||
|
}
|
||||||
|
|
||||||
// 四叉树:从数据中心一圈粗根块出发,按屏幕误差细分 → 近细远粗、铺满视野,无单层级盲区。
|
// 四叉树:从数据中心一圈粗根块出发,按屏幕误差细分 → 近细远粗、铺满视野,无单层级盲区。
|
||||||
desired_.clear();
|
desired_.clear();
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,11 @@ private:
|
||||||
std::set<long long> inFlight_; // 在途瓦片(续到起伏/平面最终落地)
|
std::set<long long> inFlight_; // 在途瓦片(续到起伏/平面最终落地)
|
||||||
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_; // 影像纹理缓存,重选/缩放回看免重拉
|
||||||
// 四叉树当前帧相机参数(refresh 写, refineTile 读):相机位置 + 投影系数。
|
// 四叉树当前帧相机参数(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;
|
||||||
bool projParallel_ = false;
|
bool projParallel_ = false;
|
||||||
|
double frustum_[24] = {0}; // 6 个视锥平面(内法向),AABB 全在某面外则剔除
|
||||||
struct PendingGet { QString url; std::function<void(QNetworkReply*)> cb; };
|
struct PendingGet { QString url; std::function<void(QNetworkReply*)> cb; };
|
||||||
std::deque<PendingGet> netQueue_; // 限并发请求队列(防瓦片暴发饱和卡死)
|
std::deque<PendingGet> netQueue_; // 限并发请求队列(防瓦片暴发饱和卡死)
|
||||||
int netInFlight_ = 0;
|
int netInFlight_ = 0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue