fix(vtk): 加请求限流(最多8并发,治瓦片暴发饱和单域名致加载不进/卡死)+精细优先于粗底排队
This commit is contained in:
parent
b5bab42825
commit
63e7874175
|
|
@ -3,6 +3,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
@ -43,6 +44,7 @@ constexpr int kRadius = 4; // 回退用:算不出可视范围时中
|
||||||
constexpr int kMaxTilesPerSide = 13; // 单边瓦片上限(防倾斜时可视范围过大拉爆请求)
|
constexpr int kMaxTilesPerSide = 13; // 单边瓦片上限(防倾斜时可视范围过大拉爆请求)
|
||||||
constexpr int kBaseZoom = 13; // 远处粗底层级(单块~4.9km)
|
constexpr int kBaseZoom = 13; // 远处粗底层级(单块~4.9km)
|
||||||
constexpr int kBaseRadius = 3; // 粗底半径 ±3 → 7x7 覆盖~34km,填到天边
|
constexpr int kBaseRadius = 3; // 粗底半径 ±3 → 7x7 覆盖~34km,填到天边
|
||||||
|
constexpr int kMaxConcurrent = 8; // 瓦片请求最大并发(防暴发饱和单域名连接)
|
||||||
constexpr int kMinZoom = 3;
|
constexpr int kMinZoom = 3;
|
||||||
constexpr int kMaxZoom = 18;
|
constexpr int kMaxZoom = 18;
|
||||||
constexpr double kGroundZ = 0.0; // 底图置于 z=0 地面参考(剖面深度向下为负,落其下)
|
constexpr double kGroundZ = 0.0; // 底图置于 z=0 地面参考(剖面深度向下为负,落其下)
|
||||||
|
|
@ -132,6 +134,26 @@ void TileBasemap::onInteractionEnd(vtkObject*, unsigned long, void* clientData,
|
||||||
if (auto* self = static_cast<TileBasemap*>(clientData)) self->refresh();
|
if (auto* self = static_cast<TileBasemap*>(clientData)) self->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileBasemap::enqueueGet(const QString& url, std::function<void(QNetworkReply*)> onDone) {
|
||||||
|
netQueue_.push_back({url, std::move(onDone)});
|
||||||
|
pumpNetQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileBasemap::pumpNetQueue() {
|
||||||
|
while (netInFlight_ < kMaxConcurrent && !netQueue_.empty()) {
|
||||||
|
const PendingGet req = std::move(netQueue_.front());
|
||||||
|
netQueue_.pop_front();
|
||||||
|
++netInFlight_;
|
||||||
|
QNetworkReply* reply = nam_.get(QNetworkRequest(QUrl(req.url)));
|
||||||
|
auto cb = req.cb;
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [this, reply, cb]() {
|
||||||
|
cb(reply); // 回调内部 deleteLater + 处理
|
||||||
|
--netInFlight_;
|
||||||
|
pumpNetQueue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TileBasemap::hide() { show(Hidden); }
|
void TileBasemap::hide() { show(Hidden); }
|
||||||
|
|
||||||
void TileBasemap::show(Kind kind) {
|
void TileBasemap::show(Kind kind) {
|
||||||
|
|
@ -143,6 +165,7 @@ void TileBasemap::show(Kind kind) {
|
||||||
baseTiles_.clear();
|
baseTiles_.clear();
|
||||||
baseLoaded_ = false;
|
baseLoaded_ = false;
|
||||||
inFlight_.clear();
|
inFlight_.clear();
|
||||||
|
netQueue_.clear(); // 丢弃换源前排队中的请求(在途的按 gen 自然作废)
|
||||||
desired_.clear();
|
desired_.clear();
|
||||||
// demCache_/texCache_ 跨隐藏-重选保留 → 重选地图秒出,不重拉。
|
// demCache_/texCache_ 跨隐藏-重选保留 → 重选地图秒出,不重拉。
|
||||||
haveBaseline_ = false; // 数据可能已换位置 → 重算基准高程
|
haveBaseline_ = false; // 数据可能已换位置 → 重算基准高程
|
||||||
|
|
@ -152,8 +175,8 @@ void TileBasemap::show(Kind kind) {
|
||||||
if (rw_) rw_->Render();
|
if (rw_) rw_->Render();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ensureBaseLayer(); // 先铺远处粗底(填到天边),再叠近处精细
|
refresh(); // 先排近处精细(优先加载,用户最先看到)
|
||||||
refresh();
|
ensureBaseLayer(); // 再排远处粗底(背景,排队在后)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileBasemap::computeView(double& centerLat, double& centerLon, int& zoom) const {
|
bool TileBasemap::computeView(double& centerLat, double& centerLon, int& zoom) const {
|
||||||
|
|
@ -334,8 +357,7 @@ void TileBasemap::fetchTile(int z, int x, int y, long long key) {
|
||||||
|
|
||||||
const int gen = generation_;
|
const int gen = generation_;
|
||||||
inFlight_.insert(key);
|
inFlight_.insert(key);
|
||||||
QNetworkReply* reply = nam_.get(QNetworkRequest(QUrl(url)));
|
enqueueGet(url, [this, key, z, x, y, gen](QNetworkReply* reply) {
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, reply, key, z, x, y, gen]() {
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
// inFlight 保持到瓦片最终落地(起伏/平面),使旧层在新块就位前不被清理 → 无空白闪烁。
|
// inFlight 保持到瓦片最终落地(起伏/平面),使旧层在新块就位前不被清理 → 无空白闪烁。
|
||||||
QImage img;
|
QImage img;
|
||||||
|
|
@ -423,8 +445,7 @@ void TileBasemap::fetchBaseTile(int z, int x, int y) {
|
||||||
const QString durl =
|
const QString durl =
|
||||||
QStringLiteral("https://api.mapbox.com/v4/mapbox.terrain-rgb/%1/%2/%3.pngraw?access_token=%4")
|
QStringLiteral("https://api.mapbox.com/v4/mapbox.terrain-rgb/%1/%2/%3.pngraw?access_token=%4")
|
||||||
.arg(z).arg(x).arg(y).arg(QString::fromLatin1(kMapboxToken));
|
.arg(z).arg(x).arg(y).arg(QString::fromLatin1(kMapboxToken));
|
||||||
QNetworkReply* dr = nam_.get(QNetworkRequest(QUrl(durl)));
|
enqueueGet(durl, [this, demKey, gen, placeBase](QNetworkReply* dr) {
|
||||||
connect(dr, &QNetworkReply::finished, this, [this, dr, demKey, gen, placeBase]() {
|
|
||||||
dr->deleteLater();
|
dr->deleteLater();
|
||||||
if (gen != generation_) return;
|
if (gen != generation_) return;
|
||||||
QImage dem;
|
QImage dem;
|
||||||
|
|
@ -445,8 +466,7 @@ void TileBasemap::fetchBaseTile(int z, int x, int y) {
|
||||||
"&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix=%2&TileRow=%3"
|
"&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix=%2&TileRow=%3"
|
||||||
"&TileCol=%4&style=default&format=tiles&tk=%5")
|
"&TileCol=%4&style=default&format=tiles&tk=%5")
|
||||||
.arg(sub).arg(z).arg(y).arg(x).arg(QString::fromLatin1(kTk));
|
.arg(sub).arg(z).arg(y).arg(x).arg(QString::fromLatin1(kTk));
|
||||||
QNetworkReply* reply = nam_.get(QNetworkRequest(QUrl(url)));
|
enqueueGet(url, [this, key, gen, onTex](QNetworkReply* reply) {
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, reply, key, gen, onTex]() {
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
if (gen != generation_ || kind_ != Satellite) return;
|
if (gen != generation_ || kind_ != Satellite) return;
|
||||||
QImage img;
|
QImage img;
|
||||||
|
|
@ -520,8 +540,7 @@ void TileBasemap::fetchTerrain(int z, int x, int y, long long key, vtkSmartPoint
|
||||||
.arg(dy)
|
.arg(dy)
|
||||||
.arg(QString::fromLatin1(kMapboxToken));
|
.arg(QString::fromLatin1(kMapboxToken));
|
||||||
const int gen = generation_;
|
const int gen = generation_;
|
||||||
QNetworkReply* reply = nam_.get(QNetworkRequest(QUrl(url)));
|
enqueueGet(url, [this, key, demKey, gen, place](QNetworkReply* reply) {
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, reply, key, demKey, gen, place]() {
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
if (gen != generation_ || kind_ != Satellite ||
|
if (gen != generation_ || kind_ != Satellite ||
|
||||||
desired_.find(key) == desired_.end() || placed_.count(key)) {
|
desired_.find(key) == desired_.end() || placed_.count(key)) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
@ -17,6 +19,7 @@ class vtkTexture;
|
||||||
class vtkRenderWindow;
|
class vtkRenderWindow;
|
||||||
class vtkInteractorObserver;
|
class vtkInteractorObserver;
|
||||||
class vtkCallbackCommand;
|
class vtkCallbackCommand;
|
||||||
|
class QNetworkReply;
|
||||||
namespace geopro::render { class Scene; }
|
namespace geopro::render { class Scene; }
|
||||||
namespace geopro::core { class GeoLocalFrame; }
|
namespace geopro::core { class GeoLocalFrame; }
|
||||||
|
|
||||||
|
|
@ -55,6 +58,9 @@ private:
|
||||||
vtkSmartPointer<vtkActor> buildWarped(int sz, int sx, int sy, int dz, int dx, int dy,
|
vtkSmartPointer<vtkActor> buildWarped(int sz, int sx, int sy, int dz, int dx, int dy,
|
||||||
vtkSmartPointer<vtkTexture> tex,
|
vtkSmartPointer<vtkTexture> tex,
|
||||||
const QImage& dem); // DEM 位移网格 + 卫星贴图
|
const QImage& dem); // DEM 位移网格 + 卫星贴图
|
||||||
|
void enqueueGet(const QString& url,
|
||||||
|
std::function<void(QNetworkReply*)> onDone); // 限并发取瓦片(回调内负责 deleteLater)
|
||||||
|
void pumpNetQueue();
|
||||||
static void onInteractionEnd(vtkObject*, unsigned long, void* clientData, void*);
|
static void onInteractionEnd(vtkObject*, unsigned long, void* clientData, void*);
|
||||||
|
|
||||||
geopro::render::Scene& scene_;
|
geopro::render::Scene& scene_;
|
||||||
|
|
@ -70,6 +76,9 @@ private:
|
||||||
std::map<long long, vtkSmartPointer<vtkTexture>> texCache_; // 影像纹理缓存,重选/缩放回看免重拉
|
std::map<long long, vtkSmartPointer<vtkTexture>> texCache_; // 影像纹理缓存,重选/缩放回看免重拉
|
||||||
std::vector<vtkSmartPointer<vtkActor>> baseTiles_; // 远处粗底层(持久,不随相机purge)
|
std::vector<vtkSmartPointer<vtkActor>> baseTiles_; // 远处粗底层(持久,不随相机purge)
|
||||||
bool baseLoaded_ = false;
|
bool baseLoaded_ = false;
|
||||||
|
struct PendingGet { QString url; std::function<void(QNetworkReply*)> cb; };
|
||||||
|
std::deque<PendingGet> netQueue_; // 限并发请求队列(防瓦片暴发饱和卡死)
|
||||||
|
int netInFlight_ = 0;
|
||||||
double baseline_ = 0.0; // 基准高程(首块中心),地形绕 z=0 起伏
|
double baseline_ = 0.0; // 基准高程(首块中心),地形绕 z=0 起伏
|
||||||
bool haveBaseline_ = false;
|
bool haveBaseline_ = false;
|
||||||
bool terrainProbed_ = false; // 首次 fetchTerrain 打一行诊断日志
|
bool terrainProbed_ = false; // 首次 fetchTerrain 打一行诊断日志
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue