Hi folks,
I am running into an issue with my app where my tiled layers sometimes are not visible, depending on the zoom level.
Starting with the SDK example with an empty basemap, I add a layer and then set the viewpoint. Many scales work fine, but sometimes it does not. For example if I do this inside the setMapView API:
if (!mapView || mapView == m_mapView) {
return;
}
m_mapView = mapView;
m_mapView->setMap(m_map);
auto layer = new WebTiledLayer("https://{subDomain}.tile.openstreetmap.org/{level}/{col}/{row}.png", QStringList { "a", "b", "c" });
m_map->basemap()->baseLayers()->append(layer);
connect(m_map, &Map::loadStatusChanged, this, [&](LoadStatus loadStatus)
{
if (loadStatus == LoadStatus::Loaded)
{
auto point = Point(-109.37801138359127, -27.102741576507512, SpatialReference::wgs84());
auto viewpoint = Viewpoint(point, 701.4829384369524);
m_mapView->setViewpointAsync(viewpoint, 0.0);
}
});
emit mapViewChanged();
Some observations:
1. Zooming in/out brings the tiles back
2. Other layer types (like ArcGISTiledLayer) work fine
3. If the initial map constructor is set like this "m_map(new Map(BasemapStyle::OsmStandard, this))", then that works.
4. I believe this happens on all platforms
Thanks!
Solved! Go to Solution.
@JustinSteventon here's another idea. You can wait for the draw status to be completed the very first time, and then zoom to the viewpoint you want. There is a momentary stutter since the map appears at one scale and then immediately zooms in, but this avoids any delay. There may be other things you can do to hide the map's visibility until the zoom happens.
connect(m_map, &Map::loadStatusChanged, this, [&](LoadStatus loadStatus)
{
if (loadStatus != LoadStatus::Loaded)
{
return;
}
connect(m_mapView, &MapQuickView::drawStatusChanged, this, [this](DrawStatus drawStatus)
{
// once draw status has completed the first time, set the viewpoint to the desired location
// which is outside the supported scale location for the service
if (drawStatus == DrawStatus::Completed)
{
auto point2 = Point(-109.37801138359127, -27.102741576507512, SpatialReference::wgs84());
auto viewpoint2 = Viewpoint(point2, 701.4829384369524);
m_mapView->setViewpointAsync(viewpoint2, 0.0);
// do this one time only
disconnect(m_mapView, &MapQuickView::drawStatusChanged, this, nullptr);
}
});
auto point = Point(-109.37801138359127, -27.102741576507512, SpatialReference::wgs84());
auto viewpoint = Viewpoint(point, 1128.5);
m_mapView->setViewpointAsync(viewpoint, 0.0);
});
Hi @JustinSteventon. Thanks for reaching out.
I did some digging and I think I know what's happening here. The maximum scale level for OpenStreetMap tiles is 1128.5. Here's how I figured that out:
auto layer = new OpenStreetMapLayer(this);
connect(layer, &Layer::doneLoading, this, [layer](const Error&)
{
qDebug() << layer->maxScale() << layer->minScale();
});
In your code you're trying to display at an initial scale of 701.4829384369524, which is outside the scale level provided by OpenStreetMap. It works after you start zooming in and out because it reaches a tile level that will work, and after we have the map tiles we start to interpolate whatever we have. Since you're using WebTiledLayer in this case, we don't know much about the service (such as min and max scale levels), and we just request tiles.
In your code if you use the max scale reported by OpenStreetMap, it should work.
connect(m_map, &Map::loadStatusChanged, this, [&](LoadStatus loadStatus)
{
if (loadStatus == LoadStatus::Loaded)
{
auto point = Point(-109.37801138359127, -27.102741576507512, SpatialReference::wgs84());
auto viewpoint = Viewpoint(point, 1128.5/*701.4829384369524*/);
m_mapView->setViewpointAsync(viewpoint, 0.0);
}
});
Additionally with some network debugging tools, I can see we are trying to fetch tiles like this one
https://b.tile.openstreetmap.org/20/205701/606350.png , when we initially load at the scale beyond the max scale and there is no such tile.
Let us know if this helps.
This is a great explanation.
Saving and restoring precise viewpoints is a scenario for me, so I will need to find a workaround. I tried this:
connect(m_map, &Map::loadStatusChanged, this, [&](LoadStatus loadStatus)
{
if (loadStatus == LoadStatus::Loaded)
{
auto point = Point(-109.37801138359127, -27.102741576507512, SpatialReference::wgs84());
auto viewpoint = Viewpoint(point, 1128.5 /*701.4829384369524*/);
auto f = m_mapView->setViewpointAsync(viewpoint, 0.0);
QObject::connect(&watcher, &QFutureWatcher<void>::finished, [&]()
{
auto point2 = Point(-109.37801138359127, -27.102741576507512, SpatialReference::wgs84());
auto viewpoint2 = Viewpoint(point2, 701.4829384369524);
m_mapView->setViewpointAsync(viewpoint2, 0.0);
});
watcher.setFuture(f);
}
});
- it 'works', but there is a delay of about 30 seconds before any tiles show up.
Let me know if you think of any other workarounds.
Thanks!
@JustinSteventon here's another idea. You can wait for the draw status to be completed the very first time, and then zoom to the viewpoint you want. There is a momentary stutter since the map appears at one scale and then immediately zooms in, but this avoids any delay. There may be other things you can do to hide the map's visibility until the zoom happens.
connect(m_map, &Map::loadStatusChanged, this, [&](LoadStatus loadStatus)
{
if (loadStatus != LoadStatus::Loaded)
{
return;
}
connect(m_mapView, &MapQuickView::drawStatusChanged, this, [this](DrawStatus drawStatus)
{
// once draw status has completed the first time, set the viewpoint to the desired location
// which is outside the supported scale location for the service
if (drawStatus == DrawStatus::Completed)
{
auto point2 = Point(-109.37801138359127, -27.102741576507512, SpatialReference::wgs84());
auto viewpoint2 = Viewpoint(point2, 701.4829384369524);
m_mapView->setViewpointAsync(viewpoint2, 0.0);
// do this one time only
disconnect(m_mapView, &MapQuickView::drawStatusChanged, this, nullptr);
}
});
auto point = Point(-109.37801138359127, -27.102741576507512, SpatialReference::wgs84());
auto viewpoint = Viewpoint(point, 1128.5);
m_mapView->setViewpointAsync(viewpoint, 0.0);
});
Thanks, this worked for me.