Select to view content in your preferred language

WebTiledLayer invisible at some zoom levels

457
4
Jump to solution
11-10-2024 09:32 PM
Labels (2)
JustinSteventon
Occasional Contributor

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!

0 Kudos
1 Solution

Accepted Solutions
JamesBallard1
Esri Regular Contributor

@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);
});

  

View solution in original post

0 Kudos
4 Replies
JamesBallard1
Esri Regular Contributor

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.

0 Kudos
JustinSteventon
Occasional Contributor

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! 

0 Kudos
JamesBallard1
Esri Regular Contributor

@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);
});

  

0 Kudos
JustinSteventon
Occasional Contributor

Thanks, this worked for me.