fix(vtk): 加远处粗底图层(z13~34km,随地形起伏,持久不purge)填到天边治倾斜露黑边;基准高程base/detail共用保连续
This commit is contained in:
parent
52f7a7d5e8
commit
b5bab42825
|
|
@ -41,6 +41,8 @@ namespace {
|
||||||
const char* kTk = "aca91d8c9f59a4f779f39061b8a07737";
|
const char* kTk = "aca91d8c9f59a4f779f39061b8a07737";
|
||||||
constexpr int kRadius = 4; // 回退用:算不出可视范围时中心 ±4
|
constexpr int kRadius = 4; // 回退用:算不出可视范围时中心 ±4
|
||||||
constexpr int kMaxTilesPerSide = 13; // 单边瓦片上限(防倾斜时可视范围过大拉爆请求)
|
constexpr int kMaxTilesPerSide = 13; // 单边瓦片上限(防倾斜时可视范围过大拉爆请求)
|
||||||
|
constexpr int kBaseZoom = 13; // 远处粗底层级(单块~4.9km)
|
||||||
|
constexpr int kBaseRadius = 3; // 粗底半径 ±3 → 7x7 覆盖~34km,填到天边
|
||||||
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 地面参考(剖面深度向下为负,落其下)
|
||||||
|
|
@ -137,15 +139,20 @@ void TileBasemap::show(Kind kind) {
|
||||||
++generation_; // 旧回包(含换源前的层)按 generation 丢弃
|
++generation_; // 旧回包(含换源前的层)按 generation 丢弃
|
||||||
for (auto& kv : placed_) scene_.renderer()->RemoveViewProp(kv.second);
|
for (auto& kv : placed_) scene_.renderer()->RemoveViewProp(kv.second);
|
||||||
placed_.clear();
|
placed_.clear();
|
||||||
|
for (auto& a : baseTiles_) scene_.renderer()->RemoveViewProp(a);
|
||||||
|
baseTiles_.clear();
|
||||||
|
baseLoaded_ = false;
|
||||||
inFlight_.clear();
|
inFlight_.clear();
|
||||||
desired_.clear();
|
desired_.clear();
|
||||||
// demCache_/texCache_ 跨隐藏-重选保留 → 重选地图秒出,不重拉。
|
// demCache_/texCache_ 跨隐藏-重选保留 → 重选地图秒出,不重拉。
|
||||||
|
haveBaseline_ = false; // 数据可能已换位置 → 重算基准高程
|
||||||
terrainProbed_ = false;
|
terrainProbed_ = false;
|
||||||
kind_ = kind;
|
kind_ = kind;
|
||||||
if (kind == Hidden) {
|
if (kind == Hidden) {
|
||||||
if (rw_) rw_->Render();
|
if (rw_) rw_->Render();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ensureBaseLayer(); // 先铺远处粗底(填到天边),再叠近处精细
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -362,6 +369,94 @@ void TileBasemap::placeActor(long long key, vtkSmartPointer<vtkActor> actor) {
|
||||||
placed_[key] = actor;
|
placed_[key] = actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileBasemap::ensureBaseline(const QImage& dem) {
|
||||||
|
if (haveBaseline_) return; // 仅首块定基准 → base/detail 共用同一基准,地形连续无断层
|
||||||
|
baseline_ = demElev(dem, 0.5, 0.5);
|
||||||
|
haveBaseline_ = true;
|
||||||
|
double mn = 1e30, mx = -1e30;
|
||||||
|
for (int yy = 0; yy < dem.height(); yy += 16)
|
||||||
|
for (int xx = 0; xx < dem.width(); xx += 16) {
|
||||||
|
const double e = demElev(dem, xx / double(dem.width() - 1), yy / double(dem.height() - 1));
|
||||||
|
mn = std::min(mn, e);
|
||||||
|
mx = std::max(mx, e);
|
||||||
|
}
|
||||||
|
qInfo() << "[basemap] 地形启用 baseline=" << baseline_ << "m 起伏=" << (mx - mn) << "m";
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileBasemap::ensureBaseLayer() {
|
||||||
|
if (baseLoaded_ || kind_ != Satellite) return;
|
||||||
|
baseLoaded_ = true;
|
||||||
|
const auto c = frame_->toLatLon(0.0, 0.0); // 数据中心(show 在重锚后调 → 已对准数据)
|
||||||
|
const geopro::render::TileXY ct = geopro::render::lonLatToTile(c.lon, c.lat, kBaseZoom);
|
||||||
|
const int n = 1 << kBaseZoom;
|
||||||
|
for (int dy = -kBaseRadius; dy <= kBaseRadius; ++dy)
|
||||||
|
for (int dx = -kBaseRadius; dx <= kBaseRadius; ++dx) {
|
||||||
|
const int tx = ct.x + dx, ty = ct.y + dy;
|
||||||
|
if (tx < 0 || ty < 0 || tx >= n || ty >= n) continue;
|
||||||
|
fetchBaseTile(kBaseZoom, tx, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileBasemap::fetchBaseTile(int z, int x, int y) {
|
||||||
|
const int gen = generation_;
|
||||||
|
const long long key = tileKey(z, x, y);
|
||||||
|
|
||||||
|
// 有了卫星纹理后 → 取 DEM(base zoom ≤ kDemMaxZoom, 同级) → warp 成持久粗底块。
|
||||||
|
auto onTex = [this, z, x, y, gen](vtkSmartPointer<vtkTexture> tex) {
|
||||||
|
const long long demKey = tileKey(z, x, y);
|
||||||
|
auto placeBase = [this, z, x, y, gen, tex](const QImage* dem) {
|
||||||
|
if (gen != generation_ || kind_ != Satellite) return; // 已隐藏/换源 → 丢弃
|
||||||
|
vtkSmartPointer<vtkActor> a;
|
||||||
|
if (dem && !dem->isNull()) {
|
||||||
|
ensureBaseline(*dem);
|
||||||
|
a = buildWarped(z, x, y, z, x, y, tex, *dem);
|
||||||
|
} else {
|
||||||
|
a = buildFlat(z, x, y, tex);
|
||||||
|
}
|
||||||
|
a->SetUseBounds(false); // 粗底不参与包围盒/取景
|
||||||
|
scene_.addActor(a);
|
||||||
|
baseTiles_.push_back(a);
|
||||||
|
if (rw_) rw_->Render();
|
||||||
|
};
|
||||||
|
auto dc = demCache_.find(demKey);
|
||||||
|
if (dc != demCache_.end()) { placeBase(&dc->second); return; }
|
||||||
|
const QString durl =
|
||||||
|
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));
|
||||||
|
QNetworkReply* dr = nam_.get(QNetworkRequest(QUrl(durl)));
|
||||||
|
connect(dr, &QNetworkReply::finished, this, [this, dr, demKey, gen, placeBase]() {
|
||||||
|
dr->deleteLater();
|
||||||
|
if (gen != generation_) return;
|
||||||
|
QImage dem;
|
||||||
|
if (dr->error() == QNetworkReply::NoError && dem.loadFromData(dr->readAll())) {
|
||||||
|
demCache_[demKey] = dem;
|
||||||
|
placeBase(&dem);
|
||||||
|
} else {
|
||||||
|
placeBase(nullptr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
auto tc = texCache_.find(key);
|
||||||
|
if (tc != texCache_.end()) { onTex(tc->second); return; }
|
||||||
|
const int sub = (x + y) % 8;
|
||||||
|
const QString url =
|
||||||
|
QStringLiteral("http://t%1.tianditu.gov.cn/img_w/wmts?service=wmts&request=GetTile"
|
||||||
|
"&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix=%2&TileRow=%3"
|
||||||
|
"&TileCol=%4&style=default&format=tiles&tk=%5")
|
||||||
|
.arg(sub).arg(z).arg(y).arg(x).arg(QString::fromLatin1(kTk));
|
||||||
|
QNetworkReply* reply = nam_.get(QNetworkRequest(QUrl(url)));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [this, reply, key, gen, onTex]() {
|
||||||
|
reply->deleteLater();
|
||||||
|
if (gen != generation_ || kind_ != Satellite) return;
|
||||||
|
QImage img;
|
||||||
|
if (reply->error() != QNetworkReply::NoError || !img.loadFromData(reply->readAll())) return;
|
||||||
|
auto tex = makeTexture(img);
|
||||||
|
texCache_[key] = tex;
|
||||||
|
onTex(tex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
vtkSmartPointer<vtkActor> TileBasemap::buildFlat(int z, int x, int y,
|
vtkSmartPointer<vtkActor> TileBasemap::buildFlat(int z, int x, int y,
|
||||||
vtkSmartPointer<vtkTexture> tex) {
|
vtkSmartPointer<vtkTexture> tex) {
|
||||||
const geopro::render::LonLatBox b = geopro::render::tileBounds(z, x, y);
|
const geopro::render::LonLatBox b = geopro::render::tileBounds(z, x, y);
|
||||||
|
|
@ -395,20 +490,7 @@ void TileBasemap::fetchTerrain(int z, int x, int y, long long key, vtkSmartPoint
|
||||||
// 落地一块瓦片:DEM 有效→起伏,否则→平面兜底;并推进 inFlight/清理。
|
// 落地一块瓦片:DEM 有效→起伏,否则→平面兜底;并推进 inFlight/清理。
|
||||||
auto place = [this, key, z, x, y, dz, dx, dy, tex](const QImage* dem) {
|
auto place = [this, key, z, x, y, dz, dx, dy, tex](const QImage* dem) {
|
||||||
if (dem && !dem->isNull()) {
|
if (dem && !dem->isNull()) {
|
||||||
if (!haveBaseline_) { // 基准高程取首块中心 → 地形整体绕 z=0 起伏
|
ensureBaseline(*dem); // 首块定基准(base/detail 共用)→ 地形连续
|
||||||
baseline_ = demElev(*dem, 0.5, 0.5);
|
|
||||||
haveBaseline_ = true;
|
|
||||||
double mn = 1e30, mx = -1e30;
|
|
||||||
for (int yy = 0; yy < dem->height(); yy += 16)
|
|
||||||
for (int xx = 0; xx < dem->width(); xx += 16) {
|
|
||||||
const double e = demElev(*dem, xx / double(dem->width() - 1),
|
|
||||||
yy / double(dem->height() - 1));
|
|
||||||
mn = std::min(mn, e);
|
|
||||||
mx = std::max(mx, e);
|
|
||||||
}
|
|
||||||
qInfo() << "[basemap] 地形启用 baseline=" << baseline_ << "m 起伏=" << (mx - mn)
|
|
||||||
<< "m";
|
|
||||||
}
|
|
||||||
placeActor(key, buildWarped(z, x, y, dz, dx, dy, tex, *dem));
|
placeActor(key, buildWarped(z, x, y, dz, dx, dy, tex, *dem));
|
||||||
} else {
|
} else {
|
||||||
placeActor(key, buildFlat(z, x, y, tex)); // DEM 拉不到 → 平面兜底
|
placeActor(key, buildFlat(z, x, y, tex)); // DEM 拉不到 → 平面兜底
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <vtkSmartPointer.h>
|
#include <vtkSmartPointer.h>
|
||||||
|
|
||||||
|
|
@ -46,6 +47,9 @@ private:
|
||||||
void fetchTerrain(int z, int x, int y, long long key,
|
void fetchTerrain(int z, int x, int y, long long key,
|
||||||
vtkSmartPointer<vtkTexture> tex); // 拉覆盖该瓦片的 DEM(z>15 取祖先块)后落地
|
vtkSmartPointer<vtkTexture> tex); // 拉覆盖该瓦片的 DEM(z>15 取祖先块)后落地
|
||||||
void placeActor(long long key, vtkSmartPointer<vtkActor> actor);
|
void placeActor(long long key, vtkSmartPointer<vtkActor> actor);
|
||||||
|
void ensureBaseline(const QImage& dem); // 首块 DEM 定基准高程(base/detail 共用→地形连续)
|
||||||
|
void ensureBaseLayer(); // 远处粗底图层(填到天边,治倾斜露黑边)
|
||||||
|
void fetchBaseTile(int z, int x, int y); // 单块粗底(sat+DEM→warp,持久不purge)
|
||||||
vtkSmartPointer<vtkActor> buildFlat(int z, int x, int y,
|
vtkSmartPointer<vtkActor> buildFlat(int z, int x, int y,
|
||||||
vtkSmartPointer<vtkTexture> tex); // 平面瓦片(DEM 兜底)
|
vtkSmartPointer<vtkTexture> tex); // 平面瓦片(DEM 兜底)
|
||||||
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,
|
||||||
|
|
@ -64,6 +68,8 @@ 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_; // 影像纹理缓存,重选/缩放回看免重拉
|
||||||
|
std::vector<vtkSmartPointer<vtkActor>> baseTiles_; // 远处粗底层(持久,不随相机purge)
|
||||||
|
bool baseLoaded_ = false;
|
||||||
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