/* ** ** @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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 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