Creation of a personalized graphic with image, texts and sensor ranges

1183
7
03-02-2020 12:01 PM
MichelGuenin
New Contributor

Hello,
I am adapting in C ++ with Qt and ArcGis my Harpoon application for Android (link on google play for the example: Harpoon pour Android – Applications sur Google Play ) that I realized in Java with the Osmdroid API. I want to switch to Qt and ArcGis to be able to run on all systems. I must be able to draw on 2D and 3D map symbols of the units with text and plots of sensor ranges and open a context menu on the unit with a long click.

I was able to draw a text:

   Point point2(-60.0,-52.0, 500.0);

   TextSymbol* textSymbol = new TextSymbol("Harpoon", QColor(Qt::black), 12.0, HorizontalAlignment::Left,    VerticalAlignment::Middle, this);

   Graphic* graphic2 = new Graphic(point2, textSymbol, this);
   m_GraphicsOverlay->graphics()->append(graphic2);

I was able to draw an image:

    Point point(-60.0,-52.0, 200.0);
    QImage *image = new QImage( ":/NTDS/Data/ntds_airbase.png" );
    PictureMarkerSymbol *symbol = new PictureMarkerSymbol(*image, this);
    symbol->setWidth(30.0f);
    symbol->setHeight(30.0f);
    Graphic *graphic = new Graphic(point3, symbol, this);
    m_GraphicsOverlay->graphics()->append(graphic3);

But I would like to customize the Graphic class to display an image and several text as well as radar ranges, and it does not seem that we can access the source of arcGis.

Graphic* graphic = new Graphic( geometry, rawAttributes, this );

But I don't see how to do it. Can you help me please?

Best regards

Michel Guenin

0 Kudos
7 Replies
LucasDanzinger
Esri Frequent Contributor

There are probably a few ways to solve this, but the most straight forward is probably to apply a LabelDefinition to the GraphicsOverlay.

This sample does this, only it applies it to a FeatureLayer instead of a GraphicsOverlay - arcgis-runtime-samples-qt/ShowLabelsOnLayers.cpp at master · Esri/arcgis-runtime-samples-qt · GitHub 

The general workflow would be:

- define a graphic

- add attributes that represent the text you want to display

- use a picture marker symbol to display the marker you want

- use a label definition to define the label under the graphic symbol (as displayed in the google play screenshot) 

0 Kudos
MichelGuenin
New Contributor

Hello Lucas,

Thanks for your quick response, I'm going to study the FeatureLayer class.
Do you think I could draw circles, arcs or spheres?
And how to open a menu on the long click on the FeatureLayer?

Regards,

0 Kudos
LucasDanzinger
Esri Frequent Contributor
Do you think I could draw circles, arcs or spheres?

Yes. SimpleMarkerSymbol has a few predefined shapes you can use. If you want to manually define vector geometry to display in your symbol, you can do that as well, but will take more work. For this, I'd suggest using VectorMarkerSymbolLayer class. This will allow you to define the symbol as a vector. I attached a sample project that shows how this work. In the example, I wanted a 5 point star symbol. Here is the relevant code snippet:

// add a vector marker layer as background
SimpleFillSymbol* simpleFillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, QColor(Qt::blue), this);
VectorMarkerSymbolElement* symbolElementPolygon = new VectorMarkerSymbolElement(Geometry::fromJson("{\"rings\":[[[0,30],[10,0],[40,0],[15,-18],[25,-45],[0,-30],[-25,-45],[-15,-18],[-40,0], [-10,0]]]}"), simpleFillSymbol->toMultilayerSymbol(this), this);
VectorMarkerSymbolLayer* vectorSymbolLayer = new VectorMarkerSymbolLayer(QList<VectorMarkerSymbolElement*> {symbolElementPolygon}, this);
vectorSymbolLayer->setSize(100.0);
vectorSymbolLayer->setOffsetY(6.0);
m_pointSymbol->symbolLayers()->insert(0, vectorSymbolLayer);‍‍‍‍‍‍‍

And how to open a menu on the long click on the FeatureLayer? 

I'd connect up to this signal - MapQuickView Class | ArcGIS for Developers 

Then when that emits, display a UI somehow. You could use a Callout like shown in our samples. You could also just define your own UI to display. We did something like that in our Dynamic Situational Awareness example app

0 Kudos
MichelGuenin
New Contributor

Lucas,

As always, the hardest part is getting started. You have to spend time learning an API. If I can't get your API to work, I'll have to give up. I'll give you the example I just made:

void Gui_MainWindow::createMapView()
{
    // Create a map
    m_Map = new Map(Basemap::streetsWithReliefVector(this), this);  // streetsWithReliefVector
    m_MapView = new MapGraphicsView(this);                                      // Create the Widget view
    m_MapView->setMap(m_Map);                                                          // Set map to map view
    m_GraphicsOverlay = new GraphicsOverlay(this);
    m_GraphicsOverlay->setRenderingMode(GraphicsRenderingMode::Dynamic);
    m_MapView->graphicsOverlays()->append(m_GraphicsOverlay);

    // Load Dictionary
    DictionarySymbolStyle *dictionarySymbolStyle = DictionarySymbolStyle::createFromFile( QDir::homePath() + "/ArcGIS/Runtime/Data/styles/arcade_style/mil2525d.stylx", this );
    DictionaryRenderer *renderer = new DictionaryRenderer(dictionarySymbolStyle, this);
    m_GraphicsOverlay->setRenderer(renderer);

    // Creation of the point of origin of the graph
    Point *point = new Point( -57.675, -51.641, SpatialReference::wgs84() );
    m_MapView->setViewpointCenter( *point, 150000 );
    m_pointGraphic = new Graphic( *point, this );

    // Draw symbol NATO
    QVariantMap *elementValues = new QVariantMap();
    elementValues->begin();
    elementValues->insert("identity","5");                             // Affiliation
    elementValues->insert("symbolset","30");                     // symbolset
    elementValues->insert("symbolentity", "120202");        // symbolentity
    elementValues->insert("echelon", "1");                         // echelon
    elementValues->insert("uniquedesignation","S001");   // uniquedesignation
    elementValues->end();
    Graphic *graphic = new Graphic( *point, *elementValues, this );
    m_GraphicsOverlay->graphics()->append( graphic );

    // Draw Motion vector
    SimpleLineSymbol *line_symbol = new SimpleLineSymbol( SimpleLineSymbolStyle::Solid, QColor(Qt::black), 1.0f, this );
    line_symbol->setAntiAlias( true );
    PolylineBuilder *polyline_builder = new PolylineBuilder( SpatialReference::wgs84(), this );
    polyline_builder->addPoint( *point );
    polyline_builder->addPoint( -57.68, -51.645 );     // here we have a problem: I want 10 pixels in length in one direction ?

    Graphic *polyline_graphic = new Graphic( polyline_builder->toGeometry(), line_symbol, this );
    m_GraphicsOverlay->graphics()->append(polyline_graphic);
    m_MapView->graphicsOverlays()->append(m_GraphicsOverlay);

    // Creation of a surface radar range
    SimpleMarkerSymbol *surfaceRadar = new SimpleMarkerSymbol( SimpleMarkerSymbolStyle::Circle, QColor("transparent"), 100.0f /*range*/, this );    // here too, I want a radius in km ?
    surfaceRadar->setOutline( new SimpleLineSymbol( SimpleLineSymbolStyle::Solid, QColor("green"), 1.0f, this) );

    // Creation of an air radar range
    SimpleMarkerSymbol *airRadar = new SimpleMarkerSymbol( SimpleMarkerSymbolStyle::Circle, QColor("transparent"), 300.0f /*range*/, this );        // same here, a radius in km ?
    airRadar->setOutline( new SimpleLineSymbol( SimpleLineSymbolStyle::Solid, QColor("red"), 1.0f, this) );

    m_pointSymbol = dynamic_cast<MultilayerPointSymbol*>( surfaceRadar->toMultilayerSymbol(this) );
    auto outlineSymbol = dynamic_cast<MultilayerPointSymbol*>( airRadar->toMultilayerSymbol(this) );

    if (outlineSymbol) {
        if (!outlineSymbol->symbolLayers()->isEmpty()) {
            outlineSymbol->symbolLayers()->at(0)->setColorLocked( true );
            m_pointSymbol->symbolLayers()->append( outlineSymbol->symbolLayers()->at(0) );
        }
    }

    m_pointGraphic->setSymbol( m_pointSymbol );                              // set symbol on the graphic
    m_GraphicsOverlay->graphics()->append( m_pointGraphic );        // add graphic to overlay
}

I don't know how to make a circle with a radius in km, and draw a line of 10 pixels on the screen?

Best regards

 

Michel Guenin

0 Kudos
LucasDanzinger
Esri Frequent Contributor

To draw a circle, I'd buffer the center point. Here is a sample for buffering - arcgis-runtime-samples-qt/ArcGISRuntimeSDKQt_CppSamples/Geometry/Buffer at master · Esri/arcgis-runt... 

Regarding drawing a line 10 pixels on screen - are you saying that it will be a fixed size and not attached to a geographic location? Or as you pan and zoom, it should always stay attached to the same center point, but will remain a fixed size of 10 pixels?

0 Kudos
MichelGuenin
New Contributor

Yes it is a vector line which indicates the movement of the unit, this line is attached to the center of the symbol and points in a direction with a length of 10 screen pixels.

0 Kudos
LucasDanzinger
Esri Frequent Contributor

I think there are a few ways we could solve this. The easiest would probably be:

- get an image of an arrow

- display in a graphic as a PictureMarkerSymbol

- set the height and width in screen pixels

- change x/y offset so the centerpoint is in the middle of the image

- change the angle on the marker symbol depending on direction

0 Kudos