Select to view content in your preferred language

Image overlay on 2D map with ArcGIS Maps 200.7

466
6
Jump to solution
04-30-2025 07:42 AM
Labels (3)
LeeCarter
Occasional Contributor

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:

  • ArcGIS Maps for Qt 200.7
  • Qt 6.8.3
  • VS: 2022

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?

0 Kudos
1 Solution

Accepted Solutions
bnoble0110
Esri Contributor

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

 

 
 

bnoble0110_3-1746117685275.png

 

 

View solution in original post

6 Replies
TroyFoster
Frequent Contributor

https://doc.qt.io/qt-6/qimage.html#fill-2:~:text=If%20the%20depth%20of%20the%20image%20is%208%2C%20t....

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

 

0 Kudos
bnoble0110
Esri Contributor

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

 

 
 

bnoble0110_3-1746117685275.png

 

 

TroyFoster
Frequent Contributor

Would connecting to the `errorOccurred` signal on either the mapview or image overlay help show when there is a spatial reference mismatch?

0 Kudos
LeeCarter
Occasional Contributor

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?

0 Kudos
bnoble0110
Esri Contributor

@TroyFoster 

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.

 

@LeeCarter 

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.

 

0 Kudos
LeeCarter
Occasional Contributor

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.