Adjusting KML placement in realtime in a MapView

1558
14
08-10-2020 09:54 AM
BrianCrist
New Contributor II

Hi,

  Background:  Working in ArcGIS Runtime for QT version 100.8 in QT version 5.14 on an Ubuntu system running release 19.10. 

  I've got a KML GroundOverlay graphic whose position I'd like to update in real-time.  The graphic is rendered just fine initially, but any subsequent calls to functions on the KmlGroundOverlay don't seem to have an effect.  As an example, here's a bit of code:

Considering the variables:

Esri::ArcGISRuntime::KmlGroundOverlay * m_groundOverlay;
Esri::ArcGISRuntime::KmlDataset *m_kdata;
Esri::ArcGISRuntime::KmlLayer *m_klayer;
Esri::ArcGISRuntime::Map *m_map;

In the "before" code - before the KML is called:

m_map(new Map(Basemap::topographicVector(this), this));

Setting up the KML Ground Overlay:

const Envelope env(-.001, 0.001, .001, 0.00, SpatialReference::wgs84());
KmlIcon * kmlIcon = new KmlIcon(QUrl("/home/bcrist/hundySquare.png")); // "hundySquare.png" is a red square shaped image file
// Create Overlay
m_groundOverlay = new Esri::ArcGISRuntime::KmlGroundOverlay(env, kmlIcon, this);
// Create Dataset
m_kdata = new Esri::ArcGISRuntime::KmlDataset(m_groundOverlay, this);
 // Create Layer
m_klayer = new Esri::ArcGISRuntime::KmlLayer(m_kdata, this);

m_map->operationalLayers()->append(m_klayer);

Subsequently trying to just spin the layer around via a timer-called separate function (for testing purposes, obviously):

m_groundOverlay->setRotation(m_groundOverlay->rotation() + 1);
if (m_groundOverlay->rotation() > 360)
{
 m_groundOverlay->setRotation(0);
}

  I've assembled the "EditKmlGroundOverlay" sample from the arcgis-runtime-samples-qt repo on Git and altered it do perform the rotation above, and it works fine.  The only difference I can figure out is that the EditKmlGroundOverlay sample uses a scene view instead of a map view.  

  Is this a limitation of Map Views or am I doing something wrong or missing something?  

0 Kudos
14 Replies
LucasDanzinger
Esri Frequent Contributor

Hey Brian-

Thanks for your email. We are wrapping up 100.9 release right now, so it is a bit hectic.

I passed your information onto our senior product managers for their consideration. Hopefully we can either get the KML Ground Overlay 2D issue fixed or Image Overlay in 2D implemented, but that timeline is unknown. What I do know is 100.9 is going to be released in a week or so, but neither of these will be in that release.

For the time being, would it be an option to use 3D instead of 2D and orient the camera in a top down manner so it looks 2D?

0 Kudos
BrianCrist
New Contributor II

Hi Lucas,

  I initially thought doing a "top-down" 3-d look would be the best option, but we need to display grid lines; the program manager has indicated losing grid-lines is a non-starter.

  The work-around I'm using feels very clumsy, but maybe it's the best I can do:

  • I can produce an envelope that is accurately sized that contains the sensor data I'm interested in displaying. 
  • If I could find a way to know the dimensions of this envelope in pixels, I could scale the QImage via QImage::scaled() to produce a corrected-sized image.
  • I'm setting the sensor data's graphic overlay setScaleSymbols flag to True
  • I have a sort of kludgey version of pixels-to-meters done by doing a GeometryEngine::DistanceGeodetic between two points in the middle of the MapView...
    • I'm running into issues with this because I don't understand how Map scaling and GraphicsView scaling relate to one-another; in other words, if the scale on the Map View viewpoint's center is the same as the Map's referenceScale everything is hunky dory.  But if I change the zoom level on the Map View, my crappy pixels-to-meters calculation does not work properly.  
  • If I had an accurate way to get pixels to meters; or if I understood what the heck I was doing with this scaling, I think I could resolve this problem and pour myself a nice glass of champagne.

Regards,

  Brian

0 Kudos
LucasDanzinger
Esri Frequent Contributor

Hi Brian-

Maybe MapView::unitsPerDIP could get you what you need - https://developersdev.arcgis.com/qt/latest/cpp/api-reference/esri-arcgisruntime-mapview.html#unitsPe... 

We added this API so users could build a scalebar, which conceptually is very similar to the need you have - to tell how many real-world units are in one device independent pixel. Real-world units will be in whatever the 0th layer in the map is, so if you are using web mercator basemap, it will be meters.

0 Kudos
BrianCrist
New Contributor II

Hi Lucas,

  This is where my ignorance of GIS comes into play.  So the map I'm using is a Basemap::TopographicVector and the mapView's spatial reference is WKID 3857, who's unit is a meter.  

  When I use unitsPerDip (which I tried quite a while ago when I was first wrestling with this) - when I render my 100 meter square at 0,0 everything is great.  But when I render it in Vermont (-72.9927854, 44.4050029 in spatial reference Wkid 4326), the size is reduced. 

  I understand this has to do with the projection somehow, but I do not understand how.  

  I came up with a pretty hacky way to solve this which seems to be working:

  When the zoom level changes, I obtain Points from two adjoining pixels in the middle of the mapView using screenToLocation and using the GeometryEngine to calculate the meters between these two points.  This gives me a "pixels to meters" which seems to calculate the size of my 100x100 square pretty accurately wherever it is in the world.

I then divide that value by the ratio of the mapView's scale to the Map's scale.

  However, I think this is probably a little more resource intensive than it should be, and it definitely feels like a hack.  Is there any way you can either email me or clarify on this thread how I take the UnitsPerDip and project them properly at various latitudes?

  Thanks so much,

  Brian

0 Kudos
BrianCrist
New Contributor II

It's probably important to note that I'm using an overlay whose setScaleSymbols flag is set to true also.  I think that's an important element to my code above functioning properly.

0 Kudos