Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/Tests/CrashDictSymbol/CrashDictSymbol.cpp
T
2026-08-13 18:33:10 +02:00

393 lines
15 KiB
C++
Executable File

/*
**
** @RDE_HEADER@
** Shows a crash when using QGraphicsItems and ESRI-Graphics in same scene
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Linux, Qt 5.7. ArcGISRuntimeQt 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 16.01.2017, JT : Initial
**
** -----------------------------------------------------------------------------------------------
*/
#include <QtCore/QDir>
#include <QtCore/QUrl>
#include <QtCore/QDebug>
#include <QtGui/QSurface>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QGraphicsScene>
#include <QtWidgets/QGraphicsPathItem>
#include <QtWidgets/QMainWindow>
#include <arcgis/Map.h>
#include <arcgis/MapGraphicsView.h>
#include <arcgis/DictionarySymbolStyle.h>
#include <arcgis/Basemap.h>
#include <arcgis/ArcGISTiledLayer.h>
#include <arcgis/Layer.h>
#include <arcgis/GraphicsOverlay.h>
#include <arcgis/MultipointBuilder.h>
#include <arcgis/SimpleMarkerSymbol.h>
#include <arcgis/PolygonBuilder.h>
#include <arcgis/Point.h>
#include <arcgis/SimpleFillSymbol.h>
#include <arcgis/DictionaryRenderer.h>
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* The class MapWindow creates a tiled base map from an UTM based TPK from Bremen. Loading the map will be done
* by clicking the "Load Map" button. When the map is loaded, you can click button "Symbol Failure" to create a
* MIL2525D symbol on map. With the combobox left of this button you can setup the geometry that will be use to
* build the symbol. The symbol with sidc="10012500002713000000" will cause always a crash. Other symbols can
* cause a crash some times if not choosing the fitting geometry.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
class MapWindow : public QWidget
{
Esri::ArcGISRuntime::ArcGISTiledLayer * m_tiledLayer;
Esri::ArcGISRuntime::Basemap * m_basemap;
Esri::ArcGISRuntime::Map * m_map;
Esri::ArcGISRuntime::MapGraphicsView * m_mapView;
QComboBox * m_cbGeometry;
QPushButton * m_pbSymbolFailure;
Esri::ArcGISRuntime::DictionarySymbolStyle * m_dictionarySymbolStyle;
public:
MapWindow() : QWidget(), m_tiledLayer(nullptr), m_dictionarySymbolStyle(nullptr)
{
m_basemap = new Esri::ArcGISRuntime::Basemap(this);
m_map = new Esri::ArcGISRuntime::Map(this);
m_map->setAutoFetchLegendInfos(true);
m_mapView = new Esri::ArcGISRuntime::MapGraphicsView(this);
m_mapView->setObjectName(QLatin1String("EsriMapView"));
m_mapView->setFrameShape(QFrame::NoFrame);
m_mapView->setWrapAroundMode(Esri::ArcGISRuntime::WrapAroundMode::Disabled);
m_mapView->setFixedSize(900,900);
m_cbGeometry = new QComboBox( this );
m_cbGeometry->addItem( "Point" );
m_cbGeometry->addItem( "Linear" );
m_cbGeometry->addItem( "Areal" );
m_cbGeometry->setCurrentIndex(0);
m_cbGeometry->setEditable(false);
QPushButton * pbLoadMap = new QPushButton(QStringLiteral("Load Map"), this);
m_pbSymbolFailure = new QPushButton(QStringLiteral("Symbol Failure"), this);
m_pbSymbolFailure -> setEnabled(false);
connect( pbLoadMap , &QPushButton::clicked, this, [this](bool) { initMap(); });
connect( m_pbSymbolFailure, &QPushButton::clicked, this, [this](bool) { buildDictSymbol(); });
QVBoxLayout * layout = new QVBoxLayout(this);
QHBoxLayout * hLayout = new QHBoxLayout();
hLayout->addStretch(2);
hLayout->addWidget(m_cbGeometry);
hLayout->addSpacing(10);
hLayout->addWidget(m_pbSymbolFailure);
hLayout->addStretch(2);
layout->addWidget(pbLoadMap);
layout->addLayout(hLayout);
layout->addWidget(m_mapView,2);
connect(m_map, &Esri::ArcGISRuntime::Map::doneLoading, this, [this](Esri::ArcGISRuntime::Error loadError)
{
if (!loadError.isEmpty())
{
qCritical() << loadError.message();
qCritical() << loadError.additionalMessage();
Esri::ArcGISRuntime::ErrorDomainType errorDomain = loadError.domain();
Esri::ArcGISRuntime::ExtendedErrorType extendedErr = loadError.extendedErrorType();
Q_UNUSED(errorDomain);
Q_UNUSED(extendedErr);
}
if (Esri::ArcGISRuntime::LoadStatus::Loaded == m_map->loadStatus())
{
if (m_dictionarySymbolStyle && (Esri::ArcGISRuntime::LoadStatus::Loaded == m_dictionarySymbolStyle->loadStatus()))
{
m_pbSymbolFailure->setEnabled(true);
}
}
});
} // MapWindow()
void initMap()
{
#define BremenMap
#ifdef BremenMap
// m_tiledLayer = new Esri::ArcGISRuntime::ArcGISTiledLayer(QUrl("http://192.168.133.90:6080/arcgis/rest/services/BremenGeoTiffUTM/MapServer"));
Esri::ArcGISRuntime::TileCache * tpkCache = new Esri::ArcGISRuntime::TileCache("Topographic.tpk", this);
m_tiledLayer = new Esri::ArcGISRuntime::ArcGISTiledLayer(tpkCache);
#else
Esri::ArcGISRuntime::TileCache * tpkCache = new Esri::ArcGISRuntime::TileCache("/usr/share/arcgis/resources/Topographic.tpk", this);
m_tiledLayer = new Esri::ArcGISRuntime::ArcGISTiledLayer(tpkCache);
#endif
m_basemap->baseLayers()->append(m_tiledLayer);
m_map->setBasemap(m_basemap);
Esri::ArcGISRuntime::GraphicsOverlayListModel * graphicsOverlayListModel = m_mapView->graphicsOverlays();
Esri::ArcGISRuntime::GraphicsOverlay * graphicalOverlay = new Esri::ArcGISRuntime::GraphicsOverlay();
graphicalOverlay->setSelectionColor(Qt::magenta);
graphicsOverlayListModel->append(graphicalOverlay);
m_mapView->setMap(m_map);
loadDictionary();
} // void initMap()
void loadDictionary()
{
#ifdef BremenMap
QString stylxPath = "C:/Program Files (x86)/ArcGIS SDKs/Qt100.0/resources/symbols/mil2525d/mil2525d.stylx"; // warning must be stylx file path
#else // if path is wrong --> crash (only Windows)
QString stylxPath = "/usr/share/arcgis/resources/symbols/mil2525d/mil2525d.stylx";
#endif
m_dictionarySymbolStyle = new Esri::ArcGISRuntime::DictionarySymbolStyle("mil2525d", stylxPath, this);
connect(m_dictionarySymbolStyle, &Esri::ArcGISRuntime::DictionarySymbolStyle::loadStatusChanged, this, [this]( Esri::ArcGISRuntime::LoadStatus loadStatus )
{
if ((Esri::ArcGISRuntime::LoadStatus::Loaded == loadStatus) && (Esri::ArcGISRuntime::LoadStatus::Loaded == m_map->loadStatus()))
{
m_pbSymbolFailure->setEnabled(true);
}
} );
m_dictionarySymbolStyle->load();
} // void loadDictionary()
~MapWindow() = default;
void buildDictSymbol()
{
Esri::ArcGISRuntime::GraphicsOverlay * layer = new Esri::ArcGISRuntime::GraphicsOverlay(this);
Esri::ArcGISRuntime::DictionaryRenderer * dictRenderer = new Esri::ArcGISRuntime::DictionaryRenderer( m_dictionarySymbolStyle, this);
connect( dictRenderer, &Esri::ArcGISRuntime::DictionaryRenderer::errorOccurred, this, [this]( const Esri::ArcGISRuntime::Error & error )
{
qCritical() << "Error loading dictionary: " << error.message() << endl;
} );
//layer->setRenderingMode(Esri::ArcGISRuntime::GraphicsRenderingMode::Static);
layer->setRenderingMode(Esri::ArcGISRuntime::GraphicsRenderingMode::Dynamic);
layer->setRenderer( dictRenderer );
QVariantMap rawAttributes;
rawAttributes["sidc"] = "10012500002713000000"; // --> always crash
// rawAttributes["sidc"] = "10012500001521000000"; // as polygon geometry --> failed to generate sequences for graphics
// or crash if swap coordinate 3 and 4 (see #define CRASH_25152100)
// as multipoint --> ok, with strange behaviour under zoom
// rawAttributes["sidc"] = "10012500003419000000"; // --> failed to generate sequences for graphics
setWindowTitle( "Crash Dictionary Symbol - Symbol Code " + rawAttributes["sidc"].toString() );
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* see mil2525d.pdf, page 600 (25 271300)
* , page 459 (25 152100)
* coordinate sequenze as follows:
*
* (3) ------------------------------------------->(4)
* green orange
*
*
*
* (1) ------------------------------------------->(2)
* red blue
*
* or page 649 (25 341900):
*
* (4)<------------------------------------------- (3)
* orange green
* ^
* |
* |
* (1) ------------------------------------------->(2)
* red blue
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* for Bremen map:
QPointF p1 = QPointF( 493200,5878900 ); // UTM Bremen 493200,5878900
QPointF p2 = QPointF( 495200,5878900 ); // UTM Bremen 495200,5878900
QPointF p3 = QPointF( 493200,5880900 ); // UTM Bremen 493200,5880900
QPointF p4 = QPointF( 495200,5880900 ); // UTM Bremen 495200,5880900
*/
QPointF p1 = QPointF( 0, 0 );
QPointF p2 = QPointF( 3000000, 0 );
QPointF p3 = QPointF( 0, 5890000 );
QPointF p4 = QPointF( 3000000, 5800000 );
// first show coordinate in map
auto drawPictureMarker = [this](const QPointF & p, const QColor & c) -> Esri::ArcGISRuntime::Graphic *
{
Esri::ArcGISRuntime::Graphic * graphic = new Esri::ArcGISRuntime::Graphic();
Esri::ArcGISRuntime::SimpleMarkerSymbol * marker = new Esri::ArcGISRuntime::SimpleMarkerSymbol();
marker->setSize(8);
marker->setStyle( Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Circle );
marker->setColor(c);
graphic->setGeometry( Esri::ArcGISRuntime::Point( p.x(), p.y(), m_map->spatialReference() ) );
graphic->setSymbol( marker );
return graphic;
}; // drawPictureMarker
if (rawAttributes["sidc"] == "10012500003419000000")
{
// swap coordinate 3 and 4 in case of Relief in Place symbol (25 341900) stay compatible with MIL2525D
QPointF swap = p3; p3 = p4; p4 = swap;
}
#define CRASH_25152100
#ifdef CRASH_25152100
if ((m_cbGeometry->currentIndex() == 2) && (rawAttributes["sidc"] == "10012500001521000000"))
{
// swap coordinate 3 and 4 in case of Suppoprt by Fire Position symbol show crash
QPointF swap = p3; p3 = p4; p4 = swap;
}
#endif
layer->graphics()->append( drawPictureMarker(p1,QColor("red" )) );
layer->graphics()->append( drawPictureMarker(p2,QColor("blue" )) );
layer->graphics()->append( drawPictureMarker(p3,QColor("green" )) );
layer->graphics()->append( drawPictureMarker(p4,QColor("orange")) );
Esri::ArcGISRuntime::Graphic * graphic = new Esri::ArcGISRuntime::Graphic();
switch(m_cbGeometry->currentIndex())
{
case 0:
case 1:
{
qWarning() << " use 4 coordinates - MultipointBuilder";
Esri::ArcGISRuntime::MultipointBuilder pointsBuilder( m_map->spatialReference() );
Esri::ArcGISRuntime::PointCollection points( m_map->spatialReference() );
points.addPoint( p1.x(),p1.y() ); // 1
points.addPoint( p2.x(),p2.y() ); // 2
points.addPoint( p3.x(),p3.y() ); // 3
points.addPoint( p4.x(),p4.y() ); // 4
pointsBuilder.setPoints( &points );
graphic->setGeometry( pointsBuilder.toGeometry() );
} break;
case 2:
{
qWarning() << " use 4 coordinates - PolygonBuilder";
Esri::ArcGISRuntime::PolygonBuilder polygonBuilder( m_map->spatialReference() );
polygonBuilder.addPoint( Esri::ArcGISRuntime::Point(p1.x(),p1.y(),m_map->spatialReference()) ); // 1
polygonBuilder.addPoint( Esri::ArcGISRuntime::Point(p2.x(),p2.y(),m_map->spatialReference()) ); // 2
polygonBuilder.addPoint( Esri::ArcGISRuntime::Point(p3.x(),p3.y(),m_map->spatialReference()) ); // 3
polygonBuilder.addPoint( Esri::ArcGISRuntime::Point(p4.x(),p4.y(),m_map->spatialReference()) ); // 4
graphic->setGeometry( polygonBuilder.toPolygon() );
}
}
qWarning() << " rawAttributes[sidc] = '" << rawAttributes[QLatin1String("sidc")] << "'";
graphic->attributes()->setAttributesMap(rawAttributes);
//add the graphic to the graphics overlay
layer->graphics()->append(graphic);
m_mapView->graphicsOverlays()->append(layer);
qWarning() << " END of buildDictSymbol";
} // void buildDictSymbol()
}; // MapWindow
int main(int argc, char* argv[])
{
QApplication app(argc,argv);
// ESRI :
#ifdef Q_OS_WIN
// Force usage of OpenGL ES through ANGLE on Windows
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif
// : ESRI
MapWindow * mapWin = new MapWindow();
QDesktopWidget wid;
int width = mapWin->frameGeometry().width();
int height = mapWin->frameGeometry().height();
int screenWidth = wid.screen()->width();
int screenHeight = wid.screen()->height();
mapWin->setGeometry((screenWidth / 2) - (width / 2), (screenHeight / 2) - (height / 2), width, height);
mapWin->setWindowTitle( "Crash Dictionary Symbol" );
mapWin->show();
app.setQuitOnLastWindowClosed(true);
int retval = app.exec();
delete mapWin;
return retval;
} // main