Select to view content in your preferred language

Elevation in 2D

1018
3
Jump to solution
12-15-2017 05:18 AM
NorbertThoden
Occasional Contributor III

Hi All!

I´m able to use the screenToLocation/screenToBaseSurface call to get the appropriate location containing x and y and also the desired elevation available at z().

The necessery assignment of the elevationSourceUrl is simple and it worsk for 3D - fine.

But whats about 2D:

Eric Bader gave me the hint to have a look at the Surface class - Surface Class | ArcGIS for Developers and its locationToElevation method.

Unfortunatly i can´t get it work.

What i did:

  1. create Esri::ArcGISRuntime::ArcGISTiledElevationSource per URL
  2. create Esri::ArcGISRuntime::Surface using the elecationSources (as QList)
  3. request elevation by
    1. connect locationToElevationCompleted to an appropriate slot (onLocationToElevationCompleted)
    2. call locationToElevation on that surface

but the result in onLocationToElevationCompleted is nan (not a number)

My questions are:

What is missing? Like:

  1. Where do i have to call Loadable::load()?On Surface (cascading loading?) or every ArcGISTiledElevationSource directly? Or both?
  2. Do i have to enable the single ArcGISTiledElevationSources? (setEnable())

I think there are many question for an essential problem, isn´t it?

Is there an example?

Thanks in advance!

Norbert

0 Kudos
1 Solution

Accepted Solutions
LukeSmallwood
Esri Contributor

Hi Norbert, I hope you are well. I don't believe we do have an example of this workflow currently - but I will recommend we add one as it seems like a useful workflow to me.

Here is some code I have put together to show how this could work. In this case I am creating a Surface and a single ArcGISTiledElevationSource. We have to manually load these since they are not added to the view in the same way we would for a 3D application.

Once these are loaded, I am connecting to the mouseClicked signal on the MapView, obtaining a location for that click and starting the operation.

I hope that helps,

Luke

    ArcGISTiledElevationSource* elevationSource = new ArcGISTiledElevationSource(
                QUrl(yourUrl), this);
    connect(elevationSource, &ArcGISTiledElevationSource::errorOccurred, this, [](Error error)
    {
        qDebug() << error.message() << error.additionalMessage();
    });
    m_surface = new Surface(this);
    m_surface->elevationSources()->append(elevationSource);
    connect(m_surface, &Surface::errorOccurred, this, [](Error error)
    {
        qDebug() << error.message() << error.additionalMessage();
    });
    connect(m_surface, &Surface::loadStatusChanged, this, [](LoadStatus loadStatus)
    {
        qDebug() << "loadStatus:" << static_cast<int>(loadStatus);
    });
    connect(m_surface, &Surface::locationToElevationCompleted, this, [](QUuid, double elevation)
    {
      qDebug() << elevation;
    });
    connect(m_surface, &Surface::doneLoading, this, [this](Error error)
    {
        if (!error.isEmpty())
            qDebug() << error.message() << error.additionalMessage();
        qDebug() << "loaded";
        connect(m_mapView, &MapGraphicsView::mouseClicked, this, [this](QMouseEvent& mouseEvent)
        {
            Point loc = m_mapView->screenToLocation(mouseEvent.x(), mouseEvent.y());
            qDebug() << "locationToElevation: " << loc.toJson();
            m_surface->locationToElevation(loc);
        });
    });
    connect(elevationSource, &ArcGISTiledElevationSource::doneLoading, this, [this](Error error)
    {
        if (!error.isEmpty())
            qDebug() << error.message() << error.additionalMessage();
        qDebug() << "elevationSource loaded";
        m_surface->load();
    });
    elevationSource->load();

View solution in original post

3 Replies
LukeSmallwood
Esri Contributor

Hi Norbert, I hope you are well. I don't believe we do have an example of this workflow currently - but I will recommend we add one as it seems like a useful workflow to me.

Here is some code I have put together to show how this could work. In this case I am creating a Surface and a single ArcGISTiledElevationSource. We have to manually load these since they are not added to the view in the same way we would for a 3D application.

Once these are loaded, I am connecting to the mouseClicked signal on the MapView, obtaining a location for that click and starting the operation.

I hope that helps,

Luke

    ArcGISTiledElevationSource* elevationSource = new ArcGISTiledElevationSource(
                QUrl(yourUrl), this);
    connect(elevationSource, &ArcGISTiledElevationSource::errorOccurred, this, [](Error error)
    {
        qDebug() << error.message() << error.additionalMessage();
    });
    m_surface = new Surface(this);
    m_surface->elevationSources()->append(elevationSource);
    connect(m_surface, &Surface::errorOccurred, this, [](Error error)
    {
        qDebug() << error.message() << error.additionalMessage();
    });
    connect(m_surface, &Surface::loadStatusChanged, this, [](LoadStatus loadStatus)
    {
        qDebug() << "loadStatus:" << static_cast<int>(loadStatus);
    });
    connect(m_surface, &Surface::locationToElevationCompleted, this, [](QUuid, double elevation)
    {
      qDebug() << elevation;
    });
    connect(m_surface, &Surface::doneLoading, this, [this](Error error)
    {
        if (!error.isEmpty())
            qDebug() << error.message() << error.additionalMessage();
        qDebug() << "loaded";
        connect(m_mapView, &MapGraphicsView::mouseClicked, this, [this](QMouseEvent& mouseEvent)
        {
            Point loc = m_mapView->screenToLocation(mouseEvent.x(), mouseEvent.y());
            qDebug() << "locationToElevation: " << loc.toJson();
            m_surface->locationToElevation(loc);
        });
    });
    connect(elevationSource, &ArcGISTiledElevationSource::doneLoading, this, [this](Error error)
    {
        if (!error.isEmpty())
            qDebug() << error.message() << error.additionalMessage();
        qDebug() << "elevationSource loaded";
        m_surface->load();
    });
    elevationSource->load();
NorbertThoden
Occasional Contributor III

Hi Luke!

Yeah i feel fine.

But in the last weeks we were struggeling with ScreenToLocation in 3D. This call is async and on destruction of scene/sceneView a segmentation fault may arise. Most likely a wrong of missing cleanup of some objects/threads...

It ´s already shared with Eric and logged (BUG-000109976 - Segmentation fault on Scene Viewer destruction)

Regaring this question:

Due to your code snippet i was able to get my code work! Thank you very much for your very quick and helpful answer!

Hopefully the cleanup for locationToElevation is done correct. Until now i was not able to get an error like described above 🙂

But one more question:

What do a have to do, if there are more than one elevationSourceUrls?

Load surface if ALL elevationSources are loaded?

Or is it sufficiant to load surface on doneLoading of ONE elevationSource?

And most important:

Luke, i wish your a merry Christmas and a happy new Year!

Thanks!

0 Kudos
LukeSmallwood
Esri Contributor

Hi Norbert - best wishes to you as well

I think that the best approach would be to wait until all the elevation sources are loaded: that's because you want to ensure that your elevation queries use all available data. I think it would work as soon as one source is loaded so you should probably wait until you have the full data ready.

It might be that the surface takes care of these load dependencies - but as I say, this is generally managed by the 3D scene/view so I'm not sure of the expectation in this scenario.

Hope that helps,

Luke

0 Kudos