I've been waiting years for this capability, so when it appeared in Maps 200.7, I thought I should try it out, but I'm not having much success.
The setup/environment is:
As the intended use is with an application that uses offline maps, I changed the DisplayMap sample (arcgis-maps-sdk-samples-qt-200.7.0.4560\CppWidgetsSamples\Maps\DisplayMap) to use an offline map and show a QImage using an ImageFrame and ImageOverlay.
Other than adding the additional include files needed, the code is unchanged except the DisplayMap constructor, which now looks like this:
DisplayMap::DisplayMap(QWidget* parent) :
QWidget(parent)
{
const QString tileBasemapFile("C:/MapData/Map.tpk");
ArcGISTiledLayer* tileBasemapLayer = new ArcGISTiledLayer(new TileCache(tileBasemapFile, this), this);
tileBasemapLayer->setName(tileBasemapFile);
tileBasemapLayer->load();
// Create a map using the offline basemap
m_map = new Map(this);
m_map->basemap()->baseLayers()->append(tileBasemapLayer);
// Create a map view, and pass in the map
m_mapView = new MapGraphicsView(m_map, this);
// Create image
QImage image(500, 500, QImage::Format_RGB32);
image.fill(qRgb(255, 0, 0));
// Define the envelope to be used for the image on the map
const Envelope env(-50.0, -50.0, 50.0, 50.0);
std::unique_ptr<ImageFrame> imageFrame = std::make_unique<ImageFrame>(image, env);
ImageOverlay* imageOverlay = new ImageOverlay(imageFrame.get(), this);
m_mapView->imageOverlays()->append(imageOverlay);
// Set up the UI
QVBoxLayout *vBoxLayout = new QVBoxLayout();
vBoxLayout->addWidget(m_mapView);
setLayout(vBoxLayout);
}
The use of std::unique_ptr<ImageFrame> was taken from the 3D scene sample code that uses ImageFrame/ImageOverlay.
The application runs, displays the basemap and allows panning/zooming as would be expected, but the ImageFrame (i.e. a big solid red area) is not shown. The application shows as "Licensed for Developer Use Only", but applying a "lite" license code makes no difference to the application's appearance/behaviour other than the message being removed.
I've checked that the ImageOverlay reports that it is visible and the opacity is 1, also after being set as the frame for the ImageOverlay, the ImageFrame retrieved from the ImageOverlay reports the correct extent.
Any suggestions as to what I'm missing/doing wrong?
Solved! Go to Solution.
Hello @LeeCarter,
The issue you might be facing is a spatial reference mismatch between the `Envelope` you're setting up and your `Map` / `MapView`. I ran into this issue myself when first trying out this API. Here is a quick example I set up based on the code snippet you provided.
DisplayMap::DisplayMap(QWidget* parent /*=nullptr*/)
: QMainWindow(parent)
{
const QString tileBasemapFile("/Users/bri12415/ArcGIS/Runtime/Data/tpk/Campus.tpk");
ArcGISTiledLayer* tileBasemapLayer = new ArcGISTiledLayer(new TileCache(tileBasemapFile, this), this);
tileBasemapLayer->setName(tileBasemapFile);
tileBasemapLayer->load();
// Create a map using the offline basemap
m_map = new Map(this);
m_map->basemap()->baseLayers()->append(tileBasemapLayer);
// Create a map view, and pass in the map
m_mapView = new MapGraphicsView(m_map, this);
qDebug() << m_mapView->spatialReference().toJson(); //WKID 102100
qDebug() << m_map->spatialReference().toJson(); //WKID 102100
// I used our `screenToLocation` API to figure out where on the map I'd like to display the red square
connect(m_mapView, &MapGraphicsView::mouseClicked, this,
[this](QMouseEvent& mouseEvent)
{
qDebug() << m_mapView->screenToLocation(mouseEvent.position().x(), mouseEvent.position().y()).toJson();
});
// Create image
QImage image(500, 500, QImage::Format_RGB32);
image.fill(qRgb(255, 0, 0));
// Define the envelope to be used for the image on the map
const Envelope env{-13046288, 4036452, -13046268, 4036472, SpatialReference(102100)};
qDebug() << env.spatialReference().toJson(); //WKID 102100
std::unique_ptr<ImageFrame> imageFrame = std::make_unique<ImageFrame>(image, env);
ImageOverlay* imageOverlay = new ImageOverlay(imageFrame.get(), this);
m_mapView->imageOverlays()->append(imageOverlay);
// set the mapView as the central widget
setCentralWidget(m_mapView);
}
You might need to set a value in the color table before the call to fill so that the Qimage works properly
https://doc.qt.io/qt-6/qimage.html#setColorTable
Hello @LeeCarter,
The issue you might be facing is a spatial reference mismatch between the `Envelope` you're setting up and your `Map` / `MapView`. I ran into this issue myself when first trying out this API. Here is a quick example I set up based on the code snippet you provided.
DisplayMap::DisplayMap(QWidget* parent /*=nullptr*/)
: QMainWindow(parent)
{
const QString tileBasemapFile("/Users/bri12415/ArcGIS/Runtime/Data/tpk/Campus.tpk");
ArcGISTiledLayer* tileBasemapLayer = new ArcGISTiledLayer(new TileCache(tileBasemapFile, this), this);
tileBasemapLayer->setName(tileBasemapFile);
tileBasemapLayer->load();
// Create a map using the offline basemap
m_map = new Map(this);
m_map->basemap()->baseLayers()->append(tileBasemapLayer);
// Create a map view, and pass in the map
m_mapView = new MapGraphicsView(m_map, this);
qDebug() << m_mapView->spatialReference().toJson(); //WKID 102100
qDebug() << m_map->spatialReference().toJson(); //WKID 102100
// I used our `screenToLocation` API to figure out where on the map I'd like to display the red square
connect(m_mapView, &MapGraphicsView::mouseClicked, this,
[this](QMouseEvent& mouseEvent)
{
qDebug() << m_mapView->screenToLocation(mouseEvent.position().x(), mouseEvent.position().y()).toJson();
});
// Create image
QImage image(500, 500, QImage::Format_RGB32);
image.fill(qRgb(255, 0, 0));
// Define the envelope to be used for the image on the map
const Envelope env{-13046288, 4036452, -13046268, 4036472, SpatialReference(102100)};
qDebug() << env.spatialReference().toJson(); //WKID 102100
std::unique_ptr<ImageFrame> imageFrame = std::make_unique<ImageFrame>(image, env);
ImageOverlay* imageOverlay = new ImageOverlay(imageFrame.get(), this);
m_mapView->imageOverlays()->append(imageOverlay);
// set the mapView as the central widget
setCentralWidget(m_mapView);
}
Would connecting to the `errorOccurred` signal on either the mapview or image overlay help show when there is a spatial reference mismatch?
Hi @bnoble0110,
Thank you for your response. It was indeed the complete lack of a SpatialReference that was the source of the problem.
When I first tried to add a spatial reference, I did the same as when creating Graphic objects to add to a GraphicsOverlay, i.e. I used SpatialReference::wgs84(). With the same basemap (where the map and map view are both webMercator spatial reference), the graphic(s) added to the graphics overlay work fine with wgs84 as the spatial reference for the geometry of the graphic objects, but the image frame added to the image overlay does not. To make it work, I have to use SpatialReference::webMercator(), so I'm having to use GeometryEngine::project(...) to convert my Envelope from wgs84 to webMercator.
Why do graphics in graphics overlays work OK as wgs84 without needing to convert the spatial reference, but image frames in image overlays do not? Is this "expected behaviour" or is (as it seems to me) something not quite right/as good as it could be with the way ImageFrame/ImageOverlays are working with 2D maps?
No, at the moment there is no error that is raised when this situation occurs. There is a warning about this kind of situation in our documentation, but under a specific constructor on `ImageFrame` here.
That being said I think it is understandable to assume some sort of error would be raised somewhere. We had discussed this situation previously, but it was not chosen as a priority issue at that time. Now that this has been reported in the wild, we can pass the info along to the appropriate persons to try and motivate the issue further.
This was brought up internally as well, specifically that there is an implicit conversion in spatial references for graphics overlays that doesn't seem to match the behavior of image overlays. I can pass along this feedback as well to the appropriate persons in order to help motivate some behavior changes in our SDK that our users would like to see.
Hi @bnoble0110,
Thank you for the feedback. If an enhancement is raised (that I would be able to subscribe to/escalate) for doing the spatial reference conversion for image overlays in the same/similar way that it happens for graphics overlays, please let me know.
As it is, I have a workable solution, so I will accept your first reply as a solution to my original question.
Many thanks.