feat/vtk-3d-view #7
|
|
@ -8,7 +8,6 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QTimer>
|
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
@ -108,10 +107,19 @@ long long TileBasemap::tileKey(int z, int x, int y) {
|
||||||
|
|
||||||
TileBasemap::TileBasemap(geopro::render::Scene& scene, vtkRenderWindow* rw,
|
TileBasemap::TileBasemap(geopro::render::Scene& scene, vtkRenderWindow* rw,
|
||||||
std::shared_ptr<geopro::core::GeoLocalFrame> frame, QObject* parent)
|
std::shared_ptr<geopro::core::GeoLocalFrame> frame, QObject* parent)
|
||||||
: QObject(parent), scene_(scene), rw_(rw), frame_(std::move(frame)) {
|
: QObject(parent), scene_(scene), rw_(rw), frame_(std::move(frame)) {}
|
||||||
refreshTimer_ = new QTimer(this);
|
|
||||||
refreshTimer_->setSingleShot(true);
|
void TileBasemap::requestRender() {
|
||||||
connect(refreshTimer_, &QTimer::timeout, this, [this]() { refresh(); });
|
// 合并渲染:同一事件循环轮次内的多次请求只渲染一帧(标准做法,避免逐瓦片重复 Render 卡顿)。
|
||||||
|
if (renderPending_) return;
|
||||||
|
renderPending_ = true;
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this,
|
||||||
|
[this]() {
|
||||||
|
renderPending_ = false;
|
||||||
|
if (rw_) rw_->Render();
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
TileBasemap::~TileBasemap() {
|
TileBasemap::~TileBasemap() {
|
||||||
|
|
@ -133,8 +141,7 @@ void TileBasemap::ensureObserver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileBasemap::onInteractionEnd(vtkObject*, unsigned long, void* clientData, void*) {
|
void TileBasemap::onInteractionEnd(vtkObject*, unsigned long, void* clientData, void*) {
|
||||||
// 防抖:交互(滚轮/旋转/平移)停止 ~140ms 后才刷新四叉树,避免每格事件都重算卡顿。
|
if (auto* self = static_cast<TileBasemap*>(clientData)) self->refresh();
|
||||||
if (auto* self = static_cast<TileBasemap*>(clientData)) self->refreshTimer_->start(140);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileBasemap::enqueueGet(const QString& url, std::function<void(QNetworkReply*)> onDone) {
|
void TileBasemap::enqueueGet(const QString& url, std::function<void(QNetworkReply*)> onDone) {
|
||||||
|
|
@ -172,7 +179,7 @@ void TileBasemap::show(Kind kind) {
|
||||||
terrainProbed_ = false;
|
terrainProbed_ = false;
|
||||||
kind_ = kind;
|
kind_ = kind;
|
||||||
if (kind == Hidden) {
|
if (kind == Hidden) {
|
||||||
if (rw_) rw_->Render();
|
requestRender();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
refresh(); // 四叉树覆盖:近细远粗一次铺满(含远处粗块,无需单独粗底层)
|
refresh(); // 四叉树覆盖:近细远粗一次铺满(含远处粗块,无需单独粗底层)
|
||||||
|
|
@ -266,7 +273,7 @@ void TileBasemap::refresh() {
|
||||||
|
|
||||||
purgeStale();
|
purgeStale();
|
||||||
ren->ResetCameraClippingRange(); // 交互后扩裁剪面以含新载入的底图瓦片(防被"蒙版"切)
|
ren->ResetCameraClippingRange(); // 交互后扩裁剪面以含新载入的底图瓦片(防被"蒙版"切)
|
||||||
if (rw_) rw_->Render();
|
requestRender();
|
||||||
refreshing_ = false;
|
refreshing_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -284,7 +291,7 @@ void TileBasemap::purgeStale() {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (removed && rw_) rw_->Render();
|
if (removed) requestRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileBasemap::fetchTile(int z, int x, int y, long long key) {
|
void TileBasemap::fetchTile(int z, int x, int y, long long key) {
|
||||||
|
|
@ -299,7 +306,7 @@ void TileBasemap::fetchTile(int z, int x, int y, long long key) {
|
||||||
placeActor(key, buildFlat(z, x, y, tex));
|
placeActor(key, buildFlat(z, x, y, tex));
|
||||||
inFlight_.erase(key);
|
inFlight_.erase(key);
|
||||||
purgeStale();
|
purgeStale();
|
||||||
if (rw_) rw_->Render();
|
requestRender();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -331,7 +338,7 @@ void TileBasemap::fetchTile(int z, int x, int y, long long key) {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
inFlight_.erase(key);
|
inFlight_.erase(key);
|
||||||
purgeStale();
|
purgeStale();
|
||||||
if (rw_) rw_->Render();
|
requestRender();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto tex = makeTexture(img);
|
auto tex = makeTexture(img);
|
||||||
|
|
@ -343,7 +350,7 @@ void TileBasemap::fetchTile(int z, int x, int y, long long key) {
|
||||||
placeActor(key, buildFlat(z, x, y, tex)); // 街道图无地形 → 直接平面
|
placeActor(key, buildFlat(z, x, y, tex)); // 街道图无地形 → 直接平面
|
||||||
inFlight_.erase(key);
|
inFlight_.erase(key);
|
||||||
purgeStale();
|
purgeStale();
|
||||||
if (rw_) rw_->Render();
|
requestRender();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -410,7 +417,7 @@ void TileBasemap::fetchTerrain(int z, int x, int y, long long key, vtkSmartPoint
|
||||||
}
|
}
|
||||||
inFlight_.erase(key);
|
inFlight_.erase(key);
|
||||||
purgeStale();
|
purgeStale();
|
||||||
if (rw_) rw_->Render();
|
requestRender();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 命中缓存:同一祖先 DEM 块的多个瓦片瞬间起伏,免重复网络。
|
// 命中缓存:同一祖先 DEM 块的多个瓦片瞬间起伏,免重复网络。
|
||||||
|
|
@ -439,7 +446,7 @@ void TileBasemap::fetchTerrain(int z, int x, int y, long long key, vtkSmartPoint
|
||||||
desired_.find(key) == desired_.end() || placed_.count(key)) {
|
desired_.find(key) == desired_.end() || placed_.count(key)) {
|
||||||
inFlight_.erase(key); // 过期/移出视野 → 不落地
|
inFlight_.erase(key); // 过期/移出视野 → 不落地
|
||||||
purgeStale();
|
purgeStale();
|
||||||
if (rw_) rw_->Render();
|
requestRender();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QImage dem;
|
QImage dem;
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ class vtkRenderWindow;
|
||||||
class vtkInteractorObserver;
|
class vtkInteractorObserver;
|
||||||
class vtkCallbackCommand;
|
class vtkCallbackCommand;
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
class QTimer;
|
|
||||||
namespace geopro::render { class Scene; }
|
namespace geopro::render { class Scene; }
|
||||||
namespace geopro::core { class GeoLocalFrame; }
|
namespace geopro::core { class GeoLocalFrame; }
|
||||||
|
|
||||||
|
|
@ -43,6 +42,7 @@ public:
|
||||||
private:
|
private:
|
||||||
static long long tileKey(int z, int x, int y);
|
static long long tileKey(int z, int x, int y);
|
||||||
void ensureObserver(); // 首次显示时挂到交互样式的 EndInteractionEvent
|
void ensureObserver(); // 首次显示时挂到交互样式的 EndInteractionEvent
|
||||||
|
void requestRender(); // 合并渲染:同一事件循环轮次多次请求只渲染一帧
|
||||||
void purgeStale(); // 本轮请求全部落地后再删旧层瓦片,避免缩放空白闪烁
|
void purgeStale(); // 本轮请求全部落地后再删旧层瓦片,避免缩放空白闪烁
|
||||||
// 四叉树细分:按瓦片投影屏幕尺寸递归(近细远粗),收集叶瓦片到 out。
|
// 四叉树细分:按瓦片投影屏幕尺寸递归(近细远粗),收集叶瓦片到 out。
|
||||||
void refineTile(int z, int x, int y, std::set<long long>& out, int& count);
|
void refineTile(int z, int x, int y, std::set<long long>& out, int& count);
|
||||||
|
|
@ -85,7 +85,7 @@ private:
|
||||||
bool terrainProbed_ = false; // 首次 fetchTerrain 打一行诊断日志
|
bool terrainProbed_ = false; // 首次 fetchTerrain 打一行诊断日志
|
||||||
vtkSmartPointer<vtkInteractorObserver> styleObs_; // 持引用保证回调期有效
|
vtkSmartPointer<vtkInteractorObserver> styleObs_; // 持引用保证回调期有效
|
||||||
vtkSmartPointer<vtkCallbackCommand> observer_;
|
vtkSmartPointer<vtkCallbackCommand> observer_;
|
||||||
QTimer* refreshTimer_ = nullptr; // 交互防抖:滚轮/旋转停止后才刷新四叉树(避免每格卡)
|
bool renderPending_ = false; // 合并渲染:同轮多次请求只渲染一帧
|
||||||
bool refreshing_ = false;
|
bool refreshing_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue