I am using dictionarySymbolStyle and dictionary renderer in ArcGIS qt 100.5 to read and display symbols from a style file. The code for the function is as follows. m_mapView is my MapGraphicsView object. The application is successfully built. The map is displayed in the output window however the points aren't displayed. The points are displayed using a simplemarkersymbol but not using the dictionary symbology. Can somebody guide me why this problem is occurring??
void offlinemap2d::addPointsFromStyleFile()
{
//create a new graphicsoverlay
GraphicsOverlay* graphicsOverlay = new GraphicsOverlay(this);
// create a list of points
const QList<Point> pointsList
{
Point(72.852642647560347, 19.092812566811544, SpatialReference::wgs84()),
Point(72.8708416959572303, 19.08444173689877, SpatialReference::wgs84()),
Point(32.6697273884990937, 56.064250073402874, SpatialReference::wgs84()),
Point(32.6395150461199726, 56.06127916736989, SpatialReference::wgs84())
};
// create the symbology for the points
dictionarySymbolStyle = new DictionarySymbolStyle("mil2525d",":/Res/mil2525d.stylx", this);
DictionaryRenderer* renderer = new DictionaryRenderer(dictionarySymbolStyle, this);
graphicsOverlay->setRenderer(renderer);
foreach (const Point &buoyPoint, pointsList)
{
graphic = new Graphic(buoyPoint, this);
graphicsOverlay->graphics()->append(graphic);
}
//add overlay to the map
m_mapView->graphicsOverlays()->append(graphicsOverlay);
}
Hi Abhijeet Satam,
The mil2525d standard requires attributes to know which graphic to display. These are provided as attributes to the Graphic each time one is created.
We do have some samples that show this workflow. Please take a look at these and let us know if this helps.
You'll notice that both samples read the attributes in from an xml file and parse that info into the coordinates and attributes for each graphic.
Hi James,
I need my application to be in native cpp . Can you provide a link or solution to read attributes and coordinates using CPP ?
Yes, our C++ example code is doing all that logic in native C++, not QML.
Please take a look at the GODictionaryRenderer::parseXmlFile and GODictionaryRenderer::createGraphic methods in these code snippets.
The xml file used by the sample code is linked on the landing page for the sample
Hi James,
Accoding to your suggesstion I have tried to incorporate the sample code into my application.
I want to display the following points on the map using mil2525 symbology: ( point - lat , long, spatial ref)
Point 1 - 72.852642647560347, 19.092812566811544, SpatialReference::wgs84()),
Point 2 - 72.8708416959572303, 19.08444173689877, SpatialReference::wgs84()),
So I added these points to the point collection using addPoint() in the createGraphic function . No changes have been made to the parseXmlFile function code. Following is the code snippet. Are any more changes needed in the sample code?
void offlinemap2d::addPointsFromStyleFile()
{
//create a new graphicsoverlay
GraphicsOverlay* graphicsOverlay = new GraphicsOverlay(this);
// create the symbology for the points
dictionarySymbolStyle = new DictionarySymbolStyle("mil2525d",":/Res/mil2525d.stylx", this);
DictionaryRenderer* renderer = new DictionaryRenderer(dictionarySymbolStyle, this);
graphicsOverlay->setRenderer(renderer);
//add overlay to the map
parseXmlFile();
m_mapView->graphicsOverlays()->append(graphicsOverlay);
}
void offlinemap2d::createGraphic(QVariantMap rawAttributes)
{
// If _wkid was absent, use WGS 1984 (4326) by default.
int wkid = rawAttributes.count(FIELD_WKID) > 0 ? rawAttributes[FIELD_WKID].toInt() : 4326;
SpatialReference sr(wkid);
Geometry geom;
// It's a multipoint
MultipointBuilder* builder = new MultipointBuilder(sr, this);
PointCollection* collection = new PointCollection(sr, this);
collection->addPoint(72.852642647560347, 19.092812566811544);
collection->addPoint(72.8708416959572303, 19.08444173689877);
builder->setPoints(collection);
geom = builder->toGeometry();
if (!geom.isEmpty())
{
// Get rid of _control_points and _wkid. They are not needed in the graphic's
// attributes.
rawAttributes.remove(FIELD_CONTROL_POINTS);
rawAttributes.remove(FIELD_WKID);
Graphic* graphic = new Graphic(geom, rawAttributes, this);
graphicsOverlay->graphics()->append(graphic);
}
}
Can you also explain what is meant by the control points attribute in the Mil2525DMessages.xml file. Are these control points coordinates where the symbol has to be displayed on the map??
>Are any more changes needed in the sample code?
Yes, more changes will be needed. In our example code, all the information is stored in the xml file. So you will need to make some changes to use your points. Be careful with the x-y (long-lat) ordering of your coordinates so they end up in the right places. Your ordering might differ from the order in the xml file, so you may need to reverse them to reuse the same logic.
>Can you also explain what is meant by the control points attribute in the Mil2525DMessages.xml file. Are these control points coordinates where the symbol has to be displayed on the map??
The control_points attrubute in the xml file is the location of the data to be placed. In some cases it's a simple point (an x-y pair) and in other cases it's a Multipoint, containing multiple x-y pairs.
Hi James,
Thanks for the reply.
1)
My current understanding about relationship between latitude / longitude and <_control_points>x, y</_control_points> needs to be ensured. I have currently assumed that control points 0,0 will display symbol at the centre of the map. Kindly explain how lat-long and x-y relationship is to be determined.
2)
Now, I have tried changing the xml file so that the code remains unchanged. However no graphics is displayed on the map. The changes in the xml are as follows: The points are in the format
<_control_points>x, y</_control_points>. I also tested the code by reversing the order. To begin with, I tried with control points as 0, 0 so that it displays symbol at the centre of map.
<message>
<_type>position_report</_type>
<_action>update</_action>
<_id>43de0a7b-0096-40de-a0f5-37d7f2e19766</_id>
<_wkid>3857</_wkid>
<sic>GFGPDLF-------X</sic>
<name>Coordinating Point</name>
<identity>3</identity>
<symbolset>25</symbolset>
<symbolentity>130600</symbolentity>
<_control_points>0, 0</_control_points>
</message>
This also did not help.
3)
>>>To make sure there is no problem with the code itself I tried running the GODictionaryRenderer example without any changes to xml file. The application displays the map but no symbology. In this sample code I have only changed the path to the stylx and xml files only. The screenshot of the application window is attached. I have zoomed in to the exact location where the symbology is supposed to be displayed according to the github example code. So is there any additional requirement for the example to run??? The latitude longitude values to the location Devizes in the image are 51.3489° N, 1.9948° W. However in the xml files the control point values are very large in value compared to the lat-long values. So I am unable to understand how the values (control points) in the xml file are obtained. Is there any particular scale by which the lat long has to be multiplied???
Hi Abhijeet Satam,
1: We have an example that shows how to do map projections. You will need to know the coordinate system for your input points, for example if they are in wgs84 or not.
2 and 3:
Let me ask, are you building and running the standalone sample? The complete sample application included in the SDK installation will download files for you if it detects you are missing any data. For example, this sample requires two pieces of data to be available on the local machine.
See at the bottom of the page, here:
And here:
GitHub - Esri/arcgis-runtime-samples-qt: ArcGIS Runtime SDK for Qt samples for Qt Creator.
If you are certain that all the data is present and all your paths are correct, then I would add some simple graphics with SimpleMarkerSymbol as the symbol and make sure you can see those on the map. That should rule out any other problems and help narrow in on what is missing.
The latitude longitude values to the location Devizes in the image are 51.3489° N, 1.9948° W. However in the xml files the control point values are very large in value compared to the lat-long values. So I am unable to understand how the values (control points) in the xml file are obtained. Is there any particular scale by which the lat long has to be multiplied??
Your coordinates are in a different format. It looks like Decimal Degrees. Fortunately, we have a sample that shows how to convert coordinates from one format to another:
You'll notice that in the xml file, there is a "_wkid" field - that is the well known ID for the spatial reference of the coordinates.
Hi James,
Thank you for the response.
1. I have checked the coordinate system using spatialreference.wkid() using the code below.
void offlinemap2d::displayLocationOnMove(QMouseEvent &mouseEvent)
{
qDebug()<<"INSIDE DISPLAY LOCATION";
// Convert clicked screen position to position on the map surface.
const Point baseSurfacePos = m_mapView->screenToLocation(mouseEvent.x(), mouseEvent.y());
const Point projectedPoint = GeometryEngine::project(baseSurfacePos, 4326);
qDebug("Projected point x cor: %lf ",projectedPoint.x());
qDebug("Projected point y cor: %lf ",projectedPoint.y());
qDebug("Basesurfacepos x cor: %lf ",baseSurfacePos.x());
qDebug("Basesurfacepos y cor: %lf ",baseSurfacePos.y());
if(baseSurfacePos.spatialReference().isProjected()==true)
{
qDebug()<<"is projected";
}
else {
{
qDebug()<<"not projected";
}
}
qDebug()<<SpatialReference().wkid();
qDebug()<<baseSurfacePos.spatialReference().wkid();
qDebug()<<SpatialReference().wgs84().wkid();
qDebug()<<projectedPoint.spatialReference().wkid();
}
The console output is as follows:
INSIDE DISPLAY LOCATION
Projected point x cor: 72.865688
Projected point y cor: 19.098172
Basesurfacepos x cor: 275454.851485
Basesurfacepos y cor: 2113058.817065
is projected
-1
32643
4326
4326
In the Mil2525DMessages.xml file I made the following Changes. I have also tried to run with the projected point coordinates as the control points. But no points are displayed on the map.
<message>
<_type>position_report</_type>
<_action>update</_action>
<_id>43de0a7b-0096-40de-a0f5-37d7f2e19766</_id>
<_wkid>4326</_wkid>
<sic>GFGPDLF-------X</sic>
<name>Coordinating Point</name>
<identity>3</identity>
<symbolset>25</symbolset>
<symbolentity>130600</symbolentity>
<_control_points>275454.851485, 2113058.817065</_control_points>
</message>
2. I am sure that the files and path are correct. have tried displaying points using a SimpleMarkerSymbol using the following code and the points are displayed on the map successfully at the specified location.
void offlinemap2d::AddPointData()
{
// create a list of points
const QList<Point> pointsList {
Point(72.852642647560347, 19.092812566811544, SpatialReference::wgs84()),
Point(72.8708416959572303, 19.08444173689877, SpatialReference::wgs84())
};
// create the symbology for the points
SimpleMarkerSymbol* sms = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Circle,
QColor("red"), 10, this);
// create a graphic and add each of them to the overlay
foreach (const Point &buoyPoint, pointsList)
{
graphic = new Graphic(buoyPoint,sms, this);
graphicsOverlay1->graphics()->append(graphic);
}
m_mapView->graphicsOverlays()->append(graphicsOverlay1);
}
Please guide further.
I have a few more suggestions, but unfortunately the team cannot help to debug this issue much further. I would encourage you to attend the 2020 Esri Dev Summit in Palm Springs where we can spend more time on this and help you get to the bottom of the issues. Many Runtime software engineers and specialists will be on hand to help you out.
It sounds like you can get some points on the map, so it's not an issue with your coordinates. That's good, it rules out problems with projections and spatial references.
The next thing to check is to see if you can actually load the DictionarySymbolStyle or not. You should be able to connect to the loadStatusChanged signal and check if it is loading. If nothing is displaying, and you're sure that your data path and graphics' attributes are being set correctly, then checking the load status of the DictionarySymbolStyle should confirm that it can access the mil2525d.stylx file.
Here's an example:
connect(dictionarySymbolStyle, &DictionarySymbolStyle::loadStatusChanged, this, [](LoadStatus loadStatus)
{
switch (loadStatus)
{
case LoadStatus::Loaded:
qDebug() << "DictionarySymbolStyle LoadStatus: Loaded"; break;
case LoadStatus::Loading:
qDebug() << "DictionarySymbolStyle LoadStatus: Loading"; break;
case LoadStatus::NotLoaded:
qDebug() << "DictionarySymbolStyle LoadStatus: NotLoaded"; break;
case LoadStatus::FailedToLoad:
qDebug() << "DictionarySymbolStyle LoadStatus: FailedToLoad"; break;
case LoadStatus::Unknown:
qDebug() << "DictionarySymbolStyle LoadStatus: Unknown"; break;
}
});
If that is loading correctly, then I would start working backwards from the existing sample code. Make sure the sample works with the provided data. Once you verify that, modify some of the points in the xml file to be your points. Trim it down to just two points (your points) and make sure that is working.
Another thing you can do is decouple the xml parsing logic and trim down the existing sample into something that adds two points with all hard-coded coordinates and attributes (or even just one point). Once you have that workflow working, it should be trivial for you to adapt that workflow to your existing needs.