Select to view content in your preferred language

Surface elevationAsync() using RasterElevationSource crashes when using multiple RasterElevationSource pointing to the same underlying data.

98
0
a week ago
imbachb
Regular Contributor

We have multiple Surface objects with their RasterElevationSource. All the RasterElevationSource objects point to the same underlying data files: DTED2 files of Germany.

One surface we use for displaying the elevation of the scene.

The other surface we use for querying the elevation. 

When we query the elevation of the surface as well as navigate to the data in the world view (i.e. it has to read the dted2 files for displaying the elevation in 3D), we experience a crash occasionally.

We query the elevation on a timer (every 10 ms).

The crash does not happen instantly, it happens suddenly over time. Sometimes it takes a minute for it to crash. Sometimes less, sometimes more. But it always happens after a while. It helps to do big jumps in the 3D view so that it needs to load the elevation from different parts of the dataset.

We are using the most recent ArcGIS Maps SDK 200.6 on Windows 10.

It is a bit difficult to reproduce this error. It is easier if we add even more surfaces using the same underlying DTED2 files and querying them all at the same time (See uncommentable code in the example)

 

MultipleElevationSources::MultipleElevationSources(QObject* parent /* = nullptr */) : QObject(parent)
{
	m_scene = new Scene(this);

	QUrl imageLayerUrl("https://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer");
	auto baseLayer = new ArcGISMapImageLayer(imageLayerUrl, this);
	auto basemap = new Basemap(baseLayer, this);
	m_scene->setBasemap(basemap);

	auto surface = new Surface(parent);
	auto sceneRasterFilesPaths =
		getRasterFilesPaths((defaultDataPath() + "/ArcGIS/Runtime/Data/raster/GermanyElevation").toStdString());
	auto elevationSource = new RasterElevationSource(sceneRasterFilesPaths, surface);
	surface->elevationSources()->append(elevationSource);
	m_scene->setBaseSurface(surface);

	m_querySurface = new Surface(parent);
	auto queryRasterFilesPaths =
		getRasterFilesPaths((defaultDataPath() + "/ArcGIS/Runtime/Data/raster/GermanyElevation").toStdString());
	auto queryElevationSource = new RasterElevationSource(queryRasterFilesPaths, m_querySurface);
	queryElevationSource->load();
	m_querySurface->elevationSources()->append(queryElevationSource);

	// Uncomment these to increase chance of crash
	//m_querySurface2 = new Surface(parent);
	//auto queryElevationSource2 = new RasterElevationSource(queryRasterFilesPaths, m_querySurface2);
	//queryElevationSource2->load();
	//m_querySurface2->elevationSources()->append(queryElevationSource2);

	//m_querySurface3 = new Surface(parent);
	//auto queryElevationSource3 = new RasterElevationSource(queryRasterFilesPaths, m_querySurface2);
	//queryElevationSource3->load();
	//m_querySurface3->elevationSources()->append(queryElevationSource3);
}

void
MultipleElevationSources::connectSignals()
{
	QTimer* timer = new QTimer(this);
	connect(timer, &QTimer::timeout, this, [this] {
		// Germany
		// x from 11.6 to 14.8
		// y from 47 to 54
		auto x = randomValue(11.6, 14.8);
		auto y = randomValue(47, 54);

		Point point{x, y, SpatialReference(4326)};
		fetchAltitude(point);
	});
	timer->start(10);
}

void
MultipleElevationSources::fetchAltitude(const Esri::ArcGISRuntime::Point& point)
{
	elevationQuery(m_elevationFuture, m_querySurface, point);
	// Uncomment these to increase chance of crash
	//elevationQuery(m_elevationFuture2, m_querySurface2, point);
	//elevationQuery(m_elevationFuture3, m_querySurface3, point);
}

void
MultipleElevationSources::elevationQuery(QFuture<double>& future, Surface* surface, const Point& point)
{
	if (future.isRunning()) {
		qDebug() << "Is running...";
		return;
	}
	if (!future.isFinished()) {
		// future.cancel();
		qDebug() << "Not finished with query yet!";
		setAltitude("Waiting");
		return;
	}

	future = surface->elevationAsync(point);
	future
		.then(
			this,
			[this](double altitude) {
				qDebug() << altitude;
				setAltitude(QString::number(altitude));
			})
		.onCanceled([this] {
			qDebug() << "Canceled";
			setAltitude("Canceled");
		})
		.onFailed([this] {
			qDebug() << "Failed";
			setAltitude("Failed");
		});
}

inline double
MultipleElevationSources::randomValue(double min, double max)
{
	std::random_device rd;
	std::mt19937 gen(rd());
	std::uniform_real_distribution<> dis(min, max);
	return dis(gen);
}

 

When the crash happens we get the following callstacks (sometimes they are slightly different)

imbachb_0-1741087886997.png

imbachb_1-1741087893348.png

Our use case is a bit special. We'd like to dynamically switch between different 3D scenes, but be able to define a "global" surface that we can query elevation no matter what scene is currently active. It can happen that 3D display and elevation query run on the same data files, in which case this crash happens occasionally.

Find attached the cpp, hpp, qml source file.

0 Kudos
0 Replies